1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wma_scan_roam.c 22 * This file contains functions related to scan and 23 * roaming functionality. 24 */ 25 26 /* Header files */ 27 28 #include "wma.h" 29 #include "wma_api.h" 30 #include "cds_api.h" 31 #include "wmi_unified_api.h" 32 #include "wlan_qct_sys.h" 33 #include "wni_api.h" 34 #include "ani_global.h" 35 #include "wmi_unified.h" 36 #include "wni_cfg.h" 37 #include <cdp_txrx_peer_ops.h> 38 #include <cdp_txrx_cfg.h> 39 #include <cdp_txrx_ctrl.h> 40 41 #include "qdf_nbuf.h" 42 #include "qdf_types.h" 43 #include "qdf_mem.h" 44 #include "wlan_dlm_api.h" 45 46 #include "wma_types.h" 47 #include "lim_api.h" 48 #include "lim_session_utils.h" 49 50 #include "cds_utils.h" 51 #include "wlan_policy_mgr_api.h" 52 #include <wlan_utility.h> 53 54 #if !defined(REMOVE_PKT_LOG) 55 #include "pktlog_ac.h" 56 #endif /* REMOVE_PKT_LOG */ 57 58 #include "dbglog_host.h" 59 #include "csr_api.h" 60 #include "ol_fw.h" 61 62 #include "wma_internal.h" 63 #if defined(CONFIG_HL_SUPPORT) 64 #include "wlan_tgt_def_config_hl.h" 65 #else 66 #include "wlan_tgt_def_config.h" 67 #endif 68 #include "wlan_reg_services_api.h" 69 #include "wlan_roam_debug.h" 70 #include "wlan_mlme_public_struct.h" 71 #include "wlan_mgmt_txrx_utils_api.h" 72 73 /* This is temporary, should be removed */ 74 #include "ol_htt_api.h" 75 #include <cdp_txrx_handle.h> 76 #include "wma_he.h" 77 #include <wlan_scan_public_structs.h> 78 #include <wlan_scan_ucfg_api.h> 79 #include "wma_nan_datapath.h" 80 #include "wlan_mlme_api.h" 81 #include <wlan_mlme_main.h> 82 #include <wlan_crypto_global_api.h> 83 #include <cdp_txrx_mon.h> 84 #include <cdp_txrx_ctrl.h> 85 #include "wlan_dlm_api.h" 86 #include "wlan_cm_roam_api.h" 87 #ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ 88 #include "host_diag_core_log.h" 89 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 90 #include <../../core/src/wlan_cm_roam_i.h> 91 #include "wlan_cm_roam_api.h" 92 #include "wlan_mlo_mgr_roam.h" 93 #ifdef FEATURE_WLAN_EXTSCAN 94 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED 95 96 /* 97 * Maximum number of entries that could be present in the 98 * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware 99 */ 100 #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10 101 #endif 102 103 static inline wmi_host_channel_width 104 wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width) 105 { 106 switch (ch_width) { 107 case CH_WIDTH_20MHZ: 108 return WMI_HOST_CHAN_WIDTH_20; 109 case CH_WIDTH_40MHZ: 110 return WMI_HOST_CHAN_WIDTH_40; 111 case CH_WIDTH_80MHZ: 112 return WMI_HOST_CHAN_WIDTH_80; 113 case CH_WIDTH_160MHZ: 114 return WMI_HOST_CHAN_WIDTH_160; 115 case CH_WIDTH_5MHZ: 116 return WMI_HOST_CHAN_WIDTH_5; 117 case CH_WIDTH_10MHZ: 118 return WMI_HOST_CHAN_WIDTH_10; 119 case CH_WIDTH_320MHZ: 120 return WMI_HOST_CHAN_WIDTH_320; 121 default: 122 return WMI_HOST_CHAN_WIDTH_20; 123 } 124 } 125 126 #define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 127 #define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 128 #define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 129 #define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 130 131 #if defined(WLAN_FEATURE_11BE) 132 static void wma_update_ch_list_11be_params(struct ch_params *ch) 133 { 134 ch->ch_width = CH_WIDTH_320MHZ; 135 } 136 #else /* !WLAN_FEATURE_11BE */ 137 static void wma_update_ch_list_11be_params(struct ch_params *ch) 138 { 139 ch->ch_width = CH_WIDTH_160MHZ; 140 } 141 #endif /* WLAN_FEATURE_11BE */ 142 143 /** 144 * wma_update_channel_list() - update channel list 145 * @handle: wma handle 146 * @chan_list: channel list 147 * 148 * Function is used to update the support channel list in fw. 149 * 150 * Return: QDF status 151 */ 152 QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, 153 tSirUpdateChanList *chan_list) 154 { 155 tp_wma_handle wma_handle = (tp_wma_handle) handle; 156 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 157 int i, len; 158 struct scan_chan_list_params *scan_ch_param; 159 struct channel_param *chan_p; 160 struct ch_params ch_params; 161 162 len = sizeof(struct channel_param) * chan_list->numChan + 163 offsetof(struct scan_chan_list_params, ch_param[0]); 164 scan_ch_param = qdf_mem_malloc(len); 165 if (!scan_ch_param) 166 return QDF_STATUS_E_NOMEM; 167 168 qdf_mem_zero(scan_ch_param, len); 169 wma_debug("no of channels = %d", chan_list->numChan); 170 chan_p = &scan_ch_param->ch_param[0]; 171 scan_ch_param->nallchans = chan_list->numChan; 172 scan_ch_param->max_bw_support_present = true; 173 wma_handle->saved_chan.num_channels = chan_list->numChan; 174 wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en, 175 chan_list->vht_en, chan_list->vht_24_en); 176 177 for (i = 0; i < chan_list->numChan; ++i) { 178 chan_p->mhz = chan_list->chanParam[i].freq; 179 chan_p->cfreq1 = chan_p->mhz; 180 chan_p->cfreq2 = 0; 181 wma_handle->saved_chan.ch_freq_list[i] = 182 chan_list->chanParam[i].freq; 183 184 if (chan_list->chanParam[i].dfsSet) { 185 chan_p->is_chan_passive = 1; 186 chan_p->dfs_set = 1; 187 } 188 189 if (chan_list->chanParam[i].nan_disabled) 190 chan_p->nan_disabled = 1; 191 192 if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) { 193 chan_p->phy_mode = MODE_11G; 194 if (chan_list->vht_en && chan_list->vht_24_en) 195 chan_p->allow_vht = 1; 196 } else { 197 chan_p->phy_mode = MODE_11A; 198 if (chan_list->vht_en && 199 !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) 200 chan_p->allow_vht = 1; 201 } 202 203 if (chan_list->ht_en && 204 !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) 205 chan_p->allow_ht = 1; 206 207 if (chan_list->he_en) 208 chan_p->allow_he = 1; 209 210 if (chan_list->eht_en) 211 chan_p->allow_eht = 1; 212 213 if (chan_list->chanParam[i].half_rate) 214 chan_p->half_rate = 1; 215 else if (chan_list->chanParam[i].quarter_rate) 216 chan_p->quarter_rate = 1; 217 218 if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz) && 219 wlan_reg_is_6ghz_psc_chan_freq(chan_p->mhz)) 220 chan_p->psc_channel = 1; 221 222 /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ 223 /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ 224 /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ 225 chan_p->maxregpower = chan_list->chanParam[i].pwr; 226 227 wma_update_ch_list_11be_params(&ch_params); 228 229 wlan_reg_set_channel_params_for_freq(wma_handle->pdev, 230 chan_p->mhz, 0, 231 &ch_params); 232 233 chan_p->max_bw_supported = 234 wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width); 235 chan_p++; 236 } 237 238 qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle, 239 scan_ch_param); 240 241 if (QDF_IS_STATUS_ERROR(qdf_status)) 242 wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); 243 244 qdf_mem_free(scan_ch_param); 245 246 return qdf_status; 247 } 248 249 /** 250 * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving 251 * @wma_handle: wma handle 252 * @vdev_id: vdev id 253 * @reason: disconnection reason from fw 254 * 255 * Return: None 256 */ 257 static void wma_handle_disconnect_reason(tp_wma_handle wma_handle, 258 uint32_t vdev_id, uint32_t reason) 259 { 260 tpDeleteStaContext del_sta_ctx; 261 262 del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext)); 263 if (!del_sta_ctx) 264 return; 265 266 del_sta_ctx->vdev_id = vdev_id; 267 del_sta_ctx->reasonCode = reason; 268 wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND, 269 (void *)del_sta_ctx, 0); 270 } 271 272 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 273 QDF_STATUS 274 cm_handle_auth_offload(struct auth_offload_event *auth_event) 275 { 276 QDF_STATUS status; 277 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 278 struct mac_context *mac_ctx; 279 280 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 281 if (!mac_ctx || !wma) { 282 QDF_ASSERT(0); 283 return QDF_STATUS_E_FAILURE; 284 } 285 286 cds_host_diag_log_work(&wma->roam_preauth_wl, 287 WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION, 288 WIFI_POWER_EVENT_WAKELOCK_WOW); 289 290 qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl, 291 WMA_ROAM_HO_WAKE_LOCK_DURATION); 292 293 lim_sae_auth_cleanup_retry(mac_ctx, auth_event->vdev_id); 294 wlan_cm_set_sae_auth_ta(mac_ctx->pdev, 295 auth_event->vdev_id, 296 auth_event->ta); 297 status = wma->csr_roam_auth_event_handle_cb(mac_ctx, auth_event->vdev_id, 298 auth_event->ap_bssid); 299 if (QDF_IS_STATUS_ERROR(status)) { 300 wma_err_rl("Trigger pre-auth failed"); 301 return QDF_STATUS_E_FAILURE; 302 } 303 return QDF_STATUS_SUCCESS; 304 } 305 306 QDF_STATUS 307 cm_handle_disconnect_reason(struct vdev_disconnect_event_data *data) 308 { 309 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 310 311 if (!wma) { 312 QDF_ASSERT(0); 313 return QDF_STATUS_E_FAILURE; 314 } 315 switch (data->reason) { 316 case CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT: 317 wma_handle_disconnect_reason(wma, data->vdev_id, 318 HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT); 319 break; 320 case CM_DISCONNECT_REASON_MOVE_TO_CELLULAR: 321 wma_handle_disconnect_reason(wma, data->vdev_id, 322 HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); 323 break; 324 default: 325 return QDF_STATUS_SUCCESS; 326 } 327 328 return QDF_STATUS_SUCCESS; 329 } 330 331 QDF_STATUS 332 cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data) 333 { 334 struct scheduler_msg sme_msg = {0}; 335 336 sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; 337 sme_msg.bodyptr = data; 338 339 if (scheduler_post_message(QDF_MODULE_ID_WMA, 340 QDF_MODULE_ID_SME, 341 QDF_MODULE_ID_SME, &sme_msg)) { 342 wma_err("Failed to post msg to SME"); 343 qdf_mem_free(sme_msg.bodyptr); 344 return -EINVAL; 345 } 346 347 return QDF_STATUS_SUCCESS; 348 } 349 350 #endif 351 352 /** 353 * wma_process_set_pdev_ie_req() - process the pdev set IE req 354 * @wma: Pointer to wma handle 355 * @ie_params: Pointer to IE data. 356 * 357 * Sends the WMI req to set the IE to FW. 358 * 359 * Return: None 360 */ 361 void wma_process_set_pdev_ie_req(tp_wma_handle wma, 362 struct set_ie_param *ie_params) 363 { 364 if (ie_params->ie_type == DOT11_HT_IE) 365 wma_process_set_pdev_ht_ie_req(wma, ie_params); 366 if (ie_params->ie_type == DOT11_VHT_IE) 367 wma_process_set_pdev_vht_ie_req(wma, ie_params); 368 369 qdf_mem_free(ie_params->ie_ptr); 370 } 371 372 /** 373 * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW 374 * @wma: Pointer to wma handle 375 * @ie_params: Pointer to IE data. 376 * @nss: Nss values to prepare the HT IE. 377 * 378 * Sends the WMI req to set the HT IE to FW. 379 * 380 * Return: None 381 */ 382 void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, 383 struct set_ie_param *ie_params) 384 { 385 QDF_STATUS status; 386 wmi_pdev_set_ht_ie_cmd_fixed_param *cmd; 387 wmi_buf_t buf; 388 uint16_t len; 389 uint16_t ie_len_pad; 390 uint8_t *buf_ptr; 391 392 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 393 ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); 394 len += ie_len_pad; 395 396 buf = wmi_buf_alloc(wma->wmi_handle, len); 397 if (!buf) 398 return; 399 400 cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf); 401 WMITLV_SET_HDR(&cmd->tlv_header, 402 WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, 403 WMITLV_GET_STRUCT_TLVLEN( 404 wmi_pdev_set_ht_ie_cmd_fixed_param)); 405 cmd->reserved0 = 0; 406 cmd->ie_len = ie_params->ie_len; 407 cmd->tx_streams = ie_params->nss; 408 cmd->rx_streams = ie_params->nss; 409 wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss); 410 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 411 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); 412 if (ie_params->ie_len) { 413 qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, 414 (uint8_t *)ie_params->ie_ptr, 415 ie_params->ie_len); 416 } 417 418 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 419 WMI_PDEV_SET_HT_CAP_IE_CMDID); 420 if (QDF_IS_STATUS_ERROR(status)) 421 wmi_buf_free(buf); 422 } 423 424 /** 425 * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW 426 * @wma: Pointer to wma handle 427 * @ie_params: Pointer to IE data. 428 * @nss: Nss values to prepare the VHT IE. 429 * 430 * Sends the WMI req to set the VHT IE to FW. 431 * 432 * Return: None 433 */ 434 void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, 435 struct set_ie_param *ie_params) 436 { 437 QDF_STATUS status; 438 wmi_pdev_set_vht_ie_cmd_fixed_param *cmd; 439 wmi_buf_t buf; 440 uint16_t len; 441 uint16_t ie_len_pad; 442 uint8_t *buf_ptr; 443 444 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 445 ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); 446 len += ie_len_pad; 447 448 buf = wmi_buf_alloc(wma->wmi_handle, len); 449 if (!buf) 450 return; 451 452 cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf); 453 WMITLV_SET_HDR(&cmd->tlv_header, 454 WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, 455 WMITLV_GET_STRUCT_TLVLEN( 456 wmi_pdev_set_vht_ie_cmd_fixed_param)); 457 cmd->reserved0 = 0; 458 cmd->ie_len = ie_params->ie_len; 459 cmd->tx_streams = ie_params->nss; 460 cmd->rx_streams = ie_params->nss; 461 wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss); 462 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 463 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); 464 if (ie_params->ie_len) { 465 qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, 466 (uint8_t *)ie_params->ie_ptr, ie_params->ie_len); 467 } 468 469 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 470 WMI_PDEV_SET_VHT_CAP_IE_CMDID); 471 if (QDF_IS_STATUS_ERROR(status)) 472 wmi_buf_free(buf); 473 } 474 475 /** 476 * wma_roam_scan_bmiss_cnt() - set bmiss count to fw 477 * @wma_handle: wma handle 478 * @first_bcnt: first bmiss count 479 * @final_bcnt: final bmiss count 480 * @vdev_id: vdev id 481 * 482 * set first & final biss count to fw. 483 * 484 * Return: QDF status 485 */ 486 QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, 487 A_INT32 first_bcnt, 488 A_UINT32 final_bcnt, uint32_t vdev_id) 489 { 490 QDF_STATUS status; 491 492 wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt); 493 494 status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, 495 WMI_VDEV_PARAM_BMISS_FIRST_BCNT, 496 first_bcnt); 497 if (QDF_IS_STATUS_ERROR(status)) { 498 wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d", 499 status); 500 return status; 501 } 502 503 status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, 504 WMI_VDEV_PARAM_BMISS_FINAL_BCNT, 505 final_bcnt); 506 if (QDF_IS_STATUS_ERROR(status)) { 507 wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d", 508 status); 509 return status; 510 } 511 512 return status; 513 } 514 515 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 516 void 517 wma_send_roam_preauth_status(tp_wma_handle wma_handle, 518 struct wmi_roam_auth_status_params *params) 519 { 520 QDF_STATUS status; 521 struct wmi_unified *wmi_handle; 522 523 if (wma_validate_handle(wma_handle)) 524 return; 525 526 wmi_handle = wma_handle->wmi_handle; 527 if (wmi_validate_handle(wmi_handle)) 528 return; 529 530 status = wmi_unified_send_roam_preauth_status(wmi_handle, params); 531 if (QDF_IS_STATUS_ERROR(status)) 532 wma_err("failed to send disconnect roam preauth status"); 533 } 534 #endif 535 536 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 537 /** 538 * wma_roam_update_vdev() - Update the STA and BSS 539 * @wma: Global WMA Handle 540 * @roam_synch_ind_ptr: Information needed for roam sync propagation 541 * 542 * This function will perform all the vdev related operations with 543 * respect to the self sta and the peer after roaming and completes 544 * the roam synch propagation with respect to WMA layer. 545 * 546 * Return: None 547 */ 548 static void 549 wma_roam_update_vdev(tp_wma_handle wma, 550 struct roam_offload_synch_ind *roam_synch_ind_ptr, 551 uint8_t roamed_vdev_id) 552 { 553 tDeleteStaParams *del_sta_params; 554 tAddStaParams *add_sta_params; 555 uint8_t vdev_id, *bssid; 556 int32_t uc_cipher, cipher_cap; 557 bool is_assoc_peer = false; 558 struct qdf_mac_addr mac_addr; 559 560 vdev_id = roamed_vdev_id; 561 wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss; 562 /* update freq and channel width */ 563 wma->interfaces[vdev_id].ch_freq = 564 roam_synch_ind_ptr->chan_freq; 565 wma->interfaces[vdev_id].chan_width = 566 roam_synch_ind_ptr->chan_width; 567 568 del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); 569 if (!del_sta_params) { 570 return; 571 } 572 573 add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params)); 574 if (!add_sta_params) { 575 qdf_mem_free(del_sta_params); 576 return; 577 } 578 579 if (is_multi_link_roam(roam_synch_ind_ptr)) 580 mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind_ptr, 581 &mac_addr); 582 else 583 mac_addr = roam_synch_ind_ptr->bssid; 584 585 qdf_mem_zero(del_sta_params, sizeof(*del_sta_params)); 586 qdf_mem_zero(add_sta_params, sizeof(*add_sta_params)); 587 588 del_sta_params->smesessionId = vdev_id; 589 add_sta_params->staType = STA_ENTRY_SELF; 590 add_sta_params->smesessionId = vdev_id; 591 qdf_mem_copy(&add_sta_params->bssId, &mac_addr, 592 QDF_MAC_ADDR_SIZE); 593 add_sta_params->assocId = roam_synch_ind_ptr->aid; 594 595 bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); 596 if (!bssid) { 597 wma_err("Failed to get bssid for vdev_%d", vdev_id); 598 return; 599 } 600 601 wma_delete_sta(wma, del_sta_params); 602 wma_delete_bss(wma, vdev_id); 603 is_assoc_peer = wlan_vdev_mlme_get_is_mlo_vdev(wma->psoc, vdev_id); 604 if (is_multi_link_roam(roam_synch_ind_ptr)) { 605 wma_create_peer(wma, mac_addr.bytes, 606 WMI_PEER_TYPE_DEFAULT, vdev_id, 607 roam_synch_ind_ptr->bssid.bytes, 608 is_assoc_peer); 609 } else { 610 wma_create_peer(wma, mac_addr.bytes, 611 WMI_PEER_TYPE_DEFAULT, 612 vdev_id, 613 NULL, 614 is_assoc_peer); 615 } 616 617 if (is_multi_link_roam(roam_synch_ind_ptr)) 618 lim_roam_mlo_create_peer(wma->mac_context, 619 roam_synch_ind_ptr, 620 vdev_id, 621 mac_addr.bytes); 622 623 /* Update new peer's uc cipher */ 624 uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, 625 WLAN_CRYPTO_PARAM_UCAST_CIPHER); 626 cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, 627 WLAN_CRYPTO_PARAM_CIPHER_CAP); 628 wma_set_peer_ucast_cipher(mac_addr.bytes, uc_cipher, 629 cipher_cap); 630 wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params); 631 wma_add_sta(wma, add_sta_params); 632 qdf_mem_copy(bssid, mac_addr.bytes, 633 QDF_MAC_ADDR_SIZE); 634 lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id, 635 roam_synch_ind_ptr); 636 qdf_mem_free(add_sta_params); 637 } 638 639 static void wma_update_phymode_on_roam(tp_wma_handle wma, 640 struct qdf_mac_addr *bssid, 641 wmi_channel *chan, 642 struct wma_txrx_node *iface) 643 { 644 enum wlan_phymode bss_phymode; 645 struct wlan_channel *des_chan; 646 struct wlan_channel *bss_chan; 647 struct vdev_mlme_obj *vdev_mlme; 648 uint8_t channel; 649 struct wlan_objmgr_pdev *pdev = NULL; 650 qdf_freq_t sec_ch_2g_freq = 0; 651 struct ch_params ch_params = {0}; 652 653 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); 654 if (!vdev_mlme) 655 return; 656 657 pdev = wlan_vdev_get_pdev(vdev_mlme->vdev); 658 659 channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq); 660 if (chan) 661 bss_phymode = 662 wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan)); 663 else 664 wma_get_phy_mode_cb(iface->ch_freq, 665 iface->chan_width, &bss_phymode); 666 667 /* Update vdev mlme channel info after roaming */ 668 des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev); 669 bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev); 670 des_chan->ch_phymode = bss_phymode; 671 des_chan->ch_width = iface->chan_width; 672 if (chan) { 673 des_chan->ch_freq = chan->mhz; 674 ch_params.ch_width = des_chan->ch_width; 675 if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq) && 676 des_chan->ch_width == CH_WIDTH_40MHZ && 677 chan->band_center_freq1) { 678 if (des_chan->ch_freq < chan->band_center_freq1) 679 sec_ch_2g_freq = des_chan->ch_freq + 20; 680 else 681 sec_ch_2g_freq = des_chan->ch_freq - 20; 682 } 683 wlan_reg_set_channel_params_for_freq(pdev, des_chan->ch_freq, 684 sec_ch_2g_freq, 685 &ch_params); 686 if (ch_params.ch_width != des_chan->ch_width || 687 ch_params.mhz_freq_seg0 != chan->band_center_freq1 || 688 ch_params.mhz_freq_seg1 != chan->band_center_freq2) 689 wma_err("ch mismatch host & fw bw (%d %d) seg0 (%d, %d) seg1 (%d, %d)", 690 ch_params.ch_width, des_chan->ch_width, 691 ch_params.mhz_freq_seg0, 692 chan->band_center_freq1, 693 ch_params.mhz_freq_seg1, 694 chan->band_center_freq2); 695 des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0; 696 des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1; 697 des_chan->ch_width = ch_params.ch_width; 698 } else { 699 wma_err("LFR3: invalid chan"); 700 } 701 qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel)); 702 703 /* Till conversion is not done in WMI we need to fill fw phy mode */ 704 vdev_mlme->mgmt.generic.phy_mode = wma_host_to_fw_phymode(bss_phymode); 705 706 /* update new phymode to peer */ 707 wma_objmgr_set_peer_mlme_phymode(wma, bssid->bytes, bss_phymode); 708 709 wma_debug("LFR3: new phymode %d freq %d (bw %d, %d %d)", 710 bss_phymode, des_chan->ch_freq, des_chan->ch_width, 711 des_chan->ch_cfreq1, des_chan->ch_cfreq2); 712 } 713 714 /** 715 * wma_set_ric_req() - set ric request element 716 * @wma: wma handle 717 * @msg: message 718 * @is_add_ts: is addts required 719 * 720 * This function sets ric request element for 11r roaming. 721 * 722 * Return: none 723 */ 724 void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) 725 { 726 if (!wma) { 727 wma_err("wma handle is NULL"); 728 return; 729 } 730 731 wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts); 732 } 733 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 734 735 #ifdef FEATURE_RSSI_MONITOR 736 QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, 737 struct rssi_monitor_param *req) 738 { 739 if (!wma) { 740 wma_err("wma handle is NULL"); 741 return QDF_STATUS_E_INVAL; 742 } 743 744 return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req); 745 } 746 747 /** 748 * wma_rssi_breached_event_handler() - rssi breached event handler 749 * @handle: wma handle 750 * @cmd_param_info: event handler data 751 * @len: length of @cmd_param_info 752 * 753 * Return: 0 on success; error number otherwise 754 */ 755 int wma_rssi_breached_event_handler(void *handle, 756 u_int8_t *cmd_param_info, u_int32_t len) 757 { 758 WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf; 759 wmi_rssi_breach_event_fixed_param *event; 760 struct rssi_breach_event rssi; 761 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 762 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 763 764 if (!mac || !wma) { 765 wma_err("Invalid mac/wma context"); 766 return -EINVAL; 767 } 768 if (!mac->sme.rssi_threshold_breached_cb) { 769 wma_err("Callback not registered"); 770 return -EINVAL; 771 } 772 param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; 773 if (!param_buf) { 774 wma_err("Invalid rssi breached event"); 775 return -EINVAL; 776 } 777 event = param_buf->fixed_param; 778 779 rssi.request_id = event->request_id; 780 rssi.session_id = event->vdev_id; 781 if (wmi_service_enabled(wma->wmi_handle, 782 wmi_service_hw_db2dbm_support)) 783 rssi.curr_rssi = event->rssi; 784 else 785 rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; 786 WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); 787 788 wma_debug("req_id: %u vdev_id: %d curr_rssi: %d", 789 rssi.request_id, rssi.session_id, rssi.curr_rssi); 790 wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT, 791 QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes)); 792 793 mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi); 794 wma_debug("Invoke HDD rssi breached callback"); 795 return 0; 796 } 797 #endif /* FEATURE_RSSI_MONITOR */ 798 799 QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id) 800 { 801 QDF_STATUS status = QDF_STATUS_SUCCESS; 802 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 803 struct wma_txrx_node *intr; 804 uint16_t beacon_interval_ori; 805 bool restart; 806 uint16_t reduced_beacon_interval; 807 struct vdev_mlme_obj *mlme_obj; 808 struct wlan_objmgr_vdev *vdev; 809 810 if (!wma) { 811 pe_err("wma is NULL"); 812 return QDF_STATUS_E_FAILURE; 813 } 814 intr = &wma->interfaces[vdev_id]; 815 if (!intr) { 816 pe_err("wma txrx node is NULL"); 817 return QDF_STATUS_E_FAILURE; 818 } 819 vdev = intr->vdev; 820 mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); 821 if (!mlme_obj) { 822 pe_err("vdev component object is NULL"); 823 return QDF_STATUS_E_FAILURE; 824 } 825 826 restart = 827 wma_get_channel_switch_in_progress(intr); 828 if (restart && intr->beacon_filter_enabled) 829 wma_remove_beacon_filter(wma, &intr->beacon_filter); 830 831 reduced_beacon_interval = 832 wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval; 833 if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) { 834 835 836 /* Reduce the beacon interval just before the channel switch. 837 * This would help in reducing the downtime on the STA side 838 * (which is waiting for beacons from the AP to resume back 839 * transmission). Switch back the beacon_interval to its 840 * original value after the channel switch based on the 841 * timeout. This would ensure there are atleast some beacons 842 * sent with increased frequency. 843 */ 844 845 wma_debug("Changing beacon interval to %d", 846 reduced_beacon_interval); 847 848 /* Add a timer to reset the beacon interval back*/ 849 beacon_interval_ori = mlme_obj->proto.generic.beacon_interval; 850 mlme_obj->proto.generic.beacon_interval = 851 reduced_beacon_interval; 852 if (wma_fill_beacon_interval_reset_req(wma, 853 vdev_id, 854 beacon_interval_ori, 855 RESET_BEACON_INTERVAL_TIMEOUT)) { 856 857 wma_debug("Failed to fill beacon interval reset req"); 858 } 859 } 860 861 status = wma_vdev_pre_start(vdev_id, restart); 862 863 return status; 864 } 865 866 QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id) 867 { 868 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 869 struct wma_txrx_node *intr; 870 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 871 struct wlan_channel *des_chan; 872 cdp_config_param_type val; 873 874 if (!wma) { 875 pe_err("wma is NULL"); 876 return QDF_STATUS_E_FAILURE; 877 } 878 intr = &wma->interfaces[vdev_id]; 879 if (!intr) { 880 pe_err("wma txrx node is NULL"); 881 return QDF_STATUS_E_FAILURE; 882 } 883 /* 884 * Record monitor mode channel here in case HW 885 * indicate RX PPDU TLV with invalid channel number. 886 */ 887 if (intr->type == WMI_VDEV_TYPE_MONITOR) { 888 des_chan = intr->vdev->vdev_mlme.des_chan; 889 val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee; 890 cdp_txrx_set_pdev_param(soc, 891 wlan_objmgr_pdev_get_pdev_id(wma->pdev), 892 CDP_MONITOR_CHANNEL, val); 893 val.cdp_pdev_param_mon_freq = des_chan->ch_freq; 894 cdp_txrx_set_pdev_param(soc, 895 wlan_objmgr_pdev_get_pdev_id(wma->pdev), 896 CDP_MONITOR_FREQUENCY, val); 897 } 898 return QDF_STATUS_SUCCESS; 899 } 900 901 #ifdef FEATURE_WLAN_ESE 902 /** 903 * wma_plm_start() - plm start request 904 * @wma: wma handle 905 * @params: plm request parameters 906 * 907 * This function request FW to start PLM. 908 * 909 * Return: QDF status 910 */ 911 static QDF_STATUS wma_plm_start(tp_wma_handle wma, 912 struct plm_req_params *params) 913 { 914 QDF_STATUS status; 915 916 wma_debug("PLM Start"); 917 918 status = wmi_unified_plm_start_cmd(wma->wmi_handle, params); 919 if (QDF_IS_STATUS_ERROR(status)) 920 return status; 921 922 wma->interfaces[params->vdev_id].plm_in_progress = true; 923 924 wma_debug("Plm start request sent successfully for vdev %d", 925 params->vdev_id); 926 927 return status; 928 } 929 930 /** 931 * wma_plm_stop() - plm stop request 932 * @wma: wma handle 933 * @params: plm request parameters 934 * 935 * This function request FW to stop PLM. 936 * 937 * Return: QDF status 938 */ 939 static QDF_STATUS wma_plm_stop(tp_wma_handle wma, 940 struct plm_req_params *params) 941 { 942 QDF_STATUS status; 943 944 if (!wma->interfaces[params->vdev_id].plm_in_progress) { 945 wma_err("No active plm req found, skip plm stop req"); 946 return QDF_STATUS_E_FAILURE; 947 } 948 949 wma_debug("PLM Stop"); 950 951 status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params); 952 if (QDF_IS_STATUS_ERROR(status)) 953 return status; 954 955 wma->interfaces[params->vdev_id].plm_in_progress = false; 956 957 wma_debug("Plm stop request sent successfully for vdev %d", 958 params->vdev_id); 959 960 return status; 961 } 962 963 /** 964 * wma_config_plm() - config PLM 965 * @wma: wma handle 966 * @params: plm request parameters 967 * 968 * Return: none 969 */ 970 void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params) 971 { 972 QDF_STATUS ret; 973 974 if (!params || !wma) 975 return; 976 977 if (params->enable) 978 ret = wma_plm_start(wma, params); 979 else 980 ret = wma_plm_stop(wma, params); 981 982 if (ret) 983 wma_err("PLM %s failed %d", 984 params->enable ? "start" : "stop", ret); 985 } 986 #endif 987 988 #ifdef FEATURE_WLAN_EXTSCAN 989 /** 990 * wma_extscan_wow_event_callback() - extscan wow event callback 991 * @handle: WMA handle 992 * @event: event buffer 993 * @len: length of @event buffer 994 * 995 * In wow case, the wow event is followed by the payload of the event 996 * which generated the wow event. 997 * payload is 4 bytes of length followed by event buffer. the first 4 bytes 998 * of event buffer is common tlv header, which is a combination 999 * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to 1000 * identify the event which triggered wow event. 1001 * Payload is extracted and converted into generic tlv structure before 1002 * being passed to this function. 1003 * 1004 * @Return: Errno 1005 */ 1006 int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len) 1007 { 1008 uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event)); 1009 1010 switch (tag) { 1011 case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: 1012 return wma_extscan_start_stop_event_handler(handle, event, len); 1013 1014 case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: 1015 return wma_extscan_operations_event_handler(handle, event, len); 1016 1017 case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: 1018 return wma_extscan_table_usage_event_handler(handle, event, 1019 len); 1020 1021 case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: 1022 return wma_extscan_cached_results_event_handler(handle, event, 1023 len); 1024 1025 case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: 1026 return wma_extscan_change_results_event_handler(handle, event, 1027 len); 1028 1029 case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: 1030 return wma_extscan_hotlist_match_event_handler(handle, event, 1031 len); 1032 1033 case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: 1034 return wma_extscan_capabilities_event_handler(handle, event, 1035 len); 1036 1037 default: 1038 wma_err("Unknown tag: %d", tag); 1039 return 0; 1040 } 1041 } 1042 1043 /** 1044 * wma_register_extscan_event_handler() - register extscan event handler 1045 * @wma_handle: wma handle 1046 * 1047 * This function register extscan related event handlers. 1048 * 1049 * Return: none 1050 */ 1051 void wma_register_extscan_event_handler(tp_wma_handle wma_handle) 1052 { 1053 if (wma_validate_handle(wma_handle)) 1054 return; 1055 1056 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1057 wmi_extscan_start_stop_event_id, 1058 wma_extscan_start_stop_event_handler, 1059 WMA_RX_SERIALIZER_CTX); 1060 1061 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1062 wmi_extscan_capabilities_event_id, 1063 wma_extscan_capabilities_event_handler, 1064 WMA_RX_SERIALIZER_CTX); 1065 1066 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1067 wmi_extscan_hotlist_match_event_id, 1068 wma_extscan_hotlist_match_event_handler, 1069 WMA_RX_SERIALIZER_CTX); 1070 1071 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1072 wmi_extscan_wlan_change_results_event_id, 1073 wma_extscan_change_results_event_handler, 1074 WMA_RX_SERIALIZER_CTX); 1075 1076 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1077 wmi_extscan_operation_event_id, 1078 wma_extscan_operations_event_handler, 1079 WMA_RX_SERIALIZER_CTX); 1080 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1081 wmi_extscan_table_usage_event_id, 1082 wma_extscan_table_usage_event_handler, 1083 WMA_RX_SERIALIZER_CTX); 1084 1085 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1086 wmi_extscan_cached_results_event_id, 1087 wma_extscan_cached_results_event_handler, 1088 WMA_RX_SERIALIZER_CTX); 1089 1090 wmi_unified_register_event_handler(wma_handle->wmi_handle, 1091 wmi_passpoint_match_event_id, 1092 wma_passpoint_match_event_handler, 1093 WMA_RX_SERIALIZER_CTX); 1094 } 1095 1096 /** 1097 * wma_extscan_start_stop_event_handler() - extscan start/stop event handler 1098 * @handle: wma handle 1099 * @cmd_param_info: event buffer 1100 * @len: data length 1101 * 1102 * This function handles different extscan related commands 1103 * like start/stop/get results etc and indicate to upper layers. 1104 * 1105 * Return: 0 for success or error code. 1106 */ 1107 int wma_extscan_start_stop_event_handler(void *handle, 1108 uint8_t *cmd_param_info, 1109 uint32_t len) 1110 { 1111 WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf; 1112 wmi_extscan_start_stop_event_fixed_param *event; 1113 struct sir_extscan_generic_response *extscan_ind; 1114 uint16_t event_type; 1115 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1116 1117 if (!mac) 1118 return -EINVAL; 1119 1120 if (!mac->sme.ext_scan_ind_cb) { 1121 wma_err("Callback not registered"); 1122 return -EINVAL; 1123 } 1124 param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) 1125 cmd_param_info; 1126 if (!param_buf) { 1127 wma_err("Invalid extscan event"); 1128 return -EINVAL; 1129 } 1130 event = param_buf->fixed_param; 1131 extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind)); 1132 if (!extscan_ind) 1133 return -ENOMEM; 1134 1135 switch (event->command) { 1136 case WMI_EXTSCAN_START_CMDID: 1137 event_type = eSIR_EXTSCAN_START_RSP; 1138 extscan_ind->status = event->status; 1139 extscan_ind->request_id = event->request_id; 1140 break; 1141 case WMI_EXTSCAN_STOP_CMDID: 1142 event_type = eSIR_EXTSCAN_STOP_RSP; 1143 extscan_ind->status = event->status; 1144 extscan_ind->request_id = event->request_id; 1145 break; 1146 case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID: 1147 extscan_ind->status = event->status; 1148 extscan_ind->request_id = event->request_id; 1149 if (event->mode == WMI_EXTSCAN_MODE_STOP) 1150 event_type = 1151 eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP; 1152 else 1153 event_type = 1154 eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP; 1155 break; 1156 case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID: 1157 extscan_ind->status = event->status; 1158 extscan_ind->request_id = event->request_id; 1159 if (event->mode == WMI_EXTSCAN_MODE_STOP) 1160 event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP; 1161 else 1162 event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP; 1163 break; 1164 case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID: 1165 extscan_ind->status = event->status; 1166 extscan_ind->request_id = event->request_id; 1167 event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP; 1168 break; 1169 case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID: 1170 extscan_ind->status = event->status; 1171 extscan_ind->request_id = event->request_id; 1172 if (event->mode == WMI_EXTSCAN_MODE_STOP) 1173 event_type = 1174 eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP; 1175 else 1176 event_type = 1177 eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP; 1178 break; 1179 default: 1180 wma_err("Unknown event(%d) from target", event->status); 1181 qdf_mem_free(extscan_ind); 1182 return -EINVAL; 1183 } 1184 mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind); 1185 wma_debug("sending event to umac for requestid %u with status %d", 1186 extscan_ind->request_id, extscan_ind->status); 1187 qdf_mem_free(extscan_ind); 1188 return 0; 1189 } 1190 1191 /** 1192 * wma_extscan_operations_event_handler() - extscan operation event handler 1193 * @handle: wma handle 1194 * @cmd_param_info: event buffer 1195 * @len: length 1196 * 1197 * This function handles different operations related event and indicate 1198 * upper layers with appropriate callback. 1199 * 1200 * Return: 0 for success or error code. 1201 */ 1202 int wma_extscan_operations_event_handler(void *handle, 1203 uint8_t *cmd_param_info, 1204 uint32_t len) 1205 { 1206 tp_wma_handle wma = (tp_wma_handle) handle; 1207 WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf; 1208 wmi_extscan_operation_event_fixed_param *oprn_event; 1209 tSirExtScanOnScanEventIndParams *oprn_ind; 1210 uint32_t cnt; 1211 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1212 1213 if (!mac) 1214 return -EINVAL; 1215 1216 if (!mac->sme.ext_scan_ind_cb) { 1217 wma_err("Callback not registered"); 1218 return -EINVAL; 1219 } 1220 param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) 1221 cmd_param_info; 1222 if (!param_buf) { 1223 wma_err("Invalid scan operation event"); 1224 return -EINVAL; 1225 } 1226 oprn_event = param_buf->fixed_param; 1227 oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind)); 1228 if (!oprn_ind) 1229 return -ENOMEM; 1230 1231 oprn_ind->requestId = oprn_event->request_id; 1232 1233 switch (oprn_event->event) { 1234 case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT: 1235 oprn_ind->status = 0; 1236 goto exit_handler; 1237 case WMI_EXTSCAN_CYCLE_STARTED_EVENT: 1238 wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT"); 1239 1240 if (oprn_event->num_buckets > param_buf->num_bucket_id) { 1241 wma_err("FW mesg num_buk %d more than TLV hdr %d", 1242 oprn_event->num_buckets, 1243 param_buf->num_bucket_id); 1244 qdf_mem_free(oprn_ind); 1245 return -EINVAL; 1246 } 1247 1248 cds_host_diag_log_work(&wma->extscan_wake_lock, 1249 WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION, 1250 WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); 1251 qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock, 1252 WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION); 1253 oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT; 1254 oprn_ind->status = 0; 1255 oprn_ind->buckets_scanned = 0; 1256 for (cnt = 0; cnt < oprn_event->num_buckets; cnt++) 1257 oprn_ind->buckets_scanned |= 1258 (1 << param_buf->bucket_id[cnt]); 1259 wma_debug("num_buckets %u request_id %u buckets_scanned %u", 1260 oprn_event->num_buckets, oprn_ind->requestId, 1261 oprn_ind->buckets_scanned); 1262 break; 1263 case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT: 1264 wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT"); 1265 qdf_wake_lock_release(&wma->extscan_wake_lock, 1266 WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); 1267 oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT; 1268 oprn_ind->status = 0; 1269 /* Set bucket scanned mask to zero on cycle complete */ 1270 oprn_ind->buckets_scanned = 0; 1271 break; 1272 case WMI_EXTSCAN_BUCKET_STARTED_EVENT: 1273 wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT"); 1274 oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT; 1275 oprn_ind->status = 0; 1276 goto exit_handler; 1277 case WMI_EXTSCAN_THRESHOLD_NUM_SCANS: 1278 wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS"); 1279 oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS; 1280 oprn_ind->status = 0; 1281 break; 1282 case WMI_EXTSCAN_THRESHOLD_PERCENT: 1283 wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT"); 1284 oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT; 1285 oprn_ind->status = 0; 1286 break; 1287 default: 1288 wma_err("Unknown event(%d) from target", oprn_event->event); 1289 qdf_mem_free(oprn_ind); 1290 return -EINVAL; 1291 } 1292 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1293 eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); 1294 wma_debug("sending scan progress event to hdd"); 1295 exit_handler: 1296 qdf_mem_free(oprn_ind); 1297 return 0; 1298 } 1299 1300 /** 1301 * wma_extscan_table_usage_event_handler() - extscan table usage event handler 1302 * @handle: wma handle 1303 * @cmd_param_info: event buffer 1304 * @len: length 1305 * 1306 * This function handles table usage related event and indicate 1307 * upper layers with appropriate callback. 1308 * 1309 * Return: 0 for success or error code. 1310 */ 1311 int wma_extscan_table_usage_event_handler(void *handle, 1312 uint8_t *cmd_param_info, 1313 uint32_t len) 1314 { 1315 WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf; 1316 wmi_extscan_table_usage_event_fixed_param *event; 1317 tSirExtScanResultsAvailableIndParams *tbl_usg_ind; 1318 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1319 1320 if (!mac) 1321 return -EINVAL; 1322 1323 if (!mac->sme.ext_scan_ind_cb) { 1324 wma_err("Callback not registered"); 1325 return -EINVAL; 1326 } 1327 param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) 1328 cmd_param_info; 1329 if (!param_buf) { 1330 wma_err("Invalid table usage event"); 1331 return -EINVAL; 1332 } 1333 event = param_buf->fixed_param; 1334 tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind)); 1335 if (!tbl_usg_ind) 1336 return -ENOMEM; 1337 1338 tbl_usg_ind->requestId = event->request_id; 1339 tbl_usg_ind->numResultsAvailable = event->entries_in_use; 1340 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1341 eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, 1342 tbl_usg_ind); 1343 wma_debug("sending scan_res available event to hdd"); 1344 qdf_mem_free(tbl_usg_ind); 1345 return 0; 1346 } 1347 1348 /** 1349 * wma_extscan_capabilities_event_handler() - extscan capabilities event handler 1350 * @handle: wma handle 1351 * @cmd_param_info: event buffer 1352 * @len: length 1353 * 1354 * This function handles capabilities event and indicate 1355 * upper layers with registered callback. 1356 * 1357 * Return: 0 for success or error code. 1358 */ 1359 int wma_extscan_capabilities_event_handler(void *handle, 1360 uint8_t *cmd_param_info, 1361 uint32_t len) 1362 { 1363 WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf; 1364 wmi_extscan_capabilities_event_fixed_param *event; 1365 wmi_extscan_cache_capabilities *src_cache; 1366 wmi_extscan_hotlist_monitor_capabilities *src_hotlist; 1367 wmi_extscan_wlan_change_monitor_capabilities *src_change; 1368 struct ext_scan_capabilities_response *dest_capab; 1369 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1370 1371 if (!mac) 1372 return -EINVAL; 1373 1374 if (!mac->sme.ext_scan_ind_cb) { 1375 wma_err("Callback not registered"); 1376 return -EINVAL; 1377 } 1378 param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) 1379 cmd_param_info; 1380 if (!param_buf) { 1381 wma_err("Invalid capabilities event"); 1382 return -EINVAL; 1383 } 1384 event = param_buf->fixed_param; 1385 src_cache = param_buf->extscan_cache_capabilities; 1386 src_hotlist = param_buf->hotlist_capabilities; 1387 src_change = param_buf->wlan_change_capabilities; 1388 1389 if (!src_cache || !src_hotlist || !src_change) { 1390 wma_err("Invalid capabilities list"); 1391 return -EINVAL; 1392 } 1393 dest_capab = qdf_mem_malloc(sizeof(*dest_capab)); 1394 if (!dest_capab) 1395 return -ENOMEM; 1396 1397 dest_capab->requestId = event->request_id; 1398 dest_capab->max_scan_buckets = src_cache->max_buckets; 1399 dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size; 1400 dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan; 1401 dest_capab->max_scan_reporting_threshold = 1402 src_cache->max_table_usage_threshold; 1403 1404 dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries; 1405 dest_capab->max_rssi_sample_size = 1406 src_change->max_rssi_averaging_samples; 1407 dest_capab->max_bssid_history_entries = 1408 src_change->max_rssi_history_entries; 1409 dest_capab->max_significant_wifi_change_aps = 1410 src_change->max_wlan_change_entries; 1411 dest_capab->max_hotlist_ssids = 1412 event->num_extscan_hotlist_ssid; 1413 dest_capab->max_number_epno_networks = 1414 event->num_epno_networks; 1415 dest_capab->max_number_epno_networks_by_ssid = 1416 event->num_epno_networks; 1417 dest_capab->max_number_of_allow_listed_ssid = 1418 event->num_roam_ssid_allowlist; 1419 dest_capab->max_number_of_deny_listed_bssid = 1420 event->num_roam_bssid_denylist; 1421 dest_capab->status = 0; 1422 1423 wma_debug("request_id: %u status: %d", 1424 dest_capab->requestId, dest_capab->status); 1425 1426 wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d", 1427 dest_capab->max_scan_buckets, 1428 dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size, 1429 dest_capab->max_ap_cache_per_scan); 1430 wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d", 1431 dest_capab->max_scan_reporting_threshold, 1432 dest_capab->max_rssi_sample_size, 1433 dest_capab->max_bssid_history_entries, 1434 dest_capab->max_significant_wifi_change_aps); 1435 1436 wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d", 1437 dest_capab->max_hotlist_ssids, 1438 dest_capab->max_number_epno_networks, 1439 dest_capab->max_number_epno_networks_by_ssid); 1440 wma_debug("max_number_of_allow_listed_ssid: %d, max_number_of_deny_listed_bssid: %d", 1441 dest_capab->max_number_of_allow_listed_ssid, 1442 dest_capab->max_number_of_deny_listed_bssid); 1443 1444 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1445 eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab); 1446 qdf_mem_free(dest_capab); 1447 return 0; 1448 } 1449 1450 /** 1451 * wma_extscan_hotlist_match_event_handler() - hotlist match event handler 1452 * @handle: wma handle 1453 * @cmd_param_info: event buffer 1454 * @len: length 1455 * 1456 * This function handles hotlist match event and indicate 1457 * upper layers with registered callback. 1458 * 1459 * Return: 0 for success or error code. 1460 */ 1461 int wma_extscan_hotlist_match_event_handler(void *handle, 1462 uint8_t *cmd_param_info, 1463 uint32_t len) 1464 { 1465 WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf; 1466 wmi_extscan_hotlist_match_event_fixed_param *event; 1467 struct extscan_hotlist_match *dest_hotlist; 1468 tSirWifiScanResult *dest_ap; 1469 wmi_extscan_wlan_descriptor *src_hotlist; 1470 uint32_t numap; 1471 int j, ap_found = 0; 1472 uint32_t buf_len; 1473 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1474 1475 if (!mac) 1476 return -EINVAL; 1477 1478 if (!mac->sme.ext_scan_ind_cb) { 1479 wma_err("Callback not registered"); 1480 return -EINVAL; 1481 } 1482 param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) 1483 cmd_param_info; 1484 if (!param_buf) { 1485 wma_err("Invalid hotlist match event"); 1486 return -EINVAL; 1487 } 1488 event = param_buf->fixed_param; 1489 src_hotlist = param_buf->hotlist_match; 1490 numap = event->total_entries; 1491 1492 if (!src_hotlist || !numap) { 1493 wma_err("Hotlist AP's list invalid"); 1494 return -EINVAL; 1495 } 1496 if (numap > param_buf->num_hotlist_match) { 1497 wma_err("Invalid no of total enteries %d", numap); 1498 return -EINVAL; 1499 } 1500 if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) { 1501 wma_err("Total Entries %u greater than max", numap); 1502 numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; 1503 } 1504 1505 buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + 1506 WMI_TLV_HDR_SIZE + 1507 (numap * sizeof(wmi_extscan_wlan_descriptor)); 1508 1509 if (buf_len > len) { 1510 wma_err("Invalid buf len from FW %d numap %d", len, numap); 1511 return -EINVAL; 1512 } 1513 1514 dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) + 1515 sizeof(*dest_ap) * numap); 1516 if (!dest_hotlist) 1517 return -ENOMEM; 1518 1519 dest_ap = &dest_hotlist->ap[0]; 1520 dest_hotlist->numOfAps = event->total_entries; 1521 dest_hotlist->requestId = event->config_request_id; 1522 1523 if (event->first_entry_index + 1524 event->num_entries_in_page < event->total_entries) 1525 dest_hotlist->moreData = 1; 1526 else 1527 dest_hotlist->moreData = 0; 1528 1529 wma_debug("Hotlist match: requestId: %u numOfAps: %d", 1530 dest_hotlist->requestId, dest_hotlist->numOfAps); 1531 1532 /* 1533 * Currently firmware sends only one bss information in-case 1534 * of both hotlist ap found and lost. 1535 */ 1536 for (j = 0; j < numap; j++) { 1537 dest_ap->rssi = 0; 1538 dest_ap->channel = src_hotlist->channel; 1539 dest_ap->ts = src_hotlist->tstamp; 1540 ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; 1541 dest_ap->rtt = src_hotlist->rtt; 1542 dest_ap->rtt_sd = src_hotlist->rtt_sd; 1543 dest_ap->beaconPeriod = src_hotlist->beacon_interval; 1544 dest_ap->capability = src_hotlist->capabilities; 1545 dest_ap->ieLength = src_hotlist->ie_length; 1546 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, 1547 dest_ap->bssid.bytes); 1548 if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) { 1549 wma_err("Invalid SSID len %d, truncating", 1550 src_hotlist->ssid.ssid_len); 1551 src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN; 1552 } 1553 qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, 1554 src_hotlist->ssid.ssid_len); 1555 dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; 1556 dest_ap++; 1557 src_hotlist++; 1558 } 1559 dest_hotlist->ap_found = ap_found; 1560 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1561 eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); 1562 wma_debug("sending hotlist match event to hdd"); 1563 qdf_mem_free(dest_hotlist); 1564 return 0; 1565 } 1566 1567 /** wma_extscan_find_unique_scan_ids() - find unique scan ids 1568 * @cmd_param_info: event data. 1569 * 1570 * This utility function parses the input bss table of information 1571 * and find the unique number of scan ids 1572 * 1573 * Return: 0 on success; error number otherwise 1574 */ 1575 static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info) 1576 { 1577 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 1578 wmi_extscan_cached_results_event_fixed_param *event; 1579 wmi_extscan_wlan_descriptor *src_hotlist; 1580 wmi_extscan_rssi_info *src_rssi; 1581 int prev_scan_id, scan_ids_cnt, i; 1582 1583 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 1584 cmd_param_info; 1585 event = param_buf->fixed_param; 1586 src_hotlist = param_buf->bssid_list; 1587 src_rssi = param_buf->rssi_list; 1588 1589 /* Find the unique number of scan_id's for grouping */ 1590 prev_scan_id = src_rssi->scan_cycle_id; 1591 scan_ids_cnt = 1; 1592 for (i = 1; i < param_buf->num_rssi_list; i++) { 1593 src_rssi++; 1594 1595 if (prev_scan_id != src_rssi->scan_cycle_id) { 1596 scan_ids_cnt++; 1597 prev_scan_id = src_rssi->scan_cycle_id; 1598 } 1599 } 1600 1601 return scan_ids_cnt; 1602 } 1603 1604 /** wma_fill_num_results_per_scan_id() - fill number of bss per scan id 1605 * @cmd_param_info: event data. 1606 * @scan_id_group: pointer to scan id group. 1607 * 1608 * This utility function parses the input bss table of information 1609 * and finds how many bss are there per unique scan id. 1610 * 1611 * Return: 0 on success; error number otherwise 1612 */ 1613 static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info, 1614 struct extscan_cached_scan_result *scan_id_group) 1615 { 1616 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 1617 wmi_extscan_cached_results_event_fixed_param *event; 1618 wmi_extscan_wlan_descriptor *src_hotlist; 1619 wmi_extscan_rssi_info *src_rssi; 1620 struct extscan_cached_scan_result *t_scan_id_grp; 1621 int i, prev_scan_id; 1622 1623 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 1624 cmd_param_info; 1625 event = param_buf->fixed_param; 1626 src_hotlist = param_buf->bssid_list; 1627 src_rssi = param_buf->rssi_list; 1628 t_scan_id_grp = scan_id_group; 1629 1630 prev_scan_id = src_rssi->scan_cycle_id; 1631 1632 t_scan_id_grp->scan_id = src_rssi->scan_cycle_id; 1633 t_scan_id_grp->flags = src_rssi->flags; 1634 t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned; 1635 t_scan_id_grp->num_results = 1; 1636 for (i = 1; i < param_buf->num_rssi_list; i++) { 1637 src_rssi++; 1638 if (prev_scan_id == src_rssi->scan_cycle_id) { 1639 t_scan_id_grp->num_results++; 1640 } else { 1641 t_scan_id_grp++; 1642 prev_scan_id = t_scan_id_grp->scan_id = 1643 src_rssi->scan_cycle_id; 1644 t_scan_id_grp->flags = src_rssi->flags; 1645 t_scan_id_grp->buckets_scanned = 1646 src_rssi->buckets_scanned; 1647 t_scan_id_grp->num_results = 1; 1648 } 1649 } 1650 return 0; 1651 } 1652 1653 /** wma_group_num_bss_to_scan_id() - group bss to scan id table 1654 * @cmd_param_info: event data. 1655 * @cached_result: pointer to cached table. 1656 * 1657 * This function reads the bss information from the format 1658 * ------------------------------------------------------------------------ 1659 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags | 1660 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags | 1661 * ........................................................................ 1662 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags | 1663 * ------------------------------------------------------------------------ 1664 * 1665 * and converts it into the below format and store it 1666 * 1667 * ------------------------------------------------------------------------ 1668 * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1 1669 * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2 1670 * ...................... 1671 * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn 1672 * ------------------------------------------------------------------------ 1673 * 1674 * Return: 0 on success; error number otherwise 1675 */ 1676 static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, 1677 struct extscan_cached_scan_results *cached_result) 1678 { 1679 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 1680 wmi_extscan_cached_results_event_fixed_param *event; 1681 wmi_extscan_wlan_descriptor *src_hotlist; 1682 wmi_extscan_rssi_info *src_rssi; 1683 struct extscan_cached_scan_results *t_cached_result; 1684 struct extscan_cached_scan_result *t_scan_id_grp; 1685 int i, j; 1686 tSirWifiScanResult *ap; 1687 1688 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 1689 cmd_param_info; 1690 event = param_buf->fixed_param; 1691 src_hotlist = param_buf->bssid_list; 1692 src_rssi = param_buf->rssi_list; 1693 t_cached_result = cached_result; 1694 t_scan_id_grp = &t_cached_result->result[0]; 1695 1696 if ((t_cached_result->num_scan_ids * 1697 QDF_MIN(t_scan_id_grp->num_results, 1698 param_buf->num_bssid_list)) > param_buf->num_bssid_list) { 1699 wma_err("num_scan_ids %d, num_results %d num_bssid_list %d", 1700 t_cached_result->num_scan_ids, 1701 t_scan_id_grp->num_results, 1702 param_buf->num_bssid_list); 1703 return -EINVAL; 1704 } 1705 1706 wma_debug("num_scan_ids:%d", 1707 t_cached_result->num_scan_ids); 1708 for (i = 0; i < t_cached_result->num_scan_ids; i++) { 1709 wma_debug("num_results:%d", t_scan_id_grp->num_results); 1710 t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results * 1711 sizeof(*ap)); 1712 if (!t_scan_id_grp->ap) 1713 return -ENOMEM; 1714 1715 ap = &t_scan_id_grp->ap[0]; 1716 for (j = 0; j < QDF_MIN(t_scan_id_grp->num_results, 1717 param_buf->num_bssid_list); j++) { 1718 ap->channel = src_hotlist->channel; 1719 ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp); 1720 ap->rtt = src_hotlist->rtt; 1721 ap->rtt_sd = src_hotlist->rtt_sd; 1722 ap->beaconPeriod = src_hotlist->beacon_interval; 1723 ap->capability = src_hotlist->capabilities; 1724 ap->ieLength = src_hotlist->ie_length; 1725 1726 /* Firmware already applied noise floor adjustment and 1727 * due to WMI interface "UINT32 rssi", host driver 1728 * receives a positive value, hence convert to 1729 * signed char to get the absolute rssi. 1730 */ 1731 ap->rssi = (signed char) src_rssi->rssi; 1732 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, 1733 ap->bssid.bytes); 1734 1735 if (src_hotlist->ssid.ssid_len > 1736 WLAN_SSID_MAX_LEN) { 1737 wma_debug("Invalid SSID len %d, truncating", 1738 src_hotlist->ssid.ssid_len); 1739 src_hotlist->ssid.ssid_len = 1740 WLAN_SSID_MAX_LEN; 1741 } 1742 qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid, 1743 src_hotlist->ssid.ssid_len); 1744 ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; 1745 ap++; 1746 src_rssi++; 1747 src_hotlist++; 1748 } 1749 t_scan_id_grp++; 1750 } 1751 return 0; 1752 } 1753 1754 /** 1755 * wma_extscan_cached_results_event_handler() - cached results event handler 1756 * @handle: wma handle 1757 * @cmd_param_info: event buffer 1758 * @len: length of @cmd_param_info 1759 * 1760 * This function handles cached results event and indicate 1761 * cached results to upper layer. 1762 * 1763 * Return: 0 for success or error code. 1764 */ 1765 int wma_extscan_cached_results_event_handler(void *handle, 1766 uint8_t *cmd_param_info, 1767 uint32_t len) 1768 { 1769 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 1770 wmi_extscan_cached_results_event_fixed_param *event; 1771 struct extscan_cached_scan_results *dest_cachelist; 1772 struct extscan_cached_scan_result *dest_result; 1773 struct extscan_cached_scan_results empty_cachelist; 1774 wmi_extscan_wlan_descriptor *src_hotlist; 1775 wmi_extscan_rssi_info *src_rssi; 1776 int i, moredata, scan_ids_cnt, buf_len, status; 1777 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1778 uint32_t total_len; 1779 bool excess_data = false; 1780 1781 if (!mac) { 1782 wma_err("Invalid mac"); 1783 return -EINVAL; 1784 } 1785 if (!mac->sme.ext_scan_ind_cb) { 1786 wma_err("Callback not registered"); 1787 return -EINVAL; 1788 } 1789 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 1790 cmd_param_info; 1791 if (!param_buf) { 1792 wma_err("Invalid cached results event"); 1793 return -EINVAL; 1794 } 1795 event = param_buf->fixed_param; 1796 src_hotlist = param_buf->bssid_list; 1797 src_rssi = param_buf->rssi_list; 1798 wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d", 1799 event->total_entries, 1800 event->first_entry_index, 1801 event->num_entries_in_page); 1802 1803 if (!src_hotlist || !src_rssi || !event->num_entries_in_page) { 1804 wma_warn("Cached results empty, send 0 results"); 1805 goto noresults; 1806 } 1807 1808 if (event->num_entries_in_page > 1809 (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) || 1810 event->num_entries_in_page > param_buf->num_bssid_list) { 1811 wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d", 1812 event->num_entries_in_page, param_buf->num_bssid_list); 1813 return -EINVAL; 1814 } else { 1815 total_len = sizeof(*event) + 1816 (event->num_entries_in_page * sizeof(*src_hotlist)); 1817 } 1818 for (i = 0; i < event->num_entries_in_page; i++) { 1819 if (src_hotlist[i].ie_length > 1820 WMI_SVC_MSG_MAX_SIZE - total_len) { 1821 excess_data = true; 1822 break; 1823 } else { 1824 total_len += src_hotlist[i].ie_length; 1825 wma_debug("total len IE: %d", total_len); 1826 } 1827 1828 if (src_hotlist[i].number_rssi_samples > 1829 (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) { 1830 excess_data = true; 1831 break; 1832 } else { 1833 total_len += (src_hotlist[i].number_rssi_samples * 1834 sizeof(*src_rssi)); 1835 wma_debug("total len RSSI samples: %d", total_len); 1836 } 1837 } 1838 if (excess_data) { 1839 wma_err("excess data in WMI event"); 1840 return -EINVAL; 1841 } 1842 1843 if (event->first_entry_index + 1844 event->num_entries_in_page < event->total_entries) 1845 moredata = 1; 1846 else 1847 moredata = 0; 1848 1849 dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist)); 1850 if (!dest_cachelist) 1851 return -ENOMEM; 1852 1853 qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist)); 1854 dest_cachelist->request_id = event->request_id; 1855 dest_cachelist->more_data = moredata; 1856 1857 scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info); 1858 wma_debug("scan_ids_cnt %d", scan_ids_cnt); 1859 dest_cachelist->num_scan_ids = scan_ids_cnt; 1860 1861 buf_len = sizeof(*dest_result) * scan_ids_cnt; 1862 dest_cachelist->result = qdf_mem_malloc(buf_len); 1863 if (!dest_cachelist->result) { 1864 qdf_mem_free(dest_cachelist); 1865 return -ENOMEM; 1866 } 1867 1868 dest_result = dest_cachelist->result; 1869 wma_fill_num_results_per_scan_id(cmd_param_info, dest_result); 1870 1871 status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist); 1872 if (!status) 1873 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1874 eSIR_EXTSCAN_CACHED_RESULTS_IND, 1875 dest_cachelist); 1876 else 1877 wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback"); 1878 1879 dest_result = dest_cachelist->result; 1880 for (i = 0; i < dest_cachelist->num_scan_ids; i++) { 1881 if (dest_result->ap) 1882 qdf_mem_free(dest_result->ap); 1883 dest_result++; 1884 } 1885 qdf_mem_free(dest_cachelist->result); 1886 qdf_mem_free(dest_cachelist); 1887 return status; 1888 1889 noresults: 1890 empty_cachelist.request_id = event->request_id; 1891 empty_cachelist.more_data = 0; 1892 empty_cachelist.num_scan_ids = 0; 1893 1894 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 1895 eSIR_EXTSCAN_CACHED_RESULTS_IND, 1896 &empty_cachelist); 1897 return 0; 1898 } 1899 1900 /** 1901 * wma_extscan_change_results_event_handler() - change results event handler 1902 * @handle: wma handle 1903 * @cmd_param_info: event buffer 1904 * @len: length 1905 * 1906 * This function handles change results event and indicate 1907 * change results to upper layer. 1908 * 1909 * Return: 0 for success or error code. 1910 */ 1911 int wma_extscan_change_results_event_handler(void *handle, 1912 uint8_t *cmd_param_info, 1913 uint32_t len) 1914 { 1915 WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf; 1916 wmi_extscan_wlan_change_results_event_fixed_param *event; 1917 tSirWifiSignificantChangeEvent *dest_chglist; 1918 tSirWifiSignificantChange *dest_ap; 1919 wmi_extscan_wlan_change_result_bssid *src_chglist; 1920 1921 uint32_t numap; 1922 int i, k; 1923 uint8_t *src_rssi; 1924 int count = 0; 1925 int moredata; 1926 uint32_t rssi_num = 0; 1927 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 1928 uint32_t buf_len; 1929 bool excess_data = false; 1930 1931 if (!mac) { 1932 wma_err("Invalid mac"); 1933 return -EINVAL; 1934 } 1935 if (!mac->sme.ext_scan_ind_cb) { 1936 wma_err("Callback not registered"); 1937 return -EINVAL; 1938 } 1939 param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) 1940 cmd_param_info; 1941 if (!param_buf) { 1942 wma_err("Invalid change monitor event"); 1943 return -EINVAL; 1944 } 1945 event = param_buf->fixed_param; 1946 src_chglist = param_buf->bssid_signal_descriptor_list; 1947 src_rssi = param_buf->rssi_list; 1948 numap = event->num_entries_in_page; 1949 1950 if (!src_chglist || !numap) { 1951 wma_err("Results invalid"); 1952 return -EINVAL; 1953 } 1954 if (numap > param_buf->num_bssid_signal_descriptor_list) { 1955 wma_err("Invalid num of entries in page: %d", numap); 1956 return -EINVAL; 1957 } 1958 for (i = 0; i < numap; i++) { 1959 if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) { 1960 wma_err("Invalid num of rssi samples %d numap %d rssi_num %d", 1961 src_chglist->num_rssi_samples, 1962 numap, rssi_num); 1963 return -EINVAL; 1964 } 1965 rssi_num += src_chglist->num_rssi_samples; 1966 src_chglist++; 1967 } 1968 src_chglist = param_buf->bssid_signal_descriptor_list; 1969 1970 if (event->first_entry_index + 1971 event->num_entries_in_page < event->total_entries) { 1972 moredata = 1; 1973 } else { 1974 moredata = 0; 1975 } 1976 1977 do { 1978 if (event->num_entries_in_page > 1979 (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/ 1980 sizeof(*src_chglist)) { 1981 excess_data = true; 1982 break; 1983 } else { 1984 buf_len = 1985 sizeof(*event) + (event->num_entries_in_page * 1986 sizeof(*src_chglist)); 1987 } 1988 if (rssi_num > 1989 (WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) { 1990 excess_data = true; 1991 break; 1992 } 1993 } while (0); 1994 1995 if (excess_data) { 1996 wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d", 1997 numap, rssi_num); 1998 QDF_ASSERT(0); 1999 return -EINVAL; 2000 } 2001 dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) + 2002 sizeof(*dest_ap) * numap + 2003 sizeof(int32_t) * rssi_num); 2004 if (!dest_chglist) 2005 return -ENOMEM; 2006 2007 dest_ap = &dest_chglist->ap[0]; 2008 for (i = 0; i < numap; i++) { 2009 dest_ap->channel = src_chglist->channel; 2010 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid, 2011 dest_ap->bssid.bytes); 2012 dest_ap->numOfRssi = src_chglist->num_rssi_samples; 2013 if (dest_ap->numOfRssi) { 2014 if ((dest_ap->numOfRssi + count) > 2015 param_buf->num_rssi_list) { 2016 wma_err("Invalid num in rssi list: %d", 2017 dest_ap->numOfRssi); 2018 qdf_mem_free(dest_chglist); 2019 return -EINVAL; 2020 } 2021 for (k = 0; k < dest_ap->numOfRssi; k++) { 2022 dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM + 2023 src_rssi[count++]; 2024 } 2025 } 2026 dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap + 2027 dest_ap->numOfRssi * sizeof(int32_t) + 2028 sizeof(*dest_ap)); 2029 src_chglist++; 2030 } 2031 dest_chglist->requestId = event->request_id; 2032 dest_chglist->moreData = moredata; 2033 dest_chglist->numResults = numap; 2034 2035 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 2036 eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, 2037 dest_chglist); 2038 wma_debug("sending change monitor results"); 2039 qdf_mem_free(dest_chglist); 2040 return 0; 2041 } 2042 2043 /** 2044 * wma_passpoint_match_event_handler() - passpoint match found event handler 2045 * @handle: WMA handle 2046 * @cmd_param_info: event data 2047 * @len: event data length 2048 * 2049 * This is the passpoint match found event handler; it reads event data from 2050 * @cmd_param_info and fill in the destination buffer and sends indication 2051 * up layer. 2052 * 2053 * Return: 0 on success; error number otherwise 2054 */ 2055 int wma_passpoint_match_event_handler(void *handle, 2056 uint8_t *cmd_param_info, 2057 uint32_t len) 2058 { 2059 WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf; 2060 wmi_passpoint_event_hdr *event; 2061 struct wifi_passpoint_match *dest_match; 2062 tSirWifiScanResult *dest_ap; 2063 uint8_t *buf_ptr; 2064 uint32_t buf_len = 0; 2065 bool excess_data = false; 2066 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 2067 2068 if (!mac) { 2069 wma_err("Invalid mac"); 2070 return -EINVAL; 2071 } 2072 if (!mac->sme.ext_scan_ind_cb) { 2073 wma_err("Callback not registered"); 2074 return -EINVAL; 2075 } 2076 2077 param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; 2078 if (!param_buf) { 2079 wma_err("Invalid passpoint match event"); 2080 return -EINVAL; 2081 } 2082 event = param_buf->fixed_param; 2083 buf_ptr = (uint8_t *)param_buf->fixed_param; 2084 2085 do { 2086 if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) { 2087 excess_data = true; 2088 break; 2089 } else { 2090 buf_len = event->ie_length; 2091 } 2092 2093 if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) { 2094 excess_data = true; 2095 break; 2096 } else { 2097 buf_len += event->anqp_length; 2098 } 2099 2100 } while (0); 2101 2102 if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) || 2103 buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) || 2104 (event->ie_length + event->anqp_length) > param_buf->num_bufp) { 2105 wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u", 2106 event->ie_length, event->anqp_length, 2107 param_buf->num_bufp); 2108 return -EINVAL; 2109 } 2110 2111 if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) { 2112 wma_debug("Invalid ssid len %d, truncating", 2113 event->ssid.ssid_len); 2114 event->ssid.ssid_len = WLAN_SSID_MAX_LEN; 2115 } 2116 2117 dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len); 2118 if (!dest_match) 2119 return -EINVAL; 2120 2121 dest_ap = &dest_match->ap; 2122 dest_match->request_id = 0; 2123 dest_match->id = event->id; 2124 dest_match->anqp_len = event->anqp_length; 2125 wma_info("passpoint match: id: %u anqp length %u", 2126 dest_match->id, dest_match->anqp_len); 2127 2128 dest_ap->channel = event->channel_mhz; 2129 dest_ap->ts = event->timestamp; 2130 dest_ap->rtt = event->rtt; 2131 dest_ap->rssi = event->rssi; 2132 dest_ap->rtt_sd = event->rtt_sd; 2133 dest_ap->beaconPeriod = event->beacon_period; 2134 dest_ap->capability = event->capability; 2135 dest_ap->ieLength = event->ie_length; 2136 WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes); 2137 qdf_mem_copy(dest_ap->ssid, event->ssid.ssid, 2138 event->ssid.ssid_len); 2139 dest_ap->ssid[event->ssid.ssid_len] = '\0'; 2140 qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) + 2141 WMI_TLV_HDR_SIZE, dest_ap->ieLength); 2142 qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) + 2143 WMI_TLV_HDR_SIZE + dest_ap->ieLength, 2144 dest_match->anqp_len); 2145 2146 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 2147 eSIR_PASSPOINT_NETWORK_FOUND_IND, 2148 dest_match); 2149 wma_debug("sending passpoint match event to hdd"); 2150 qdf_mem_free(dest_match); 2151 return 0; 2152 } 2153 2154 QDF_STATUS wma_start_extscan(tp_wma_handle wma, 2155 struct wifi_scan_cmd_req_params *params) 2156 { 2157 QDF_STATUS status; 2158 struct wmi_unified *wmi_handle; 2159 2160 if (wma_validate_handle(wma)) 2161 return QDF_STATUS_E_INVAL; 2162 2163 wmi_handle = wma->wmi_handle; 2164 if (wmi_validate_handle(wmi_handle)) 2165 return QDF_STATUS_E_INVAL; 2166 2167 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2168 wma_err("extscan not enabled"); 2169 return QDF_STATUS_E_FAILURE; 2170 } 2171 2172 if (!params) { 2173 wma_err("NULL param"); 2174 return QDF_STATUS_E_NOMEM; 2175 } 2176 2177 status = wmi_unified_start_extscan_cmd(wmi_handle, params); 2178 if (QDF_IS_STATUS_SUCCESS(status)) 2179 wma->interfaces[params->vdev_id].extscan_in_progress = true; 2180 2181 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 2182 2183 return status; 2184 } 2185 2186 QDF_STATUS wma_stop_extscan(tp_wma_handle wma, 2187 struct extscan_stop_req_params *params) 2188 { 2189 QDF_STATUS status; 2190 struct wmi_unified *wmi_handle; 2191 2192 if (wma_validate_handle(wma)) 2193 return QDF_STATUS_E_INVAL; 2194 2195 wmi_handle = wma->wmi_handle; 2196 if (wmi_validate_handle(wmi_handle)) 2197 return QDF_STATUS_E_INVAL; 2198 2199 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2200 wma_err("extscan not enabled"); 2201 return QDF_STATUS_E_FAILURE; 2202 } 2203 2204 status = wmi_unified_stop_extscan_cmd(wmi_handle, params); 2205 if (QDF_IS_STATUS_ERROR(status)) 2206 return status; 2207 2208 wma->interfaces[params->vdev_id].extscan_in_progress = false; 2209 wma_debug("Extscan stop request sent successfully for vdev %d", 2210 params->vdev_id); 2211 2212 return status; 2213 } 2214 2215 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, 2216 struct extscan_bssid_hotlist_set_params *params) 2217 { 2218 struct wmi_unified *wmi_handle; 2219 2220 if (wma_validate_handle(wma)) 2221 return QDF_STATUS_E_INVAL; 2222 2223 wmi_handle = wma->wmi_handle; 2224 if (wmi_validate_handle(wmi_handle)) 2225 return QDF_STATUS_E_INVAL; 2226 2227 if (!params) { 2228 wma_err("Invalid params"); 2229 return QDF_STATUS_E_INVAL; 2230 } 2231 2232 return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle, 2233 params); 2234 } 2235 2236 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, 2237 struct extscan_bssid_hotlist_reset_params *params) 2238 { 2239 struct wmi_unified *wmi_handle; 2240 2241 if (wma_validate_handle(wma)) 2242 return QDF_STATUS_E_INVAL; 2243 2244 wmi_handle = wma->wmi_handle; 2245 if (wmi_validate_handle(wmi_handle)) 2246 return QDF_STATUS_E_INVAL; 2247 2248 if (!params) { 2249 wma_err("Invalid params"); 2250 return QDF_STATUS_E_INVAL; 2251 } 2252 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2253 wma_err("extscan not enabled"); 2254 return QDF_STATUS_E_FAILURE; 2255 } 2256 2257 return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle, 2258 params); 2259 } 2260 2261 QDF_STATUS 2262 wma_extscan_start_change_monitor(tp_wma_handle wma, 2263 struct extscan_set_sig_changereq_params *params) 2264 { 2265 QDF_STATUS status; 2266 struct wmi_unified *wmi_handle; 2267 2268 if (wma_validate_handle(wma)) 2269 return QDF_STATUS_E_INVAL; 2270 2271 wmi_handle = wma->wmi_handle; 2272 if (wmi_validate_handle(wmi_handle)) 2273 return QDF_STATUS_E_INVAL; 2274 2275 if (!params) { 2276 wma_err("NULL params"); 2277 return QDF_STATUS_E_NOMEM; 2278 } 2279 2280 status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle, 2281 params); 2282 return status; 2283 } 2284 2285 QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, 2286 struct extscan_capabilities_reset_params *params) 2287 { 2288 struct wmi_unified *wmi_handle; 2289 2290 if (wma_validate_handle(wma)) 2291 return QDF_STATUS_E_INVAL; 2292 2293 wmi_handle = wma->wmi_handle; 2294 if (wmi_validate_handle(wmi_handle)) 2295 return QDF_STATUS_E_INVAL; 2296 2297 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2298 wma_err("ext scan not enabled"); 2299 return QDF_STATUS_E_FAILURE; 2300 } 2301 2302 return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle, 2303 params); 2304 } 2305 2306 QDF_STATUS 2307 wma_extscan_get_cached_results(tp_wma_handle wma, 2308 struct extscan_cached_result_params *params) 2309 { 2310 struct wmi_unified *wmi_handle; 2311 2312 if (wma_validate_handle(wma)) 2313 return QDF_STATUS_E_INVAL; 2314 2315 wmi_handle = wma->wmi_handle; 2316 if (wmi_validate_handle(wmi_handle)) 2317 return QDF_STATUS_E_INVAL; 2318 2319 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2320 wma_err("extscan not enabled"); 2321 return QDF_STATUS_E_FAILURE; 2322 } 2323 2324 return wmi_unified_extscan_get_cached_results_cmd(wmi_handle, 2325 params); 2326 } 2327 2328 QDF_STATUS 2329 wma_extscan_get_capabilities(tp_wma_handle wma, 2330 struct extscan_capabilities_params *params) 2331 { 2332 struct wmi_unified *wmi_handle; 2333 2334 if (wma_validate_handle(wma)) 2335 return QDF_STATUS_E_INVAL; 2336 2337 wmi_handle = wma->wmi_handle; 2338 if (wmi_validate_handle(wmi_handle)) 2339 return QDF_STATUS_E_INVAL; 2340 2341 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2342 wma_err("extscan not enabled"); 2343 return QDF_STATUS_E_FAILURE; 2344 } 2345 2346 return wmi_unified_extscan_get_capabilities_cmd(wmi_handle, 2347 params); 2348 } 2349 2350 QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, 2351 struct wifi_enhanced_pno_params *req) 2352 { 2353 QDF_STATUS status; 2354 struct wmi_unified *wmi_handle; 2355 2356 wma_debug("Enter"); 2357 2358 if (wma_validate_handle(wma)) 2359 return QDF_STATUS_E_FAILURE; 2360 2361 wmi_handle = wma->wmi_handle; 2362 if (wmi_validate_handle(wmi_handle)) 2363 return QDF_STATUS_E_FAILURE; 2364 2365 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2366 wma_err("extscan not enabled"); 2367 return QDF_STATUS_E_NOSUPPORT; 2368 } 2369 2370 status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req); 2371 wma_debug("Exit, vdev %d, status %d", req->vdev_id, status); 2372 2373 return status; 2374 } 2375 2376 QDF_STATUS 2377 wma_set_passpoint_network_list(tp_wma_handle wma, 2378 struct wifi_passpoint_req_param *params) 2379 { 2380 QDF_STATUS status; 2381 struct wmi_unified *wmi_handle; 2382 2383 wma_debug("Enter"); 2384 2385 if (wma_validate_handle(wma)) 2386 return QDF_STATUS_E_FAILURE; 2387 2388 wmi_handle = wma->wmi_handle; 2389 if (wmi_validate_handle(wmi_handle)) 2390 return QDF_STATUS_E_FAILURE; 2391 2392 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2393 wma_err("extscan not enabled"); 2394 return QDF_STATUS_E_NOSUPPORT; 2395 } 2396 2397 status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle, 2398 params); 2399 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 2400 2401 return status; 2402 } 2403 2404 QDF_STATUS 2405 wma_reset_passpoint_network_list(tp_wma_handle wma, 2406 struct wifi_passpoint_req_param *params) 2407 { 2408 QDF_STATUS status; 2409 struct wmi_unified *wmi_handle; 2410 2411 wma_debug("Enter"); 2412 2413 if (wma_validate_handle(wma)) 2414 return QDF_STATUS_E_FAILURE; 2415 2416 wmi_handle = wma->wmi_handle; 2417 if (wmi_validate_handle(wmi_handle)) 2418 return QDF_STATUS_E_FAILURE; 2419 2420 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 2421 wma_err("extscan not enabled"); 2422 return QDF_STATUS_E_NOSUPPORT; 2423 } 2424 2425 status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle, 2426 params); 2427 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 2428 2429 return status; 2430 } 2431 2432 #endif 2433 2434 QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, 2435 struct scan_mac_oui *set_oui) 2436 { 2437 struct wmi_unified *wmi_handle; 2438 2439 if (wma_validate_handle(wma)) 2440 return QDF_STATUS_E_INVAL; 2441 2442 wmi_handle = wma->wmi_handle; 2443 if (wmi_validate_handle(wmi_handle)) 2444 return QDF_STATUS_E_INVAL; 2445 2446 if (!wma_is_vdev_valid(set_oui->vdev_id)) { 2447 wma_err("vdev_id: %d is not active", set_oui->vdev_id); 2448 return QDF_STATUS_E_INVAL; 2449 } 2450 2451 return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui); 2452 } 2453 2454 /** 2455 * wma_roam_better_ap_handler() - better ap event handler 2456 * @wma: wma handle 2457 * @vdev_id: vdev id 2458 * 2459 * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome. 2460 * This event means roam algorithm in Rome has found a better matching 2461 * candidate AP. The indication is sent to SME. 2462 * 2463 * Return: none 2464 */ 2465 void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id) 2466 { 2467 struct scheduler_msg msg = {0}; 2468 QDF_STATUS status; 2469 struct cm_host_roam_start_ind *ind; 2470 2471 ind = qdf_mem_malloc(sizeof(*ind)); 2472 if (!ind) 2473 return; 2474 2475 ind->pdev = wma->pdev; 2476 ind->vdev_id = vdev_id; 2477 msg.bodyptr = ind; 2478 msg.callback = wlan_cm_host_roam_start; 2479 wma_debug("Posting ROam start ind to connection manager, vdev %d", 2480 vdev_id); 2481 status = scheduler_post_message(QDF_MODULE_ID_WMA, 2482 QDF_MODULE_ID_OS_IF, 2483 QDF_MODULE_ID_SCAN, &msg); 2484 2485 if (QDF_IS_STATUS_ERROR(status)) 2486 qdf_mem_free(msg.bodyptr); 2487 } 2488 2489 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 2490 /** 2491 * wma_invalid_roam_reason_handler() - Handle Invalid roam notification 2492 * @wma: wma handle 2493 * @vdev_id: vdev id 2494 * @op_code: Operation to be done by the callback 2495 * 2496 * This function calls pe and csr callbacks with proper op_code 2497 * 2498 * Return: None 2499 */ 2500 static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle, 2501 uint32_t vdev_id, 2502 enum cm_roam_notif notif) 2503 { 2504 struct roam_offload_synch_ind *roam_synch_data; 2505 enum sir_roam_op_code op_code; 2506 2507 if (notif == CM_ROAM_NOTIF_ROAM_START) { 2508 op_code = SIR_ROAMING_START; 2509 } else if (notif == CM_ROAM_NOTIF_ROAM_ABORT) { 2510 op_code = SIR_ROAMING_ABORT; 2511 lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); 2512 } else { 2513 wma_debug("Invalid notif %d", notif); 2514 return; 2515 } 2516 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 2517 if (!roam_synch_data) 2518 return; 2519 2520 roam_synch_data->roamed_vdev_id = vdev_id; 2521 if (notif != CM_ROAM_NOTIF_ROAM_START) 2522 wma_handle->pe_roam_synch_cb(wma_handle->mac_context, 2523 roam_synch_data->roamed_vdev_id, 2524 roam_synch_data, 0, op_code); 2525 2526 if (notif == CM_ROAM_NOTIF_ROAM_START) 2527 cm_fw_roam_start_req(wma_handle->psoc, vdev_id); 2528 else 2529 cm_fw_roam_abort_req(wma_handle->psoc, vdev_id); 2530 2531 qdf_mem_free(roam_synch_data); 2532 } 2533 2534 void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle, 2535 struct roam_sync_timeout_timer_info *info) 2536 { 2537 wma_invalid_roam_reason_handler(wma_handle, info->vdev_id, 2538 CM_ROAM_NOTIF_ROAM_ABORT); 2539 } 2540 2541 void cm_invalid_roam_reason_handler(uint32_t vdev_id, enum cm_roam_notif notif) 2542 { 2543 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2544 2545 if (!wma_handle) { 2546 QDF_ASSERT(0); 2547 return; 2548 } 2549 wma_invalid_roam_reason_handler(wma_handle, vdev_id, notif); 2550 2551 if (notif == CM_ROAM_NOTIF_SCAN_START || 2552 notif == CM_ROAM_NOTIF_SCAN_END) 2553 cm_report_roam_rt_stats(wma_handle->psoc, vdev_id, 2554 ROAM_RT_STATS_TYPE_SCAN_STATE, 2555 NULL, notif, 0); 2556 } 2557 #endif 2558 2559 static void 2560 wma_handle_roam_reason_invoke_roam_fail(tp_wma_handle wma_handle, 2561 uint8_t vdev_id, uint32_t notif_params) 2562 { 2563 struct roam_offload_synch_ind *roam_synch_data; 2564 2565 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 2566 if (!roam_synch_data) 2567 return; 2568 2569 lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); 2570 roam_synch_data->roamed_vdev_id = vdev_id; 2571 cm_fw_roam_invoke_fail(wma_handle->psoc, vdev_id); 2572 wlan_cm_update_roam_states(wma_handle->psoc, vdev_id, 2573 notif_params, 2574 ROAM_INVOKE_FAIL_REASON); 2575 qdf_mem_free(roam_synch_data); 2576 } 2577 2578 static void wma_handle_roam_reason_btm(uint8_t vdev_id) 2579 { 2580 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2581 2582 if (!wma_handle) { 2583 QDF_ASSERT(0); 2584 return; 2585 } 2586 /* 2587 * This event is received from firmware if firmware is unable to 2588 * find candidate AP after roam scan and BTM request from AP 2589 * has disassoc imminent bit set. 2590 */ 2591 wma_debug("Kickout due to btm request"); 2592 wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, vdev_id, NULL); 2593 wma_handle_disconnect_reason(wma_handle, vdev_id, 2594 HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); 2595 } 2596 2597 static void wma_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi) 2598 { 2599 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2600 2601 if (!wma_handle) { 2602 QDF_ASSERT(0); 2603 return; 2604 } 2605 /* 2606 * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so 2607 * avoid using CSR/PE structure directly 2608 */ 2609 wma_debug("Beacon Miss for vdevid %x", vdev_id); 2610 mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi); 2611 wma_beacon_miss_handler(wma_handle, vdev_id, rssi); 2612 wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, vdev_id, NULL); 2613 } 2614 2615 static void wma_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi) 2616 { 2617 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2618 2619 if (!wma_handle) { 2620 QDF_ASSERT(0); 2621 return; 2622 } 2623 /* 2624 * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context, 2625 * so avoid using CSR/PE structure directly. 2626 */ 2627 wma_debug("Better AP found for vdevid %x, rssi %d", vdev_id, rssi); 2628 mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev, 2629 false); 2630 wma_roam_better_ap_handler(wma_handle, vdev_id); 2631 } 2632 2633 static void wma_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi) 2634 { 2635 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2636 2637 if (!wma_handle) { 2638 QDF_ASSERT(0); 2639 return; 2640 } 2641 /* 2642 * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ 2643 * context, so avoid using CSR/PE structure directly. 2644 */ 2645 mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev, 2646 true); 2647 mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi); 2648 wma_debug("Bmiss scan AP found for vdevid %x, rssi %d", vdev_id, rssi); 2649 wma_roam_better_ap_handler(wma_handle, vdev_id); 2650 } 2651 2652 static void 2653 wma_update_pdev_hw_mode_trans_ind(tp_wma_handle wma, 2654 struct cm_hw_mode_trans_ind *trans_ind) 2655 { 2656 uint32_t i; 2657 2658 /* Store the vdev-mac map in WMA and send to policy manager */ 2659 for (i = 0; i < trans_ind->num_vdev_mac_entries; i++) 2660 wma_update_intf_hw_mode_params( 2661 trans_ind->vdev_mac_map[i].vdev_id, 2662 trans_ind->vdev_mac_map[i].mac_id, 2663 trans_ind->new_hw_mode_index); 2664 2665 wma->old_hw_mode_index = trans_ind->old_hw_mode_index; 2666 wma->new_hw_mode_index = trans_ind->new_hw_mode_index; 2667 policy_mgr_update_new_hw_mode_index(wma->psoc, 2668 trans_ind->new_hw_mode_index); 2669 policy_mgr_update_old_hw_mode_index(wma->psoc, 2670 trans_ind->old_hw_mode_index); 2671 2672 wma_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d", 2673 wma->old_hw_mode_index, wma->new_hw_mode_index); 2674 } 2675 2676 static void 2677 wma_handle_hw_mode_trans_ind(tp_wma_handle wma_handle, 2678 struct cm_hw_mode_trans_ind *hw_mode_trans_ind) 2679 { 2680 struct scheduler_msg sme_msg = {0}; 2681 QDF_STATUS status; 2682 2683 if (hw_mode_trans_ind) { 2684 wma_update_pdev_hw_mode_trans_ind(wma_handle, 2685 hw_mode_trans_ind); 2686 wma_debug("Update HW mode"); 2687 sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND; 2688 sme_msg.bodyptr = hw_mode_trans_ind; 2689 2690 status = scheduler_post_message(QDF_MODULE_ID_WMA, 2691 QDF_MODULE_ID_SME, 2692 QDF_MODULE_ID_SME, &sme_msg); 2693 if (QDF_IS_STATUS_ERROR(status)) 2694 qdf_mem_free(hw_mode_trans_ind); 2695 } else { 2696 wma_debug("hw_mode transition fixed param is NULL"); 2697 } 2698 } 2699 2700 int cm_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif) 2701 { 2702 return wma_rso_cmd_status_event_handler(vdev_id, notif); 2703 } 2704 2705 void 2706 cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id, uint32_t notif_params, 2707 struct cm_hw_mode_trans_ind *trans_ind) 2708 { 2709 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2710 2711 if (!wma_handle) { 2712 QDF_ASSERT(0); 2713 return; 2714 } 2715 wma_handle_hw_mode_trans_ind(wma_handle, trans_ind); 2716 wma_handle_roam_reason_invoke_roam_fail(wma_handle, vdev_id, 2717 notif_params); 2718 cm_report_roam_rt_stats(wma_handle->psoc, vdev_id, 2719 ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON, 2720 NULL, notif_params, 0); 2721 } 2722 2723 void 2724 cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind *trans_ind) 2725 { 2726 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2727 struct cm_hw_mode_trans_ind *trans_ind_data; 2728 2729 if (!wma_handle) { 2730 wma_err("invalid wma handle"); 2731 return; 2732 } 2733 trans_ind_data = qdf_mem_malloc(sizeof(*trans_ind_data)); 2734 if (!trans_ind_data) 2735 return; 2736 qdf_mem_copy(trans_ind_data, trans_ind, sizeof(*trans_ind_data)); 2737 wma_handle_hw_mode_trans_ind(wma_handle, trans_ind_data); 2738 } 2739 2740 static void 2741 wma_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params, 2742 uint32_t notif_params1, 2743 uint8_t *deauth_disassoc_frame) 2744 { 2745 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2746 struct roam_offload_synch_ind *roam_synch_data; 2747 2748 if (!wma_handle) { 2749 QDF_ASSERT(0); 2750 return; 2751 } 2752 wma_debug("Received disconnect roam event reason:%d", notif_params); 2753 wma_handle->pe_disconnect_cb(wma_handle->mac_context, 2754 vdev_id, 2755 deauth_disassoc_frame, notif_params1, 2756 notif_params); 2757 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 2758 if (!roam_synch_data) 2759 return; 2760 2761 roam_synch_data->roamed_vdev_id = vdev_id; 2762 qdf_mem_free(roam_synch_data); 2763 } 2764 2765 void cm_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params, 2766 uint8_t *deauth_disassoc_frame, 2767 uint32_t frame_len) 2768 { 2769 if (!deauth_disassoc_frame) { 2770 wma_debug("deauth_disassoc_frame is NULL"); 2771 return; 2772 } 2773 2774 wma_handle_roam_reason_deauth(vdev_id, notif_params, frame_len, 2775 deauth_disassoc_frame); 2776 } 2777 2778 void cm_handle_roam_reason_btm(uint8_t vdev_id) 2779 { 2780 wma_handle_roam_reason_btm(vdev_id); 2781 } 2782 2783 void cm_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi) 2784 { 2785 wma_handle_roam_reason_bmiss(vdev_id, rssi); 2786 } 2787 2788 void cm_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi) 2789 { 2790 wma_handle_roam_reason_better_ap(vdev_id, rssi); 2791 } 2792 2793 void cm_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi) 2794 { 2795 wma_handle_roam_reason_suitable_ap(vdev_id, rssi); 2796 } 2797 2798 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 2799 static void 2800 wma_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, 2801 struct cm_hw_mode_trans_ind *hw_mode_trans_ind) 2802 { 2803 tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); 2804 2805 if (!wma_handle) { 2806 QDF_ASSERT(0); 2807 return; 2808 } 2809 /* 2810 * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context, 2811 * so avoid using CSR/PE structure directly. 2812 */ 2813 wma_err("LFR3:Hand-Off Failed for vdevid %x", vdev_id); 2814 wma_debug("mac addr to avoid " QDF_MAC_ADDR_FMT, 2815 QDF_MAC_ADDR_REF(bssid.bytes)); 2816 wma_handle_hw_mode_trans_ind(wma_handle, hw_mode_trans_ind); 2817 cm_fw_ho_fail_req(wma_handle->psoc, vdev_id, bssid); 2818 lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); 2819 } 2820 2821 void 2822 cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, 2823 struct cm_hw_mode_trans_ind *hw_mode_trans_ind) 2824 { 2825 wma_handle_roam_reason_ho_failed(vdev_id, bssid, hw_mode_trans_ind); 2826 } 2827 #endif 2828 2829 #ifdef FEATURE_LFR_SUBNET_DETECTION 2830 QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, 2831 struct gateway_update_req_param *req) 2832 { 2833 if (wma_validate_handle(wma)) 2834 return QDF_STATUS_E_INVAL; 2835 2836 return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req); 2837 } 2838 #endif /* FEATURE_LFR_SUBNET_DETECTION */ 2839 2840 /** 2841 * wma_ht40_stop_obss_scan() - ht40 obss stop scan 2842 * @wma: WMA handle 2843 * @vdev_id: vdev identifier 2844 * 2845 * Return: Return QDF_STATUS, otherwise appropriate failure code 2846 */ 2847 QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id) 2848 { 2849 QDF_STATUS status; 2850 wmi_buf_t buf; 2851 wmi_obss_scan_disable_cmd_fixed_param *cmd; 2852 int len = sizeof(*cmd); 2853 2854 buf = wmi_buf_alloc(wma->wmi_handle, len); 2855 if (!buf) 2856 return QDF_STATUS_E_NOMEM; 2857 2858 wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id); 2859 2860 cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf); 2861 WMITLV_SET_HDR(&cmd->tlv_header, 2862 WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, 2863 WMITLV_GET_STRUCT_TLVLEN( 2864 wmi_obss_scan_disable_cmd_fixed_param)); 2865 2866 cmd->vdev_id = vdev_id; 2867 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 2868 WMI_OBSS_SCAN_DISABLE_CMDID); 2869 if (QDF_IS_STATUS_ERROR(status)) 2870 wmi_buf_free(buf); 2871 2872 return status; 2873 } 2874 2875 /** 2876 * wma_send_ht40_obss_scanind() - ht40 obss start scan indication 2877 * @wma: WMA handle 2878 * @req: start scan request 2879 * 2880 * Return: Return QDF_STATUS, otherwise appropriate failure code 2881 */ 2882 QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, 2883 struct obss_ht40_scanind *req) 2884 { 2885 QDF_STATUS status; 2886 wmi_buf_t buf; 2887 wmi_obss_scan_enable_cmd_fixed_param *cmd; 2888 int len = 0; 2889 uint8_t *buf_ptr, i; 2890 uint8_t *channel_list; 2891 uint32_t *chan_freq_list; 2892 2893 len += sizeof(wmi_obss_scan_enable_cmd_fixed_param); 2894 2895 len += WMI_TLV_HDR_SIZE; 2896 len += qdf_roundup(sizeof(uint8_t) * req->channel_count, 2897 sizeof(uint32_t)); 2898 2899 len += WMI_TLV_HDR_SIZE; 2900 len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); 2901 2902 /* length calculation for chan_freqs */ 2903 len += WMI_TLV_HDR_SIZE; 2904 len += sizeof(uint32_t) * req->channel_count; 2905 2906 wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d", 2907 len, req->bss_id, req->channel_count, req->iefield_len); 2908 2909 wma_debug("scantype %d active_time %d passive %d Obss interval %d", 2910 req->scan_type, req->obss_active_dwelltime, 2911 req->obss_passive_dwelltime, 2912 req->obss_width_trigger_interval); 2913 2914 buf = wmi_buf_alloc(wma->wmi_handle, len); 2915 if (!buf) 2916 return QDF_STATUS_E_NOMEM; 2917 2918 cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf); 2919 WMITLV_SET_HDR(&cmd->tlv_header, 2920 WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, 2921 WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param)); 2922 2923 buf_ptr = (uint8_t *) cmd; 2924 2925 cmd->vdev_id = req->bss_id; 2926 cmd->scan_type = req->scan_type; 2927 cmd->obss_scan_active_dwell = 2928 req->obss_active_dwelltime; 2929 cmd->obss_scan_passive_dwell = 2930 req->obss_passive_dwelltime; 2931 cmd->bss_channel_width_trigger_scan_interval = 2932 req->obss_width_trigger_interval; 2933 cmd->bss_width_channel_transition_delay_factor = 2934 req->bsswidth_ch_trans_delay; 2935 cmd->obss_scan_active_total_per_channel = 2936 req->obss_active_total_per_channel; 2937 cmd->obss_scan_passive_total_per_channel = 2938 req->obss_passive_total_per_channel; 2939 cmd->obss_scan_activity_threshold = 2940 req->obss_activity_threshold; 2941 2942 cmd->channel_len = req->channel_count; 2943 cmd->forty_mhz_intolerant = req->fortymhz_intolerent; 2944 cmd->current_operating_class = req->current_operatingclass; 2945 cmd->ie_len = req->iefield_len; 2946 2947 buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param); 2948 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 2949 qdf_roundup(req->channel_count, sizeof(uint32_t))); 2950 2951 buf_ptr += WMI_TLV_HDR_SIZE; 2952 channel_list = (uint8_t *) buf_ptr; 2953 2954 for (i = 0; i < req->channel_count; i++) { 2955 channel_list[i] = 2956 wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]); 2957 wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]); 2958 } 2959 2960 buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count, 2961 sizeof(uint32_t)); 2962 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 2963 qdf_roundup(1, sizeof(uint32_t))); 2964 buf_ptr += WMI_TLV_HDR_SIZE; 2965 2966 buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); 2967 2968 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 2969 sizeof(uint32_t) * req->channel_count); 2970 buf_ptr += WMI_TLV_HDR_SIZE; 2971 2972 chan_freq_list = (uint32_t *)buf_ptr; 2973 for (i = 0; i < req->channel_count; i++) { 2974 chan_freq_list[i] = req->chan_freq_list[i]; 2975 wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]); 2976 } 2977 2978 buf_ptr += sizeof(uint32_t) * req->channel_count; 2979 2980 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 2981 WMI_OBSS_SCAN_ENABLE_CMDID); 2982 if (QDF_IS_STATUS_ERROR(status)) 2983 wmi_buf_free(buf); 2984 2985 return status; 2986 } 2987 2988 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 2989 void cm_roam_update_vdev(struct roam_offload_synch_ind *sync_ind, 2990 uint8_t vdev_id) 2991 { 2992 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 2993 2994 if (!wma) 2995 return; 2996 2997 wma_roam_update_vdev(wma, sync_ind, vdev_id); 2998 } 2999 3000 QDF_STATUS 3001 cm_roam_pe_sync_callback(struct roam_offload_synch_ind *sync_ind, 3002 uint8_t vdev_id, uint16_t ie_len) 3003 { 3004 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 3005 struct pe_session *pe_session; 3006 QDF_STATUS status; 3007 3008 if (!wma) 3009 return QDF_STATUS_E_INVAL; 3010 3011 pe_session = pe_find_session_by_vdev_id(wma->mac_context, vdev_id); 3012 if (!pe_session) { 3013 /* Legacy to MLO roaming: create new pe session */ 3014 status = lim_create_and_fill_link_session(wma->mac_context, 3015 vdev_id, 3016 sync_ind, ie_len); 3017 3018 if (QDF_IS_STATUS_ERROR(status)) { 3019 wma_err("MLO ROAM: pe session creation failed vdev id %d", 3020 vdev_id); 3021 return status; 3022 } 3023 } 3024 status = wma->pe_roam_synch_cb(wma->mac_context, 3025 vdev_id, sync_ind, ie_len, 3026 SIR_ROAM_SYNCH_PROPAGATION); 3027 3028 return status; 3029 } 3030 3031 void cm_update_phymode_on_roam(uint8_t vdev_id, 3032 struct roam_offload_synch_ind *sync_ind) 3033 { 3034 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 3035 struct qdf_mac_addr link_bssid; 3036 wmi_channel link_chan; 3037 3038 if (!wma) 3039 return; 3040 3041 if (is_multi_link_roam(sync_ind)) { 3042 mlo_roam_get_bssid_chan_for_link(vdev_id, sync_ind, 3043 &link_bssid, 3044 &link_chan); 3045 wma_update_phymode_on_roam(wma, &link_bssid, 3046 &link_chan, 3047 &wma->interfaces[vdev_id]); 3048 } else { 3049 wma_update_phymode_on_roam(wma, &sync_ind->bssid, 3050 &sync_ind->chan, 3051 &wma->interfaces[vdev_id]); 3052 } 3053 } 3054 3055 enum wlan_phymode 3056 wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode) 3057 { 3058 return wma_fw_to_host_phymode(phymode); 3059 } 3060 #endif 3061