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