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; 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 int TdlsCommand::setCallbackHandler(wifi_tdls_handler nHandler, u32 event) 286 { 287 int res = 0; 288 mHandler = nHandler; 289 res = registerVendorHandler(mVendor_id, event); 290 if (res != 0) { 291 /* Error case should not happen print log */ 292 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u", 293 __FUNCTION__, mVendor_id, mSubcmd); 294 } 295 return res; 296 } 297 298 void TdlsCommand::unregisterHandler(u32 subCmd) 299 { 300 unregisterVendorHandler(mVendor_id, subCmd); 301 } 302 303 void TdlsCommand::getStatusRspParams(wifi_tdls_status *status) 304 { 305 status->channel = mTDLSgetStatusRspParams.channel; 306 status->global_operating_class = 307 mTDLSgetStatusRspParams.global_operating_class; 308 status->state = mTDLSgetStatusRspParams.state; 309 status->reason = mTDLSgetStatusRspParams.reason; 310 } 311 312 int TdlsCommand::requestResponse() 313 { 314 return WifiCommand::requestResponse(mMsg); 315 } 316 317 void TdlsCommand::getCapsRspParams(wifi_tdls_capabilities *caps) 318 { 319 caps->max_concurrent_tdls_session_num = 320 mTDLSgetCaps.maxConcurrentTdlsSessionNum; 321 caps->is_global_tdls_supported = 322 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_GLOBAL_TDLS_SUPPORTED); 323 caps->is_per_mac_tdls_supported = 324 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_PER_MAC_TDLS_SUPPORTED); 325 caps->is_off_channel_tdls_supported = 326 !!(mTDLSgetCaps.tdlsSupportedFeatures & IS_OFF_CHANNEL_TDLS_SUPPORTED); 327 ALOGV("TDLS capabilities:"); 328 ALOGV("max_concurrent_tdls_session_numChannel : %d\n", 329 caps->max_concurrent_tdls_session_num); 330 ALOGV("is_global_tdls_supported : %d\n", 331 caps->is_global_tdls_supported); 332 ALOGV("is_per_mac_tdls_supported : %d\n", 333 caps->is_per_mac_tdls_supported); 334 ALOGV("is_off_channel_tdls_supported : %d \n", 335 caps->is_off_channel_tdls_supported); 336 } 337 338 /* wifi_enable_tdls - enables TDLS-auto mode for a specific route 339 * 340 * params specifies hints, which provide more information about 341 * why TDLS is being sought. The firmware should do its best to 342 * honor the hints before downgrading regular AP link 343 * 344 * On successful completion, must fire on_tdls_state_changed event 345 * to indicate the status of TDLS operation. 346 */ 347 wifi_error wifi_enable_tdls(wifi_interface_handle iface, 348 mac_addr addr, 349 wifi_tdls_params *params, 350 wifi_tdls_handler handler) 351 { 352 int ret = 0; 353 TdlsCommand *pTdlsCommand; 354 struct nlattr *nl_data; 355 interface_info *iinfo = getIfaceInfo(iface); 356 wifi_handle handle = getWifiHandle(iface); 357 pTdlsCommand = TdlsCommand::instance(handle); 358 359 if (pTdlsCommand == NULL) { 360 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__); 361 return WIFI_ERROR_UNKNOWN; 362 } 363 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE); 364 365 /* Create the message */ 366 ret = pTdlsCommand->create(); 367 if (ret < 0) 368 goto cleanup; 369 370 ret = pTdlsCommand->set_iface_id(iinfo->name); 371 if (ret < 0) 372 goto cleanup; 373 374 /* Add the attributes */ 375 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 376 if (!nl_data) 377 goto cleanup; 378 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr)); 379 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR, 380 (char *)addr, 6); 381 if (ret < 0) 382 goto cleanup; 383 384 if (params != NULL) { 385 ALOGV("%s: Channel: %d, Global operating class: %d, " 386 "Max Latency: %dms, Min Bandwidth: %dKbps", 387 __FUNCTION__, params->channel, params->global_operating_class, 388 params->max_latency_ms, params->min_bandwidth_kbps); 389 ret = pTdlsCommand->put_u32( 390 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL, 391 params->channel) | 392 pTdlsCommand->put_u32( 393 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS, 394 params->global_operating_class) | 395 pTdlsCommand->put_u32( 396 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS, 397 params->max_latency_ms) | 398 pTdlsCommand->put_u32( 399 QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS, 400 params->min_bandwidth_kbps); 401 if (ret < 0) 402 goto cleanup; 403 } 404 405 pTdlsCommand->attr_end(nl_data); 406 407 ret = pTdlsCommand->setCallbackHandler(handler, 408 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE); 409 if (ret < 0) 410 goto cleanup; 411 412 ret = pTdlsCommand->requestResponse(); 413 if (ret != 0) { 414 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret); 415 } 416 417 cleanup: 418 return (wifi_error)ret; 419 } 420 421 /* wifi_disable_tdls - disables TDLS-auto mode for a specific route 422 * 423 * This terminates any existing TDLS with addr device, and frees the 424 * device resources to make TDLS connections on new routes. 425 * 426 * DON'T fire any more events on 'handler' specified in earlier call to 427 * wifi_enable_tdls after this action. 428 */ 429 wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr) 430 { 431 int ret = 0; 432 TdlsCommand *pTdlsCommand; 433 struct nlattr *nl_data; 434 interface_info *iinfo = getIfaceInfo(iface); 435 wifi_handle handle = getWifiHandle(iface); 436 pTdlsCommand = TdlsCommand::instance(handle); 437 438 if (pTdlsCommand == NULL) { 439 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__); 440 return WIFI_ERROR_UNKNOWN; 441 } 442 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE); 443 444 /* Create the message */ 445 ret = pTdlsCommand->create(); 446 if (ret < 0) 447 goto cleanup; 448 449 ret = pTdlsCommand->set_iface_id(iinfo->name); 450 if (ret < 0) 451 goto cleanup; 452 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret); 453 ALOGV("%s: MAC_ADDR: " MAC_ADDR_STR, __FUNCTION__, MAC_ADDR_ARRAY(addr)); 454 455 /* Add the attributes */ 456 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 457 if (!nl_data) 458 goto cleanup; 459 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR, 460 (char *)addr, 6); 461 if (ret < 0) 462 goto cleanup; 463 pTdlsCommand->attr_end(nl_data); 464 465 ret = pTdlsCommand->requestResponse(); 466 if (ret != 0) { 467 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret); 468 } 469 470 cleanup: 471 delete pTdlsCommand; 472 return (wifi_error)ret; 473 } 474 475 /* wifi_get_tdls_status - allows getting the status of TDLS for a specific 476 * route 477 */ 478 wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr, 479 wifi_tdls_status *status) 480 { 481 int ret = 0; 482 TdlsCommand *pTdlsCommand; 483 struct nlattr *nl_data; 484 interface_info *iinfo = getIfaceInfo(iface); 485 wifi_handle handle = getWifiHandle(iface); 486 pTdlsCommand = TdlsCommand::instance(handle); 487 488 if (pTdlsCommand == NULL) { 489 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__); 490 return WIFI_ERROR_UNKNOWN; 491 } 492 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS); 493 494 /* Create the message */ 495 ret = pTdlsCommand->create(); 496 if (ret < 0) 497 goto cleanup; 498 499 ret = pTdlsCommand->set_iface_id(iinfo->name); 500 if (ret < 0) 501 goto cleanup; 502 ALOGV("%s: ifindex obtained:%d", __FUNCTION__, ret); 503 504 /* Add the attributes */ 505 nl_data = pTdlsCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 506 if (!nl_data) 507 goto cleanup; 508 ret = pTdlsCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR, 509 (char *)addr, 6); 510 if (ret < 0) 511 goto cleanup; 512 pTdlsCommand->attr_end(nl_data); 513 514 ret = pTdlsCommand->requestResponse(); 515 if (ret != 0) { 516 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret); 517 } 518 pTdlsCommand->getStatusRspParams(status); 519 520 cleanup: 521 return (wifi_error)ret; 522 } 523 524 /* return the current HW + Firmware combination's TDLS capabilities */ 525 wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface, 526 wifi_tdls_capabilities *capabilities) 527 { 528 int ret = 0; 529 TdlsCommand *pTdlsCommand; 530 531 if (capabilities == NULL) { 532 ALOGE("%s: capabilities is NULL", __FUNCTION__); 533 return WIFI_ERROR_INVALID_ARGS; 534 } 535 536 interface_info *iinfo = getIfaceInfo(iface); 537 wifi_handle handle = getWifiHandle(iface); 538 pTdlsCommand = TdlsCommand::instance(handle); 539 540 if (pTdlsCommand == NULL) { 541 ALOGE("%s: Error TdlsCommand NULL", __FUNCTION__); 542 return WIFI_ERROR_UNKNOWN; 543 } 544 pTdlsCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES); 545 546 /* Create the message */ 547 ret = pTdlsCommand->create(); 548 if (ret < 0) 549 goto cleanup; 550 551 ret = pTdlsCommand->set_iface_id(iinfo->name); 552 if (ret < 0) 553 goto cleanup; 554 555 ret = pTdlsCommand->requestResponse(); 556 if (ret != 0) { 557 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret); 558 goto cleanup; 559 } 560 pTdlsCommand->getCapsRspParams(capabilities); 561 562 cleanup: 563 if (ret < 0) 564 memset(capabilities, 0, sizeof(wifi_tdls_capabilities)); 565 delete pTdlsCommand; 566 return (wifi_error)ret; 567 } 568