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 * Changes from Qualcomm Innovation Center are provided under the following license:
29
30 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
31 * SPDX-License-Identifier: BSD-3-Clause-Clear
32 */
33
34 #include "sync.h"
35
36 #define LOG_TAG "WifiHAL"
37
38 #include <utils/Log.h>
39
40 #include <hardware_legacy/wifi_hal.h>
41 #include "common.h"
42 #include "cpp_bindings.h"
43 #include "tdlsCommand.h"
44 #include "vendor_definitions.h"
45
46 /* Singleton Static Instance */
47 TdlsCommand* TdlsCommand::mTdlsCommandInstance = NULL;
TdlsCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)48 TdlsCommand::TdlsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
49 : WifiVendorCommand(handle, id, vendor_id, subcmd)
50 {
51 memset(&mHandler, 0, sizeof(mHandler));
52 memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
53 mRequestId = 0;
54 }
55
~TdlsCommand()56 TdlsCommand::~TdlsCommand()
57 {
58 mTdlsCommandInstance = NULL;
59 unregisterVendorHandler(mVendor_id, mSubcmd);
60 }
61
instance(wifi_handle handle)62 TdlsCommand* TdlsCommand::instance(wifi_handle handle)
63 {
64 if (handle == NULL) {
65 ALOGE("Interface Handle is invalid");
66 return NULL;
67 }
68 if (mTdlsCommandInstance == NULL) {
69 mTdlsCommandInstance = new TdlsCommand(handle, 0,
70 OUI_QCA,
71 QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE);
72 ALOGV("TdlsCommand %p created", mTdlsCommandInstance);
73 return mTdlsCommandInstance;
74 }
75 else
76 {
77 if (handle != getWifiHandle(mTdlsCommandInstance->mInfo))
78 {
79 /* upper layer must have cleaned up the handle and reinitialized,
80 so we need to update the same */
81 ALOGV("Handle different, update the handle");
82 mTdlsCommandInstance->mInfo = (hal_info *)handle;
83 }
84 }
85 ALOGV("TdlsCommand %p created already", mTdlsCommandInstance);
86 return mTdlsCommandInstance;
87 }
88
setSubCmd(u32 subcmd)89 void TdlsCommand::setSubCmd(u32 subcmd)
90 {
91 mSubcmd = subcmd;
92 }
93
94 /* This function will be the main handler for incoming event SUBCMD_TDLS
95 * Call the appropriate callback handler after parsing the vendor data.
96 */
handleEvent(WifiEvent & event)97 int TdlsCommand::handleEvent(WifiEvent &event)
98 {
99 ALOGV("Got a TDLS message from Driver");
100 WifiVendorCommand::handleEvent(event);
101
102 /* Parse the vendordata and get the attribute */
103 switch(mSubcmd)
104 {
105 case QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE:
106 {
107 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX
108 + 1];
109 mac_addr addr;
110 wifi_tdls_status status;
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 WifiVendorCommand::handleResponse(reply);
191
192 switch(mSubcmd)
193 {
194 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS:
195 {
196 struct nlattr *tb_vendor[
197 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1];
198 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX,
199 (struct nlattr *)mVendorData,
200 mDataLen, NULL);
201
202 ALOGV("QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS Received");
203 memset(&mTDLSgetStatusRspParams, 0, sizeof(wifi_tdls_status));
204
205 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE])
206 {
207 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE"
208 " not found", __FUNCTION__);
209 return WIFI_ERROR_INVALID_ARGS;
210 }
211 mTDLSgetStatusRspParams.state = (wifi_tdls_state)get_u32(
212 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE]);
213 ALOGV("TDLS: State : %u ", mTDLSgetStatusRspParams.state);
214
215 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON])
216 {
217 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON"
218 " not found", __FUNCTION__);
219 return WIFI_ERROR_INVALID_ARGS;
220 }
221 mTDLSgetStatusRspParams.reason = (wifi_tdls_reason)get_s32(
222 tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON]);
223 ALOGV("TDLS: Reason : %d ", mTDLSgetStatusRspParams.reason);
224
225 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL])
226 {
227 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL"
228 " not found", __FUNCTION__);
229 return WIFI_ERROR_INVALID_ARGS;
230 }
231 mTDLSgetStatusRspParams.channel = get_u32(tb_vendor[
232 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL]);
233 ALOGV("TDLS: channel : %d ", mTDLSgetStatusRspParams.channel);
234
235 if (!tb_vendor[
236 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS])
237 {
238 ALOGE("%s:"
239 "QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS"
240 " not found", __FUNCTION__);
241 return WIFI_ERROR_INVALID_ARGS;
242 }
243 mTDLSgetStatusRspParams.global_operating_class =
244 get_u32(tb_vendor[
245 QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS]);
246 ALOGV("TDLS: global_operating_class: %d ",
247 mTDLSgetStatusRspParams.global_operating_class);
248 }
249 break;
250 case QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES:
251 {
252 struct nlattr *tb_vendor[
253 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX + 1];
254 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX,
255 (struct nlattr *)mVendorData,
256 mDataLen, NULL);
257
258 memset(&mTDLSgetCaps, 0, sizeof(wifiTdlsCapabilities));
259
260 if (!tb_vendor[
261 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]
262 )
263 {
264 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
265 "MAX_CONC_SESSIONS not found", __FUNCTION__);
266 return WIFI_ERROR_INVALID_ARGS;
267 }
268 mTDLSgetCaps.maxConcurrentTdlsSessionNum = get_u32(tb_vendor[
269 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS]);
270
271 if (!tb_vendor[
272 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED])
273 {
274 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_"
275 "FEATURES_SUPPORTED not found", __FUNCTION__);
276 return WIFI_ERROR_INVALID_ARGS;
277 }
278 mTDLSgetCaps.tdlsSupportedFeatures = get_u32(tb_vendor[
279 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED]);
280 }
281 break;
282 default :
283 ALOGE("%s: Wrong TDLS subcmd response received %d",
284 __FUNCTION__, mSubcmd);
285 }
286 return NL_SKIP;
287 }
288
289
setCallbackHandler(wifi_tdls_handler nHandler,u32 event)290 wifi_error TdlsCommand::setCallbackHandler(wifi_tdls_handler nHandler, u32 event)
291 {
292 wifi_error res;
293 mHandler = nHandler;
294
295 res = registerVendorHandler(mVendor_id, event);
296 if (res != WIFI_SUCCESS) {
297 /* Error case should not happen print log */
298 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
299 __FUNCTION__, mVendor_id, mSubcmd);
300 }
301 return res;
302 }
303
unregisterHandler(u32 subCmd)304 void TdlsCommand::unregisterHandler(u32 subCmd)
305 {
306 unregisterVendorHandler(mVendor_id, subCmd);
307 }
308
getStatusRspParams(wifi_tdls_status * status)309 void TdlsCommand::getStatusRspParams(wifi_tdls_status *status)
310 {
311 status->channel = mTDLSgetStatusRspParams.channel;
312 status->global_operating_class =
313 mTDLSgetStatusRspParams.global_operating_class;
314 status->state = mTDLSgetStatusRspParams.state;
315 status->reason = mTDLSgetStatusRspParams.reason;
316 }
317
requestResponse()318 wifi_error TdlsCommand::requestResponse()
319 {
320 return WifiCommand::requestResponse(mMsg);
321 }
322
getCapsRspParams(wifi_tdls_capabilities * caps)323 void TdlsCommand::getCapsRspParams(wifi_tdls_capabilities *caps)
324 {
325 caps->max_concurrent_tdls_session_num =
326 mTDLSgetCaps.maxConcurrentTdlsSessionNum;
327 caps->is_global_tdls_supported =
328 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_GLOBAL_TDLS_SUPPORTED);
329 caps->is_per_mac_tdls_supported =
330 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_PER_MAC_TDLS_SUPPORTED);
331 caps->is_off_channel_tdls_supported =
332 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_OFF_CHANNEL_TDLS_SUPPORTED);
333 ALOGV("TDLS capabilities:");
334 ALOGV("max_concurrent_tdls_session_numChannel : %d\n",
335 caps->max_concurrent_tdls_session_num);
336 ALOGV("is_global_tdls_supported : %d\n",
337 caps->is_global_tdls_supported);
338 ALOGV("is_per_mac_tdls_supported : %d\n",
339 caps->is_per_mac_tdls_supported);
340 ALOGV("is_off_channel_tdls_supported : %d \n",
341 caps->is_off_channel_tdls_supported);
342 }
343
344 /* wifi_enable_tdls - enables TDLS-auto mode for a specific route
345 *
346 * params specifies hints, which provide more information about
347 * why TDLS is being sought. The firmware should do its best to
348 * honor the hints before downgrading regular AP link
349 *
350 * On successful completion, must fire on_tdls_state_changed event
351 * to indicate the status of TDLS operation.
352 */
wifi_enable_tdls(wifi_interface_handle iface,mac_addr addr,wifi_tdls_params * params,wifi_tdls_handler handler)353 wifi_error wifi_enable_tdls(wifi_interface_handle iface,
354 mac_addr addr,
355 wifi_tdls_params *params,
356 wifi_tdls_handler handler)
357 {
358 wifi_error ret;
359 TdlsCommand *pTdlsCommand;
360 struct nlattr *nl_data;
361 interface_info *iinfo = getIfaceInfo(iface);
362 wifi_handle handle = getWifiHandle(iface);
363 pTdlsCommand = TdlsCommand::instance(handle);
364
365 if (pTdlsCommand == NULL) {
366 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
367 return WIFI_ERROR_UNKNOWN;
368 }
369 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE);
370
371 /* Create the message */
372 ret = pTdlsCommand->create();
373 if (ret != WIFI_SUCCESS)
374 goto cleanup;
375
376 ret = pTdlsCommand->set_iface_id(iinfo->name);
377 if (ret != WIFI_SUCCESS)
378 goto cleanup;
379
380 /* Add the attributes */
381 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
382 if (!nl_data){
383 ret = WIFI_ERROR_UNKNOWN;
384 goto cleanup;
385 }
386 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
387 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR,
388 (char *)addr, 6);
389 if (ret != WIFI_SUCCESS)
390 goto cleanup;
391
392 if (params != NULL) {
393 ALOGV("%s: Channel: %d, Global operating class: %d, "
394 "Max Latency: %dms, Min Bandwidth: %dKbps",
395 __FUNCTION__, params->channel, params->global_operating_class,
396 params->max_latency_ms, params->min_bandwidth_kbps);
397 ret = pTdlsCommand->put_u32(
398 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL,
399 params->channel);
400 if (ret != WIFI_SUCCESS)
401 goto cleanup;
402 ret = pTdlsCommand->put_u32(
403 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS,
404 params->global_operating_class);
405 if (ret != WIFI_SUCCESS)
406 goto cleanup;
407 ret = pTdlsCommand->put_u32(
408 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS,
409 params->max_latency_ms);
410 if (ret != WIFI_SUCCESS)
411 goto cleanup;
412 ret = pTdlsCommand->put_u32(
413 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS,
414 params->min_bandwidth_kbps);
415 if (ret != WIFI_SUCCESS)
416 goto cleanup;
417 }
418
419 pTdlsCommand->attr_end(nl_data);
420
421 ret = pTdlsCommand->setCallbackHandler(handler,
422 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE);
423 if (ret != WIFI_SUCCESS)
424 goto cleanup;
425
426 ret = pTdlsCommand->requestResponse();
427 if (ret != WIFI_SUCCESS)
428 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
429
430 cleanup:
431 return ret;
432 }
433
434 /* wifi_disable_tdls - disables TDLS-auto mode for a specific route
435 *
436 * This terminates any existing TDLS with addr device, and frees the
437 * device resources to make TDLS connections on new routes.
438 *
439 * DON'T fire any more events on 'handler' specified in earlier call to
440 * wifi_enable_tdls after this action.
441 */
wifi_disable_tdls(wifi_interface_handle iface,mac_addr addr)442 wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr)
443 {
444 wifi_error ret;
445 TdlsCommand *pTdlsCommand;
446 struct nlattr *nl_data;
447 interface_info *iinfo = getIfaceInfo(iface);
448 wifi_handle handle = getWifiHandle(iface);
449 pTdlsCommand = TdlsCommand::instance(handle);
450
451 if (pTdlsCommand == NULL) {
452 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
453 return WIFI_ERROR_UNKNOWN;
454 }
455 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE);
456
457 /* Create the message */
458 ret = pTdlsCommand->create();
459 if (ret != WIFI_SUCCESS)
460 goto cleanup;
461
462 ret = pTdlsCommand->set_iface_id(iinfo->name);
463 if (ret != WIFI_SUCCESS)
464 goto cleanup;
465 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
466 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr));
467
468 /* Add the attributes */
469 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
470 if (!nl_data){
471 ret = WIFI_ERROR_UNKNOWN;
472 goto cleanup;
473 }
474 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR,
475 (char *)addr, 6);
476 if (ret != WIFI_SUCCESS)
477 goto cleanup;
478 pTdlsCommand->attr_end(nl_data);
479
480 ret = pTdlsCommand->requestResponse();
481 if (ret != WIFI_SUCCESS)
482 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
483
484 cleanup:
485 delete pTdlsCommand;
486 return ret;
487 }
488
489 /* wifi_get_tdls_status - allows getting the status of TDLS for a specific
490 * route
491 */
wifi_get_tdls_status(wifi_interface_handle iface,mac_addr addr,wifi_tdls_status * status)492 wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
493 wifi_tdls_status *status)
494 {
495 wifi_error ret;
496 TdlsCommand *pTdlsCommand;
497 struct nlattr *nl_data;
498 interface_info *iinfo = getIfaceInfo(iface);
499 wifi_handle handle = getWifiHandle(iface);
500 pTdlsCommand = TdlsCommand::instance(handle);
501
502 if (pTdlsCommand == NULL) {
503 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
504 return WIFI_ERROR_UNKNOWN;
505 }
506 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS);
507
508 /* Create the message */
509 ret = pTdlsCommand->create();
510 if (ret != WIFI_SUCCESS)
511 goto cleanup;
512
513 ret = pTdlsCommand->set_iface_id(iinfo->name);
514 if (ret != WIFI_SUCCESS)
515 goto cleanup;
516 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret);
517
518 /* Add the attributes */
519 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
520 if (!nl_data){
521 ret = WIFI_ERROR_UNKNOWN;
522 goto cleanup;
523 }
524 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR,
525 (char *)addr, 6);
526 if (ret != WIFI_SUCCESS)
527 goto cleanup;
528 pTdlsCommand->attr_end(nl_data);
529
530 ret = pTdlsCommand->requestResponse();
531 if (ret != WIFI_SUCCESS)
532 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
533
534 pTdlsCommand->getStatusRspParams(status);
535
536 cleanup:
537 return ret;
538 }
539
540 /* return the current HW + Firmware combination's TDLS capabilities */
wifi_get_tdls_capabilities(wifi_interface_handle iface,wifi_tdls_capabilities * capabilities)541 wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
542 wifi_tdls_capabilities *capabilities)
543 {
544 wifi_error ret;
545 TdlsCommand *pTdlsCommand;
546
547 if (capabilities == NULL) {
548 ALOGE("%s: capabilities is NULL", __FUNCTION__);
549 return WIFI_ERROR_INVALID_ARGS;
550 }
551
552 interface_info *iinfo = getIfaceInfo(iface);
553 wifi_handle handle = getWifiHandle(iface);
554 pTdlsCommand = TdlsCommand::instance(handle);
555
556 if (pTdlsCommand == NULL) {
557 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__);
558 return WIFI_ERROR_UNKNOWN;
559 }
560 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES);
561
562 /* Create the message */
563 ret = pTdlsCommand->create();
564 if (ret != WIFI_SUCCESS)
565 goto cleanup;
566
567 ret = pTdlsCommand->set_iface_id(iinfo->name);
568 if (ret != WIFI_SUCCESS)
569 goto cleanup;
570
571 ret = pTdlsCommand->requestResponse();
572 if (ret != WIFI_SUCCESS) {
573 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
574 goto cleanup;
575 }
576 pTdlsCommand->getCapsRspParams(capabilities);
577
578 cleanup:
579 if (ret != WIFI_SUCCESS)
580 memset(capabilities, 0, sizeof(wifi_tdls_capabilities));
581 delete pTdlsCommand;
582 return ret;
583 }
584