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