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