1 /* Copyright (c) 2014, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in
10 * the documentation and/or other materials provided with the
11 * distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "sync.h"
30
31 #define LOG_TAG "WifiHAL"
32
33 #include <utils/Log.h>
34
35 #include "wifi_hal.h"
36 #include "common.h"
37 #include "cpp_bindings.h"
38 #include "tdlsCommand.h"
39 #include "vendor_definitions.h"
40
41 /* Singleton Static Instance */
42 TdlsCommand* TdlsCommand::mTdlsCommandInstance = NULL;
TdlsCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)43 TdlsCommand::TdlsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
44 : WifiVendorCommand(handle, id, vendor_id, subcmd)
45 {
46 memset(&mHandler, 0, sizeof(mHandler));
47 memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
48 mRequestId = 0;
49 }
50
~TdlsCommand()51 TdlsCommand::~TdlsCommand()
52 {
53 mTdlsCommandInstance = NULL;
54 unregisterVendorHandler(mVendor_id, mSubcmd);
55 }
56
instance(wifi_handle handle)57 TdlsCommand* TdlsCommand::instance(wifi_handle handle)
58 {
59 if (handle == NULL) {
60 ALOGE("Interface Handle is invalid");
61 return NULL;
62 }
63 if (mTdlsCommandInstance == NULL) {
64 mTdlsCommandInstance = new TdlsCommand(handle, 0,
65 OUI_QCA,
66 QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE);
67 ALOGV("TdlsCommand %p created", mTdlsCommandInstance);
68 return mTdlsCommandInstance;
69 }
70 else
71 {
72 if (handle != getWifiHandle(mTdlsCommandInstance->mInfo))
73 {
74 /* upper layer must have cleaned up the handle and reinitialized,
75 so we need to update the same */
76 ALOGV("Handle different, update the handle");
77 mTdlsCommandInstance->mInfo = (hal_info *)handle;
78 }
79 }
80 ALOGV("TdlsCommand %p created already", mTdlsCommandInstance);
81 return mTdlsCommandInstance;
82 }
83
setSubCmd(u32 subcmd)84 void TdlsCommand::setSubCmd(u32 subcmd)
85 {
86 mSubcmd = subcmd;
87 }
88
89 /* This function will be the main handler for incoming event SUBCMD_TDLS
90 * Call the appropriate callback handler after parsing the vendor data.
91 */
handleEvent(WifiEvent & event)92 int TdlsCommand::handleEvent(WifiEvent &event)
93 {
94 ALOGV("Got a TDLS message from Driver");
95 unsigned i=0;
96 u32 status;
97 int ret = WIFI_SUCCESS;
98 WifiVendorCommand::handleEvent(event);
99
100 /* Parse the vendordata and get the attribute */
101 switch(mSubcmd)
102 {
103 case QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE:
104 {
105 wifi_request_id id;
106 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX
107 + 1];
108 mac_addr addr;
109 wifi_tdls_status status;
110 int rem;
111
112 memset(&addr, 0, sizeof(mac_addr));
113 memset(&status, 0, sizeof(wifi_tdls_status));
114 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX,
115 (struct nlattr *)mVendorData,
116 mDataLen, NULL);
117
118 ALOGV("QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE Received");
119 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR])
120 {
121 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR not found",
122 __FUNCTION__);
123 return WIFI_ERROR_INVALID_ARGS;
124 }
125 memcpy(addr,
126 (u8 *)nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR]),
127 nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR]));
128
129 ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
130
131 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE])
132 {
133 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_STATE not found",
134 __FUNCTION__);
135 return WIFI_ERROR_INVALID_ARGS;
136 }
137 status.state = (wifi_tdls_state)
138 get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE]);
139 ALOGV("TDLS: State New : %d ", status.state);
140
141 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_REASON])
142 {
143 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_REASON not found",
144 __FUNCTION__);
145 return WIFI_ERROR_INVALID_ARGS;
146 }
147 status.reason = (wifi_tdls_reason)
148 get_s32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_REASON]);
149 ALOGV("TDLS: Reason : %d ", status.reason);
150
151 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL])
152 {
153 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL not found",
154 __FUNCTION__);
155 return WIFI_ERROR_INVALID_ARGS;
156 }
157 status.channel =
158 get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL]);
159 ALOGV("TDLS: channel : %d ", status.channel);
160
161 if (!tb_vendor[
162 QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS])
163 {
164 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS"
165 " not found", __FUNCTION__);
166 return WIFI_ERROR_INVALID_ARGS;
167 }
168 status.global_operating_class = get_u32(
169 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS]);
170 ALOGV("TDLS: global_operating_class: %d ",
171 status.global_operating_class);
172
173 if (mHandler.on_tdls_state_changed)
174 (*mHandler.on_tdls_state_changed)(addr, status);
175 else
176 ALOGE("TDLS: No Callback registered: ");
177 }
178 break;
179
180 default:
181 /* Error case should not happen print log */
182 ALOGE("%s: Wrong TDLS subcmd received %d", __FUNCTION__, mSubcmd);
183 }
184
185 return NL_SKIP;
186 }
187
handleResponse(WifiEvent & reply)188 int TdlsCommand::handleResponse(WifiEvent &reply)
189 {
190 u32 status;
191 int i = 0;
192 WifiVendorCommand::handleResponse(reply);
193
194 switch(mSubcmd)
195 {
196 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS:
197 {
198 wifi_request_id id;
199 struct nlattr *tb_vendor[
200 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1];
201 int rem;
202 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX,
203 (struct nlattr *)mVendorData,
204 mDataLen, NULL);
205
206 ALOGV("QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS Received");
207 memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
208
209 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE])
210 {
211 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE"
212 " not found", __FUNCTION__);
213 return WIFI_ERROR_INVALID_ARGS;
214 }
215 mTDLSgetStatusRspParams.state = (wifi_tdls_state)get_u32(
216 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE]);
217 ALOGV("TDLS: State : %u ", mTDLSgetStatusRspParams.state);
218
219 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON])
220 {
221 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON"
222 " not found", __FUNCTION__);
223 return WIFI_ERROR_INVALID_ARGS;
224 }
225 mTDLSgetStatusRspParams.reason = (wifi_tdls_reason)get_s32(
226 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON]);
227 ALOGV("TDLS: Reason : %d ", mTDLSgetStatusRspParams.reason);
228
229 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL])
230 {
231 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL"
232 " not found", __FUNCTION__);
233 return WIFI_ERROR_INVALID_ARGS;
234 }
235 mTDLSgetStatusRspParams.channel = get_u32(tb_vendor[
236 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL]);
237 ALOGV("TDLS: channel : %d ", mTDLSgetStatusRspParams.channel);
238
239 if (!tb_vendor[
240 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS])
241 {
242 ALOGE("%s:"
243 "QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS"
244 " not found", __FUNCTION__);
245 return WIFI_ERROR_INVALID_ARGS;
246 }
247 mTDLSgetStatusRspParams.global_operating_class =
248 get_u32(tb_vendor[
249 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS]);
250 ALOGV("TDLS: global_operating_class: %d ",
251 mTDLSgetStatusRspParams.global_operating_class);
252 }
253 break;
254 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES:
255 {
256 struct nlattr *tb_vendor[
257 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX + 1];
258 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX,
259 (struct nlattr *)mVendorData,
260 mDataLen, NULL);
261
262 memset(&mTDLSgetCaps, 0, sizeof(wifiTdlsCapabilities));
263
264 if (!tb_vendor[
265 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]
266 )
267 {
268 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
269 "MAX_CONC_SESSIONS not found", __FUNCTION__);
270 return WIFI_ERROR_INVALID_ARGS;
271 }
272 mTDLSgetCaps.maxConcurrentTdlsSessionNum = get_u32(tb_vendor[
273 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]);
274
275 if (!tb_vendor[
276 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED])
277 {
278 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
279 "FEATURES_SUPPORTED not found", __FUNCTION__);
280 return WIFI_ERROR_INVALID_ARGS;
281 }
282 mTDLSgetCaps.tdlsSupportedFeatures = get_u32(tb_vendor[
283 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED]);
284 }
285 break;
286 default :
287 ALOGE("%s: Wrong TDLS subcmd response received %d",
288 __FUNCTION__, mSubcmd);
289 }
290 return NL_SKIP;
291 }
292
293
setCallbackHandler(wifi_tdls_handler nHandler,u32 event)294 int TdlsCommand::setCallbackHandler(wifi_tdls_handler nHandler, u32 event)
295 {
296 int res = 0;
297 mHandler = nHandler;
298 res = registerVendorHandler(mVendor_id, event);
299 if (res != 0) {
300 /* Error case should not happen print log */
301 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
302 __FUNCTION__, mVendor_id, mSubcmd);
303 }
304 return res;
305 }
306
unregisterHandler(u32 subCmd)307 void TdlsCommand::unregisterHandler(u32 subCmd)
308 {
309 unregisterVendorHandler(mVendor_id, subCmd);
310 }
311
getStatusRspParams(wifi_tdls_status * status)312 void TdlsCommand::getStatusRspParams(wifi_tdls_status *status)
313 {
314 status->channel = mTDLSgetStatusRspParams.channel;
315 status->global_operating_class =
316 mTDLSgetStatusRspParams.global_operating_class;
317 status->state = mTDLSgetStatusRspParams.state;
318 status->reason = mTDLSgetStatusRspParams.reason;
319 }
320
requestResponse()321 int TdlsCommand::requestResponse()
322 {
323 return WifiCommand::requestResponse(mMsg);
324 }
325
getCapsRspParams(wifi_tdls_capabilities * caps)326 void TdlsCommand::getCapsRspParams(wifi_tdls_capabilities *caps)
327 {
328 caps->max_concurrent_tdls_session_num =
329 mTDLSgetCaps.maxConcurrentTdlsSessionNum;
330 caps->is_global_tdls_supported =
331 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_GLOBAL_TDLS_SUPPORTED);
332 caps->is_per_mac_tdls_supported =
333 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_PER_MAC_TDLS_SUPPORTED);
334 caps->is_off_channel_tdls_supported =
335 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_OFF_CHANNEL_TDLS_SUPPORTED);
336 ALOGV("TDLS capabilities:");
337 ALOGV("max_concurrent_tdls_session_numChannel : %d\n",
338 caps->max_concurrent_tdls_session_num);
339 ALOGV("is_global_tdls_supported : %d\n",
340 caps->is_global_tdls_supported);
341 ALOGV("is_per_mac_tdls_supported : %d\n",
342 caps->is_per_mac_tdls_supported);
343 ALOGV("is_off_channel_tdls_supported : %d \n",
344 caps->is_off_channel_tdls_supported);
345 }
346
347 /* wifi_enable_tdls - enables TDLS-auto mode for a specific route
348 *
349 * params specifies hints, which provide more information about
350 * why TDLS is being sought. The firmware should do its best to
351 * honor the hints before downgrading regular AP link
352 *
353 * On successful completion, must fire on_tdls_state_changed event
354 * to indicate the status of TDLS operation.
355 */
wifi_enable_tdls(wifi_interface_handle iface,mac_addr addr,wifi_tdls_params * params,wifi_tdls_handler handler)356 wifi_error wifi_enable_tdls(wifi_interface_handle iface,
357 mac_addr addr,
358 wifi_tdls_params *params,
359 wifi_tdls_handler handler)
360 {
361 int ret = 0;
362 TdlsCommand *pTdlsCommand;
363 struct nlattr *nl_data;
364 interface_info *iinfo = getIfaceInfo(iface);
365 wifi_handle handle = getWifiHandle(iface);
366 pTdlsCommand = TdlsCommand::instance(handle);
367
368 if (pTdlsCommand == NULL) {
369 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
370 return WIFI_ERROR_UNKNOWN;
371 }
372 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE);
373
374 /* Create the message */
375 ret = pTdlsCommand->create();
376 if (ret < 0)
377 goto cleanup;
378
379 ret = pTdlsCommand->set_iface_id(iinfo->name);
380 if (ret < 0)
381 goto cleanup;
382
383 /* Add the attributes */
384 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
385 if (!nl_data)
386 goto cleanup;
387 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
388 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR,
389 (char *)addr, 6);
390 if (ret < 0)
391 goto cleanup;
392
393 if (params != NULL) {
394 ALOGV("%s: Channel: %d, Global operating class: %d, "
395 "Max Latency: %dms, Min Bandwidth: %dKbps",
396 __FUNCTION__, params->channel, params->global_operating_class,
397 params->max_latency_ms, params->min_bandwidth_kbps);
398 ret = pTdlsCommand->put_u32(
399 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL,
400 params->channel) |
401 pTdlsCommand->put_u32(
402 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS,
403 params->global_operating_class) |
404 pTdlsCommand->put_u32(
405 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS,
406 params->max_latency_ms) |
407 pTdlsCommand->put_u32(
408 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS,
409 params->min_bandwidth_kbps);
410 if (ret < 0)
411 goto cleanup;
412 }
413
414 pTdlsCommand->attr_end(nl_data);
415
416 ret = pTdlsCommand->setCallbackHandler(handler,
417 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE);
418 if (ret < 0)
419 goto cleanup;
420
421 ret = pTdlsCommand->requestResponse();
422 if (ret != 0) {
423 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
424 }
425
426 cleanup:
427 return (wifi_error)ret;
428 }
429
430 /* wifi_disable_tdls - disables TDLS-auto mode for a specific route
431 *
432 * This terminates any existing TDLS with addr device, and frees the
433 * device resources to make TDLS connections on new routes.
434 *
435 * DON'T fire any more events on 'handler' specified in earlier call to
436 * wifi_enable_tdls after this action.
437 */
wifi_disable_tdls(wifi_interface_handle iface,mac_addr addr)438 wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr)
439 {
440 int ret = 0;
441 TdlsCommand *pTdlsCommand;
442 struct nlattr *nl_data;
443 interface_info *iinfo = getIfaceInfo(iface);
444 wifi_handle handle = getWifiHandle(iface);
445 pTdlsCommand = TdlsCommand::instance(handle);
446
447 if (pTdlsCommand == NULL) {
448 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
449 return WIFI_ERROR_UNKNOWN;
450 }
451 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE);
452
453 /* Create the message */
454 ret = pTdlsCommand->create();
455 if (ret < 0)
456 goto cleanup;
457
458 ret = pTdlsCommand->set_iface_id(iinfo->name);
459 if (ret < 0)
460 goto cleanup;
461 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
462 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
463
464 /* Add the attributes */
465 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
466 if (!nl_data)
467 goto cleanup;
468 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR,
469 (char *)addr, 6);
470 if (ret < 0)
471 goto cleanup;
472 pTdlsCommand->attr_end(nl_data);
473
474 ret = pTdlsCommand->requestResponse();
475 if (ret != 0) {
476 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
477 }
478
479 cleanup:
480 delete pTdlsCommand;
481 return (wifi_error)ret;
482 }
483
484 /* wifi_get_tdls_status - allows getting the status of TDLS for a specific
485 * route
486 */
wifi_get_tdls_status(wifi_interface_handle iface,mac_addr addr,wifi_tdls_status * status)487 wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
488 wifi_tdls_status *status)
489 {
490 int ret = 0;
491 TdlsCommand *pTdlsCommand;
492 struct nlattr *nl_data;
493 interface_info *iinfo = getIfaceInfo(iface);
494 wifi_handle handle = getWifiHandle(iface);
495 pTdlsCommand = TdlsCommand::instance(handle);
496
497 if (pTdlsCommand == NULL) {
498 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
499 return WIFI_ERROR_UNKNOWN;
500 }
501 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS);
502
503 /* Create the message */
504 ret = pTdlsCommand->create();
505 if (ret < 0)
506 goto cleanup;
507
508 ret = pTdlsCommand->set_iface_id(iinfo->name);
509 if (ret < 0)
510 goto cleanup;
511 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
512
513 /* Add the attributes */
514 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
515 if (!nl_data)
516 goto cleanup;
517 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR,
518 (char *)addr, 6);
519 if (ret < 0)
520 goto cleanup;
521 pTdlsCommand->attr_end(nl_data);
522
523 ret = pTdlsCommand->requestResponse();
524 if (ret != 0) {
525 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
526 }
527 pTdlsCommand->getStatusRspParams(status);
528
529 cleanup:
530 return (wifi_error)ret;
531 }
532
533 /* return the current HW + Firmware combination's TDLS capabilities */
wifi_get_tdls_capabilities(wifi_interface_handle iface,wifi_tdls_capabilities * capabilities)534 wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
535 wifi_tdls_capabilities *capabilities)
536 {
537 int ret = 0;
538 TdlsCommand *pTdlsCommand;
539
540 if (capabilities == NULL) {
541 ALOGE("%s: capabilities is NULL", __FUNCTION__);
542 return WIFI_ERROR_INVALID_ARGS;
543 }
544
545 interface_info *iinfo = getIfaceInfo(iface);
546 wifi_handle handle = getWifiHandle(iface);
547 pTdlsCommand = TdlsCommand::instance(handle);
548
549 if (pTdlsCommand == NULL) {
550 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
551 return WIFI_ERROR_UNKNOWN;
552 }
553 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES);
554
555 /* Create the message */
556 ret = pTdlsCommand->create();
557 if (ret < 0)
558 goto cleanup;
559
560 ret = pTdlsCommand->set_iface_id(iinfo->name);
561 if (ret < 0)
562 goto cleanup;
563
564 ret = pTdlsCommand->requestResponse();
565 if (ret != 0) {
566 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
567 goto cleanup;
568 }
569 pTdlsCommand->getCapsRspParams(capabilities);
570
571 cleanup:
572 if (ret < 0)
573 memset(capabilities, 0, sizeof(wifi_tdls_capabilities));
574 delete pTdlsCommand;
575 return (wifi_error)ret;
576 }
577