Home | History | Annotate | Download | only in wifi_hal
      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;
     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 
     51 TdlsCommand::~TdlsCommand()
     52 {
     53     mTdlsCommandInstance = NULL;
     54     unregisterVendorHandler(mVendor_id, mSubcmd);
     55 }
     56 
     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 
     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  */
     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 
    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 
    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 
    299 void TdlsCommand::unregisterHandler(u32 subCmd)
    300 {
    301     unregisterVendorHandler(mVendor_id, subCmd);
    302 }
    303 
    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 
    313 wifi_error TdlsCommand::requestResponse()
    314 {
    315     return WifiCommand::requestResponse(mMsg);
    316 }
    317 
    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  */
    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  */
    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  */
    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 */
    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