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