1 /* Copyright (c) 2014, 2018 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 WifiVendorCommand::handleEvent(event);
96
97 /* Parse the vendordata and get the attribute */
98 switch(mSubcmd)
99 {
100 case QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE:
101 {
102 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX
103 + 1];
104 mac_addr addr;
105 wifi_tdls_status status;
106
107 memset(&addr, 0, sizeof(mac_addr));
108 memset(&status, 0, sizeof(wifi_tdls_status));
109 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX,
110 (struct nlattr *)mVendorData,
111 mDataLen, NULL);
112
113 ALOGV("QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE Received");
114 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR])
115 {
116 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR not found",
117 __FUNCTION__);
118 return WIFI_ERROR_INVALID_ARGS;
119 }
120 memcpy(addr,
121 (u8 *)nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR]),
122 nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_MAC_ADDR]));
123
124 ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
125
126 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE])
127 {
128 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_STATE not found",
129 __FUNCTION__);
130 return WIFI_ERROR_INVALID_ARGS;
131 }
132 status.state = (wifi_tdls_state)
133 get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE]);
134 ALOGV("TDLS: State New : %d ", status.state);
135
136 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_REASON])
137 {
138 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_REASON not found",
139 __FUNCTION__);
140 return WIFI_ERROR_INVALID_ARGS;
141 }
142 status.reason = (wifi_tdls_reason)
143 get_s32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_REASON]);
144 ALOGV("TDLS: Reason : %d ", status.reason);
145
146 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL])
147 {
148 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL not found",
149 __FUNCTION__);
150 return WIFI_ERROR_INVALID_ARGS;
151 }
152 status.channel =
153 get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_CHANNEL]);
154 ALOGV("TDLS: channel : %d ", status.channel);
155
156 if (!tb_vendor[
157 QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS])
158 {
159 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS"
160 " not found", __FUNCTION__);
161 return WIFI_ERROR_INVALID_ARGS;
162 }
163 status.global_operating_class = get_u32(
164 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GLOBAL_OPERATING_CLASS]);
165 ALOGV("TDLS: global_operating_class: %d ",
166 status.global_operating_class);
167
168 if (mHandler.on_tdls_state_changed)
169 (*mHandler.on_tdls_state_changed)(addr, status);
170 else
171 ALOGE("TDLS: No Callback registered: ");
172 }
173 break;
174
175 default:
176 /* Error case should not happen print log */
177 ALOGE("%s: Wrong TDLS subcmd received %d", __FUNCTION__, mSubcmd);
178 }
179
180 return NL_SKIP;
181 }
182
handleResponse(WifiEvent & reply)183 int TdlsCommand::handleResponse(WifiEvent &reply)
184 {
185 WifiVendorCommand::handleResponse(reply);
186
187 switch(mSubcmd)
188 {
189 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS:
190 {
191 struct nlattr *tb_vendor[
192 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1];
193 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX,
194 (struct nlattr *)mVendorData,
195 mDataLen, NULL);
196
197 ALOGV("QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS Received");
198 memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
199
200 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE])
201 {
202 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE"
203 " not found", __FUNCTION__);
204 return WIFI_ERROR_INVALID_ARGS;
205 }
206 mTDLSgetStatusRspParams.state = (wifi_tdls_state)get_u32(
207 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE]);
208 ALOGV("TDLS: State : %u ", mTDLSgetStatusRspParams.state);
209
210 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON])
211 {
212 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON"
213 " not found", __FUNCTION__);
214 return WIFI_ERROR_INVALID_ARGS;
215 }
216 mTDLSgetStatusRspParams.reason = (wifi_tdls_reason)get_s32(
217 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON]);
218 ALOGV("TDLS: Reason : %d ", mTDLSgetStatusRspParams.reason);
219
220 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL])
221 {
222 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL"
223 " not found", __FUNCTION__);
224 return WIFI_ERROR_INVALID_ARGS;
225 }
226 mTDLSgetStatusRspParams.channel = get_u32(tb_vendor[
227 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL]);
228 ALOGV("TDLS: channel : %d ", mTDLSgetStatusRspParams.channel);
229
230 if (!tb_vendor[
231 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS])
232 {
233 ALOGE("%s:"
234 "QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS"
235 " not found", __FUNCTION__);
236 return WIFI_ERROR_INVALID_ARGS;
237 }
238 mTDLSgetStatusRspParams.global_operating_class =
239 get_u32(tb_vendor[
240 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS]);
241 ALOGV("TDLS: global_operating_class: %d ",
242 mTDLSgetStatusRspParams.global_operating_class);
243 }
244 break;
245 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES:
246 {
247 struct nlattr *tb_vendor[
248 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX + 1];
249 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX,
250 (struct nlattr *)mVendorData,
251 mDataLen, NULL);
252
253 memset(&mTDLSgetCaps, 0, sizeof(wifiTdlsCapabilities));
254
255 if (!tb_vendor[
256 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]
257 )
258 {
259 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
260 "MAX_CONC_SESSIONS not found", __FUNCTION__);
261 return WIFI_ERROR_INVALID_ARGS;
262 }
263 mTDLSgetCaps.maxConcurrentTdlsSessionNum = get_u32(tb_vendor[
264 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]);
265
266 if (!tb_vendor[
267 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED])
268 {
269 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
270 "FEATURES_SUPPORTED not found", __FUNCTION__);
271 return WIFI_ERROR_INVALID_ARGS;
272 }
273 mTDLSgetCaps.tdlsSupportedFeatures = get_u32(tb_vendor[
274 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED]);
275 }
276 break;
277 default :
278 ALOGE("%s: Wrong TDLS subcmd response received %d",
279 __FUNCTION__, mSubcmd);
280 }
281 return NL_SKIP;
282 }
283
284
setCallbackHandler(wifi_tdls_handler nHandler,u32 event)285 wifi_error TdlsCommand::setCallbackHandler(wifi_tdls_handler nHandler, u32 event)
286 {
287 wifi_error res;
288 mHandler = nHandler;
289
290 res = registerVendorHandler(mVendor_id, event);
291 if (res != WIFI_SUCCESS) {
292 /* Error case should not happen print log */
293 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
294 __FUNCTION__, mVendor_id, mSubcmd);
295 }
296 return res;
297 }
298
unregisterHandler(u32 subCmd)299 void TdlsCommand::unregisterHandler(u32 subCmd)
300 {
301 unregisterVendorHandler(mVendor_id, subCmd);
302 }
303
getStatusRspParams(wifi_tdls_status * status)304 void TdlsCommand::getStatusRspParams(wifi_tdls_status *status)
305 {
306 status->channel = mTDLSgetStatusRspParams.channel;
307 status->global_operating_class =
308 mTDLSgetStatusRspParams.global_operating_class;
309 status->state = mTDLSgetStatusRspParams.state;
310 status->reason = mTDLSgetStatusRspParams.reason;
311 }
312
requestResponse()313 wifi_error TdlsCommand::requestResponse()
314 {
315 return WifiCommand::requestResponse(mMsg);
316 }
317
getCapsRspParams(wifi_tdls_capabilities * caps)318 void TdlsCommand::getCapsRspParams(wifi_tdls_capabilities *caps)
319 {
320 caps->max_concurrent_tdls_session_num =
321 mTDLSgetCaps.maxConcurrentTdlsSessionNum;
322 caps->is_global_tdls_supported =
323 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_GLOBAL_TDLS_SUPPORTED);
324 caps->is_per_mac_tdls_supported =
325 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_PER_MAC_TDLS_SUPPORTED);
326 caps->is_off_channel_tdls_supported =
327 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_OFF_CHANNEL_TDLS_SUPPORTED);
328 ALOGV("TDLS capabilities:");
329 ALOGV("max_concurrent_tdls_session_numChannel : %d\n",
330 caps->max_concurrent_tdls_session_num);
331 ALOGV("is_global_tdls_supported : %d\n",
332 caps->is_global_tdls_supported);
333 ALOGV("is_per_mac_tdls_supported : %d\n",
334 caps->is_per_mac_tdls_supported);
335 ALOGV("is_off_channel_tdls_supported : %d \n",
336 caps->is_off_channel_tdls_supported);
337 }
338
339 /* wifi_enable_tdls - enables TDLS-auto mode for a specific route
340 *
341 * params specifies hints, which provide more information about
342 * why TDLS is being sought. The firmware should do its best to
343 * honor the hints before downgrading regular AP link
344 *
345 * On successful completion, must fire on_tdls_state_changed event
346 * to indicate the status of TDLS operation.
347 */
wifi_enable_tdls(wifi_interface_handle iface,mac_addr addr,wifi_tdls_params * params,wifi_tdls_handler handler)348 wifi_error wifi_enable_tdls(wifi_interface_handle iface,
349 mac_addr addr,
350 wifi_tdls_params *params,
351 wifi_tdls_handler handler)
352 {
353 wifi_error ret;
354 TdlsCommand *pTdlsCommand;
355 struct nlattr *nl_data;
356 interface_info *iinfo = getIfaceInfo(iface);
357 wifi_handle handle = getWifiHandle(iface);
358 pTdlsCommand = TdlsCommand::instance(handle);
359
360 if (pTdlsCommand == NULL) {
361 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
362 return WIFI_ERROR_UNKNOWN;
363 }
364 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE);
365
366 /* Create the message */
367 ret = pTdlsCommand->create();
368 if (ret != WIFI_SUCCESS)
369 goto cleanup;
370
371 ret = pTdlsCommand->set_iface_id(iinfo->name);
372 if (ret != WIFI_SUCCESS)
373 goto cleanup;
374
375 /* Add the attributes */
376 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
377 if (!nl_data)
378 goto cleanup;
379 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
380 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR,
381 (char *)addr, 6);
382 if (ret != WIFI_SUCCESS)
383 goto cleanup;
384
385 if (params != NULL) {
386 ALOGV("%s: Channel: %d, Global operating class: %d, "
387 "Max Latency: %dms, Min Bandwidth: %dKbps",
388 __FUNCTION__, params->channel, params->global_operating_class,
389 params->max_latency_ms, params->min_bandwidth_kbps);
390 ret = pTdlsCommand->put_u32(
391 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL,
392 params->channel);
393 if (ret != WIFI_SUCCESS)
394 goto cleanup;
395 ret = pTdlsCommand->put_u32(
396 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS,
397 params->global_operating_class);
398 if (ret != WIFI_SUCCESS)
399 goto cleanup;
400 ret = pTdlsCommand->put_u32(
401 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS,
402 params->max_latency_ms);
403 if (ret != WIFI_SUCCESS)
404 goto cleanup;
405 ret = pTdlsCommand->put_u32(
406 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS,
407 params->min_bandwidth_kbps);
408 if (ret != WIFI_SUCCESS)
409 goto cleanup;
410 }
411
412 pTdlsCommand->attr_end(nl_data);
413
414 ret = pTdlsCommand->setCallbackHandler(handler,
415 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE);
416 if (ret != WIFI_SUCCESS)
417 goto cleanup;
418
419 ret = pTdlsCommand->requestResponse();
420 if (ret != WIFI_SUCCESS)
421 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
422
423 cleanup:
424 return ret;
425 }
426
427 /* wifi_disable_tdls - disables TDLS-auto mode for a specific route
428 *
429 * This terminates any existing TDLS with addr device, and frees the
430 * device resources to make TDLS connections on new routes.
431 *
432 * DON'T fire any more events on 'handler' specified in earlier call to
433 * wifi_enable_tdls after this action.
434 */
wifi_disable_tdls(wifi_interface_handle iface,mac_addr addr)435 wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr)
436 {
437 wifi_error ret;
438 TdlsCommand *pTdlsCommand;
439 struct nlattr *nl_data;
440 interface_info *iinfo = getIfaceInfo(iface);
441 wifi_handle handle = getWifiHandle(iface);
442 pTdlsCommand = TdlsCommand::instance(handle);
443
444 if (pTdlsCommand == NULL) {
445 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
446 return WIFI_ERROR_UNKNOWN;
447 }
448 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE);
449
450 /* Create the message */
451 ret = pTdlsCommand->create();
452 if (ret != WIFI_SUCCESS)
453 goto cleanup;
454
455 ret = pTdlsCommand->set_iface_id(iinfo->name);
456 if (ret != WIFI_SUCCESS)
457 goto cleanup;
458 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
459 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
460
461 /* Add the attributes */
462 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
463 if (!nl_data)
464 goto cleanup;
465 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR,
466 (char *)addr, 6);
467 if (ret != WIFI_SUCCESS)
468 goto cleanup;
469 pTdlsCommand->attr_end(nl_data);
470
471 ret = pTdlsCommand->requestResponse();
472 if (ret != WIFI_SUCCESS)
473 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
474
475 cleanup:
476 delete pTdlsCommand;
477 return ret;
478 }
479
480 /* wifi_get_tdls_status - allows getting the status of TDLS for a specific
481 * route
482 */
wifi_get_tdls_status(wifi_interface_handle iface,mac_addr addr,wifi_tdls_status * status)483 wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
484 wifi_tdls_status *status)
485 {
486 wifi_error ret;
487 TdlsCommand *pTdlsCommand;
488 struct nlattr *nl_data;
489 interface_info *iinfo = getIfaceInfo(iface);
490 wifi_handle handle = getWifiHandle(iface);
491 pTdlsCommand = TdlsCommand::instance(handle);
492
493 if (pTdlsCommand == NULL) {
494 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
495 return WIFI_ERROR_UNKNOWN;
496 }
497 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS);
498
499 /* Create the message */
500 ret = pTdlsCommand->create();
501 if (ret != WIFI_SUCCESS)
502 goto cleanup;
503
504 ret = pTdlsCommand->set_iface_id(iinfo->name);
505 if (ret != WIFI_SUCCESS)
506 goto cleanup;
507 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
508
509 /* Add the attributes */
510 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
511 if (!nl_data)
512 goto cleanup;
513 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR,
514 (char *)addr, 6);
515 if (ret != WIFI_SUCCESS)
516 goto cleanup;
517 pTdlsCommand->attr_end(nl_data);
518
519 ret = pTdlsCommand->requestResponse();
520 if (ret != WIFI_SUCCESS)
521 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
522
523 pTdlsCommand->getStatusRspParams(status);
524
525 cleanup:
526 return ret;
527 }
528
529 /* return the current HW + Firmware combination's TDLS capabilities */
wifi_get_tdls_capabilities(wifi_interface_handle iface,wifi_tdls_capabilities * capabilities)530 wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
531 wifi_tdls_capabilities *capabilities)
532 {
533 wifi_error ret;
534 TdlsCommand *pTdlsCommand;
535
536 if (capabilities == NULL) {
537 ALOGE("%s: capabilities is NULL", __FUNCTION__);
538 return WIFI_ERROR_INVALID_ARGS;
539 }
540
541 interface_info *iinfo = getIfaceInfo(iface);
542 wifi_handle handle = getWifiHandle(iface);
543 pTdlsCommand = TdlsCommand::instance(handle);
544
545 if (pTdlsCommand == NULL) {
546 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
547 return WIFI_ERROR_UNKNOWN;
548 }
549 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES);
550
551 /* Create the message */
552 ret = pTdlsCommand->create();
553 if (ret != WIFI_SUCCESS)
554 goto cleanup;
555
556 ret = pTdlsCommand->set_iface_id(iinfo->name);
557 if (ret != WIFI_SUCCESS)
558 goto cleanup;
559
560 ret = pTdlsCommand->requestResponse();
561 if (ret != WIFI_SUCCESS) {
562 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
563 goto cleanup;
564 }
565 pTdlsCommand->getCapsRspParams(capabilities);
566
567 cleanup:
568 if (ret != WIFI_SUCCESS)
569 memset(capabilities, 0, sizeof(wifi_tdls_capabilities));
570 delete pTdlsCommand;
571 return ret;
572 }
573