1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: wma_scan_roam.c 21 * This file contains functions related to scan and 22 * roaming functionality. 23 */ 24 25 /* Header files */ 26 27 #include "wma.h" 28 #include "wma_api.h" 29 #include "cds_api.h" 30 #include "wmi_unified_api.h" 31 #include "wlan_qct_sys.h" 32 #include "wni_api.h" 33 #include "ani_global.h" 34 #include "wmi_unified.h" 35 #include "wni_cfg.h" 36 #include <cdp_txrx_peer_ops.h> 37 #include <cdp_txrx_cfg.h> 38 #include <cdp_txrx_ctrl.h> 39 40 #include "qdf_nbuf.h" 41 #include "qdf_types.h" 42 #include "qdf_mem.h" 43 #include "wlan_blm_api.h" 44 45 #include "wma_types.h" 46 #include "lim_api.h" 47 #include "lim_session_utils.h" 48 49 #include "cds_utils.h" 50 #include "wlan_policy_mgr_api.h" 51 #include <wlan_utility.h> 52 53 #if !defined(REMOVE_PKT_LOG) 54 #include "pktlog_ac.h" 55 #endif /* REMOVE_PKT_LOG */ 56 57 #include "dbglog_host.h" 58 #include "csr_api.h" 59 #include "ol_fw.h" 60 61 #include "wma_internal.h" 62 #if defined(CONFIG_HL_SUPPORT) 63 #include "wlan_tgt_def_config_hl.h" 64 #else 65 #include "wlan_tgt_def_config.h" 66 #endif 67 #include "wlan_reg_services_api.h" 68 #include "wlan_roam_debug.h" 69 #include "wlan_mlme_public_struct.h" 70 71 /* This is temporary, should be removed */ 72 #include "ol_htt_api.h" 73 #include <cdp_txrx_handle.h> 74 #include "wma_he.h" 75 #include <wlan_scan_public_structs.h> 76 #include <wlan_scan_ucfg_api.h> 77 #include "wma_nan_datapath.h" 78 #include "wlan_mlme_api.h" 79 #include <wlan_mlme_main.h> 80 #include <wlan_crypto_global_api.h> 81 #include <cdp_txrx_mon.h> 82 #include <cdp_txrx_ctrl.h> 83 #include "wlan_blm_api.h" 84 #include "wlan_cm_roam_api.h" 85 #ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ 86 #include "host_diag_core_log.h" 87 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 88 #ifdef FEATURE_CM_ENABLE 89 #include <../../core/src/wlan_cm_roam_i.h> 90 #endif 91 92 #ifdef FEATURE_WLAN_EXTSCAN 93 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED 94 95 /* 96 * Maximum number of entires that could be present in the 97 * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware 98 */ 99 #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10 100 #endif 101 102 static inline wmi_host_channel_width 103 wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width) 104 { 105 switch (ch_width) { 106 case CH_WIDTH_20MHZ: 107 return WMI_HOST_CHAN_WIDTH_20; 108 case CH_WIDTH_40MHZ: 109 return WMI_HOST_CHAN_WIDTH_40; 110 case CH_WIDTH_80MHZ: 111 return WMI_HOST_CHAN_WIDTH_80; 112 case CH_WIDTH_160MHZ: 113 return WMI_HOST_CHAN_WIDTH_160; 114 case CH_WIDTH_5MHZ: 115 return WMI_HOST_CHAN_WIDTH_5; 116 case CH_WIDTH_10MHZ: 117 return WMI_HOST_CHAN_WIDTH_10; 118 #ifdef WLAN_FEATURE_11BE 119 case CH_WIDTH_320MHZ: 120 return WMI_HOST_CHAN_WIDTH_320; 121 #endif 122 default: 123 return WMI_HOST_CHAN_WIDTH_20; 124 } 125 } 126 127 #define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 128 #define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 129 #define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 130 #define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 131 132 #ifdef WLAN_FEATURE_11BE 133 static void wma_update_ch_list_11be_params(struct ch_params *ch) 134 { 135 ch->ch_width = CH_WIDTH_320MHZ; 136 } 137 #else /* !WLAN_FEATURE_11BE */ 138 static void wma_update_ch_list_11be_params(struct ch_params *ch) 139 { 140 ch->ch_width = CH_WIDTH_160MHZ; 141 } 142 #endif /* WLAN_FEATURE_11BE */ 143 144 /** 145 * wma_update_channel_list() - update channel list 146 * @handle: wma handle 147 * @chan_list: channel list 148 * 149 * Function is used to update the support channel list in fw. 150 * 151 * Return: QDF status 152 */ 153 QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, 154 tSirUpdateChanList *chan_list) 155 { 156 tp_wma_handle wma_handle = (tp_wma_handle) handle; 157 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 158 int i, len; 159 struct scan_chan_list_params *scan_ch_param; 160 struct channel_param *chan_p; 161 struct ch_params ch_params; 162 163 len = sizeof(struct channel_param) * chan_list->numChan + 164 offsetof(struct scan_chan_list_params, ch_param[0]); 165 scan_ch_param = qdf_mem_malloc(len); 166 if (!scan_ch_param) 167 return QDF_STATUS_E_NOMEM; 168 169 qdf_mem_zero(scan_ch_param, len); 170 wma_debug("no of channels = %d", chan_list->numChan); 171 chan_p = &scan_ch_param->ch_param[0]; 172 scan_ch_param->nallchans = chan_list->numChan; 173 scan_ch_param->max_bw_support_present = true; 174 wma_handle->saved_chan.num_channels = chan_list->numChan; 175 wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en, 176 chan_list->vht_en, chan_list->vht_24_en); 177 178 for (i = 0; i < chan_list->numChan; ++i) { 179 chan_p->mhz = chan_list->chanParam[i].freq; 180 chan_p->cfreq1 = chan_p->mhz; 181 chan_p->cfreq2 = 0; 182 wma_handle->saved_chan.ch_freq_list[i] = 183 chan_list->chanParam[i].freq; 184 185 if (chan_list->chanParam[i].dfsSet) { 186 chan_p->is_chan_passive = 1; 187 chan_p->dfs_set = 1; 188 } 189 190 if (chan_list->chanParam[i].nan_disabled) 191 chan_p->nan_disabled = 1; 192 193 if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) { 194 chan_p->phy_mode = MODE_11G; 195 if (chan_list->vht_en && chan_list->vht_24_en) 196 chan_p->allow_vht = 1; 197 } else { 198 chan_p->phy_mode = MODE_11A; 199 if (chan_list->vht_en && 200 !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) 201 chan_p->allow_vht = 1; 202 } 203 204 if (chan_list->ht_en && 205 !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) 206 chan_p->allow_ht = 1; 207 208 if (chan_list->he_en) 209 chan_p->allow_he = 1; 210 211 if (chan_list->chanParam[i].half_rate) 212 chan_p->half_rate = 1; 213 else if (chan_list->chanParam[i].quarter_rate) 214 chan_p->quarter_rate = 1; 215 216 if (wlan_reg_is_6ghz_psc_chan_freq( 217 chan_p->mhz)) 218 chan_p->psc_channel = 1; 219 220 /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ 221 /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ 222 /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ 223 chan_p->maxregpower = chan_list->chanParam[i].pwr; 224 225 wma_update_ch_list_11be_params(&ch_params); 226 227 wlan_reg_set_channel_params_for_freq(wma_handle->pdev, 228 chan_p->mhz, 0, 229 &ch_params); 230 231 chan_p->max_bw_supported = 232 wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width); 233 chan_p++; 234 } 235 236 qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle, 237 scan_ch_param); 238 239 if (QDF_IS_STATUS_ERROR(qdf_status)) 240 wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); 241 242 qdf_mem_free(scan_ch_param); 243 244 return qdf_status; 245 } 246 247 /** 248 * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving 249 * @wma_handle: wma handle 250 * @vdev_id: vdev id 251 * @reason: disconnection reason from fw 252 * 253 * Return: None 254 */ 255 static void wma_handle_disconnect_reason(tp_wma_handle wma_handle, 256 uint32_t vdev_id, uint32_t reason) 257 { 258 tpDeleteStaContext del_sta_ctx; 259 260 del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext)); 261 if (!del_sta_ctx) 262 return; 263 264 del_sta_ctx->vdev_id = vdev_id; 265 del_sta_ctx->reasonCode = reason; 266 wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND, 267 (void *)del_sta_ctx, 0); 268 } 269 270 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 271 int wma_roam_vdev_disconnect_event_handler(void *handle, uint8_t *event, 272 uint32_t len) 273 { 274 WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *param_buf; 275 wmi_vdev_disconnect_event_fixed_param *roam_vdev_disc_ev; 276 tp_wma_handle wma = (tp_wma_handle)handle; 277 278 if (!event) { 279 wma_err("received null event from target"); 280 return -EINVAL; 281 } 282 283 param_buf = (WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *)event; 284 285 roam_vdev_disc_ev = param_buf->fixed_param; 286 if (!roam_vdev_disc_ev) { 287 wma_err("roam cap event is NULL"); 288 return -EINVAL; 289 } 290 if (roam_vdev_disc_ev->vdev_id >= wma->max_bssid) { 291 wma_err("Invalid vdev id %d", roam_vdev_disc_ev->vdev_id); 292 return -EINVAL; 293 } 294 295 wma_debug("Received disconnect roam event on vdev_id : %d, reason:%d", 296 roam_vdev_disc_ev->vdev_id, roam_vdev_disc_ev->reason); 297 298 switch (roam_vdev_disc_ev->reason) { 299 case WLAN_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT: 300 wma_handle_disconnect_reason(wma, roam_vdev_disc_ev->vdev_id, 301 HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT); 302 break; 303 case WLAN_DISCONNECT_REASON_MOVE_TO_CELLULAR: 304 wma_handle_disconnect_reason(wma, roam_vdev_disc_ev->vdev_id, 305 HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); 306 break; 307 default: 308 return 0; 309 } 310 311 return 0; 312 } 313 #endif 314 315 /** 316 * wma_process_set_pdev_ie_req() - process the pdev set IE req 317 * @wma: Pointer to wma handle 318 * @ie_params: Pointer to IE data. 319 * 320 * Sends the WMI req to set the IE to FW. 321 * 322 * Return: None 323 */ 324 void wma_process_set_pdev_ie_req(tp_wma_handle wma, 325 struct set_ie_param *ie_params) 326 { 327 if (ie_params->ie_type == DOT11_HT_IE) 328 wma_process_set_pdev_ht_ie_req(wma, ie_params); 329 if (ie_params->ie_type == DOT11_VHT_IE) 330 wma_process_set_pdev_vht_ie_req(wma, ie_params); 331 332 qdf_mem_free(ie_params->ie_ptr); 333 } 334 335 /** 336 * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW 337 * @wma: Pointer to wma handle 338 * @ie_params: Pointer to IE data. 339 * @nss: Nss values to prepare the HT IE. 340 * 341 * Sends the WMI req to set the HT IE to FW. 342 * 343 * Return: None 344 */ 345 void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, 346 struct set_ie_param *ie_params) 347 { 348 QDF_STATUS status; 349 wmi_pdev_set_ht_ie_cmd_fixed_param *cmd; 350 wmi_buf_t buf; 351 uint16_t len; 352 uint16_t ie_len_pad; 353 uint8_t *buf_ptr; 354 355 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 356 ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); 357 len += ie_len_pad; 358 359 buf = wmi_buf_alloc(wma->wmi_handle, len); 360 if (!buf) 361 return; 362 363 cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf); 364 WMITLV_SET_HDR(&cmd->tlv_header, 365 WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, 366 WMITLV_GET_STRUCT_TLVLEN( 367 wmi_pdev_set_ht_ie_cmd_fixed_param)); 368 cmd->reserved0 = 0; 369 cmd->ie_len = ie_params->ie_len; 370 cmd->tx_streams = ie_params->nss; 371 cmd->rx_streams = ie_params->nss; 372 wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss); 373 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 374 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); 375 if (ie_params->ie_len) { 376 qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, 377 (uint8_t *)ie_params->ie_ptr, 378 ie_params->ie_len); 379 } 380 381 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 382 WMI_PDEV_SET_HT_CAP_IE_CMDID); 383 if (QDF_IS_STATUS_ERROR(status)) 384 wmi_buf_free(buf); 385 } 386 387 /** 388 * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW 389 * @wma: Pointer to wma handle 390 * @ie_params: Pointer to IE data. 391 * @nss: Nss values to prepare the VHT IE. 392 * 393 * Sends the WMI req to set the VHT IE to FW. 394 * 395 * Return: None 396 */ 397 void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, 398 struct set_ie_param *ie_params) 399 { 400 QDF_STATUS status; 401 wmi_pdev_set_vht_ie_cmd_fixed_param *cmd; 402 wmi_buf_t buf; 403 uint16_t len; 404 uint16_t ie_len_pad; 405 uint8_t *buf_ptr; 406 407 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; 408 ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); 409 len += ie_len_pad; 410 411 buf = wmi_buf_alloc(wma->wmi_handle, len); 412 if (!buf) 413 return; 414 415 cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf); 416 WMITLV_SET_HDR(&cmd->tlv_header, 417 WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, 418 WMITLV_GET_STRUCT_TLVLEN( 419 wmi_pdev_set_vht_ie_cmd_fixed_param)); 420 cmd->reserved0 = 0; 421 cmd->ie_len = ie_params->ie_len; 422 cmd->tx_streams = ie_params->nss; 423 cmd->rx_streams = ie_params->nss; 424 wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss); 425 buf_ptr = (uint8_t *)cmd + sizeof(*cmd); 426 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); 427 if (ie_params->ie_len) { 428 qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, 429 (uint8_t *)ie_params->ie_ptr, ie_params->ie_len); 430 } 431 432 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 433 WMI_PDEV_SET_VHT_CAP_IE_CMDID); 434 if (QDF_IS_STATUS_ERROR(status)) 435 wmi_buf_free(buf); 436 } 437 438 /** 439 * wma_roam_scan_bmiss_cnt() - set bmiss count to fw 440 * @wma_handle: wma handle 441 * @first_bcnt: first bmiss count 442 * @final_bcnt: final bmiss count 443 * @vdev_id: vdev id 444 * 445 * set first & final biss count to fw. 446 * 447 * Return: QDF status 448 */ 449 QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, 450 A_INT32 first_bcnt, 451 A_UINT32 final_bcnt, uint32_t vdev_id) 452 { 453 QDF_STATUS status; 454 455 wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt); 456 457 status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, 458 WMI_VDEV_PARAM_BMISS_FIRST_BCNT, 459 first_bcnt); 460 if (QDF_IS_STATUS_ERROR(status)) { 461 wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d", 462 status); 463 return status; 464 } 465 466 status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, 467 WMI_VDEV_PARAM_BMISS_FINAL_BCNT, 468 final_bcnt); 469 if (QDF_IS_STATUS_ERROR(status)) { 470 wma_err("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d", 471 status); 472 return status; 473 } 474 475 return status; 476 } 477 478 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 479 void 480 wma_send_roam_preauth_status(tp_wma_handle wma_handle, 481 struct wmi_roam_auth_status_params *params) 482 { 483 QDF_STATUS status; 484 struct wmi_unified *wmi_handle; 485 486 if (wma_validate_handle(wma_handle)) 487 return; 488 489 wmi_handle = wma_handle->wmi_handle; 490 if (wmi_validate_handle(wmi_handle)) 491 return; 492 493 status = wmi_unified_send_roam_preauth_status(wmi_handle, params); 494 if (QDF_IS_STATUS_ERROR(status)) 495 wma_err("failed to send disconnect roam preauth status"); 496 } 497 #endif 498 499 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 500 #ifndef FEATURE_CM_ENABLE 501 /** 502 * wma_process_roam_invoke() - send roam invoke command to fw. 503 * @handle: wma handle 504 * @roaminvoke: roam invoke command 505 * 506 * Send roam invoke command to fw for fastreassoc. 507 * 508 * Return: none 509 */ 510 void wma_process_roam_invoke(WMA_HANDLE handle, 511 struct roam_invoke_req *roaminvoke) 512 { 513 tp_wma_handle wma_handle = (tp_wma_handle) handle; 514 struct wmi_unified *wmi_handle; 515 516 if (wma_validate_handle(wma_handle)) 517 goto free_frame_buf; 518 519 wmi_handle = wma_handle->wmi_handle; 520 if (wmi_validate_handle(wmi_handle)) 521 goto free_frame_buf; 522 523 if (!wma_is_vdev_valid(roaminvoke->vdev_id)) { 524 wma_err("Invalid vdev id:%d", roaminvoke->vdev_id); 525 goto free_frame_buf; 526 } 527 wma_err("Sending ROAM INVOKE CMD vdev id:%d", roaminvoke->vdev_id); 528 529 wmi_unified_roam_invoke_cmd(wmi_handle, 530 (struct roam_invoke_req *)roaminvoke); 531 free_frame_buf: 532 if (roaminvoke->frame_len) { 533 qdf_mem_free(roaminvoke->frame_buf); 534 roaminvoke->frame_buf = NULL; 535 } 536 } 537 538 /** 539 * wma_process_roam_synch_fail() -roam synch failure handle 540 * @handle: wma handle 541 * @synch_fail: roam synch fail parameters 542 * 543 * Return: none 544 */ 545 void wma_process_roam_synch_fail(WMA_HANDLE handle, 546 struct roam_offload_synch_fail *synch_fail) 547 { 548 tp_wma_handle wma_handle = (tp_wma_handle) handle; 549 struct wmi_unified *wmi_handle; 550 551 if (wma_validate_handle(wma_handle)) 552 return; 553 554 wmi_handle = wma_handle->wmi_handle; 555 if (wmi_validate_handle(wmi_handle)) 556 return; 557 558 wlan_roam_debug_log(synch_fail->session_id, 559 DEBUG_ROAM_SYNCH_FAIL, 560 DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); 561 } 562 #endif 563 564 /** 565 * wma_free_roam_synch_frame_ind() - Free the bcn_probe_rsp, reassoc_req, 566 * reassoc_rsp received as part of the ROAM_SYNC_FRAME event 567 * 568 * @iface - interaface corresponding to a vdev 569 * 570 * This API is used to free the buffer allocated during the ROAM_SYNC_FRAME 571 * event 572 * 573 */ 574 static void wma_free_roam_synch_frame_ind(struct wma_txrx_node *iface) 575 { 576 if (iface->roam_synch_frame_ind.bcn_probe_rsp) { 577 qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp); 578 iface->roam_synch_frame_ind.bcn_probe_rsp_len = 0; 579 iface->roam_synch_frame_ind.bcn_probe_rsp = NULL; 580 } 581 if (iface->roam_synch_frame_ind.reassoc_req) { 582 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); 583 iface->roam_synch_frame_ind.reassoc_req_len = 0; 584 iface->roam_synch_frame_ind.reassoc_req = NULL; 585 } 586 if (iface->roam_synch_frame_ind.reassoc_rsp) { 587 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); 588 iface->roam_synch_frame_ind.reassoc_rsp_len = 0; 589 iface->roam_synch_frame_ind.reassoc_rsp = NULL; 590 } 591 } 592 593 /** 594 * wma_fill_data_synch_frame_event() - Fill the the roam sync data buffer using 595 * synch frame event data 596 * @wma: Global WMA Handle 597 * @roam_synch_ind_ptr: Buffer to be filled 598 * @param_buf: Source buffer 599 * 600 * Firmware sends all the required information required for roam 601 * synch propagation as TLV's and stored in param_buf. These 602 * parameters are parsed and filled into the roam synch indication 603 * buffer which will be used at different layers for propagation. 604 * 605 * Return: None 606 */ 607 static void wma_fill_data_synch_frame_event(tp_wma_handle wma, 608 struct roam_offload_synch_ind *roam_synch_ind_ptr, 609 struct wma_txrx_node *iface) 610 { 611 uint8_t *bcn_probersp_ptr; 612 uint8_t *reassoc_rsp_ptr; 613 uint8_t *reassoc_req_ptr; 614 615 /* Beacon/Probe Rsp data */ 616 roam_synch_ind_ptr->beaconProbeRespOffset = 617 sizeof(struct roam_offload_synch_ind); 618 bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr + 619 roam_synch_ind_ptr->beaconProbeRespOffset; 620 roam_synch_ind_ptr->beaconProbeRespLength = 621 iface->roam_synch_frame_ind.bcn_probe_rsp_len; 622 qdf_mem_copy(bcn_probersp_ptr, 623 iface->roam_synch_frame_ind.bcn_probe_rsp, 624 roam_synch_ind_ptr->beaconProbeRespLength); 625 qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp); 626 iface->roam_synch_frame_ind.bcn_probe_rsp = NULL; 627 628 /* ReAssoc Rsp data */ 629 roam_synch_ind_ptr->reassocRespOffset = 630 sizeof(struct roam_offload_synch_ind) + 631 roam_synch_ind_ptr->beaconProbeRespLength; 632 roam_synch_ind_ptr->reassocRespLength = 633 iface->roam_synch_frame_ind.reassoc_rsp_len; 634 reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + 635 roam_synch_ind_ptr->reassocRespOffset; 636 qdf_mem_copy(reassoc_rsp_ptr, 637 iface->roam_synch_frame_ind.reassoc_rsp, 638 roam_synch_ind_ptr->reassocRespLength); 639 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); 640 iface->roam_synch_frame_ind.reassoc_rsp = NULL; 641 642 /* ReAssoc Req data */ 643 roam_synch_ind_ptr->reassoc_req_offset = 644 sizeof(struct roam_offload_synch_ind) + 645 roam_synch_ind_ptr->beaconProbeRespLength + 646 roam_synch_ind_ptr->reassocRespLength; 647 roam_synch_ind_ptr->reassoc_req_length = 648 iface->roam_synch_frame_ind.reassoc_req_len; 649 reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr + 650 roam_synch_ind_ptr->reassoc_req_offset; 651 qdf_mem_copy(reassoc_req_ptr, 652 iface->roam_synch_frame_ind.reassoc_req, 653 roam_synch_ind_ptr->reassoc_req_length); 654 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); 655 iface->roam_synch_frame_ind.reassoc_req = NULL; 656 } 657 658 /** 659 * wma_fill_data_synch_event() - Fill the the roam sync data buffer using synch 660 * event data 661 * @wma: Global WMA Handle 662 * @roam_synch_ind_ptr: Buffer to be filled 663 * @param_buf: Source buffer 664 * 665 * Firmware sends all the required information required for roam 666 * synch propagation as TLV's and stored in param_buf. These 667 * parameters are parsed and filled into the roam synch indication 668 * buffer which will be used at different layers for propagation. 669 * 670 * Return: None 671 */ 672 static void wma_fill_data_synch_event(tp_wma_handle wma, 673 struct roam_offload_synch_ind *roam_synch_ind_ptr, 674 WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) 675 { 676 uint8_t *bcn_probersp_ptr; 677 uint8_t *reassoc_rsp_ptr; 678 uint8_t *reassoc_req_ptr; 679 wmi_roam_synch_event_fixed_param *synch_event; 680 681 synch_event = param_buf->fixed_param; 682 683 /* Beacon/Probe Rsp data */ 684 roam_synch_ind_ptr->beaconProbeRespOffset = 685 sizeof(struct roam_offload_synch_ind); 686 bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr + 687 roam_synch_ind_ptr->beaconProbeRespOffset; 688 roam_synch_ind_ptr->beaconProbeRespLength = 689 synch_event->bcn_probe_rsp_len; 690 qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame, 691 roam_synch_ind_ptr->beaconProbeRespLength); 692 /* ReAssoc Rsp data */ 693 roam_synch_ind_ptr->reassocRespOffset = 694 sizeof(struct roam_offload_synch_ind) + 695 roam_synch_ind_ptr->beaconProbeRespLength; 696 roam_synch_ind_ptr->reassocRespLength = synch_event->reassoc_rsp_len; 697 reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + 698 roam_synch_ind_ptr->reassocRespOffset; 699 qdf_mem_copy(reassoc_rsp_ptr, 700 param_buf->reassoc_rsp_frame, 701 roam_synch_ind_ptr->reassocRespLength); 702 703 /* ReAssoc Req data */ 704 roam_synch_ind_ptr->reassoc_req_offset = 705 sizeof(struct roam_offload_synch_ind) + 706 roam_synch_ind_ptr->beaconProbeRespLength + 707 roam_synch_ind_ptr->reassocRespLength; 708 roam_synch_ind_ptr->reassoc_req_length = synch_event->reassoc_req_len; 709 reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr + 710 roam_synch_ind_ptr->reassoc_req_offset; 711 qdf_mem_copy(reassoc_req_ptr, param_buf->reassoc_req_frame, 712 roam_synch_ind_ptr->reassoc_req_length); 713 } 714 715 /** 716 * wma_fill_roam_synch_buffer() - Fill the the roam sync buffer 717 * @wma: Global WMA Handle 718 * @roam_synch_ind_ptr: Buffer to be filled 719 * @param_buf: Source buffer 720 * 721 * Firmware sends all the required information required for roam 722 * synch propagation as TLV's and stored in param_buf. These 723 * parameters are parsed and filled into the roam synch indication 724 * buffer which will be used at different layers for propagation. 725 * 726 * Return: Success or Failure 727 */ 728 static int wma_fill_roam_synch_buffer(tp_wma_handle wma, 729 struct roam_offload_synch_ind *roam_synch_ind_ptr, 730 WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) 731 { 732 wmi_roam_synch_event_fixed_param *synch_event; 733 wmi_channel *chan; 734 wmi_key_material *key; 735 wmi_key_material_ext *key_ft; 736 struct wma_txrx_node *iface = NULL; 737 wmi_roam_fils_synch_tlv_param *fils_info; 738 wmi_roam_pmk_cache_synch_tlv_param *pmk_cache_info; 739 int status = -EINVAL; 740 uint8_t kck_len; 741 uint8_t kek_len; 742 743 synch_event = param_buf->fixed_param; 744 roam_synch_ind_ptr->roamed_vdev_id = synch_event->vdev_id; 745 roam_synch_ind_ptr->auth_status = synch_event->auth_status; 746 roam_synch_ind_ptr->roam_reason = synch_event->roam_reason; 747 roam_synch_ind_ptr->rssi = synch_event->rssi; 748 iface = &wma->interfaces[synch_event->vdev_id]; 749 WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, 750 roam_synch_ind_ptr->bssid.bytes); 751 wma_debug("roamedVdevId %d authStatus %d roamReason %d rssi %d isBeacon %d", 752 roam_synch_ind_ptr->roamed_vdev_id, 753 roam_synch_ind_ptr->auth_status, 754 roam_synch_ind_ptr->roam_reason, 755 roam_synch_ind_ptr->rssi, 756 roam_synch_ind_ptr->isBeacon); 757 758 #ifdef FEATURE_CM_ENABLE 759 if (!QDF_IS_STATUS_SUCCESS( 760 cm_fw_roam_sync_start_ind(iface->vdev, 761 roam_synch_ind_ptr))) 762 #else 763 if (!QDF_IS_STATUS_SUCCESS( 764 wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr, 765 NULL, SIR_ROAMING_DEREGISTER_STA))) 766 #endif 767 { 768 wma_err("LFR3: CSR Roam synch cb failed"); 769 wma_free_roam_synch_frame_ind(iface); 770 return status; 771 } 772 773 /* 774 * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in 775 * synch_event driver would have received bcn_probe_rsp, reassoc_req 776 * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID 777 */ 778 if ((!synch_event->bcn_probe_rsp_len) && 779 (!synch_event->reassoc_req_len) && 780 (!synch_event->reassoc_rsp_len)) { 781 if (!iface->roam_synch_frame_ind.bcn_probe_rsp) { 782 wma_err("LFR3: bcn_probe_rsp is NULL"); 783 QDF_ASSERT(iface->roam_synch_frame_ind. 784 bcn_probe_rsp); 785 wma_free_roam_synch_frame_ind(iface); 786 return status; 787 } 788 if (!iface->roam_synch_frame_ind.reassoc_rsp) { 789 wma_err("LFR3: reassoc_rsp is NULL"); 790 QDF_ASSERT(iface->roam_synch_frame_ind. 791 reassoc_rsp); 792 wma_free_roam_synch_frame_ind(iface); 793 return status; 794 } 795 if (!iface->roam_synch_frame_ind.reassoc_req) { 796 wma_err("LFR3: reassoc_req is NULL"); 797 QDF_ASSERT(iface->roam_synch_frame_ind. 798 reassoc_req); 799 wma_free_roam_synch_frame_ind(iface); 800 return status; 801 } 802 wma_fill_data_synch_frame_event(wma, roam_synch_ind_ptr, iface); 803 } else { 804 wma_fill_data_synch_event(wma, roam_synch_ind_ptr, param_buf); 805 } 806 chan = param_buf->chan; 807 if (chan) { 808 roam_synch_ind_ptr->chan_freq = chan->mhz; 809 roam_synch_ind_ptr->phy_mode = 810 wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan)); 811 } else { 812 roam_synch_ind_ptr->phy_mode = WLAN_PHYMODE_AUTO; 813 } 814 815 key = param_buf->key; 816 key_ft = param_buf->key_ext; 817 if (key) { 818 roam_synch_ind_ptr->kck_len = KCK_KEY_LEN; 819 qdf_mem_copy(roam_synch_ind_ptr->kck, key->kck, 820 KCK_KEY_LEN); 821 roam_synch_ind_ptr->kek_len = SIR_KEK_KEY_LEN; 822 qdf_mem_copy(roam_synch_ind_ptr->kek, key->kek, 823 SIR_KEK_KEY_LEN); 824 qdf_mem_copy(roam_synch_ind_ptr->replay_ctr, 825 key->replay_counter, REPLAY_CTR_LEN); 826 } else if (key_ft) { 827 /* 828 * For AKM 00:0F:AC (FT suite-B-SHA384) 829 * KCK-bits:192 KEK-bits:256 830 * Firmware sends wmi_key_material_ext tlv now only if 831 * auth is FT Suite-B SHA-384 auth. If further new suites 832 * are added, add logic to get kck, kek bits based on 833 * akm protocol 834 */ 835 kck_len = KCK_192BIT_KEY_LEN; 836 kek_len = KEK_256BIT_KEY_LEN; 837 838 roam_synch_ind_ptr->kck_len = kck_len; 839 qdf_mem_copy(roam_synch_ind_ptr->kck, 840 key_ft->key_buffer, kck_len); 841 842 roam_synch_ind_ptr->kek_len = kek_len; 843 qdf_mem_copy(roam_synch_ind_ptr->kek, 844 (key_ft->key_buffer + kck_len), 845 kek_len); 846 847 qdf_mem_copy(roam_synch_ind_ptr->replay_ctr, 848 (key_ft->key_buffer + kek_len + kck_len), 849 REPLAY_CTR_LEN); 850 } 851 852 if (param_buf->hw_mode_transition_fixed_param) 853 wma_process_pdev_hw_mode_trans_ind(wma, 854 param_buf->hw_mode_transition_fixed_param, 855 param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, 856 &roam_synch_ind_ptr->hw_mode_trans_ind); 857 else 858 wma_debug("hw_mode transition fixed param is NULL"); 859 860 fils_info = param_buf->roam_fils_synch_info; 861 if (fils_info) { 862 if ((fils_info->kek_len > MAX_KEK_LENGTH) || 863 (fils_info->pmk_len > MAX_PMK_LEN)) { 864 wma_err("Invalid kek_len %d or pmk_len %d", 865 fils_info->kek_len, 866 fils_info->pmk_len); 867 wma_free_roam_synch_frame_ind(iface); 868 return status; 869 } 870 871 roam_synch_ind_ptr->kek_len = fils_info->kek_len; 872 qdf_mem_copy(roam_synch_ind_ptr->kek, fils_info->kek, 873 fils_info->kek_len); 874 875 roam_synch_ind_ptr->pmk_len = fils_info->pmk_len; 876 qdf_mem_copy(roam_synch_ind_ptr->pmk, fils_info->pmk, 877 fils_info->pmk_len); 878 879 qdf_mem_copy(roam_synch_ind_ptr->pmkid, fils_info->pmkid, 880 PMKID_LEN); 881 882 roam_synch_ind_ptr->update_erp_next_seq_num = 883 fils_info->update_erp_next_seq_num; 884 roam_synch_ind_ptr->next_erp_seq_num = 885 fils_info->next_erp_seq_num; 886 887 wma_debug("Update ERP Seq Num %d, Next ERP Seq Num %d", 888 roam_synch_ind_ptr->update_erp_next_seq_num, 889 roam_synch_ind_ptr->next_erp_seq_num); 890 } 891 892 pmk_cache_info = param_buf->roam_pmk_cache_synch_info; 893 if (pmk_cache_info && (pmk_cache_info->pmk_len)) { 894 if (pmk_cache_info->pmk_len > MAX_PMK_LEN) { 895 wma_err("Invalid pmk_len %d", 896 pmk_cache_info->pmk_len); 897 wma_free_roam_synch_frame_ind(iface); 898 return status; 899 } 900 901 roam_synch_ind_ptr->pmk_len = pmk_cache_info->pmk_len; 902 qdf_mem_copy(roam_synch_ind_ptr->pmk, 903 pmk_cache_info->pmk, pmk_cache_info->pmk_len); 904 qdf_mem_copy(roam_synch_ind_ptr->pmkid, 905 pmk_cache_info->pmkid, PMKID_LEN); 906 } 907 wma_free_roam_synch_frame_ind(iface); 908 return 0; 909 } 910 911 /** 912 * wma_roam_update_vdev() - Update the STA and BSS 913 * @wma: Global WMA Handle 914 * @roam_synch_ind_ptr: Information needed for roam sync propagation 915 * 916 * This function will perform all the vdev related operations with 917 * respect to the self sta and the peer after roaming and completes 918 * the roam synch propagation with respect to WMA layer. 919 * 920 * Return: None 921 */ 922 static void 923 wma_roam_update_vdev(tp_wma_handle wma, 924 struct roam_offload_synch_ind *roam_synch_ind_ptr) 925 { 926 tDeleteStaParams *del_sta_params; 927 tAddStaParams *add_sta_params; 928 uint8_t vdev_id, *bssid; 929 int32_t uc_cipher, cipher_cap; 930 931 vdev_id = roam_synch_ind_ptr->roamed_vdev_id; 932 wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss; 933 934 del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); 935 if (!del_sta_params) { 936 return; 937 } 938 939 add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params)); 940 if (!add_sta_params) { 941 qdf_mem_free(del_sta_params); 942 return; 943 } 944 945 qdf_mem_zero(del_sta_params, sizeof(*del_sta_params)); 946 qdf_mem_zero(add_sta_params, sizeof(*add_sta_params)); 947 948 del_sta_params->smesessionId = vdev_id; 949 add_sta_params->staType = STA_ENTRY_SELF; 950 add_sta_params->smesessionId = vdev_id; 951 qdf_mem_copy(&add_sta_params->bssId, &roam_synch_ind_ptr->bssid.bytes, 952 QDF_MAC_ADDR_SIZE); 953 add_sta_params->assocId = roam_synch_ind_ptr->aid; 954 955 bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); 956 if (!bssid) { 957 wma_err("Failed to get bssid for vdev_%d", vdev_id); 958 return; 959 } 960 961 wma_delete_sta(wma, del_sta_params); 962 wma_delete_bss(wma, vdev_id); 963 wma_create_peer(wma, roam_synch_ind_ptr->bssid.bytes, 964 WMI_PEER_TYPE_DEFAULT, vdev_id); 965 966 /* Update new peer's uc cipher */ 967 uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, 968 WLAN_CRYPTO_PARAM_UCAST_CIPHER); 969 cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, 970 WLAN_CRYPTO_PARAM_CIPHER_CAP); 971 wma_set_peer_ucast_cipher(roam_synch_ind_ptr->bssid.bytes, uc_cipher, 972 cipher_cap); 973 wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params); 974 wma_add_sta(wma, add_sta_params); 975 qdf_mem_copy(bssid, roam_synch_ind_ptr->bssid.bytes, 976 QDF_MAC_ADDR_SIZE); 977 lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id, 978 roam_synch_ind_ptr); 979 qdf_mem_free(add_sta_params); 980 } 981 982 static void wma_update_phymode_on_roam(tp_wma_handle wma, uint8_t *bssid, 983 wmi_channel *chan, 984 struct wma_txrx_node *iface) 985 { 986 enum wlan_phymode bss_phymode; 987 struct wlan_channel *des_chan; 988 struct wlan_channel *bss_chan; 989 struct vdev_mlme_obj *vdev_mlme; 990 uint8_t channel; 991 struct wlan_objmgr_pdev *pdev = NULL; 992 993 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); 994 if (!vdev_mlme) 995 return; 996 997 pdev = wlan_vdev_get_pdev(vdev_mlme->vdev); 998 999 channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq); 1000 if (chan) 1001 bss_phymode = 1002 wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan)); 1003 else 1004 wma_get_phy_mode_cb(iface->ch_freq, 1005 iface->chan_width, &bss_phymode); 1006 1007 /* Update vdev mlme channel info after roaming */ 1008 des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev); 1009 bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev); 1010 des_chan->ch_phymode = bss_phymode; 1011 des_chan->ch_width = iface->chan_width; 1012 if (chan) { 1013 des_chan->ch_freq = chan->mhz; 1014 des_chan->ch_cfreq1 = chan->band_center_freq1; 1015 des_chan->ch_cfreq2 = chan->band_center_freq2; 1016 } else { 1017 wma_err("LFR3: invalid chan"); 1018 } 1019 qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel)); 1020 1021 /* Till conversion is not done in WMI we need to fill fw phy mode */ 1022 vdev_mlme->mgmt.generic.phy_mode = wma_host_to_fw_phymode(bss_phymode); 1023 1024 /* update new phymode to peer */ 1025 wma_objmgr_set_peer_mlme_phymode(wma, bssid, bss_phymode); 1026 1027 wma_debug("LFR3: new phymode %d", bss_phymode); 1028 } 1029 1030 #ifndef FEATURE_CM_ENABLE 1031 static void wma_post_roam_sync_failure(tp_wma_handle wma, uint8_t vdev_id) 1032 { 1033 wlan_cm_roam_stop_req(wma->psoc, vdev_id, REASON_ROAM_SYNCH_FAILED); 1034 wma_debug("In cleanup: RSO Command:%d, reason %d vdev %d", 1035 ROAM_SCAN_OFFLOAD_STOP, REASON_ROAM_SYNCH_FAILED, vdev_id); 1036 } 1037 #endif 1038 1039 int wma_mlme_roam_synch_event_handler_cb(void *handle, uint8_t *event, 1040 uint32_t len) 1041 { 1042 WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; 1043 wmi_roam_synch_event_fixed_param *synch_event = NULL; 1044 tp_wma_handle wma = (tp_wma_handle) handle; 1045 struct roam_offload_synch_ind *roam_synch_ind_ptr = NULL; 1046 struct bss_description *bss_desc_ptr = NULL; 1047 uint16_t ie_len = 0; 1048 int status = -EINVAL; 1049 qdf_time_t roam_synch_received = qdf_get_system_timestamp(); 1050 uint32_t roam_synch_data_len; 1051 A_UINT32 bcn_probe_rsp_len; 1052 A_UINT32 reassoc_rsp_len; 1053 A_UINT32 reassoc_req_len; 1054 1055 wma_debug("LFR3: Received WMA_ROAM_OFFLOAD_SYNCH_IND"); 1056 if (!event) { 1057 wma_err("event param null"); 1058 goto cleanup_label; 1059 } 1060 1061 param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event; 1062 if (!param_buf) { 1063 wma_err("received null buf from target"); 1064 goto cleanup_label; 1065 } 1066 1067 synch_event = param_buf->fixed_param; 1068 if (!synch_event) { 1069 wma_err("received null event data from target"); 1070 goto cleanup_label; 1071 } 1072 1073 if (synch_event->vdev_id >= wma->max_bssid) { 1074 wma_err("received invalid vdev_id %d", synch_event->vdev_id); 1075 return status; 1076 } 1077 1078 /* 1079 * This flag is set during ROAM_START and once this event is being 1080 * executed which is a run to completion, no other event can interrupt 1081 * this in MC thread context. So, it is OK to reset the flag here as 1082 * soon as we receive this event. 1083 */ 1084 wma->interfaces[synch_event->vdev_id].roaming_in_progress = false; 1085 1086 if (synch_event->bcn_probe_rsp_len > 1087 param_buf->num_bcn_probe_rsp_frame || 1088 synch_event->reassoc_req_len > 1089 param_buf->num_reassoc_req_frame || 1090 synch_event->reassoc_rsp_len > 1091 param_buf->num_reassoc_rsp_frame) { 1092 wma_debug("Invalid synch payload: LEN bcn:%d, req:%d, rsp:%d", 1093 synch_event->bcn_probe_rsp_len, 1094 synch_event->reassoc_req_len, 1095 synch_event->reassoc_rsp_len); 1096 goto cleanup_label; 1097 } 1098 1099 wlan_roam_debug_log(synch_event->vdev_id, DEBUG_ROAM_SYNCH_IND, 1100 DEBUG_INVALID_PEER_ID, NULL, NULL, 1101 synch_event->bssid.mac_addr31to0, 1102 synch_event->bssid.mac_addr47to32); 1103 DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, 1104 synch_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, 1105 QDF_PROTO_TYPE_EVENT, QDF_ROAM_SYNCH)); 1106 1107 if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(wma->psoc, synch_event->vdev_id)) { 1108 wma_err("Ignoring RSI since one is already in progress"); 1109 goto cleanup_label; 1110 } 1111 1112 /* 1113 * All below length fields are unsigned and hence positive numbers. 1114 * Maximum number during the addition would be (3 * MAX_LIMIT(UINT32) + 1115 * few fixed fields). 1116 */ 1117 wma_debug("synch payload: LEN bcn:%d, req:%d, rsp:%d", 1118 synch_event->bcn_probe_rsp_len, 1119 synch_event->reassoc_req_len, 1120 synch_event->reassoc_rsp_len); 1121 1122 /* 1123 * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in 1124 * synch_event driver would have received bcn_probe_rsp, reassoc_req 1125 * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID 1126 */ 1127 if ((!synch_event->bcn_probe_rsp_len) && 1128 (!synch_event->reassoc_req_len) && 1129 (!synch_event->reassoc_rsp_len)) { 1130 bcn_probe_rsp_len = wma->interfaces[synch_event->vdev_id]. 1131 roam_synch_frame_ind. 1132 bcn_probe_rsp_len; 1133 reassoc_req_len = wma->interfaces[synch_event->vdev_id]. 1134 roam_synch_frame_ind.reassoc_req_len; 1135 reassoc_rsp_len = wma->interfaces[synch_event->vdev_id]. 1136 roam_synch_frame_ind.reassoc_rsp_len; 1137 1138 roam_synch_data_len = bcn_probe_rsp_len + reassoc_rsp_len + 1139 reassoc_req_len + sizeof(struct roam_offload_synch_ind); 1140 1141 wma_debug("Updated synch payload: LEN bcn:%d, req:%d, rsp:%d", 1142 bcn_probe_rsp_len, 1143 reassoc_req_len, 1144 reassoc_rsp_len); 1145 } else { 1146 bcn_probe_rsp_len = synch_event->bcn_probe_rsp_len; 1147 reassoc_req_len = synch_event->reassoc_req_len; 1148 reassoc_rsp_len = synch_event->reassoc_rsp_len; 1149 1150 if (synch_event->bcn_probe_rsp_len > WMI_SVC_MSG_MAX_SIZE) 1151 goto cleanup_label; 1152 if (synch_event->reassoc_rsp_len > 1153 (WMI_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len)) 1154 goto cleanup_label; 1155 if (synch_event->reassoc_req_len > 1156 WMI_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len + 1157 synch_event->reassoc_rsp_len)) 1158 goto cleanup_label; 1159 1160 roam_synch_data_len = bcn_probe_rsp_len + 1161 reassoc_rsp_len + reassoc_req_len; 1162 1163 /* 1164 * Below is the check for the entire size of the message 1165 * received from the firmware. 1166 */ 1167 if (roam_synch_data_len > WMI_SVC_MSG_MAX_SIZE - 1168 (sizeof(*synch_event) + sizeof(wmi_channel) + 1169 sizeof(wmi_key_material) + sizeof(uint32_t))) 1170 goto cleanup_label; 1171 1172 roam_synch_data_len += sizeof(struct roam_offload_synch_ind); 1173 } 1174 1175 cds_host_diag_log_work(&wma->roam_ho_wl, 1176 WMA_ROAM_HO_WAKE_LOCK_DURATION, 1177 WIFI_POWER_EVENT_WAKELOCK_WOW); 1178 qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl, 1179 WMA_ROAM_HO_WAKE_LOCK_DURATION); 1180 1181 roam_synch_ind_ptr = qdf_mem_malloc(roam_synch_data_len); 1182 if (!roam_synch_ind_ptr) { 1183 QDF_ASSERT(roam_synch_ind_ptr); 1184 status = -ENOMEM; 1185 goto cleanup_label; 1186 } 1187 qdf_mem_zero(roam_synch_ind_ptr, roam_synch_data_len); 1188 status = wma_fill_roam_synch_buffer(wma, 1189 roam_synch_ind_ptr, param_buf); 1190 if (status != 0) 1191 goto cleanup_label; 1192 /* 24 byte MAC header and 12 byte to ssid IE */ 1193 if (roam_synch_ind_ptr->beaconProbeRespLength > 1194 (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { 1195 ie_len = roam_synch_ind_ptr->beaconProbeRespLength - 1196 (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); 1197 } else { 1198 wma_err("LFR3: Invalid Beacon Length"); 1199 goto cleanup_label; 1200 } 1201 bss_desc_ptr = qdf_mem_malloc(sizeof(struct bss_description) + ie_len); 1202 if (!bss_desc_ptr) { 1203 QDF_ASSERT(bss_desc_ptr); 1204 status = -ENOMEM; 1205 goto cleanup_label; 1206 } 1207 qdf_mem_zero(bss_desc_ptr, sizeof(struct bss_description) + ie_len); 1208 if (QDF_IS_STATUS_ERROR(wma->pe_roam_synch_cb(wma->mac_context, 1209 roam_synch_ind_ptr, bss_desc_ptr, 1210 SIR_ROAM_SYNCH_PROPAGATION))) { 1211 wma_err("LFR3: PE roam synch cb failed"); 1212 status = -EBUSY; 1213 goto cleanup_label; 1214 } 1215 1216 wma_roam_update_vdev(wma, roam_synch_ind_ptr); 1217 /* update freq and channel width */ 1218 wma->interfaces[synch_event->vdev_id].ch_freq = 1219 roam_synch_ind_ptr->chan_freq; 1220 wma->interfaces[synch_event->vdev_id].chan_width = 1221 roam_synch_ind_ptr->chan_width; 1222 /* 1223 * update phy_mode in wma to avoid mismatch in phymode between host and 1224 * firmware. The phymode stored in peer->peer_mlme.phymode is 1225 * sent to firmware as part of opmode update during either - vht opmode 1226 * action frame received or during opmode change detected while 1227 * processing beacon. Any mismatch of this value with firmware phymode 1228 * results in firmware assert. 1229 */ 1230 wma_update_phymode_on_roam(wma, roam_synch_ind_ptr->bssid.bytes, 1231 param_buf->chan, 1232 &wma->interfaces[synch_event->vdev_id]); 1233 #ifdef FEATURE_CM_ENABLE 1234 cm_fw_roam_sync_propagation(wma->psoc, 1235 synch_event->vdev_id, 1236 roam_synch_ind_ptr); 1237 #else 1238 wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr, 1239 bss_desc_ptr, SIR_ROAM_SYNCH_PROPAGATION); 1240 wma_process_roam_synch_complete(wma, synch_event->vdev_id); 1241 wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr, 1242 bss_desc_ptr, SIR_ROAM_SYNCH_COMPLETE); 1243 #endif 1244 1245 wma->interfaces[synch_event->vdev_id].roam_synch_delay = 1246 qdf_get_system_timestamp() - roam_synch_received; 1247 wma_debug("LFR3: roam_synch_delay:%d", 1248 wma->interfaces[synch_event->vdev_id].roam_synch_delay); 1249 #ifndef FEATURE_CM_ENABLE 1250 wma->csr_roam_synch_cb(wma->mac_context, roam_synch_ind_ptr, 1251 bss_desc_ptr, SIR_ROAM_SYNCH_NAPI_OFF); 1252 #endif 1253 1254 status = 0; 1255 1256 cleanup_label: 1257 if (status != 0) { 1258 #ifdef FEATURE_CM_ENABLE 1259 if (synch_event) { 1260 cm_fw_roam_abort_req(wma->psoc, synch_event->vdev_id); 1261 cm_roam_stop_req(wma->psoc, synch_event->vdev_id, 1262 REASON_ROAM_SYNCH_FAILED); 1263 } 1264 #else 1265 if (roam_synch_ind_ptr) 1266 wma->csr_roam_synch_cb(wma->mac_context, 1267 roam_synch_ind_ptr, NULL, 1268 SIR_ROAMING_ABORT); 1269 if (synch_event) 1270 wma_post_roam_sync_failure(wma, synch_event->vdev_id); 1271 #endif 1272 } 1273 1274 if (roam_synch_ind_ptr && roam_synch_ind_ptr->ric_tspec_data) 1275 qdf_mem_free(roam_synch_ind_ptr->ric_tspec_data); 1276 if (roam_synch_ind_ptr) 1277 qdf_mem_free(roam_synch_ind_ptr); 1278 if (bss_desc_ptr) 1279 qdf_mem_free(bss_desc_ptr); 1280 1281 return status; 1282 } 1283 1284 int wma_roam_synch_frame_event_handler(void *handle, uint8_t *event, 1285 uint32_t len) 1286 { 1287 WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *param_buf = NULL; 1288 wmi_roam_synch_frame_event_fixed_param *synch_frame_event = NULL; 1289 tp_wma_handle wma = (tp_wma_handle) handle; 1290 A_UINT32 vdev_id; 1291 struct wma_txrx_node *iface = NULL; 1292 int status = -EINVAL; 1293 1294 if (!event) { 1295 wma_err("event param null"); 1296 return status; 1297 } 1298 1299 param_buf = (WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *) event; 1300 if (!param_buf) { 1301 wma_err("received null buf from target"); 1302 return status; 1303 } 1304 1305 synch_frame_event = param_buf->fixed_param; 1306 if (!synch_frame_event) { 1307 wma_err("received null event data from target"); 1308 return status; 1309 } 1310 1311 if (synch_frame_event->vdev_id >= wma->max_bssid) { 1312 wma_err("received invalid vdev_id %d", 1313 synch_frame_event->vdev_id); 1314 return status; 1315 } 1316 1317 if (synch_frame_event->bcn_probe_rsp_len > 1318 param_buf->num_bcn_probe_rsp_frame || 1319 synch_frame_event->reassoc_req_len > 1320 param_buf->num_reassoc_req_frame || 1321 synch_frame_event->reassoc_rsp_len > 1322 param_buf->num_reassoc_rsp_frame) { 1323 wma_err("fixed/actual len err: bcn:%d/%d req:%d/%d rsp:%d/%d", 1324 synch_frame_event->bcn_probe_rsp_len, 1325 param_buf->num_bcn_probe_rsp_frame, 1326 synch_frame_event->reassoc_req_len, 1327 param_buf->num_reassoc_req_frame, 1328 synch_frame_event->reassoc_rsp_len, 1329 param_buf->num_reassoc_rsp_frame); 1330 return status; 1331 } 1332 1333 vdev_id = synch_frame_event->vdev_id; 1334 iface = &wma->interfaces[vdev_id]; 1335 1336 if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id)) { 1337 wma_err("Ignoring this event as it is unexpected"); 1338 wma_free_roam_synch_frame_ind(iface); 1339 return status; 1340 } 1341 1342 wma_debug("LFR3: Roam synch frame payload: LEN bcn:%d, req:%d, rsp:%d morefrag: %d", 1343 synch_frame_event->bcn_probe_rsp_len, 1344 synch_frame_event->reassoc_req_len, 1345 synch_frame_event->reassoc_rsp_len, 1346 synch_frame_event->more_frag); 1347 1348 if (synch_frame_event->bcn_probe_rsp_len) { 1349 iface->roam_synch_frame_ind.bcn_probe_rsp_len = 1350 synch_frame_event->bcn_probe_rsp_len; 1351 iface->roam_synch_frame_ind.is_beacon = 1352 synch_frame_event->is_beacon; 1353 1354 if (iface->roam_synch_frame_ind.bcn_probe_rsp) 1355 qdf_mem_free(iface->roam_synch_frame_ind. 1356 bcn_probe_rsp); 1357 iface->roam_synch_frame_ind.bcn_probe_rsp = 1358 qdf_mem_malloc(iface->roam_synch_frame_ind. 1359 bcn_probe_rsp_len); 1360 if (!iface->roam_synch_frame_ind.bcn_probe_rsp) { 1361 QDF_ASSERT(iface->roam_synch_frame_ind. 1362 bcn_probe_rsp); 1363 status = -ENOMEM; 1364 wma_free_roam_synch_frame_ind(iface); 1365 return status; 1366 } 1367 qdf_mem_copy(iface->roam_synch_frame_ind. 1368 bcn_probe_rsp, 1369 param_buf->bcn_probe_rsp_frame, 1370 iface->roam_synch_frame_ind.bcn_probe_rsp_len); 1371 } 1372 1373 if (synch_frame_event->reassoc_req_len) { 1374 iface->roam_synch_frame_ind.reassoc_req_len = 1375 synch_frame_event->reassoc_req_len; 1376 1377 if (iface->roam_synch_frame_ind.reassoc_req) 1378 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); 1379 iface->roam_synch_frame_ind.reassoc_req = 1380 qdf_mem_malloc(iface->roam_synch_frame_ind. 1381 reassoc_req_len); 1382 if (!iface->roam_synch_frame_ind.reassoc_req) { 1383 QDF_ASSERT(iface->roam_synch_frame_ind. 1384 reassoc_req); 1385 status = -ENOMEM; 1386 wma_free_roam_synch_frame_ind(iface); 1387 return status; 1388 } 1389 qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_req, 1390 param_buf->reassoc_req_frame, 1391 iface->roam_synch_frame_ind.reassoc_req_len); 1392 } 1393 1394 if (synch_frame_event->reassoc_rsp_len) { 1395 iface->roam_synch_frame_ind.reassoc_rsp_len = 1396 synch_frame_event->reassoc_rsp_len; 1397 1398 if (iface->roam_synch_frame_ind.reassoc_rsp) 1399 qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); 1400 1401 iface->roam_synch_frame_ind.reassoc_rsp = 1402 qdf_mem_malloc(iface->roam_synch_frame_ind. 1403 reassoc_rsp_len); 1404 if (!iface->roam_synch_frame_ind.reassoc_rsp) { 1405 QDF_ASSERT(iface->roam_synch_frame_ind. 1406 reassoc_rsp); 1407 status = -ENOMEM; 1408 wma_free_roam_synch_frame_ind(iface); 1409 return status; 1410 } 1411 qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_rsp, 1412 param_buf->reassoc_rsp_frame, 1413 iface->roam_synch_frame_ind.reassoc_rsp_len); 1414 } 1415 return 0; 1416 } 1417 1418 /** 1419 * __wma_roam_synch_event_handler() - roam synch event handler 1420 * @handle: wma handle 1421 * @event: event data 1422 * @len: length of data 1423 * 1424 * This function is roam synch event handler.It sends roam 1425 * indication for upper layer. 1426 * 1427 * Return: Success or Failure status 1428 */ 1429 int wma_roam_synch_event_handler(void *handle, uint8_t *event, 1430 uint32_t len) 1431 { 1432 int status = -EINVAL; 1433 wmi_roam_synch_event_fixed_param *synch_event = NULL; 1434 WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; 1435 tp_wma_handle wma = (tp_wma_handle)handle; 1436 #ifndef FEATURE_CM_ENABLE 1437 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; 1438 struct wma_txrx_node *iface = NULL; 1439 struct vdev_mlme_obj *mlme_obj; 1440 #endif 1441 if (!event) { 1442 wma_err_rl("event param null"); 1443 return status; 1444 } 1445 1446 param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *)event; 1447 if (!param_buf) { 1448 wma_err_rl("received null buf from target"); 1449 return status; 1450 } 1451 synch_event = param_buf->fixed_param; 1452 if (!synch_event) { 1453 wma_err_rl("received null event data from target"); 1454 return status; 1455 } 1456 1457 if (synch_event->vdev_id >= wma->max_bssid) { 1458 wma_err_rl("received invalid vdev_id %d", 1459 synch_event->vdev_id); 1460 return status; 1461 } 1462 #ifdef FEATURE_CM_ENABLE 1463 cm_fw_roam_sync_req(wma->psoc, synch_event->vdev_id, event, len); 1464 #else 1465 iface = &wma->interfaces[synch_event->vdev_id]; 1466 mlme_obj = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); 1467 if (mlme_obj) 1468 mlme_obj->mgmt.generic.tx_pwrlimit = 1469 synch_event->max_allowed_tx_power; 1470 1471 qdf_status = wlan_vdev_mlme_sm_deliver_evt(iface->vdev, 1472 WLAN_VDEV_SM_EV_ROAM, 1473 len, 1474 event); 1475 if (QDF_IS_STATUS_ERROR(qdf_status)) { 1476 wma_err("Failed to send the EV_ROAM"); 1477 wma_post_roam_sync_failure(wma, synch_event->vdev_id); 1478 return status; 1479 } 1480 wma_debug("Posted EV_ROAM to VDEV SM"); 1481 #endif 1482 return 0; 1483 } 1484 1485 int wma_roam_auth_offload_event_handler(WMA_HANDLE handle, uint8_t *event, 1486 uint32_t len) 1487 { 1488 QDF_STATUS status; 1489 tp_wma_handle wma = (tp_wma_handle) handle; 1490 struct mac_context *mac_ctx; 1491 wmi_roam_preauth_start_event_fixed_param *rso_auth_start_ev; 1492 WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *param_buf; 1493 struct qdf_mac_addr ap_bssid; 1494 uint8_t vdev_id; 1495 1496 if (!event) { 1497 wma_err_rl("received null event from target"); 1498 return -EINVAL; 1499 } 1500 1501 param_buf = (WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *) event; 1502 if (!param_buf) { 1503 wma_err_rl("received null buf from target"); 1504 return -EINVAL; 1505 } 1506 1507 rso_auth_start_ev = param_buf->fixed_param; 1508 if (!rso_auth_start_ev) { 1509 wma_err_rl("received null event data from target"); 1510 return -EINVAL; 1511 } 1512 1513 if (rso_auth_start_ev->vdev_id > wma->max_bssid) { 1514 wma_err_rl("received invalid vdev_id %d", 1515 rso_auth_start_ev->vdev_id); 1516 return -EINVAL; 1517 } 1518 1519 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 1520 if (!mac_ctx) { 1521 wma_err("NULL mac ptr"); 1522 QDF_ASSERT(0); 1523 return -EINVAL; 1524 } 1525 1526 cds_host_diag_log_work(&wma->roam_preauth_wl, 1527 WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION, 1528 WIFI_POWER_EVENT_WAKELOCK_WOW); 1529 qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl, 1530 WMA_ROAM_HO_WAKE_LOCK_DURATION); 1531 1532 WMI_MAC_ADDR_TO_CHAR_ARRAY(&rso_auth_start_ev->candidate_ap_bssid, 1533 ap_bssid.bytes); 1534 if (qdf_is_macaddr_zero(&ap_bssid) || 1535 qdf_is_macaddr_broadcast(&ap_bssid) || 1536 qdf_is_macaddr_group(&ap_bssid)) { 1537 wma_err_rl("Invalid bssid"); 1538 return -EINVAL; 1539 } 1540 1541 vdev_id = rso_auth_start_ev->vdev_id; 1542 wma_debug("Received Roam auth offload event for bss:"QDF_MAC_ADDR_FMT" vdev_id:%d", 1543 QDF_MAC_ADDR_REF(ap_bssid.bytes), vdev_id); 1544 1545 lim_sae_auth_cleanup_retry(mac_ctx, vdev_id); 1546 status = wma->csr_roam_auth_event_handle_cb(mac_ctx, vdev_id, ap_bssid); 1547 if (QDF_IS_STATUS_ERROR(status)) { 1548 wma_err_rl("Trigger pre-auth failed"); 1549 return -EINVAL; 1550 } 1551 1552 return 0; 1553 } 1554 1555 int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, 1556 uint8_t *event, 1557 uint32_t len) 1558 { 1559 tp_wma_handle wma = (tp_wma_handle)handle; 1560 WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *param_buf; 1561 wmi_roam_scan_channel_list_event_fixed_param *fixed_param; 1562 uint8_t vdev_id, i = 0, num_ch = 0; 1563 struct roam_scan_ch_resp *resp; 1564 struct scheduler_msg sme_msg = {0}; 1565 1566 param_buf = (WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *)event; 1567 if (!param_buf) { 1568 wma_err_rl("NULL event received from target"); 1569 return -EINVAL; 1570 } 1571 1572 fixed_param = param_buf->fixed_param; 1573 if (!fixed_param) { 1574 wma_err_rl(" NULL fixed param"); 1575 return -EINVAL; 1576 } 1577 1578 vdev_id = fixed_param->vdev_id; 1579 if (vdev_id >= wma->max_bssid) { 1580 wma_err_rl("Invalid vdev_id %d", vdev_id); 1581 return -EINVAL; 1582 } 1583 1584 num_ch = (param_buf->num_channel_list < 1585 WNI_CFG_VALID_CHANNEL_LIST_LEN) ? 1586 param_buf->num_channel_list : 1587 WNI_CFG_VALID_CHANNEL_LIST_LEN; 1588 1589 resp = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp) + 1590 num_ch * sizeof(param_buf->channel_list[0])); 1591 if (!resp) 1592 return -EINVAL; 1593 1594 resp->chan_list = (uint32_t *)(resp + 1); 1595 resp->vdev_id = vdev_id; 1596 resp->command_resp = fixed_param->command_response; 1597 resp->num_channels = param_buf->num_channel_list; 1598 1599 for (i = 0; i < num_ch; i++) 1600 resp->chan_list[i] = param_buf->channel_list[i]; 1601 1602 sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; 1603 sme_msg.bodyptr = resp; 1604 1605 if (scheduler_post_message(QDF_MODULE_ID_WMA, 1606 QDF_MODULE_ID_SME, 1607 QDF_MODULE_ID_SME, &sme_msg)) { 1608 wma_err("Failed to post msg to SME"); 1609 qdf_mem_free(sme_msg.bodyptr); 1610 return -EINVAL; 1611 } 1612 1613 return 0; 1614 } 1615 1616 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 1617 /** 1618 * wma_get_trigger_detail_str - Return roam trigger string from the 1619 * enum WMI_ROAM_TRIGGER_REASON 1620 * @roam_info: Pointer to the roam trigger info 1621 * @buf: Destination buffer to write the reason string 1622 * 1623 * Return: None 1624 */ 1625 static void 1626 wma_get_trigger_detail_str(struct wmi_roam_trigger_info *roam_info, char *buf) 1627 { 1628 uint16_t buf_cons, buf_left = MAX_ROAM_DEBUG_BUF_SIZE; 1629 char *temp = buf; 1630 1631 buf_cons = qdf_snprint(temp, buf_left, "Reason: \"%s\" ", 1632 mlme_get_roam_trigger_str(roam_info->trigger_reason)); 1633 temp += buf_cons; 1634 buf_left -= buf_cons; 1635 1636 if (roam_info->trigger_sub_reason) { 1637 buf_cons = qdf_snprint( 1638 temp, buf_left, "Sub-Reason: %s", 1639 mlme_get_sub_reason_str(roam_info->trigger_sub_reason)); 1640 temp += buf_cons; 1641 buf_left -= buf_cons; 1642 } 1643 1644 switch (roam_info->trigger_reason) { 1645 case WMI_ROAM_TRIGGER_REASON_PER: 1646 case WMI_ROAM_TRIGGER_REASON_BMISS: 1647 case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI: 1648 case WMI_ROAM_TRIGGER_REASON_MAWC: 1649 case WMI_ROAM_TRIGGER_REASON_DENSE: 1650 case WMI_ROAM_TRIGGER_REASON_BACKGROUND: 1651 case WMI_ROAM_TRIGGER_REASON_IDLE: 1652 case WMI_ROAM_TRIGGER_REASON_FORCED: 1653 case WMI_ROAM_TRIGGER_REASON_UNIT_TEST: 1654 return; 1655 case WMI_ROAM_TRIGGER_REASON_BTM: 1656 buf_cons = qdf_snprint(temp, buf_left, 1657 "Req_mode: %d Disassoc_timer: %d", 1658 roam_info->btm_trig_data.btm_request_mode, 1659 roam_info->btm_trig_data.disassoc_timer); 1660 temp += buf_cons; 1661 buf_left -= buf_cons; 1662 1663 buf_cons = qdf_snprint(temp, buf_left, 1664 "validity_interval: %d candidate_list_cnt: %d resp_status: %d, bss_termination_timeout: %d, mbo_assoc_retry_timeout: %d", 1665 roam_info->btm_trig_data.validity_interval, 1666 roam_info->btm_trig_data.candidate_list_count, 1667 roam_info->btm_trig_data.btm_resp_status, 1668 roam_info->btm_trig_data. 1669 btm_bss_termination_timeout, 1670 roam_info->btm_trig_data. 1671 btm_mbo_assoc_retry_timeout); 1672 buf_left -= buf_cons; 1673 temp += buf_cons; 1674 return; 1675 case WMI_ROAM_TRIGGER_REASON_BSS_LOAD: 1676 buf_cons = qdf_snprint(temp, buf_left, "CU: %d %% ", 1677 roam_info->cu_trig_data.cu_load); 1678 temp += buf_cons; 1679 buf_left -= buf_cons; 1680 return; 1681 case WMI_ROAM_TRIGGER_REASON_DEAUTH: 1682 buf_cons = qdf_snprint(temp, buf_left, "Type: %d Reason: %d ", 1683 roam_info->deauth_trig_data.type, 1684 roam_info->deauth_trig_data.reason); 1685 temp += buf_cons; 1686 buf_left -= buf_cons; 1687 return; 1688 case WMI_ROAM_TRIGGER_REASON_LOW_RSSI: 1689 case WMI_ROAM_TRIGGER_REASON_PERIODIC: 1690 /* 1691 * Use roam_info->current_rssi get the RSSI of current AP after 1692 * roam scan is triggered. This avoids discrepency with the 1693 * next rssi threshold value printed in roam scan details. 1694 * roam_info->rssi_trig_data.threshold gives the rssi threshold 1695 * for the Low Rssi/Periodic scan trigger. 1696 */ 1697 buf_cons = qdf_snprint(temp, buf_left, 1698 " Cur_Rssi threshold:%d Current AP RSSI: %d", 1699 roam_info->rssi_trig_data.threshold, 1700 roam_info->current_rssi); 1701 temp += buf_cons; 1702 buf_left -= buf_cons; 1703 return; 1704 case WMI_ROAM_TRIGGER_REASON_WTC_BTM: 1705 buf_cons = 1706 qdf_snprint(temp, buf_left, "Roaming Mode: %d, Trigger Reason: %d, Sub code:%d, wtc mode:%d, wtc scan mode:%d, wtc rssi th:%d, wtc candi rssi th:%d", 1707 roam_info->wtc_btm_trig_data.roaming_mode, 1708 roam_info->wtc_btm_trig_data.vsie_trigger_reason, 1709 roam_info->wtc_btm_trig_data.sub_code, 1710 roam_info->wtc_btm_trig_data.wtc_mode, 1711 roam_info->wtc_btm_trig_data.wtc_scan_mode, 1712 roam_info->wtc_btm_trig_data.wtc_rssi_th, 1713 roam_info->wtc_btm_trig_data.wtc_candi_rssi_th); 1714 temp += buf_cons; 1715 buf_left -= buf_cons; 1716 return; 1717 default: 1718 return; 1719 } 1720 } 1721 1722 /** 1723 * wma_rso_print_trigger_info - Roam trigger related details 1724 * @data: Pointer to the roam trigger data 1725 * @vdev_id: Vdev ID 1726 * 1727 * Prints the vdev, roam trigger reason, time of the day at which roaming 1728 * was triggered. 1729 * 1730 * Return: None 1731 */ 1732 static void 1733 wma_rso_print_trigger_info(struct wmi_roam_trigger_info *data, uint8_t vdev_id) 1734 { 1735 char *buf; 1736 char time[TIME_STRING_LEN]; 1737 1738 buf = qdf_mem_malloc(MAX_ROAM_DEBUG_BUF_SIZE); 1739 if (!buf) 1740 return; 1741 1742 wma_get_trigger_detail_str(data, buf); 1743 mlme_get_converted_timestamp(data->timestamp, time); 1744 wma_nofl_info("%s [ROAM_TRIGGER]: VDEV[%d] %s", time, vdev_id, buf); 1745 1746 qdf_mem_free(buf); 1747 } 1748 1749 /** 1750 * wma_rso_print_btm_rsp_info - BTM RSP related details 1751 * @data: Pointer to the btm rsp data 1752 * @vdev_id: vdev id 1753 * 1754 * Prints the vdev, btm status, target_bssid and vsie reason 1755 * 1756 * Return: None 1757 */ 1758 static void 1759 wma_rso_print_btm_rsp_info(struct roam_btm_response_data *data, 1760 uint8_t vdev_id) 1761 { 1762 char time[TIME_STRING_LEN]; 1763 1764 mlme_get_converted_timestamp(data->timestamp, time); 1765 wma_nofl_info("%s [BTM RSP]: VDEV[%d], Status: %d, VSIE reason: %d, BSSID: " QDF_MAC_ADDR_FMT, 1766 time, vdev_id, data->btm_status, data->vsie_reason, 1767 QDF_MAC_ADDR_REF(data->target_bssid.bytes)); 1768 } 1769 1770 /** 1771 * wma_rso_print_roam_initial_info - Roaming related initial details 1772 * @data: Pointer to the btm rsp data 1773 * @vdev_id: vdev id 1774 * 1775 * Prints the vdev, roam_full_scan_count, channel and rssi 1776 * utilization threhold and timer 1777 * 1778 * Return: None 1779 */ 1780 static void 1781 wma_rso_print_roam_initial_info(struct roam_initial_data *data, 1782 uint8_t vdev_id) 1783 { 1784 wma_nofl_info("[ROAM INIT INFO]: VDEV[%d], roam_full_scan_count: %d, rssi_th: %d, cu_th: %d, fw_cancel_timer_bitmap: %d", 1785 vdev_id, data->roam_full_scan_count, data->rssi_th, 1786 data->cu_th, data->fw_cancel_timer_bitmap); 1787 } 1788 1789 /** 1790 * wma_rso_print_roam_msg_info - Roaming related message details 1791 * @data: Pointer to the btm rsp data 1792 * @vdev_id: vdev id 1793 * 1794 * Prints the vdev, msg_id, msg_param1, msg_param2 and timer 1795 * 1796 * Return: None 1797 */ 1798 static void wma_rso_print_roam_msg_info(struct roam_msg_info *data, 1799 uint8_t vdev_id) 1800 { 1801 char time[TIME_STRING_LEN]; 1802 static const char msg_id1_str[] = "Roam RSSI TH Reset"; 1803 1804 if (data->msg_id == WMI_ROAM_MSG_RSSI_RECOVERED) { 1805 mlme_get_converted_timestamp(data->timestamp, time); 1806 wma_info("%s [ROAM MSG INFO]: VDEV[%d] %s, Current rssi: %d dbm, next_rssi_threshold: %d dbm", 1807 time, vdev_id, msg_id1_str, data->msg_param1, 1808 data->msg_param2); 1809 } 1810 } 1811 1812 /** 1813 * wma_log_roam_scan_candidates - Print roam scan candidate AP info 1814 * @ap: Pointer to the candidate AP list 1815 * @num_entries: Number of candidate APs 1816 * 1817 * Print the RSSI, CU load, Cu score, RSSI score, total score, BSSID 1818 * and time stamp at which the candidate was found details. 1819 * 1820 * Return: None 1821 */ 1822 static void 1823 wma_log_roam_scan_candidates(struct wmi_roam_candidate_info *ap, 1824 uint8_t num_entries) 1825 { 1826 uint16_t i; 1827 char time[TIME_STRING_LEN], time2[TIME_STRING_LEN]; 1828 1829 wma_nofl_info("%62s%62s", LINE_STR, LINE_STR); 1830 wma_nofl_info("%13s %16s %8s %4s %4s %5s/%3s %3s/%3s %7s %7s %6s %12s %20s", 1831 "AP BSSID", "TSTAMP", "CH", "TY", "ETP", "RSSI", 1832 "SCR", "CU%", "SCR", "TOT_SCR", "BL_RSN", "BL_SRC", 1833 "BL_TSTAMP", "BL_TIMEOUT(ms)"); 1834 wma_nofl_info("%62s%62s", LINE_STR, LINE_STR); 1835 1836 if (num_entries > MAX_ROAM_CANDIDATE_AP) 1837 num_entries = MAX_ROAM_CANDIDATE_AP; 1838 1839 for (i = 0; i < num_entries; i++) { 1840 mlme_get_converted_timestamp(ap->timestamp, time); 1841 mlme_get_converted_timestamp(ap->bl_timestamp, time2); 1842 wma_nofl_info(QDF_MAC_ADDR_FMT " %17s %4d %-4s %4d %3d/%-4d %2d/%-4d %5d %7d %7d %17s %9d", 1843 QDF_MAC_ADDR_REF(ap->bssid.bytes), time, 1844 ap->freq, 1845 ((ap->type == 0) ? "C_AP" : 1846 ((ap->type == 2) ? "R_AP" : "P_AP")), 1847 ap->etp, ap->rssi, ap->rssi_score, ap->cu_load, 1848 ap->cu_score, ap->total_score, ap->bl_reason, 1849 ap->bl_source, time2, ap->bl_original_timeout); 1850 ap++; 1851 } 1852 } 1853 1854 /** 1855 * wma_rso_print_scan_info - Print the roam scan details and candidate AP 1856 * details 1857 * @scan: Pointer to the received tlv after sanitization 1858 * @vdev_id: Vdev ID 1859 * @trigger: Roam scan trigger reason 1860 * @timestamp: Host timestamp in millisecs 1861 * 1862 * Prinst the roam scan details with time of the day when the scan was 1863 * triggered and roam candidate AP with score details 1864 * 1865 * Return: None 1866 */ 1867 static void 1868 wma_rso_print_scan_info(struct wmi_roam_scan_data *scan, uint8_t vdev_id, 1869 uint32_t trigger, uint32_t timestamp) 1870 { 1871 uint16_t num_ch = scan->num_chan; 1872 uint16_t buf_cons = 0, buf_left = ROAM_CHANNEL_BUF_SIZE; 1873 uint8_t i; 1874 char *buf, *buf1, *tmp; 1875 char time[TIME_STRING_LEN]; 1876 1877 buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE); 1878 if (!buf) 1879 return; 1880 1881 tmp = buf; 1882 /* For partial scans, print the channel info */ 1883 if (!scan->type) { 1884 buf_cons = qdf_snprint(tmp, buf_left, "{"); 1885 buf_left -= buf_cons; 1886 tmp += buf_cons; 1887 1888 for (i = 0; i < num_ch; i++) { 1889 buf_cons = qdf_snprint(tmp, buf_left, "%d ", 1890 scan->chan_freq[i]); 1891 buf_left -= buf_cons; 1892 tmp += buf_cons; 1893 } 1894 buf_cons = qdf_snprint(tmp, buf_left, "}"); 1895 buf_left -= buf_cons; 1896 tmp += buf_cons; 1897 } 1898 1899 buf1 = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE); 1900 if (!buf1) { 1901 qdf_mem_free(buf); 1902 return; 1903 } 1904 1905 if (WMI_ROAM_TRIGGER_REASON_LOW_RSSI == trigger || 1906 WMI_ROAM_TRIGGER_REASON_PERIODIC == trigger) 1907 qdf_snprint(buf1, ROAM_FAILURE_BUF_SIZE, 1908 "next_rssi_threshold: %d dBm", 1909 scan->next_rssi_threshold); 1910 1911 mlme_get_converted_timestamp(timestamp, time); 1912 wma_nofl_info("%s [ROAM_SCAN]: VDEV[%d] Scan_type: %s %s %s", 1913 time, vdev_id, mlme_get_roam_scan_type_str(scan->type), 1914 buf1, buf); 1915 wma_log_roam_scan_candidates(scan->ap, scan->num_ap); 1916 1917 qdf_mem_free(buf); 1918 qdf_mem_free(buf1); 1919 } 1920 1921 /** 1922 * wma_rso_print_roam_result() - Print roam result related info 1923 * @res: Roam result strucure pointer 1924 * @vdev_id: Vdev id 1925 * 1926 * Print roam result and failure reason if roaming failed. 1927 * 1928 * Return: None 1929 */ 1930 static void 1931 wma_rso_print_roam_result(struct wmi_roam_result *res, 1932 uint8_t vdev_id) 1933 { 1934 char *buf; 1935 char time[TIME_STRING_LEN]; 1936 1937 buf = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE); 1938 if (!buf) 1939 return; 1940 1941 if (res->status == 1) 1942 qdf_snprint(buf, ROAM_FAILURE_BUF_SIZE, "Reason: %s", 1943 mlme_get_roam_fail_reason_str(res->fail_reason)); 1944 1945 mlme_get_converted_timestamp(res->timestamp, time); 1946 wma_nofl_info("%s [ROAM_RESULT]: VDEV[%d] %s %s", 1947 time, vdev_id, mlme_get_roam_status_str(res->status), 1948 buf); 1949 1950 qdf_mem_free(buf); 1951 } 1952 1953 /** 1954 * wma_rso_print_11kv_info - Print neighbor report/BTM related data 1955 * @neigh_rpt: Pointer to the extracted TLV structure 1956 * @vdev_id: Vdev ID 1957 * 1958 * Print BTM/neighbor report info that is sent by firmware after 1959 * connection/roaming to an AP. 1960 * 1961 * Return: none 1962 */ 1963 static void 1964 wma_rso_print_11kv_info(struct wmi_neighbor_report_data *neigh_rpt, 1965 uint8_t vdev_id) 1966 { 1967 char time[TIME_STRING_LEN], time1[TIME_STRING_LEN]; 1968 char *buf, *tmp; 1969 uint8_t type = neigh_rpt->req_type, i; 1970 uint16_t buf_left = ROAM_CHANNEL_BUF_SIZE, buf_cons; 1971 uint8_t num_ch = neigh_rpt->num_freq; 1972 1973 if (!type) 1974 return; 1975 1976 buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE); 1977 if (!buf) 1978 return; 1979 1980 tmp = buf; 1981 if (num_ch) { 1982 buf_cons = qdf_snprint(tmp, buf_left, "{ "); 1983 buf_left -= buf_cons; 1984 tmp += buf_cons; 1985 1986 for (i = 0; i < num_ch; i++) { 1987 buf_cons = qdf_snprint(tmp, buf_left, "%d ", 1988 neigh_rpt->freq[i]); 1989 buf_left -= buf_cons; 1990 tmp += buf_cons; 1991 } 1992 1993 buf_cons = qdf_snprint(tmp, buf_left, "}"); 1994 buf_left -= buf_cons; 1995 tmp += buf_cons; 1996 } 1997 1998 mlme_get_converted_timestamp(neigh_rpt->req_time, time); 1999 wma_nofl_info("%s [%s] VDEV[%d]", time, 2000 (type == 1) ? "BTM_QUERY" : "NEIGH_RPT_REQ", vdev_id); 2001 2002 if (neigh_rpt->resp_time) { 2003 mlme_get_converted_timestamp(neigh_rpt->resp_time, time1); 2004 wma_nofl_info("%s [%s] VDEV[%d] %s", time1, 2005 (type == 1) ? "BTM_REQ" : "NEIGH_RPT_RSP", 2006 vdev_id, 2007 (num_ch > 0) ? buf : "NO Ch update"); 2008 } else { 2009 wma_nofl_info("%s No response received from AP", 2010 (type == 1) ? "BTM" : "NEIGH_RPT"); 2011 } 2012 qdf_mem_free(buf); 2013 } 2014 2015 int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event, 2016 uint32_t len) 2017 { 2018 tp_wma_handle wma = (tp_wma_handle) handle; 2019 WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; 2020 wmi_roam_stats_event_fixed_param *fixed_param; 2021 struct mlme_roam_debug_info *roam_info = NULL; 2022 uint8_t vdev_id, i; 2023 uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0, rem_tlv = 0; 2024 uint32_t rem_len; 2025 QDF_STATUS status; 2026 2027 param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)event; 2028 if (!param_buf) { 2029 wma_err_rl("NULL event received from target"); 2030 goto err; 2031 } 2032 2033 fixed_param = param_buf->fixed_param; 2034 if (!fixed_param) { 2035 wma_err_rl(" NULL fixed param"); 2036 goto err; 2037 } 2038 2039 vdev_id = fixed_param->vdev_id; 2040 if (vdev_id >= wma->max_bssid) { 2041 wma_err_rl("Invalid vdev_id %d", vdev_id); 2042 goto err; 2043 } 2044 2045 num_tlv = fixed_param->roam_scan_trigger_count; 2046 if (num_tlv > MAX_ROAM_SCAN_STATS_TLV) { 2047 wma_err_rl("Limiting roam triggers to 5"); 2048 num_tlv = MAX_ROAM_SCAN_STATS_TLV; 2049 } 2050 2051 rem_len = WMI_SVC_MSG_MAX_SIZE - sizeof(*fixed_param); 2052 if (rem_len < num_tlv * sizeof(wmi_roam_trigger_reason)) { 2053 wma_err_rl("Invalid roam trigger data"); 2054 goto err; 2055 } 2056 2057 rem_len -= num_tlv * sizeof(wmi_roam_trigger_reason); 2058 if (rem_len < num_tlv * sizeof(wmi_roam_scan_info)) { 2059 wma_err_rl("Invalid roam scan data"); 2060 goto err; 2061 } 2062 2063 rem_len -= num_tlv * sizeof(wmi_roam_scan_info); 2064 if (rem_len < num_tlv * sizeof(wmi_roam_result)) { 2065 wma_err_rl("Invalid roam result data"); 2066 goto err; 2067 } 2068 2069 rem_len -= num_tlv * sizeof(wmi_roam_result); 2070 if (rem_len < (num_tlv * sizeof(wmi_roam_neighbor_report_info))) { 2071 wma_err_rl("Invalid roam neighbor report data"); 2072 goto err; 2073 } 2074 2075 rem_len -= num_tlv * sizeof(wmi_roam_neighbor_report_info); 2076 if (rem_len < (param_buf->num_roam_scan_chan_info * 2077 sizeof(wmi_roam_scan_channel_info))) { 2078 wma_err_rl("Invalid roam chan data num_tlv:%d", 2079 param_buf->num_roam_scan_chan_info); 2080 goto err; 2081 } 2082 2083 rem_len -= param_buf->num_roam_scan_chan_info * 2084 sizeof(wmi_roam_scan_channel_info); 2085 2086 if (rem_len < (param_buf->num_roam_ap_info * 2087 sizeof(wmi_roam_ap_info))) { 2088 wma_err_rl("Invalid roam ap data num_tlv:%d", 2089 param_buf->num_roam_ap_info); 2090 goto err; 2091 } 2092 2093 rem_len -= param_buf->num_roam_ap_info * sizeof(wmi_roam_ap_info); 2094 if (rem_len < (param_buf->num_roam_neighbor_report_chan_info * 2095 sizeof(wmi_roam_neighbor_report_channel_info))) { 2096 wma_err_rl("Invalid roam neigb rpt chan data num_tlv:%d", 2097 param_buf->num_roam_neighbor_report_chan_info); 2098 goto err; 2099 } 2100 2101 rem_len -= param_buf->num_roam_neighbor_report_chan_info * 2102 sizeof(wmi_roam_neighbor_report_channel_info); 2103 if (rem_len < param_buf->num_roam_btm_response_info * 2104 sizeof(wmi_roam_btm_response_info)) { 2105 wma_err_rl("Invalid btm rsp data"); 2106 goto err; 2107 } 2108 2109 rem_len -= param_buf->num_roam_btm_response_info * 2110 sizeof(wmi_roam_btm_response_info); 2111 if (rem_len < param_buf->num_roam_initial_info * 2112 sizeof(wmi_roam_initial_info)) { 2113 wma_err_rl("Invalid Initial roam info"); 2114 goto err; 2115 } 2116 2117 rem_len -= param_buf->num_roam_initial_info * 2118 sizeof(wmi_roam_initial_info); 2119 if (rem_len < param_buf->num_roam_msg_info * 2120 sizeof(wmi_roam_msg_info)) { 2121 wma_err_rl("Invalid roam msg info"); 2122 goto err; 2123 } 2124 2125 for (i = 0; i < num_tlv; i++) { 2126 roam_info = qdf_mem_malloc(sizeof(*roam_info)); 2127 if (!roam_info) 2128 return -ENOMEM; 2129 2130 /* 2131 * Roam Trigger id and that specific roam trigger related 2132 * details. 2133 */ 2134 status = wmi_unified_extract_roam_trigger_stats( 2135 wma->wmi_handle, event, 2136 &roam_info->trigger, i); 2137 if (QDF_IS_STATUS_ERROR(status)) { 2138 wma_debug_rl("Extract roam trigger stats failed vdev %d at %d iteration", 2139 vdev_id, i); 2140 qdf_mem_free(roam_info); 2141 return -EINVAL; 2142 } 2143 2144 if (roam_info->trigger.present) { 2145 wma_rso_print_trigger_info(&roam_info->trigger, 2146 vdev_id); 2147 wlan_cm_update_roam_states(wma->psoc, vdev_id, 2148 roam_info->trigger.trigger_reason, 2149 ROAM_TRIGGER_REASON); 2150 } 2151 2152 /* Roam scan related details - Scan channel, scan type .. */ 2153 status = wmi_unified_extract_roam_scan_stats( 2154 wma->wmi_handle, event, 2155 &roam_info->scan, i, 2156 num_chan, num_ap); 2157 if (QDF_IS_STATUS_ERROR(status)) { 2158 wma_debug_rl("Roam scan stats extract failed vdev %d at %d iteration", 2159 vdev_id, i); 2160 qdf_mem_free(roam_info); 2161 return -EINVAL; 2162 } 2163 num_chan += roam_info->scan.num_chan; 2164 num_ap += roam_info->scan.num_ap; 2165 2166 if (roam_info->scan.present && roam_info->trigger.present) 2167 wma_rso_print_scan_info(&roam_info->scan, vdev_id, 2168 roam_info->trigger.trigger_reason, 2169 roam_info->trigger.timestamp); 2170 2171 /* Roam result - Success/Failure status, failure reason */ 2172 status = wmi_unified_extract_roam_result_stats( 2173 wma->wmi_handle, event, 2174 &roam_info->result, i); 2175 if (QDF_IS_STATUS_ERROR(status)) { 2176 wma_debug_rl("Roam result stats extract failed vdev %d at %d iteration", 2177 vdev_id, i); 2178 qdf_mem_free(roam_info); 2179 return -EINVAL; 2180 } 2181 if (roam_info->result.present) { 2182 wma_rso_print_roam_result(&roam_info->result, vdev_id); 2183 wlan_cm_update_roam_states(wma->psoc, vdev_id, 2184 roam_info->result.fail_reason, 2185 ROAM_FAIL_REASON); 2186 } 2187 /* BTM resp info */ 2188 status = wlan_cm_roam_extract_btm_response(wma->wmi_handle, 2189 event, 2190 &roam_info->btm_rsp, 2191 i); 2192 if (QDF_IS_STATUS_ERROR(status)) { 2193 wma_debug_rl("Roam btm rsp stats extract fail vdev %d at %d iteration", 2194 vdev_id, i); 2195 qdf_mem_free(roam_info); 2196 return -EINVAL; 2197 } 2198 2199 /* 2200 * Print BTM resp TLV info (wmi_roam_btm_response_info) only 2201 * when trigger reason is BTM or WTC_BTM. As for other roam 2202 * triggers this TLV contains zeros, so host should not print. 2203 */ 2204 if ((roam_info->btm_rsp.present) && 2205 (roam_info->trigger.present && 2206 (roam_info->trigger.trigger_reason == 2207 WMI_ROAM_TRIGGER_REASON_WTC_BTM || 2208 roam_info->trigger.trigger_reason == 2209 WMI_ROAM_TRIGGER_REASON_BTM))) 2210 wma_rso_print_btm_rsp_info(&roam_info->btm_rsp, 2211 vdev_id); 2212 2213 /* Initial Roam info */ 2214 status = wlan_cm_roam_extract_roam_initial_info( 2215 wma->wmi_handle, event, 2216 &roam_info->roam_init_info, i); 2217 if (QDF_IS_STATUS_ERROR(status)) { 2218 wma_debug_rl("Initial roam stats extract fail vdev %d at %d iteration", 2219 vdev_id, i); 2220 qdf_mem_free(roam_info); 2221 return -EINVAL; 2222 } 2223 if (roam_info->roam_init_info.present) 2224 wma_rso_print_roam_initial_info( 2225 &roam_info->roam_init_info, vdev_id); 2226 2227 /* Roam message info */ 2228 status = wlan_cm_roam_extract_roam_msg_info( 2229 wma->wmi_handle, event, 2230 &roam_info->roam_msg_info, i); 2231 if (QDF_IS_STATUS_ERROR(status)) { 2232 wma_err("roam msg stats extract fail vdev %d", 2233 vdev_id); 2234 qdf_mem_free(roam_info); 2235 return -EINVAL; 2236 } 2237 if (roam_info->roam_msg_info.present) { 2238 rem_tlv++; 2239 wma_rso_print_roam_msg_info( 2240 &roam_info->roam_msg_info, vdev_id); 2241 2242 /* BTM req/resp or Neighbor report/response info */ 2243 status = wmi_unified_extract_roam_11kv_stats( 2244 wma->wmi_handle, event, 2245 &roam_info->data_11kv, i, num_rpt); 2246 if (QDF_IS_STATUS_ERROR(status)) { 2247 wma_debug_rl("Roam 11kv stats extract failed vdev %d at %d iteration", 2248 vdev_id, i); 2249 qdf_mem_free(roam_info); 2250 return -EINVAL; 2251 } 2252 num_rpt += roam_info->data_11kv.num_freq; 2253 if (roam_info->data_11kv.present) 2254 wma_rso_print_11kv_info(&roam_info->data_11kv, vdev_id); 2255 } 2256 2257 qdf_mem_free(roam_info); 2258 } 2259 2260 if (!num_tlv) { 2261 roam_info = qdf_mem_malloc(sizeof(*roam_info)); 2262 if (!roam_info) 2263 return -ENOMEM; 2264 2265 status = wmi_unified_extract_roam_11kv_stats( 2266 wma->wmi_handle, event, 2267 &roam_info->data_11kv, 0, 0); 2268 if (QDF_IS_STATUS_ERROR(status)) { 2269 wma_err("Roam 11kv stats extract failed vdev %d", 2270 vdev_id); 2271 qdf_mem_free(roam_info); 2272 return -EINVAL; 2273 } 2274 2275 if (roam_info->data_11kv.present) 2276 wma_rso_print_11kv_info(&roam_info->data_11kv, vdev_id); 2277 2278 status = wmi_unified_extract_roam_trigger_stats( 2279 wma->wmi_handle, event, 2280 &roam_info->trigger, 0); 2281 if (QDF_IS_STATUS_ERROR(status)) { 2282 wma_debug_rl("Extract roam trigger stats failed vdev %d", 2283 vdev_id); 2284 qdf_mem_free(roam_info); 2285 return -EINVAL; 2286 } 2287 2288 if (roam_info->trigger.present) 2289 wma_rso_print_trigger_info(&roam_info->trigger, 2290 vdev_id); 2291 2292 status = wmi_unified_extract_roam_scan_stats(wma->wmi_handle, 2293 event, 2294 &roam_info->scan, 2295 0, 0, 0); 2296 if (QDF_IS_STATUS_ERROR(status)) { 2297 wma_debug_rl("Roam scan stats extract failed vdev %d", 2298 vdev_id); 2299 qdf_mem_free(roam_info); 2300 return -EINVAL; 2301 } 2302 2303 if (roam_info->scan.present && roam_info->trigger.present) 2304 wma_rso_print_scan_info(&roam_info->scan, vdev_id, 2305 roam_info->trigger.trigger_reason, 2306 roam_info->trigger.timestamp); 2307 2308 status = wlan_cm_roam_extract_btm_response(wma->wmi_handle, 2309 event, 2310 &roam_info->btm_rsp, 2311 0); 2312 if (QDF_IS_STATUS_ERROR(status)) { 2313 wma_debug_rl("Roam btm rsp stats extract fail vdev %d", 2314 vdev_id); 2315 qdf_mem_free(roam_info); 2316 return -EINVAL; 2317 } 2318 2319 if (roam_info->btm_rsp.present) 2320 wma_rso_print_btm_rsp_info(&roam_info->btm_rsp, 2321 vdev_id); 2322 2323 qdf_mem_free(roam_info); 2324 } 2325 2326 if (param_buf->roam_msg_info && param_buf->num_roam_msg_info && 2327 param_buf->num_roam_msg_info - rem_tlv) { 2328 for (i = 0; i < (param_buf->num_roam_msg_info - rem_tlv); i++) { 2329 roam_info = qdf_mem_malloc(sizeof(*roam_info)); 2330 if (!roam_info) 2331 return -ENOMEM; 2332 status = wlan_cm_roam_extract_roam_msg_info( 2333 wma->wmi_handle, event, 2334 &roam_info->roam_msg_info, rem_tlv + i); 2335 if (QDF_IS_STATUS_ERROR(status)) { 2336 wma_err("roam msg stats extract fail vdev %d", 2337 vdev_id); 2338 qdf_mem_free(roam_info); 2339 return -EINVAL; 2340 } 2341 2342 if (roam_info->roam_msg_info.present) 2343 wma_rso_print_roam_msg_info( 2344 &roam_info->roam_msg_info, 2345 vdev_id); 2346 qdf_mem_free(roam_info); 2347 } 2348 } 2349 2350 return 0; 2351 2352 err: 2353 return -EINVAL; 2354 } 2355 #endif 2356 2357 /** 2358 * wma_set_ric_req() - set ric request element 2359 * @wma: wma handle 2360 * @msg: message 2361 * @is_add_ts: is addts required 2362 * 2363 * This function sets ric request element for 11r roaming. 2364 * 2365 * Return: none 2366 */ 2367 void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) 2368 { 2369 if (!wma) { 2370 wma_err("wma handle is NULL"); 2371 return; 2372 } 2373 2374 wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts); 2375 } 2376 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 2377 2378 #ifdef FEATURE_RSSI_MONITOR 2379 QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, 2380 struct rssi_monitor_param *req) 2381 { 2382 if (!wma) { 2383 wma_err("wma handle is NULL"); 2384 return QDF_STATUS_E_INVAL; 2385 } 2386 2387 return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req); 2388 } 2389 2390 /** 2391 * wma_rssi_breached_event_handler() - rssi breached event handler 2392 * @handle: wma handle 2393 * @cmd_param_info: event handler data 2394 * @len: length of @cmd_param_info 2395 * 2396 * Return: 0 on success; error number otherwise 2397 */ 2398 int wma_rssi_breached_event_handler(void *handle, 2399 u_int8_t *cmd_param_info, u_int32_t len) 2400 { 2401 WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf; 2402 wmi_rssi_breach_event_fixed_param *event; 2403 struct rssi_breach_event rssi; 2404 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 2405 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 2406 2407 if (!mac || !wma) { 2408 wma_err("Invalid mac/wma context"); 2409 return -EINVAL; 2410 } 2411 if (!mac->sme.rssi_threshold_breached_cb) { 2412 wma_err("Callback not registered"); 2413 return -EINVAL; 2414 } 2415 param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; 2416 if (!param_buf) { 2417 wma_err("Invalid rssi breached event"); 2418 return -EINVAL; 2419 } 2420 event = param_buf->fixed_param; 2421 2422 rssi.request_id = event->request_id; 2423 rssi.session_id = event->vdev_id; 2424 if (wmi_service_enabled(wma->wmi_handle, 2425 wmi_service_hw_db2dbm_support)) 2426 rssi.curr_rssi = event->rssi; 2427 else 2428 rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; 2429 WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); 2430 2431 wma_debug("req_id: %u vdev_id: %d curr_rssi: %d", 2432 rssi.request_id, rssi.session_id, rssi.curr_rssi); 2433 wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT, 2434 QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes)); 2435 2436 mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi); 2437 wma_debug("Invoke HDD rssi breached callback"); 2438 return 0; 2439 } 2440 #endif /* FEATURE_RSSI_MONITOR */ 2441 2442 #ifndef FEATURE_CM_ENABLE 2443 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 2444 /** 2445 * wma_roam_ho_fail_handler() - LFR3.0 roam hand off failed handler 2446 * @wma: wma handle 2447 * @vdev_id: vdev id 2448 * 2449 * Return: none 2450 */ 2451 static void 2452 wma_roam_ho_fail_handler(tp_wma_handle wma, uint32_t vdev_id, 2453 struct qdf_mac_addr bssid) 2454 { 2455 struct handoff_failure_ind *ho_failure_ind; 2456 struct scheduler_msg sme_msg = { 0 }; 2457 QDF_STATUS qdf_status; 2458 2459 ho_failure_ind = qdf_mem_malloc(sizeof(*ho_failure_ind)); 2460 if (!ho_failure_ind) 2461 return; 2462 2463 ho_failure_ind->vdev_id = vdev_id; 2464 ho_failure_ind->bssid = bssid; 2465 2466 sme_msg.type = eWNI_SME_HO_FAIL_IND; 2467 sme_msg.bodyptr = ho_failure_ind; 2468 sme_msg.bodyval = 0; 2469 2470 qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, 2471 QDF_MODULE_ID_SME, 2472 QDF_MODULE_ID_SME, &sme_msg); 2473 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 2474 wma_err("Fail to post eWNI_SME_HO_FAIL_IND msg to SME"); 2475 qdf_mem_free(ho_failure_ind); 2476 return; 2477 } 2478 } 2479 2480 /** 2481 * wma_process_roam_synch_complete() - roam synch complete command to fw. 2482 * @handle: wma handle 2483 * @synchcnf: offload synch confirmation params 2484 * 2485 * This function sends roam synch complete event to fw. 2486 * 2487 * Return: none 2488 */ 2489 void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id) 2490 { 2491 tp_wma_handle wma_handle = (tp_wma_handle) handle; 2492 struct wmi_unified *wmi_handle; 2493 2494 if (wma_validate_handle(wma_handle)) 2495 return; 2496 2497 wmi_handle = wma_handle->wmi_handle; 2498 if (wmi_validate_handle(wmi_handle)) 2499 return; 2500 2501 if (!wma_is_vdev_valid(vdev_id)) 2502 return; 2503 2504 if (wmi_unified_roam_synch_complete_cmd(wmi_handle, vdev_id)) 2505 return; 2506 2507 DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, 2508 vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, 2509 QDF_PROTO_TYPE_EVENT, QDF_ROAM_COMPLETE)); 2510 2511 wma_info("LFR3: vdev[%d] Sent ROAM_SYNCH_COMPLETE", vdev_id); 2512 wlan_roam_debug_log(vdev_id, DEBUG_ROAM_SYNCH_CNF, 2513 DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); 2514 2515 } 2516 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 2517 #endif /* FEATURE_CM_ENABLE */ 2518 2519 QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id) 2520 { 2521 QDF_STATUS status = QDF_STATUS_SUCCESS; 2522 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 2523 struct wma_txrx_node *intr; 2524 uint16_t beacon_interval_ori; 2525 bool restart; 2526 uint16_t reduced_beacon_interval; 2527 struct vdev_mlme_obj *mlme_obj; 2528 struct wlan_objmgr_vdev *vdev; 2529 2530 if (!wma) { 2531 pe_err("wma is NULL"); 2532 return QDF_STATUS_E_FAILURE; 2533 } 2534 intr = &wma->interfaces[vdev_id]; 2535 if (!intr) { 2536 pe_err("wma txrx node is NULL"); 2537 return QDF_STATUS_E_FAILURE; 2538 } 2539 vdev = intr->vdev; 2540 mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); 2541 if (!mlme_obj) { 2542 pe_err("vdev component object is NULL"); 2543 return QDF_STATUS_E_FAILURE; 2544 } 2545 2546 restart = 2547 wma_get_channel_switch_in_progress(intr); 2548 if (restart && intr->beacon_filter_enabled) 2549 wma_remove_beacon_filter(wma, &intr->beacon_filter); 2550 2551 reduced_beacon_interval = 2552 wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval; 2553 if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) { 2554 2555 2556 /* Reduce the beacon interval just before the channel switch. 2557 * This would help in reducing the downtime on the STA side 2558 * (which is waiting for beacons from the AP to resume back 2559 * transmission). Switch back the beacon_interval to its 2560 * original value after the channel switch based on the 2561 * timeout. This would ensure there are atleast some beacons 2562 * sent with increased frequency. 2563 */ 2564 2565 wma_debug("Changing beacon interval to %d", 2566 reduced_beacon_interval); 2567 2568 /* Add a timer to reset the beacon interval back*/ 2569 beacon_interval_ori = mlme_obj->proto.generic.beacon_interval; 2570 mlme_obj->proto.generic.beacon_interval = 2571 reduced_beacon_interval; 2572 if (wma_fill_beacon_interval_reset_req(wma, 2573 vdev_id, 2574 beacon_interval_ori, 2575 RESET_BEACON_INTERVAL_TIMEOUT)) { 2576 2577 wma_debug("Failed to fill beacon interval reset req"); 2578 } 2579 } 2580 2581 status = wma_vdev_pre_start(vdev_id, restart); 2582 2583 return status; 2584 } 2585 2586 QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id) 2587 { 2588 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 2589 struct wma_txrx_node *intr; 2590 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 2591 struct wlan_channel *des_chan; 2592 cdp_config_param_type val; 2593 2594 if (!wma) { 2595 pe_err("wma is NULL"); 2596 return QDF_STATUS_E_FAILURE; 2597 } 2598 intr = &wma->interfaces[vdev_id]; 2599 if (!intr) { 2600 pe_err("wma txrx node is NULL"); 2601 return QDF_STATUS_E_FAILURE; 2602 } 2603 /* 2604 * Record monitor mode channel here in case HW 2605 * indicate RX PPDU TLV with invalid channel number. 2606 */ 2607 if (intr->type == WMI_VDEV_TYPE_MONITOR) { 2608 des_chan = intr->vdev->vdev_mlme.des_chan; 2609 val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee; 2610 cdp_txrx_set_pdev_param(soc, 2611 wlan_objmgr_pdev_get_pdev_id(wma->pdev), 2612 CDP_MONITOR_CHANNEL, val); 2613 val.cdp_pdev_param_mon_freq = des_chan->ch_freq; 2614 cdp_txrx_set_pdev_param(soc, 2615 wlan_objmgr_pdev_get_pdev_id(wma->pdev), 2616 CDP_MONITOR_FREQUENCY, val); 2617 } 2618 return QDF_STATUS_SUCCESS; 2619 } 2620 2621 #ifdef FEATURE_WLAN_ESE 2622 /** 2623 * wma_plm_start() - plm start request 2624 * @wma: wma handle 2625 * @params: plm request parameters 2626 * 2627 * This function request FW to start PLM. 2628 * 2629 * Return: QDF status 2630 */ 2631 static QDF_STATUS wma_plm_start(tp_wma_handle wma, 2632 struct plm_req_params *params) 2633 { 2634 QDF_STATUS status; 2635 2636 wma_debug("PLM Start"); 2637 2638 status = wmi_unified_plm_start_cmd(wma->wmi_handle, params); 2639 if (QDF_IS_STATUS_ERROR(status)) 2640 return status; 2641 2642 wma->interfaces[params->vdev_id].plm_in_progress = true; 2643 2644 wma_debug("Plm start request sent successfully for vdev %d", 2645 params->vdev_id); 2646 2647 return status; 2648 } 2649 2650 /** 2651 * wma_plm_stop() - plm stop request 2652 * @wma: wma handle 2653 * @params: plm request parameters 2654 * 2655 * This function request FW to stop PLM. 2656 * 2657 * Return: QDF status 2658 */ 2659 static QDF_STATUS wma_plm_stop(tp_wma_handle wma, 2660 struct plm_req_params *params) 2661 { 2662 QDF_STATUS status; 2663 2664 if (!wma->interfaces[params->vdev_id].plm_in_progress) { 2665 wma_err("No active plm req found, skip plm stop req"); 2666 return QDF_STATUS_E_FAILURE; 2667 } 2668 2669 wma_debug("PLM Stop"); 2670 2671 status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params); 2672 if (QDF_IS_STATUS_ERROR(status)) 2673 return status; 2674 2675 wma->interfaces[params->vdev_id].plm_in_progress = false; 2676 2677 wma_debug("Plm stop request sent successfully for vdev %d", 2678 params->vdev_id); 2679 2680 return status; 2681 } 2682 2683 /** 2684 * wma_config_plm() - config PLM 2685 * @wma: wma handle 2686 * @params: plm request parameters 2687 * 2688 * Return: none 2689 */ 2690 void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params) 2691 { 2692 QDF_STATUS ret; 2693 2694 if (!params || !wma) 2695 return; 2696 2697 if (params->enable) 2698 ret = wma_plm_start(wma, params); 2699 else 2700 ret = wma_plm_stop(wma, params); 2701 2702 if (ret) 2703 wma_err("PLM %s failed %d", 2704 params->enable ? "start" : "stop", ret); 2705 } 2706 #endif 2707 2708 #ifdef FEATURE_WLAN_EXTSCAN 2709 /** 2710 * wma_extscan_wow_event_callback() - extscan wow event callback 2711 * @handle: WMA handle 2712 * @event: event buffer 2713 * @len: length of @event buffer 2714 * 2715 * In wow case, the wow event is followed by the payload of the event 2716 * which generated the wow event. 2717 * payload is 4 bytes of length followed by event buffer. the first 4 bytes 2718 * of event buffer is common tlv header, which is a combination 2719 * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to 2720 * identify the event which triggered wow event. 2721 * Payload is extracted and converted into generic tlv structure before 2722 * being passed to this function. 2723 * 2724 * @Return: Errno 2725 */ 2726 int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len) 2727 { 2728 uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event)); 2729 2730 switch (tag) { 2731 case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: 2732 return wma_extscan_start_stop_event_handler(handle, event, len); 2733 2734 case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: 2735 return wma_extscan_operations_event_handler(handle, event, len); 2736 2737 case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: 2738 return wma_extscan_table_usage_event_handler(handle, event, 2739 len); 2740 2741 case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: 2742 return wma_extscan_cached_results_event_handler(handle, event, 2743 len); 2744 2745 case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: 2746 return wma_extscan_change_results_event_handler(handle, event, 2747 len); 2748 2749 case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: 2750 return wma_extscan_hotlist_match_event_handler(handle, event, 2751 len); 2752 2753 case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: 2754 return wma_extscan_capabilities_event_handler(handle, event, 2755 len); 2756 2757 default: 2758 wma_err("Unknown tag: %d", tag); 2759 return 0; 2760 } 2761 } 2762 2763 /** 2764 * wma_register_extscan_event_handler() - register extscan event handler 2765 * @wma_handle: wma handle 2766 * 2767 * This function register extscan related event handlers. 2768 * 2769 * Return: none 2770 */ 2771 void wma_register_extscan_event_handler(tp_wma_handle wma_handle) 2772 { 2773 if (wma_validate_handle(wma_handle)) 2774 return; 2775 2776 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2777 wmi_extscan_start_stop_event_id, 2778 wma_extscan_start_stop_event_handler, 2779 WMA_RX_SERIALIZER_CTX); 2780 2781 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2782 wmi_extscan_capabilities_event_id, 2783 wma_extscan_capabilities_event_handler, 2784 WMA_RX_SERIALIZER_CTX); 2785 2786 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2787 wmi_extscan_hotlist_match_event_id, 2788 wma_extscan_hotlist_match_event_handler, 2789 WMA_RX_SERIALIZER_CTX); 2790 2791 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2792 wmi_extscan_wlan_change_results_event_id, 2793 wma_extscan_change_results_event_handler, 2794 WMA_RX_SERIALIZER_CTX); 2795 2796 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2797 wmi_extscan_operation_event_id, 2798 wma_extscan_operations_event_handler, 2799 WMA_RX_SERIALIZER_CTX); 2800 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2801 wmi_extscan_table_usage_event_id, 2802 wma_extscan_table_usage_event_handler, 2803 WMA_RX_SERIALIZER_CTX); 2804 2805 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2806 wmi_extscan_cached_results_event_id, 2807 wma_extscan_cached_results_event_handler, 2808 WMA_RX_SERIALIZER_CTX); 2809 2810 wmi_unified_register_event_handler(wma_handle->wmi_handle, 2811 wmi_passpoint_match_event_id, 2812 wma_passpoint_match_event_handler, 2813 WMA_RX_SERIALIZER_CTX); 2814 } 2815 2816 /** 2817 * wma_extscan_start_stop_event_handler() - extscan start/stop event handler 2818 * @handle: wma handle 2819 * @cmd_param_info: event buffer 2820 * @len: data length 2821 * 2822 * This function handles different extscan related commands 2823 * like start/stop/get results etc and indicate to upper layers. 2824 * 2825 * Return: 0 for success or error code. 2826 */ 2827 int wma_extscan_start_stop_event_handler(void *handle, 2828 uint8_t *cmd_param_info, 2829 uint32_t len) 2830 { 2831 WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf; 2832 wmi_extscan_start_stop_event_fixed_param *event; 2833 struct sir_extscan_generic_response *extscan_ind; 2834 uint16_t event_type; 2835 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 2836 2837 if (!mac) 2838 return -EINVAL; 2839 2840 if (!mac->sme.ext_scan_ind_cb) { 2841 wma_err("Callback not registered"); 2842 return -EINVAL; 2843 } 2844 param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) 2845 cmd_param_info; 2846 if (!param_buf) { 2847 wma_err("Invalid extscan event"); 2848 return -EINVAL; 2849 } 2850 event = param_buf->fixed_param; 2851 extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind)); 2852 if (!extscan_ind) 2853 return -ENOMEM; 2854 2855 switch (event->command) { 2856 case WMI_EXTSCAN_START_CMDID: 2857 event_type = eSIR_EXTSCAN_START_RSP; 2858 extscan_ind->status = event->status; 2859 extscan_ind->request_id = event->request_id; 2860 break; 2861 case WMI_EXTSCAN_STOP_CMDID: 2862 event_type = eSIR_EXTSCAN_STOP_RSP; 2863 extscan_ind->status = event->status; 2864 extscan_ind->request_id = event->request_id; 2865 break; 2866 case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID: 2867 extscan_ind->status = event->status; 2868 extscan_ind->request_id = event->request_id; 2869 if (event->mode == WMI_EXTSCAN_MODE_STOP) 2870 event_type = 2871 eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP; 2872 else 2873 event_type = 2874 eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP; 2875 break; 2876 case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID: 2877 extscan_ind->status = event->status; 2878 extscan_ind->request_id = event->request_id; 2879 if (event->mode == WMI_EXTSCAN_MODE_STOP) 2880 event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP; 2881 else 2882 event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP; 2883 break; 2884 case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID: 2885 extscan_ind->status = event->status; 2886 extscan_ind->request_id = event->request_id; 2887 event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP; 2888 break; 2889 case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID: 2890 extscan_ind->status = event->status; 2891 extscan_ind->request_id = event->request_id; 2892 if (event->mode == WMI_EXTSCAN_MODE_STOP) 2893 event_type = 2894 eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP; 2895 else 2896 event_type = 2897 eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP; 2898 break; 2899 default: 2900 wma_err("Unknown event(%d) from target", event->status); 2901 qdf_mem_free(extscan_ind); 2902 return -EINVAL; 2903 } 2904 mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind); 2905 wma_debug("sending event to umac for requestid %u with status %d", 2906 extscan_ind->request_id, extscan_ind->status); 2907 qdf_mem_free(extscan_ind); 2908 return 0; 2909 } 2910 2911 /** 2912 * wma_extscan_operations_event_handler() - extscan operation event handler 2913 * @handle: wma handle 2914 * @cmd_param_info: event buffer 2915 * @len: length 2916 * 2917 * This function handles different operations related event and indicate 2918 * upper layers with appropriate callback. 2919 * 2920 * Return: 0 for success or error code. 2921 */ 2922 int wma_extscan_operations_event_handler(void *handle, 2923 uint8_t *cmd_param_info, 2924 uint32_t len) 2925 { 2926 tp_wma_handle wma = (tp_wma_handle) handle; 2927 WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf; 2928 wmi_extscan_operation_event_fixed_param *oprn_event; 2929 tSirExtScanOnScanEventIndParams *oprn_ind; 2930 uint32_t cnt; 2931 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 2932 2933 if (!mac) 2934 return -EINVAL; 2935 2936 if (!mac->sme.ext_scan_ind_cb) { 2937 wma_err("Callback not registered"); 2938 return -EINVAL; 2939 } 2940 param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) 2941 cmd_param_info; 2942 if (!param_buf) { 2943 wma_err("Invalid scan operation event"); 2944 return -EINVAL; 2945 } 2946 oprn_event = param_buf->fixed_param; 2947 oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind)); 2948 if (!oprn_ind) 2949 return -ENOMEM; 2950 2951 oprn_ind->requestId = oprn_event->request_id; 2952 2953 switch (oprn_event->event) { 2954 case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT: 2955 oprn_ind->status = 0; 2956 goto exit_handler; 2957 case WMI_EXTSCAN_CYCLE_STARTED_EVENT: 2958 wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT"); 2959 2960 if (oprn_event->num_buckets > param_buf->num_bucket_id) { 2961 wma_err("FW mesg num_buk %d more than TLV hdr %d", 2962 oprn_event->num_buckets, 2963 param_buf->num_bucket_id); 2964 qdf_mem_free(oprn_ind); 2965 return -EINVAL; 2966 } 2967 2968 cds_host_diag_log_work(&wma->extscan_wake_lock, 2969 WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION, 2970 WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); 2971 qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock, 2972 WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION); 2973 oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT; 2974 oprn_ind->status = 0; 2975 oprn_ind->buckets_scanned = 0; 2976 for (cnt = 0; cnt < oprn_event->num_buckets; cnt++) 2977 oprn_ind->buckets_scanned |= 2978 (1 << param_buf->bucket_id[cnt]); 2979 wma_debug("num_buckets %u request_id %u buckets_scanned %u", 2980 oprn_event->num_buckets, oprn_ind->requestId, 2981 oprn_ind->buckets_scanned); 2982 break; 2983 case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT: 2984 wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT"); 2985 qdf_wake_lock_release(&wma->extscan_wake_lock, 2986 WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); 2987 oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT; 2988 oprn_ind->status = 0; 2989 /* Set bucket scanned mask to zero on cycle complete */ 2990 oprn_ind->buckets_scanned = 0; 2991 break; 2992 case WMI_EXTSCAN_BUCKET_STARTED_EVENT: 2993 wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT"); 2994 oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT; 2995 oprn_ind->status = 0; 2996 goto exit_handler; 2997 case WMI_EXTSCAN_THRESHOLD_NUM_SCANS: 2998 wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS"); 2999 oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS; 3000 oprn_ind->status = 0; 3001 break; 3002 case WMI_EXTSCAN_THRESHOLD_PERCENT: 3003 wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT"); 3004 oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT; 3005 oprn_ind->status = 0; 3006 break; 3007 default: 3008 wma_err("Unknown event(%d) from target", oprn_event->event); 3009 qdf_mem_free(oprn_ind); 3010 return -EINVAL; 3011 } 3012 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3013 eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); 3014 wma_debug("sending scan progress event to hdd"); 3015 exit_handler: 3016 qdf_mem_free(oprn_ind); 3017 return 0; 3018 } 3019 3020 /** 3021 * wma_extscan_table_usage_event_handler() - extscan table usage event handler 3022 * @handle: wma handle 3023 * @cmd_param_info: event buffer 3024 * @len: length 3025 * 3026 * This function handles table usage related event and indicate 3027 * upper layers with appropriate callback. 3028 * 3029 * Return: 0 for success or error code. 3030 */ 3031 int wma_extscan_table_usage_event_handler(void *handle, 3032 uint8_t *cmd_param_info, 3033 uint32_t len) 3034 { 3035 WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf; 3036 wmi_extscan_table_usage_event_fixed_param *event; 3037 tSirExtScanResultsAvailableIndParams *tbl_usg_ind; 3038 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3039 3040 if (!mac) 3041 return -EINVAL; 3042 3043 if (!mac->sme.ext_scan_ind_cb) { 3044 wma_err("Callback not registered"); 3045 return -EINVAL; 3046 } 3047 param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) 3048 cmd_param_info; 3049 if (!param_buf) { 3050 wma_err("Invalid table usage event"); 3051 return -EINVAL; 3052 } 3053 event = param_buf->fixed_param; 3054 tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind)); 3055 if (!tbl_usg_ind) 3056 return -ENOMEM; 3057 3058 tbl_usg_ind->requestId = event->request_id; 3059 tbl_usg_ind->numResultsAvailable = event->entries_in_use; 3060 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3061 eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, 3062 tbl_usg_ind); 3063 wma_debug("sending scan_res available event to hdd"); 3064 qdf_mem_free(tbl_usg_ind); 3065 return 0; 3066 } 3067 3068 /** 3069 * wma_extscan_capabilities_event_handler() - extscan capabilities event handler 3070 * @handle: wma handle 3071 * @cmd_param_info: event buffer 3072 * @len: length 3073 * 3074 * This function handles capabilities event and indicate 3075 * upper layers with registered callback. 3076 * 3077 * Return: 0 for success or error code. 3078 */ 3079 int wma_extscan_capabilities_event_handler(void *handle, 3080 uint8_t *cmd_param_info, 3081 uint32_t len) 3082 { 3083 WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf; 3084 wmi_extscan_capabilities_event_fixed_param *event; 3085 wmi_extscan_cache_capabilities *src_cache; 3086 wmi_extscan_hotlist_monitor_capabilities *src_hotlist; 3087 wmi_extscan_wlan_change_monitor_capabilities *src_change; 3088 struct ext_scan_capabilities_response *dest_capab; 3089 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3090 3091 if (!mac) 3092 return -EINVAL; 3093 3094 if (!mac->sme.ext_scan_ind_cb) { 3095 wma_err("Callback not registered"); 3096 return -EINVAL; 3097 } 3098 param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) 3099 cmd_param_info; 3100 if (!param_buf) { 3101 wma_err("Invalid capabilities event"); 3102 return -EINVAL; 3103 } 3104 event = param_buf->fixed_param; 3105 src_cache = param_buf->extscan_cache_capabilities; 3106 src_hotlist = param_buf->hotlist_capabilities; 3107 src_change = param_buf->wlan_change_capabilities; 3108 3109 if (!src_cache || !src_hotlist || !src_change) { 3110 wma_err("Invalid capabilities list"); 3111 return -EINVAL; 3112 } 3113 dest_capab = qdf_mem_malloc(sizeof(*dest_capab)); 3114 if (!dest_capab) 3115 return -ENOMEM; 3116 3117 dest_capab->requestId = event->request_id; 3118 dest_capab->max_scan_buckets = src_cache->max_buckets; 3119 dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size; 3120 dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan; 3121 dest_capab->max_scan_reporting_threshold = 3122 src_cache->max_table_usage_threshold; 3123 3124 dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries; 3125 dest_capab->max_rssi_sample_size = 3126 src_change->max_rssi_averaging_samples; 3127 dest_capab->max_bssid_history_entries = 3128 src_change->max_rssi_history_entries; 3129 dest_capab->max_significant_wifi_change_aps = 3130 src_change->max_wlan_change_entries; 3131 dest_capab->max_hotlist_ssids = 3132 event->num_extscan_hotlist_ssid; 3133 dest_capab->max_number_epno_networks = 3134 event->num_epno_networks; 3135 dest_capab->max_number_epno_networks_by_ssid = 3136 event->num_epno_networks; 3137 dest_capab->max_number_of_white_listed_ssid = 3138 event->num_roam_ssid_whitelist; 3139 dest_capab->max_number_of_black_listed_bssid = 3140 event->num_roam_bssid_blacklist; 3141 dest_capab->status = 0; 3142 3143 wma_debug("request_id: %u status: %d", 3144 dest_capab->requestId, dest_capab->status); 3145 3146 wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d", 3147 dest_capab->max_scan_buckets, 3148 dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size, 3149 dest_capab->max_ap_cache_per_scan); 3150 wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d", 3151 dest_capab->max_scan_reporting_threshold, 3152 dest_capab->max_rssi_sample_size, 3153 dest_capab->max_bssid_history_entries, 3154 dest_capab->max_significant_wifi_change_aps); 3155 3156 wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d", 3157 dest_capab->max_hotlist_ssids, 3158 dest_capab->max_number_epno_networks, 3159 dest_capab->max_number_epno_networks_by_ssid); 3160 wma_debug("max_number_of_white_listed_ssid: %d, max_number_of_black_listed_bssid: %d", 3161 dest_capab->max_number_of_white_listed_ssid, 3162 dest_capab->max_number_of_black_listed_bssid); 3163 3164 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3165 eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab); 3166 qdf_mem_free(dest_capab); 3167 return 0; 3168 } 3169 3170 /** 3171 * wma_extscan_hotlist_match_event_handler() - hotlist match event handler 3172 * @handle: wma handle 3173 * @cmd_param_info: event buffer 3174 * @len: length 3175 * 3176 * This function handles hotlist match event and indicate 3177 * upper layers with registered callback. 3178 * 3179 * Return: 0 for success or error code. 3180 */ 3181 int wma_extscan_hotlist_match_event_handler(void *handle, 3182 uint8_t *cmd_param_info, 3183 uint32_t len) 3184 { 3185 WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf; 3186 wmi_extscan_hotlist_match_event_fixed_param *event; 3187 struct extscan_hotlist_match *dest_hotlist; 3188 tSirWifiScanResult *dest_ap; 3189 wmi_extscan_wlan_descriptor *src_hotlist; 3190 uint32_t numap; 3191 int j, ap_found = 0; 3192 uint32_t buf_len; 3193 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3194 3195 if (!mac) 3196 return -EINVAL; 3197 3198 if (!mac->sme.ext_scan_ind_cb) { 3199 wma_err("Callback not registered"); 3200 return -EINVAL; 3201 } 3202 param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) 3203 cmd_param_info; 3204 if (!param_buf) { 3205 wma_err("Invalid hotlist match event"); 3206 return -EINVAL; 3207 } 3208 event = param_buf->fixed_param; 3209 src_hotlist = param_buf->hotlist_match; 3210 numap = event->total_entries; 3211 3212 if (!src_hotlist || !numap) { 3213 wma_err("Hotlist AP's list invalid"); 3214 return -EINVAL; 3215 } 3216 if (numap > param_buf->num_hotlist_match) { 3217 wma_err("Invalid no of total enteries %d", numap); 3218 return -EINVAL; 3219 } 3220 if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) { 3221 wma_err("Total Entries %u greater than max", numap); 3222 numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; 3223 } 3224 3225 buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + 3226 WMI_TLV_HDR_SIZE + 3227 (numap * sizeof(wmi_extscan_wlan_descriptor)); 3228 3229 if (buf_len > len) { 3230 wma_err("Invalid buf len from FW %d numap %d", len, numap); 3231 return -EINVAL; 3232 } 3233 3234 dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) + 3235 sizeof(*dest_ap) * numap); 3236 if (!dest_hotlist) 3237 return -ENOMEM; 3238 3239 dest_ap = &dest_hotlist->ap[0]; 3240 dest_hotlist->numOfAps = event->total_entries; 3241 dest_hotlist->requestId = event->config_request_id; 3242 3243 if (event->first_entry_index + 3244 event->num_entries_in_page < event->total_entries) 3245 dest_hotlist->moreData = 1; 3246 else 3247 dest_hotlist->moreData = 0; 3248 3249 wma_debug("Hotlist match: requestId: %u numOfAps: %d", 3250 dest_hotlist->requestId, dest_hotlist->numOfAps); 3251 3252 /* 3253 * Currently firmware sends only one bss information in-case 3254 * of both hotlist ap found and lost. 3255 */ 3256 for (j = 0; j < numap; j++) { 3257 dest_ap->rssi = 0; 3258 dest_ap->channel = src_hotlist->channel; 3259 dest_ap->ts = src_hotlist->tstamp; 3260 ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; 3261 dest_ap->rtt = src_hotlist->rtt; 3262 dest_ap->rtt_sd = src_hotlist->rtt_sd; 3263 dest_ap->beaconPeriod = src_hotlist->beacon_interval; 3264 dest_ap->capability = src_hotlist->capabilities; 3265 dest_ap->ieLength = src_hotlist->ie_length; 3266 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, 3267 dest_ap->bssid.bytes); 3268 if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) { 3269 wma_err("Invalid SSID len %d, truncating", 3270 src_hotlist->ssid.ssid_len); 3271 src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN; 3272 } 3273 qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, 3274 src_hotlist->ssid.ssid_len); 3275 dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; 3276 dest_ap++; 3277 src_hotlist++; 3278 } 3279 dest_hotlist->ap_found = ap_found; 3280 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3281 eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); 3282 wma_debug("sending hotlist match event to hdd"); 3283 qdf_mem_free(dest_hotlist); 3284 return 0; 3285 } 3286 3287 /** wma_extscan_find_unique_scan_ids() - find unique scan ids 3288 * @cmd_param_info: event data. 3289 * 3290 * This utility function parses the input bss table of information 3291 * and find the unique number of scan ids 3292 * 3293 * Return: 0 on success; error number otherwise 3294 */ 3295 static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info) 3296 { 3297 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 3298 wmi_extscan_cached_results_event_fixed_param *event; 3299 wmi_extscan_wlan_descriptor *src_hotlist; 3300 wmi_extscan_rssi_info *src_rssi; 3301 int prev_scan_id, scan_ids_cnt, i; 3302 3303 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 3304 cmd_param_info; 3305 event = param_buf->fixed_param; 3306 src_hotlist = param_buf->bssid_list; 3307 src_rssi = param_buf->rssi_list; 3308 3309 /* Find the unique number of scan_id's for grouping */ 3310 prev_scan_id = src_rssi->scan_cycle_id; 3311 scan_ids_cnt = 1; 3312 for (i = 1; i < param_buf->num_rssi_list; i++) { 3313 src_rssi++; 3314 3315 if (prev_scan_id != src_rssi->scan_cycle_id) { 3316 scan_ids_cnt++; 3317 prev_scan_id = src_rssi->scan_cycle_id; 3318 } 3319 } 3320 3321 return scan_ids_cnt; 3322 } 3323 3324 /** wma_fill_num_results_per_scan_id() - fill number of bss per scan id 3325 * @cmd_param_info: event data. 3326 * @scan_id_group: pointer to scan id group. 3327 * 3328 * This utility function parses the input bss table of information 3329 * and finds how many bss are there per unique scan id. 3330 * 3331 * Return: 0 on success; error number otherwise 3332 */ 3333 static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info, 3334 struct extscan_cached_scan_result *scan_id_group) 3335 { 3336 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 3337 wmi_extscan_cached_results_event_fixed_param *event; 3338 wmi_extscan_wlan_descriptor *src_hotlist; 3339 wmi_extscan_rssi_info *src_rssi; 3340 struct extscan_cached_scan_result *t_scan_id_grp; 3341 int i, prev_scan_id; 3342 3343 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 3344 cmd_param_info; 3345 event = param_buf->fixed_param; 3346 src_hotlist = param_buf->bssid_list; 3347 src_rssi = param_buf->rssi_list; 3348 t_scan_id_grp = scan_id_group; 3349 3350 prev_scan_id = src_rssi->scan_cycle_id; 3351 3352 t_scan_id_grp->scan_id = src_rssi->scan_cycle_id; 3353 t_scan_id_grp->flags = src_rssi->flags; 3354 t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned; 3355 t_scan_id_grp->num_results = 1; 3356 for (i = 1; i < param_buf->num_rssi_list; i++) { 3357 src_rssi++; 3358 if (prev_scan_id == src_rssi->scan_cycle_id) { 3359 t_scan_id_grp->num_results++; 3360 } else { 3361 t_scan_id_grp++; 3362 prev_scan_id = t_scan_id_grp->scan_id = 3363 src_rssi->scan_cycle_id; 3364 t_scan_id_grp->flags = src_rssi->flags; 3365 t_scan_id_grp->buckets_scanned = 3366 src_rssi->buckets_scanned; 3367 t_scan_id_grp->num_results = 1; 3368 } 3369 } 3370 return 0; 3371 } 3372 3373 /** wma_group_num_bss_to_scan_id() - group bss to scan id table 3374 * @cmd_param_info: event data. 3375 * @cached_result: pointer to cached table. 3376 * 3377 * This function reads the bss information from the format 3378 * ------------------------------------------------------------------------ 3379 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags | 3380 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags | 3381 * ........................................................................ 3382 * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags | 3383 * ------------------------------------------------------------------------ 3384 * 3385 * and converts it into the below format and store it 3386 * 3387 * ------------------------------------------------------------------------ 3388 * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1 3389 * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2 3390 * ...................... 3391 * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn 3392 * ------------------------------------------------------------------------ 3393 * 3394 * Return: 0 on success; error number otherwise 3395 */ 3396 static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, 3397 struct extscan_cached_scan_results *cached_result) 3398 { 3399 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 3400 wmi_extscan_cached_results_event_fixed_param *event; 3401 wmi_extscan_wlan_descriptor *src_hotlist; 3402 wmi_extscan_rssi_info *src_rssi; 3403 struct extscan_cached_scan_results *t_cached_result; 3404 struct extscan_cached_scan_result *t_scan_id_grp; 3405 int i, j; 3406 tSirWifiScanResult *ap; 3407 3408 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 3409 cmd_param_info; 3410 event = param_buf->fixed_param; 3411 src_hotlist = param_buf->bssid_list; 3412 src_rssi = param_buf->rssi_list; 3413 t_cached_result = cached_result; 3414 t_scan_id_grp = &t_cached_result->result[0]; 3415 3416 if ((t_cached_result->num_scan_ids * 3417 QDF_MIN(t_scan_id_grp->num_results, 3418 param_buf->num_bssid_list)) > param_buf->num_bssid_list) { 3419 wma_err("num_scan_ids %d, num_results %d num_bssid_list %d", 3420 t_cached_result->num_scan_ids, 3421 t_scan_id_grp->num_results, 3422 param_buf->num_bssid_list); 3423 return -EINVAL; 3424 } 3425 3426 wma_debug("num_scan_ids:%d", 3427 t_cached_result->num_scan_ids); 3428 for (i = 0; i < t_cached_result->num_scan_ids; i++) { 3429 wma_debug("num_results:%d", t_scan_id_grp->num_results); 3430 t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results * 3431 sizeof(*ap)); 3432 if (!t_scan_id_grp->ap) 3433 return -ENOMEM; 3434 3435 ap = &t_scan_id_grp->ap[0]; 3436 for (j = 0; j < QDF_MIN(t_scan_id_grp->num_results, 3437 param_buf->num_bssid_list); j++) { 3438 ap->channel = src_hotlist->channel; 3439 ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp); 3440 ap->rtt = src_hotlist->rtt; 3441 ap->rtt_sd = src_hotlist->rtt_sd; 3442 ap->beaconPeriod = src_hotlist->beacon_interval; 3443 ap->capability = src_hotlist->capabilities; 3444 ap->ieLength = src_hotlist->ie_length; 3445 3446 /* Firmware already applied noise floor adjustment and 3447 * due to WMI interface "UINT32 rssi", host driver 3448 * receives a positive value, hence convert to 3449 * signed char to get the absolute rssi. 3450 */ 3451 ap->rssi = (signed char) src_rssi->rssi; 3452 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, 3453 ap->bssid.bytes); 3454 3455 if (src_hotlist->ssid.ssid_len > 3456 WLAN_SSID_MAX_LEN) { 3457 wma_debug("Invalid SSID len %d, truncating", 3458 src_hotlist->ssid.ssid_len); 3459 src_hotlist->ssid.ssid_len = 3460 WLAN_SSID_MAX_LEN; 3461 } 3462 qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid, 3463 src_hotlist->ssid.ssid_len); 3464 ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; 3465 ap++; 3466 src_rssi++; 3467 src_hotlist++; 3468 } 3469 t_scan_id_grp++; 3470 } 3471 return 0; 3472 } 3473 3474 /** 3475 * wma_extscan_cached_results_event_handler() - cached results event handler 3476 * @handle: wma handle 3477 * @cmd_param_info: event buffer 3478 * @len: length of @cmd_param_info 3479 * 3480 * This function handles cached results event and indicate 3481 * cached results to upper layer. 3482 * 3483 * Return: 0 for success or error code. 3484 */ 3485 int wma_extscan_cached_results_event_handler(void *handle, 3486 uint8_t *cmd_param_info, 3487 uint32_t len) 3488 { 3489 WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; 3490 wmi_extscan_cached_results_event_fixed_param *event; 3491 struct extscan_cached_scan_results *dest_cachelist; 3492 struct extscan_cached_scan_result *dest_result; 3493 struct extscan_cached_scan_results empty_cachelist; 3494 wmi_extscan_wlan_descriptor *src_hotlist; 3495 wmi_extscan_rssi_info *src_rssi; 3496 int i, moredata, scan_ids_cnt, buf_len, status; 3497 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3498 uint32_t total_len; 3499 bool excess_data = false; 3500 3501 if (!mac) { 3502 wma_err("Invalid mac"); 3503 return -EINVAL; 3504 } 3505 if (!mac->sme.ext_scan_ind_cb) { 3506 wma_err("Callback not registered"); 3507 return -EINVAL; 3508 } 3509 param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) 3510 cmd_param_info; 3511 if (!param_buf) { 3512 wma_err("Invalid cached results event"); 3513 return -EINVAL; 3514 } 3515 event = param_buf->fixed_param; 3516 src_hotlist = param_buf->bssid_list; 3517 src_rssi = param_buf->rssi_list; 3518 wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d", 3519 event->total_entries, 3520 event->first_entry_index, 3521 event->num_entries_in_page); 3522 3523 if (!src_hotlist || !src_rssi || !event->num_entries_in_page) { 3524 wma_warn("Cached results empty, send 0 results"); 3525 goto noresults; 3526 } 3527 3528 if (event->num_entries_in_page > 3529 (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) || 3530 event->num_entries_in_page > param_buf->num_bssid_list) { 3531 wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d", 3532 event->num_entries_in_page, param_buf->num_bssid_list); 3533 return -EINVAL; 3534 } else { 3535 total_len = sizeof(*event) + 3536 (event->num_entries_in_page * sizeof(*src_hotlist)); 3537 } 3538 for (i = 0; i < event->num_entries_in_page; i++) { 3539 if (src_hotlist[i].ie_length > 3540 WMI_SVC_MSG_MAX_SIZE - total_len) { 3541 excess_data = true; 3542 break; 3543 } else { 3544 total_len += src_hotlist[i].ie_length; 3545 wma_debug("total len IE: %d", total_len); 3546 } 3547 3548 if (src_hotlist[i].number_rssi_samples > 3549 (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) { 3550 excess_data = true; 3551 break; 3552 } else { 3553 total_len += (src_hotlist[i].number_rssi_samples * 3554 sizeof(*src_rssi)); 3555 wma_debug("total len RSSI samples: %d", total_len); 3556 } 3557 } 3558 if (excess_data) { 3559 wma_err("excess data in WMI event"); 3560 return -EINVAL; 3561 } 3562 3563 if (event->first_entry_index + 3564 event->num_entries_in_page < event->total_entries) 3565 moredata = 1; 3566 else 3567 moredata = 0; 3568 3569 dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist)); 3570 if (!dest_cachelist) 3571 return -ENOMEM; 3572 3573 qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist)); 3574 dest_cachelist->request_id = event->request_id; 3575 dest_cachelist->more_data = moredata; 3576 3577 scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info); 3578 wma_debug("scan_ids_cnt %d", scan_ids_cnt); 3579 dest_cachelist->num_scan_ids = scan_ids_cnt; 3580 3581 buf_len = sizeof(*dest_result) * scan_ids_cnt; 3582 dest_cachelist->result = qdf_mem_malloc(buf_len); 3583 if (!dest_cachelist->result) { 3584 qdf_mem_free(dest_cachelist); 3585 return -ENOMEM; 3586 } 3587 3588 dest_result = dest_cachelist->result; 3589 wma_fill_num_results_per_scan_id(cmd_param_info, dest_result); 3590 3591 status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist); 3592 if (!status) 3593 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3594 eSIR_EXTSCAN_CACHED_RESULTS_IND, 3595 dest_cachelist); 3596 else 3597 wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback"); 3598 3599 dest_result = dest_cachelist->result; 3600 for (i = 0; i < dest_cachelist->num_scan_ids; i++) { 3601 if (dest_result->ap) 3602 qdf_mem_free(dest_result->ap); 3603 dest_result++; 3604 } 3605 qdf_mem_free(dest_cachelist->result); 3606 qdf_mem_free(dest_cachelist); 3607 return status; 3608 3609 noresults: 3610 empty_cachelist.request_id = event->request_id; 3611 empty_cachelist.more_data = 0; 3612 empty_cachelist.num_scan_ids = 0; 3613 3614 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3615 eSIR_EXTSCAN_CACHED_RESULTS_IND, 3616 &empty_cachelist); 3617 return 0; 3618 } 3619 3620 /** 3621 * wma_extscan_change_results_event_handler() - change results event handler 3622 * @handle: wma handle 3623 * @cmd_param_info: event buffer 3624 * @len: length 3625 * 3626 * This function handles change results event and indicate 3627 * change results to upper layer. 3628 * 3629 * Return: 0 for success or error code. 3630 */ 3631 int wma_extscan_change_results_event_handler(void *handle, 3632 uint8_t *cmd_param_info, 3633 uint32_t len) 3634 { 3635 WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf; 3636 wmi_extscan_wlan_change_results_event_fixed_param *event; 3637 tSirWifiSignificantChangeEvent *dest_chglist; 3638 tSirWifiSignificantChange *dest_ap; 3639 wmi_extscan_wlan_change_result_bssid *src_chglist; 3640 3641 uint32_t numap; 3642 int i, k; 3643 uint8_t *src_rssi; 3644 int count = 0; 3645 int moredata; 3646 uint32_t rssi_num = 0; 3647 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3648 uint32_t buf_len; 3649 bool excess_data = false; 3650 3651 if (!mac) { 3652 wma_err("Invalid mac"); 3653 return -EINVAL; 3654 } 3655 if (!mac->sme.ext_scan_ind_cb) { 3656 wma_err("Callback not registered"); 3657 return -EINVAL; 3658 } 3659 param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) 3660 cmd_param_info; 3661 if (!param_buf) { 3662 wma_err("Invalid change monitor event"); 3663 return -EINVAL; 3664 } 3665 event = param_buf->fixed_param; 3666 src_chglist = param_buf->bssid_signal_descriptor_list; 3667 src_rssi = param_buf->rssi_list; 3668 numap = event->num_entries_in_page; 3669 3670 if (!src_chglist || !numap) { 3671 wma_err("Results invalid"); 3672 return -EINVAL; 3673 } 3674 if (numap > param_buf->num_bssid_signal_descriptor_list) { 3675 wma_err("Invalid num of entries in page: %d", numap); 3676 return -EINVAL; 3677 } 3678 for (i = 0; i < numap; i++) { 3679 if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) { 3680 wma_err("Invalid num of rssi samples %d numap %d rssi_num %d", 3681 src_chglist->num_rssi_samples, 3682 numap, rssi_num); 3683 return -EINVAL; 3684 } 3685 rssi_num += src_chglist->num_rssi_samples; 3686 src_chglist++; 3687 } 3688 src_chglist = param_buf->bssid_signal_descriptor_list; 3689 3690 if (event->first_entry_index + 3691 event->num_entries_in_page < event->total_entries) { 3692 moredata = 1; 3693 } else { 3694 moredata = 0; 3695 } 3696 3697 do { 3698 if (event->num_entries_in_page > 3699 (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/ 3700 sizeof(*src_chglist)) { 3701 excess_data = true; 3702 break; 3703 } else { 3704 buf_len = 3705 sizeof(*event) + (event->num_entries_in_page * 3706 sizeof(*src_chglist)); 3707 } 3708 if (rssi_num > 3709 (WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) { 3710 excess_data = true; 3711 break; 3712 } 3713 } while (0); 3714 3715 if (excess_data) { 3716 wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d", 3717 numap, rssi_num); 3718 QDF_ASSERT(0); 3719 return -EINVAL; 3720 } 3721 dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) + 3722 sizeof(*dest_ap) * numap + 3723 sizeof(int32_t) * rssi_num); 3724 if (!dest_chglist) 3725 return -ENOMEM; 3726 3727 dest_ap = &dest_chglist->ap[0]; 3728 for (i = 0; i < numap; i++) { 3729 dest_ap->channel = src_chglist->channel; 3730 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid, 3731 dest_ap->bssid.bytes); 3732 dest_ap->numOfRssi = src_chglist->num_rssi_samples; 3733 if (dest_ap->numOfRssi) { 3734 if ((dest_ap->numOfRssi + count) > 3735 param_buf->num_rssi_list) { 3736 wma_err("Invalid num in rssi list: %d", 3737 dest_ap->numOfRssi); 3738 qdf_mem_free(dest_chglist); 3739 return -EINVAL; 3740 } 3741 for (k = 0; k < dest_ap->numOfRssi; k++) { 3742 dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM + 3743 src_rssi[count++]; 3744 } 3745 } 3746 dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap + 3747 dest_ap->numOfRssi * sizeof(int32_t) + 3748 sizeof(*dest_ap)); 3749 src_chglist++; 3750 } 3751 dest_chglist->requestId = event->request_id; 3752 dest_chglist->moreData = moredata; 3753 dest_chglist->numResults = numap; 3754 3755 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3756 eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, 3757 dest_chglist); 3758 wma_debug("sending change monitor results"); 3759 qdf_mem_free(dest_chglist); 3760 return 0; 3761 } 3762 3763 /** 3764 * wma_passpoint_match_event_handler() - passpoint match found event handler 3765 * @handle: WMA handle 3766 * @cmd_param_info: event data 3767 * @len: event data length 3768 * 3769 * This is the passpoint match found event handler; it reads event data from 3770 * @cmd_param_info and fill in the destination buffer and sends indication 3771 * up layer. 3772 * 3773 * Return: 0 on success; error number otherwise 3774 */ 3775 int wma_passpoint_match_event_handler(void *handle, 3776 uint8_t *cmd_param_info, 3777 uint32_t len) 3778 { 3779 WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf; 3780 wmi_passpoint_event_hdr *event; 3781 struct wifi_passpoint_match *dest_match; 3782 tSirWifiScanResult *dest_ap; 3783 uint8_t *buf_ptr; 3784 uint32_t buf_len = 0; 3785 bool excess_data = false; 3786 struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); 3787 3788 if (!mac) { 3789 wma_err("Invalid mac"); 3790 return -EINVAL; 3791 } 3792 if (!mac->sme.ext_scan_ind_cb) { 3793 wma_err("Callback not registered"); 3794 return -EINVAL; 3795 } 3796 3797 param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; 3798 if (!param_buf) { 3799 wma_err("Invalid passpoint match event"); 3800 return -EINVAL; 3801 } 3802 event = param_buf->fixed_param; 3803 buf_ptr = (uint8_t *)param_buf->fixed_param; 3804 3805 do { 3806 if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) { 3807 excess_data = true; 3808 break; 3809 } else { 3810 buf_len = event->ie_length; 3811 } 3812 3813 if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) { 3814 excess_data = true; 3815 break; 3816 } else { 3817 buf_len += event->anqp_length; 3818 } 3819 3820 } while (0); 3821 3822 if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) || 3823 buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) || 3824 (event->ie_length + event->anqp_length) > param_buf->num_bufp) { 3825 wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u", 3826 event->ie_length, event->anqp_length, 3827 param_buf->num_bufp); 3828 return -EINVAL; 3829 } 3830 3831 if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) { 3832 wma_debug("Invalid ssid len %d, truncating", 3833 event->ssid.ssid_len); 3834 event->ssid.ssid_len = WLAN_SSID_MAX_LEN; 3835 } 3836 3837 dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len); 3838 if (!dest_match) 3839 return -EINVAL; 3840 3841 dest_ap = &dest_match->ap; 3842 dest_match->request_id = 0; 3843 dest_match->id = event->id; 3844 dest_match->anqp_len = event->anqp_length; 3845 wma_info("passpoint match: id: %u anqp length %u", 3846 dest_match->id, dest_match->anqp_len); 3847 3848 dest_ap->channel = event->channel_mhz; 3849 dest_ap->ts = event->timestamp; 3850 dest_ap->rtt = event->rtt; 3851 dest_ap->rssi = event->rssi; 3852 dest_ap->rtt_sd = event->rtt_sd; 3853 dest_ap->beaconPeriod = event->beacon_period; 3854 dest_ap->capability = event->capability; 3855 dest_ap->ieLength = event->ie_length; 3856 WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes); 3857 qdf_mem_copy(dest_ap->ssid, event->ssid.ssid, 3858 event->ssid.ssid_len); 3859 dest_ap->ssid[event->ssid.ssid_len] = '\0'; 3860 qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) + 3861 WMI_TLV_HDR_SIZE, dest_ap->ieLength); 3862 qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) + 3863 WMI_TLV_HDR_SIZE + dest_ap->ieLength, 3864 dest_match->anqp_len); 3865 3866 mac->sme.ext_scan_ind_cb(mac->hdd_handle, 3867 eSIR_PASSPOINT_NETWORK_FOUND_IND, 3868 dest_match); 3869 wma_debug("sending passpoint match event to hdd"); 3870 qdf_mem_free(dest_match); 3871 return 0; 3872 } 3873 3874 QDF_STATUS wma_start_extscan(tp_wma_handle wma, 3875 struct wifi_scan_cmd_req_params *params) 3876 { 3877 QDF_STATUS status; 3878 struct wmi_unified *wmi_handle; 3879 3880 if (wma_validate_handle(wma)) 3881 return QDF_STATUS_E_INVAL; 3882 3883 wmi_handle = wma->wmi_handle; 3884 if (wmi_validate_handle(wmi_handle)) 3885 return QDF_STATUS_E_INVAL; 3886 3887 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 3888 wma_err("extscan not enabled"); 3889 return QDF_STATUS_E_FAILURE; 3890 } 3891 3892 if (!params) { 3893 wma_err("NULL param"); 3894 return QDF_STATUS_E_NOMEM; 3895 } 3896 3897 status = wmi_unified_start_extscan_cmd(wmi_handle, params); 3898 if (QDF_IS_STATUS_SUCCESS(status)) 3899 wma->interfaces[params->vdev_id].extscan_in_progress = true; 3900 3901 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 3902 3903 return status; 3904 } 3905 3906 QDF_STATUS wma_stop_extscan(tp_wma_handle wma, 3907 struct extscan_stop_req_params *params) 3908 { 3909 QDF_STATUS status; 3910 struct wmi_unified *wmi_handle; 3911 3912 if (wma_validate_handle(wma)) 3913 return QDF_STATUS_E_INVAL; 3914 3915 wmi_handle = wma->wmi_handle; 3916 if (wmi_validate_handle(wmi_handle)) 3917 return QDF_STATUS_E_INVAL; 3918 3919 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 3920 wma_err("extscan not enabled"); 3921 return QDF_STATUS_E_FAILURE; 3922 } 3923 3924 status = wmi_unified_stop_extscan_cmd(wmi_handle, params); 3925 if (QDF_IS_STATUS_ERROR(status)) 3926 return status; 3927 3928 wma->interfaces[params->vdev_id].extscan_in_progress = false; 3929 wma_debug("Extscan stop request sent successfully for vdev %d", 3930 params->vdev_id); 3931 3932 return status; 3933 } 3934 3935 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, 3936 struct extscan_bssid_hotlist_set_params *params) 3937 { 3938 struct wmi_unified *wmi_handle; 3939 3940 if (wma_validate_handle(wma)) 3941 return QDF_STATUS_E_INVAL; 3942 3943 wmi_handle = wma->wmi_handle; 3944 if (wmi_validate_handle(wmi_handle)) 3945 return QDF_STATUS_E_INVAL; 3946 3947 if (!params) { 3948 wma_err("Invalid params"); 3949 return QDF_STATUS_E_INVAL; 3950 } 3951 3952 return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle, 3953 params); 3954 } 3955 3956 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, 3957 struct extscan_bssid_hotlist_reset_params *params) 3958 { 3959 struct wmi_unified *wmi_handle; 3960 3961 if (wma_validate_handle(wma)) 3962 return QDF_STATUS_E_INVAL; 3963 3964 wmi_handle = wma->wmi_handle; 3965 if (wmi_validate_handle(wmi_handle)) 3966 return QDF_STATUS_E_INVAL; 3967 3968 if (!params) { 3969 wma_err("Invalid params"); 3970 return QDF_STATUS_E_INVAL; 3971 } 3972 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 3973 wma_err("extscan not enabled"); 3974 return QDF_STATUS_E_FAILURE; 3975 } 3976 3977 return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle, 3978 params); 3979 } 3980 3981 QDF_STATUS 3982 wma_extscan_start_change_monitor(tp_wma_handle wma, 3983 struct extscan_set_sig_changereq_params *params) 3984 { 3985 QDF_STATUS status; 3986 struct wmi_unified *wmi_handle; 3987 3988 if (wma_validate_handle(wma)) 3989 return QDF_STATUS_E_INVAL; 3990 3991 wmi_handle = wma->wmi_handle; 3992 if (wmi_validate_handle(wmi_handle)) 3993 return QDF_STATUS_E_INVAL; 3994 3995 if (!params) { 3996 wma_err("NULL params"); 3997 return QDF_STATUS_E_NOMEM; 3998 } 3999 4000 status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle, 4001 params); 4002 return status; 4003 } 4004 4005 QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, 4006 struct extscan_capabilities_reset_params *params) 4007 { 4008 struct wmi_unified *wmi_handle; 4009 4010 if (wma_validate_handle(wma)) 4011 return QDF_STATUS_E_INVAL; 4012 4013 wmi_handle = wma->wmi_handle; 4014 if (wmi_validate_handle(wmi_handle)) 4015 return QDF_STATUS_E_INVAL; 4016 4017 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4018 wma_err("ext scan not enabled"); 4019 return QDF_STATUS_E_FAILURE; 4020 } 4021 4022 return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle, 4023 params); 4024 } 4025 4026 QDF_STATUS 4027 wma_extscan_get_cached_results(tp_wma_handle wma, 4028 struct extscan_cached_result_params *params) 4029 { 4030 struct wmi_unified *wmi_handle; 4031 4032 if (wma_validate_handle(wma)) 4033 return QDF_STATUS_E_INVAL; 4034 4035 wmi_handle = wma->wmi_handle; 4036 if (wmi_validate_handle(wmi_handle)) 4037 return QDF_STATUS_E_INVAL; 4038 4039 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4040 wma_err("extscan not enabled"); 4041 return QDF_STATUS_E_FAILURE; 4042 } 4043 4044 return wmi_unified_extscan_get_cached_results_cmd(wmi_handle, 4045 params); 4046 } 4047 4048 QDF_STATUS 4049 wma_extscan_get_capabilities(tp_wma_handle wma, 4050 struct extscan_capabilities_params *params) 4051 { 4052 struct wmi_unified *wmi_handle; 4053 4054 if (wma_validate_handle(wma)) 4055 return QDF_STATUS_E_INVAL; 4056 4057 wmi_handle = wma->wmi_handle; 4058 if (wmi_validate_handle(wmi_handle)) 4059 return QDF_STATUS_E_INVAL; 4060 4061 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4062 wma_err("extscan not enabled"); 4063 return QDF_STATUS_E_FAILURE; 4064 } 4065 4066 return wmi_unified_extscan_get_capabilities_cmd(wmi_handle, 4067 params); 4068 } 4069 4070 QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, 4071 struct wifi_enhanced_pno_params *req) 4072 { 4073 QDF_STATUS status; 4074 struct wmi_unified *wmi_handle; 4075 4076 wma_debug("Enter"); 4077 4078 if (wma_validate_handle(wma)) 4079 return QDF_STATUS_E_FAILURE; 4080 4081 wmi_handle = wma->wmi_handle; 4082 if (wmi_validate_handle(wmi_handle)) 4083 return QDF_STATUS_E_FAILURE; 4084 4085 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4086 wma_err("extscan not enabled"); 4087 return QDF_STATUS_E_NOSUPPORT; 4088 } 4089 4090 status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req); 4091 wma_debug("Exit, vdev %d, status %d", req->vdev_id, status); 4092 4093 return status; 4094 } 4095 4096 QDF_STATUS 4097 wma_set_passpoint_network_list(tp_wma_handle wma, 4098 struct wifi_passpoint_req_param *params) 4099 { 4100 QDF_STATUS status; 4101 struct wmi_unified *wmi_handle; 4102 4103 wma_debug("Enter"); 4104 4105 if (wma_validate_handle(wma)) 4106 return QDF_STATUS_E_FAILURE; 4107 4108 wmi_handle = wma->wmi_handle; 4109 if (wmi_validate_handle(wmi_handle)) 4110 return QDF_STATUS_E_FAILURE; 4111 4112 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4113 wma_err("extscan not enabled"); 4114 return QDF_STATUS_E_NOSUPPORT; 4115 } 4116 4117 status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle, 4118 params); 4119 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 4120 4121 return status; 4122 } 4123 4124 QDF_STATUS 4125 wma_reset_passpoint_network_list(tp_wma_handle wma, 4126 struct wifi_passpoint_req_param *params) 4127 { 4128 QDF_STATUS status; 4129 struct wmi_unified *wmi_handle; 4130 4131 wma_debug("Enter"); 4132 4133 if (wma_validate_handle(wma)) 4134 return QDF_STATUS_E_FAILURE; 4135 4136 wmi_handle = wma->wmi_handle; 4137 if (wmi_validate_handle(wmi_handle)) 4138 return QDF_STATUS_E_FAILURE; 4139 4140 if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { 4141 wma_err("extscan not enabled"); 4142 return QDF_STATUS_E_NOSUPPORT; 4143 } 4144 4145 status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle, 4146 params); 4147 wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); 4148 4149 return status; 4150 } 4151 4152 #endif 4153 4154 QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, 4155 struct scan_mac_oui *set_oui) 4156 { 4157 struct wmi_unified *wmi_handle; 4158 4159 if (wma_validate_handle(wma)) 4160 return QDF_STATUS_E_INVAL; 4161 4162 wmi_handle = wma->wmi_handle; 4163 if (wmi_validate_handle(wmi_handle)) 4164 return QDF_STATUS_E_INVAL; 4165 4166 if (!wma_is_vdev_valid(set_oui->vdev_id)) { 4167 wma_err("vdev_id: %d is not active", set_oui->vdev_id); 4168 return QDF_STATUS_E_INVAL; 4169 } 4170 4171 return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui); 4172 } 4173 4174 /** 4175 * wma_roam_better_ap_handler() - better ap event handler 4176 * @wma: wma handle 4177 * @vdev_id: vdev id 4178 * 4179 * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome. 4180 * This event means roam algorithm in Rome has found a better matching 4181 * candidate AP. The indication is sent to SME. 4182 * 4183 * Return: none 4184 */ 4185 void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id) 4186 { 4187 struct scheduler_msg msg = {0}; 4188 QDF_STATUS status; 4189 #ifdef FEATURE_CM_ENABLE 4190 struct cm_host_roam_start_ind *ind; 4191 #else 4192 tSirSmeCandidateFoundInd *candidate_ind; 4193 #endif 4194 4195 #ifdef FEATURE_CM_ENABLE 4196 ind = qdf_mem_malloc(sizeof(*ind)); 4197 if (!ind) 4198 return; 4199 4200 wma->interfaces[vdev_id].roaming_in_progress = true; 4201 ind->pdev = wma->pdev; 4202 ind->vdev_id = vdev_id; 4203 msg.bodyptr = ind; 4204 msg.callback = wlan_cm_host_roam_start; 4205 wma_debug("Posting ROam start ind to connection manager, vdev %d", 4206 vdev_id); 4207 status = scheduler_post_message(QDF_MODULE_ID_WMA, 4208 QDF_MODULE_ID_OS_IF, 4209 QDF_MODULE_ID_SCAN, &msg); 4210 4211 #else 4212 candidate_ind = qdf_mem_malloc(sizeof(tSirSmeCandidateFoundInd)); 4213 if (!candidate_ind) 4214 return; 4215 4216 wma->interfaces[vdev_id].roaming_in_progress = true; 4217 candidate_ind->messageType = eWNI_SME_CANDIDATE_FOUND_IND; 4218 candidate_ind->sessionId = vdev_id; 4219 candidate_ind->length = sizeof(tSirSmeCandidateFoundInd); 4220 4221 msg.type = eWNI_SME_CANDIDATE_FOUND_IND; 4222 msg.bodyptr = candidate_ind; 4223 msg.callback = sme_mc_process_handler; 4224 wma_debug("Posting candidate ind to SME, vdev %d", vdev_id); 4225 4226 status = scheduler_post_message(QDF_MODULE_ID_WMA, QDF_MODULE_ID_SME, 4227 QDF_MODULE_ID_SCAN, &msg); 4228 #endif 4229 if (QDF_IS_STATUS_ERROR(status)) 4230 qdf_mem_free(msg.bodyptr); 4231 } 4232 4233 /** 4234 * wma_handle_hw_mode_in_roam_fail() - Fill hw mode info if present in policy 4235 * manager. 4236 * @wma: wma handle 4237 * @param: roam event params 4238 * 4239 * Return: None 4240 */ 4241 static int wma_handle_hw_mode_transition(tp_wma_handle wma, 4242 WMI_ROAM_EVENTID_param_tlvs *param) 4243 { 4244 struct cm_hw_mode_trans_ind *hw_mode_trans_ind; 4245 struct scheduler_msg sme_msg = {0}; 4246 QDF_STATUS status; 4247 4248 if (param->hw_mode_transition_fixed_param) { 4249 hw_mode_trans_ind = qdf_mem_malloc(sizeof(*hw_mode_trans_ind)); 4250 if (!hw_mode_trans_ind) 4251 return -ENOMEM; 4252 wma_process_pdev_hw_mode_trans_ind(wma, 4253 param->hw_mode_transition_fixed_param, 4254 param->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, 4255 hw_mode_trans_ind); 4256 4257 wma_debug("Update HW mode"); 4258 sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND; 4259 sme_msg.bodyptr = hw_mode_trans_ind; 4260 4261 status = scheduler_post_message(QDF_MODULE_ID_WMA, 4262 QDF_MODULE_ID_SME, 4263 QDF_MODULE_ID_SME, &sme_msg); 4264 if (QDF_IS_STATUS_ERROR(status)) 4265 qdf_mem_free(hw_mode_trans_ind); 4266 } else { 4267 wma_debug("hw_mode transition fixed param is NULL"); 4268 } 4269 4270 return 0; 4271 } 4272 4273 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 4274 /** 4275 * wma_invalid_roam_reason_handler() - Handle Invalid roam notification 4276 * @wma: wma handle 4277 * @vdev_id: vdev id 4278 * @op_code: Operation to be done by the callback 4279 * 4280 * This function calls pe and csr callbacks with proper op_code 4281 * 4282 * Return: None 4283 */ 4284 static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle, 4285 uint32_t vdev_id, 4286 uint32_t notif) 4287 { 4288 struct roam_offload_synch_ind *roam_synch_data; 4289 enum sir_roam_op_code op_code; 4290 4291 if (notif == WMI_ROAM_NOTIF_ROAM_START) { 4292 wma_handle->interfaces[vdev_id].roaming_in_progress = true; 4293 op_code = SIR_ROAMING_START; 4294 } else if (notif == WMI_ROAM_NOTIF_ROAM_ABORT) { 4295 wma_handle->interfaces[vdev_id].roaming_in_progress = false; 4296 op_code = SIR_ROAMING_ABORT; 4297 lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); 4298 } else { 4299 wma_debug("Invalid notif %d", notif); 4300 return; 4301 } 4302 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 4303 if (!roam_synch_data) 4304 return; 4305 4306 roam_synch_data->roamed_vdev_id = vdev_id; 4307 if (notif != WMI_ROAM_NOTIF_ROAM_START) 4308 wma_handle->pe_roam_synch_cb(wma_handle->mac_context, 4309 roam_synch_data, NULL, op_code); 4310 #ifdef FEATURE_CM_ENABLE 4311 if (notif == WMI_ROAM_NOTIF_ROAM_START) 4312 cm_fw_roam_start_req(wma_handle->psoc, vdev_id); 4313 else 4314 cm_fw_roam_abort_req(wma_handle->psoc, vdev_id); 4315 #else 4316 wma_handle->csr_roam_synch_cb(wma_handle->mac_context, roam_synch_data, 4317 NULL, op_code); 4318 #endif 4319 qdf_mem_free(roam_synch_data); 4320 } 4321 4322 void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle, 4323 struct roam_sync_timeout_timer_info *info) 4324 { 4325 wma_invalid_roam_reason_handler(wma_handle, info->vdev_id, 4326 WMI_ROAM_NOTIF_ROAM_ABORT); 4327 } 4328 #endif 4329 4330 static char *wma_get_roam_event_reason_string(uint32_t reason) 4331 { 4332 switch (reason) { 4333 case WMI_ROAM_REASON_INVALID: 4334 return "Default"; 4335 case WMI_ROAM_REASON_BETTER_AP: 4336 return "Better AP"; 4337 case WMI_ROAM_REASON_BMISS: 4338 return "BMISS"; 4339 case WMI_ROAM_REASON_LOW_RSSI: 4340 return "Low Rssi"; 4341 case WMI_ROAM_REASON_SUITABLE_AP: 4342 return "Suitable AP"; 4343 case WMI_ROAM_REASON_HO_FAILED: 4344 return "Hand-off Failed"; 4345 case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: 4346 return "Roam Invoke failed"; 4347 case WMI_ROAM_REASON_RSO_STATUS: 4348 return "RSO status"; 4349 case WMI_ROAM_REASON_BTM: 4350 return "BTM"; 4351 case WMI_ROAM_REASON_DEAUTH: 4352 return "Deauth"; 4353 default: 4354 return "Invalid"; 4355 } 4356 4357 return "Invalid"; 4358 } 4359 4360 /** 4361 * wma_roam_event_callback() - roam event callback 4362 * @handle: wma handle 4363 * @event_buf: event buffer 4364 * @len: buffer length 4365 * 4366 * Handler for all events from roam engine in firmware 4367 * 4368 * Return: 0 for success or error code 4369 */ 4370 int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, 4371 uint32_t len) 4372 { 4373 tp_wma_handle wma_handle = (tp_wma_handle) handle; 4374 WMI_ROAM_EVENTID_param_tlvs *param_buf; 4375 wmi_roam_event_fixed_param *wmi_event; 4376 struct roam_offload_synch_ind *roam_synch_data; 4377 uint8_t *frame = NULL; 4378 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 4379 struct qdf_mac_addr bssid; 4380 #endif 4381 4382 param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf; 4383 if (!param_buf) { 4384 wma_err("Invalid roam event buffer"); 4385 return -EINVAL; 4386 } 4387 4388 wmi_event = param_buf->fixed_param; 4389 if (wmi_event->vdev_id >= wma_handle->max_bssid) { 4390 wma_err("Invalid vdev id from firmware"); 4391 return -EINVAL; 4392 } 4393 wlan_roam_debug_log(wmi_event->vdev_id, DEBUG_ROAM_EVENT, 4394 DEBUG_INVALID_PEER_ID, NULL, NULL, 4395 wmi_event->reason, 4396 (wmi_event->reason == WMI_ROAM_REASON_INVALID) ? 4397 wmi_event->notif : wmi_event->rssi); 4398 4399 DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, 4400 wmi_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, 4401 QDF_PROTO_TYPE_EVENT, QDF_ROAM_EVENTID)); 4402 4403 wma_debug("FW_ROAM_EVT: Reason:%s[%d], Notif %x for vdevid %x, rssi %d", 4404 wma_get_roam_event_reason_string(wmi_event->reason), 4405 wmi_event->reason, 4406 wmi_event->notif, wmi_event->vdev_id, wmi_event->rssi); 4407 4408 switch (wmi_event->reason) { 4409 case WMI_ROAM_REASON_BTM: 4410 /* 4411 * This event is received from firmware if firmware is unable to 4412 * find candidate AP after roam scan and BTM request from AP 4413 * has disassoc imminent bit set. 4414 */ 4415 wma_debug("Kickout due to btm request"); 4416 wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, 4417 wmi_event->vdev_id, NULL); 4418 wma_handle_disconnect_reason(wma_handle, wmi_event->vdev_id, 4419 HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); 4420 break; 4421 case WMI_ROAM_REASON_BMISS: 4422 /* 4423 * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so 4424 * avoid using CSR/PE structure directly 4425 */ 4426 wma_debug("Beacon Miss for vdevid %x", wmi_event->vdev_id); 4427 wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id, 4428 wmi_event->rssi); 4429 wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, 4430 wmi_event->vdev_id, NULL); 4431 break; 4432 case WMI_ROAM_REASON_BETTER_AP: 4433 /* 4434 * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context, 4435 * so avoid using CSR/PE structure directly. 4436 */ 4437 wma_debug("Better AP found for vdevid %x, rssi %d", 4438 wmi_event->vdev_id, wmi_event->rssi); 4439 mlme_set_roam_reason_better_ap( 4440 wma_handle->interfaces[wmi_event->vdev_id].vdev, false); 4441 wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); 4442 break; 4443 case WMI_ROAM_REASON_SUITABLE_AP: 4444 /* 4445 * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ 4446 * context, so avoid using CSR/PE structure directly. 4447 */ 4448 mlme_set_roam_reason_better_ap( 4449 wma_handle->interfaces[wmi_event->vdev_id].vdev, true); 4450 mlme_set_hb_ap_rssi( 4451 wma_handle->interfaces[wmi_event->vdev_id].vdev, 4452 wmi_event->rssi); 4453 wma_debug("Bmiss scan AP found for vdevid %x, rssi %d", 4454 wmi_event->vdev_id, wmi_event->rssi); 4455 wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); 4456 break; 4457 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 4458 case WMI_ROAM_REASON_HO_FAILED: 4459 /* 4460 * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context, 4461 * so avoid using CSR/PE structure directly. 4462 */ 4463 wma_err("LFR3:Hand-Off Failed for vdevid %x", 4464 wmi_event->vdev_id); 4465 bssid.bytes[0] = wmi_event->notif_params >> 0 & 0xFF; 4466 bssid.bytes[1] = wmi_event->notif_params >> 8 & 0xFF; 4467 bssid.bytes[2] = wmi_event->notif_params >> 16 & 0xFF; 4468 bssid.bytes[3] = wmi_event->notif_params >> 24 & 0xFF; 4469 bssid.bytes[4] = wmi_event->notif_params1 >> 0 & 0xFF; 4470 bssid.bytes[5] = wmi_event->notif_params1 >> 8 & 0xFF; 4471 wma_debug("mac addr to avoid "QDF_MAC_ADDR_FMT, 4472 QDF_MAC_ADDR_REF(bssid.bytes)); 4473 wma_handle_hw_mode_transition(wma_handle, param_buf); 4474 #ifdef FEATURE_CM_ENABLE 4475 cm_fw_ho_fail_req(wma_handle->psoc, wmi_event->vdev_id, bssid); 4476 #else 4477 wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id, bssid); 4478 #endif 4479 lim_sae_auth_cleanup_retry(wma_handle->mac_context, 4480 wmi_event->vdev_id); 4481 break; 4482 case WMI_ROAM_REASON_INVALID: 4483 wma_invalid_roam_reason_handler(wma_handle, wmi_event->vdev_id, 4484 wmi_event->notif); 4485 break; 4486 #endif 4487 case WMI_ROAM_REASON_RSO_STATUS: 4488 wma_rso_cmd_status_event_handler(wmi_event); 4489 break; 4490 case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: 4491 wma_handle_hw_mode_transition(wma_handle, param_buf); 4492 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 4493 if (!roam_synch_data) 4494 return -ENOMEM; 4495 4496 lim_sae_auth_cleanup_retry(wma_handle->mac_context, 4497 wmi_event->vdev_id); 4498 roam_synch_data->roamed_vdev_id = wmi_event->vdev_id; 4499 #ifdef FEATURE_CM_ENABLE 4500 cm_fw_roam_invoke_fail(wma_handle->psoc, wmi_event->vdev_id); 4501 #else 4502 wma_handle->csr_roam_synch_cb(wma_handle->mac_context, 4503 roam_synch_data, NULL, 4504 SIR_ROAMING_INVOKE_FAIL); 4505 #endif 4506 wlan_cm_update_roam_states(wma_handle->psoc, wmi_event->vdev_id, 4507 wmi_event->notif_params, 4508 ROAM_INVOKE_FAIL_REASON); 4509 4510 qdf_mem_free(roam_synch_data); 4511 break; 4512 case WMI_ROAM_REASON_DEAUTH: 4513 wma_debug("Received disconnect roam event reason:%d", 4514 wmi_event->notif_params); 4515 if (wmi_event->notif_params1) 4516 frame = param_buf->deauth_disassoc_frame; 4517 wma_handle->pe_disconnect_cb(wma_handle->mac_context, 4518 wmi_event->vdev_id, 4519 frame, wmi_event->notif_params1, 4520 wmi_event->notif_params); 4521 roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); 4522 if (!roam_synch_data) 4523 return -ENOMEM; 4524 4525 roam_synch_data->roamed_vdev_id = wmi_event->vdev_id; 4526 #ifndef FEATURE_CM_ENABLE 4527 wma_handle->csr_roam_synch_cb( 4528 wma_handle->mac_context, 4529 roam_synch_data, NULL, SIR_ROAMING_DEAUTH); 4530 #endif 4531 qdf_mem_free(roam_synch_data); 4532 break; 4533 default: 4534 wma_debug("Unhandled Roam Event %x for vdevid %x", 4535 wmi_event->reason, wmi_event->vdev_id); 4536 break; 4537 } 4538 return 0; 4539 } 4540 4541 #ifdef FEATURE_LFR_SUBNET_DETECTION 4542 QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, 4543 struct gateway_update_req_param *req) 4544 { 4545 if (wma_validate_handle(wma)) 4546 return QDF_STATUS_E_INVAL; 4547 4548 return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req); 4549 } 4550 #endif /* FEATURE_LFR_SUBNET_DETECTION */ 4551 4552 /** 4553 * wma_ht40_stop_obss_scan() - ht40 obss stop scan 4554 * @wma: WMA handel 4555 * @vdev_id: vdev identifier 4556 * 4557 * Return: Return QDF_STATUS, otherwise appropriate failure code 4558 */ 4559 QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id) 4560 { 4561 QDF_STATUS status; 4562 wmi_buf_t buf; 4563 wmi_obss_scan_disable_cmd_fixed_param *cmd; 4564 int len = sizeof(*cmd); 4565 4566 buf = wmi_buf_alloc(wma->wmi_handle, len); 4567 if (!buf) 4568 return QDF_STATUS_E_NOMEM; 4569 4570 wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id); 4571 4572 cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf); 4573 WMITLV_SET_HDR(&cmd->tlv_header, 4574 WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, 4575 WMITLV_GET_STRUCT_TLVLEN( 4576 wmi_obss_scan_disable_cmd_fixed_param)); 4577 4578 cmd->vdev_id = vdev_id; 4579 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 4580 WMI_OBSS_SCAN_DISABLE_CMDID); 4581 if (QDF_IS_STATUS_ERROR(status)) 4582 wmi_buf_free(buf); 4583 4584 return status; 4585 } 4586 4587 /** 4588 * wma_send_ht40_obss_scanind() - ht40 obss start scan indication 4589 * @wma: WMA handel 4590 * @req: start scan request 4591 * 4592 * Return: Return QDF_STATUS, otherwise appropriate failure code 4593 */ 4594 QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, 4595 struct obss_ht40_scanind *req) 4596 { 4597 QDF_STATUS status; 4598 wmi_buf_t buf; 4599 wmi_obss_scan_enable_cmd_fixed_param *cmd; 4600 int len = 0; 4601 uint8_t *buf_ptr, i; 4602 uint8_t *channel_list; 4603 uint32_t *chan_freq_list; 4604 4605 len += sizeof(wmi_obss_scan_enable_cmd_fixed_param); 4606 4607 len += WMI_TLV_HDR_SIZE; 4608 len += qdf_roundup(sizeof(uint8_t) * req->channel_count, 4609 sizeof(uint32_t)); 4610 4611 len += WMI_TLV_HDR_SIZE; 4612 len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); 4613 4614 /* length calculation for chan_freqs */ 4615 len += WMI_TLV_HDR_SIZE; 4616 len += sizeof(uint32_t) * req->channel_count; 4617 4618 wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d", 4619 len, req->bss_id, req->channel_count, req->iefield_len); 4620 4621 wma_debug("scantype %d active_time %d passive %d Obss interval %d", 4622 req->scan_type, req->obss_active_dwelltime, 4623 req->obss_passive_dwelltime, 4624 req->obss_width_trigger_interval); 4625 4626 buf = wmi_buf_alloc(wma->wmi_handle, len); 4627 if (!buf) 4628 return QDF_STATUS_E_NOMEM; 4629 4630 cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf); 4631 WMITLV_SET_HDR(&cmd->tlv_header, 4632 WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, 4633 WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param)); 4634 4635 buf_ptr = (uint8_t *) cmd; 4636 4637 cmd->vdev_id = req->bss_id; 4638 cmd->scan_type = req->scan_type; 4639 cmd->obss_scan_active_dwell = 4640 req->obss_active_dwelltime; 4641 cmd->obss_scan_passive_dwell = 4642 req->obss_passive_dwelltime; 4643 cmd->bss_channel_width_trigger_scan_interval = 4644 req->obss_width_trigger_interval; 4645 cmd->bss_width_channel_transition_delay_factor = 4646 req->bsswidth_ch_trans_delay; 4647 cmd->obss_scan_active_total_per_channel = 4648 req->obss_active_total_per_channel; 4649 cmd->obss_scan_passive_total_per_channel = 4650 req->obss_passive_total_per_channel; 4651 cmd->obss_scan_activity_threshold = 4652 req->obss_activity_threshold; 4653 4654 cmd->channel_len = req->channel_count; 4655 cmd->forty_mhz_intolerant = req->fortymhz_intolerent; 4656 cmd->current_operating_class = req->current_operatingclass; 4657 cmd->ie_len = req->iefield_len; 4658 4659 buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param); 4660 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 4661 qdf_roundup(req->channel_count, sizeof(uint32_t))); 4662 4663 buf_ptr += WMI_TLV_HDR_SIZE; 4664 channel_list = (uint8_t *) buf_ptr; 4665 4666 for (i = 0; i < req->channel_count; i++) { 4667 channel_list[i] = 4668 wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]); 4669 wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]); 4670 } 4671 4672 buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count, 4673 sizeof(uint32_t)); 4674 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 4675 qdf_roundup(1, sizeof(uint32_t))); 4676 buf_ptr += WMI_TLV_HDR_SIZE; 4677 4678 buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); 4679 4680 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 4681 sizeof(uint32_t) * req->channel_count); 4682 buf_ptr += WMI_TLV_HDR_SIZE; 4683 4684 chan_freq_list = (uint32_t *)buf_ptr; 4685 for (i = 0; i < req->channel_count; i++) { 4686 chan_freq_list[i] = req->chan_freq_list[i]; 4687 wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]); 4688 } 4689 4690 buf_ptr += sizeof(uint32_t) * req->channel_count; 4691 4692 status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, 4693 WMI_OBSS_SCAN_ENABLE_CMDID); 4694 if (QDF_IS_STATUS_ERROR(status)) 4695 wmi_buf_free(buf); 4696 4697 return status; 4698 } 4699 4700 static enum blm_reject_ap_reason wma_get_reject_reason(uint32_t reason) 4701 { 4702 switch(reason) { 4703 case WMI_BL_REASON_NUD_FAILURE: 4704 return REASON_NUD_FAILURE; 4705 case WMI_BL_REASON_STA_KICKOUT: 4706 return REASON_STA_KICKOUT; 4707 case WMI_BL_REASON_ROAM_HO_FAILURE: 4708 return REASON_ROAM_HO_FAILURE; 4709 case WMI_BL_REASON_ASSOC_REJECT_POOR_RSSI: 4710 return REASON_ASSOC_REJECT_POOR_RSSI; 4711 case WMI_BL_REASON_ASSOC_REJECT_OCE: 4712 return REASON_ASSOC_REJECT_OCE; 4713 case WMI_BL_REASON_USERSPACE_BL: 4714 return REASON_USERSPACE_BL; 4715 case WMI_BL_REASON_USERSPACE_AVOID_LIST: 4716 return REASON_USERSPACE_AVOID_LIST; 4717 case WMI_BL_REASON_BTM_DIASSOC_IMMINENT: 4718 return REASON_BTM_DISASSOC_IMMINENT; 4719 case WMI_BL_REASON_BTM_BSS_TERMINATION: 4720 return REASON_BTM_BSS_TERMINATION; 4721 case WMI_BL_REASON_BTM_MBO_RETRY: 4722 return REASON_BTM_MBO_RETRY; 4723 case WMI_BL_REASON_REASSOC_RSSI_REJECT: 4724 return REASON_REASSOC_RSSI_REJECT; 4725 case WMI_BL_REASON_REASSOC_NO_MORE_STAS: 4726 return REASON_REASSOC_NO_MORE_STAS; 4727 default: 4728 return REASON_UNKNOWN; 4729 } 4730 } 4731 4732 int wma_handle_btm_blacklist_event(void *handle, uint8_t *cmd_param_info, 4733 uint32_t len) 4734 { 4735 tp_wma_handle wma = (tp_wma_handle) handle; 4736 WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *param_buf; 4737 wmi_roam_blacklist_event_fixed_param *resp_event; 4738 wmi_roam_blacklist_with_timeout_tlv_param *src_list; 4739 struct roam_blacklist_event *dst_list; 4740 struct roam_blacklist_timeout *roam_blacklist; 4741 uint32_t num_entries, i; 4742 4743 param_buf = (WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *)cmd_param_info; 4744 if (!param_buf) { 4745 wma_err("Invalid event buffer"); 4746 return -EINVAL; 4747 } 4748 4749 resp_event = param_buf->fixed_param; 4750 if (!resp_event) { 4751 wma_err("received null event data from target"); 4752 return -EINVAL; 4753 } 4754 4755 if (resp_event->vdev_id >= wma->max_bssid) { 4756 wma_err("received invalid vdev_id %d", resp_event->vdev_id); 4757 return -EINVAL; 4758 } 4759 4760 num_entries = param_buf->num_blacklist_with_timeout; 4761 if (num_entries == 0) { 4762 /* no aps to blacklist just return*/ 4763 wma_err("No APs in blacklist received"); 4764 return 0; 4765 } 4766 4767 if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) { 4768 wma_err("num blacklist entries:%d exceeds maximum value", 4769 num_entries); 4770 return -EINVAL; 4771 } 4772 4773 src_list = param_buf->blacklist_with_timeout; 4774 if (len < (sizeof(*resp_event) + (num_entries * sizeof(*src_list)))) { 4775 wma_err("Invalid length:%d", len); 4776 return -EINVAL; 4777 } 4778 4779 dst_list = qdf_mem_malloc(sizeof(struct roam_blacklist_event) + 4780 (sizeof(struct roam_blacklist_timeout) * 4781 num_entries)); 4782 if (!dst_list) 4783 return -ENOMEM; 4784 4785 roam_blacklist = &dst_list->roam_blacklist[0]; 4786 for (i = 0; i < num_entries; i++) { 4787 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid, 4788 roam_blacklist->bssid.bytes); 4789 roam_blacklist->timeout = src_list->timeout; 4790 roam_blacklist->received_time = src_list->timestamp; 4791 roam_blacklist->original_timeout = src_list->original_timeout; 4792 roam_blacklist->reject_reason = 4793 wma_get_reject_reason(src_list->reason); 4794 roam_blacklist->source = src_list->source; 4795 roam_blacklist++; 4796 src_list++; 4797 } 4798 4799 dst_list->num_entries = num_entries; 4800 wma_send_msg(wma, WMA_ROAM_BLACKLIST_MSG, (void *)dst_list, 0); 4801 return 0; 4802 } 4803 4804 #if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_FIPS) 4805 void wma_register_pmkid_req_event_handler(tp_wma_handle wma_handle) 4806 { 4807 if (wma_validate_handle(wma_handle)) 4808 return; 4809 4810 wmi_unified_register_event_handler(wma_handle->wmi_handle, 4811 wmi_roam_pmkid_request_event_id, 4812 wma_roam_pmkid_request_event_handler, 4813 WMA_RX_SERIALIZER_CTX); 4814 } 4815 4816 int wma_roam_pmkid_request_event_handler(void *handle, uint8_t *event, 4817 uint32_t len) 4818 { 4819 WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *param_buf; 4820 wmi_roam_pmkid_request_event_fixed_param *roam_pmkid_req_ev; 4821 wmi_roam_pmkid_request_tlv_param *src_list; 4822 tp_wma_handle wma = (tp_wma_handle)handle; 4823 struct roam_pmkid_req_event *dst_list; 4824 struct qdf_mac_addr *roam_bsslist; 4825 uint32_t num_entries, i; 4826 QDF_STATUS status; 4827 4828 if (!event) { 4829 wma_err("received null event from target"); 4830 return -EINVAL; 4831 } 4832 4833 param_buf = (WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *)event; 4834 if (!param_buf) { 4835 wma_err("received null buf from target"); 4836 return -EINVAL; 4837 } 4838 4839 roam_pmkid_req_ev = param_buf->fixed_param; 4840 if (!roam_pmkid_req_ev) { 4841 wma_err("received null event data from target"); 4842 return -EINVAL; 4843 } 4844 4845 if (roam_pmkid_req_ev->vdev_id >= wma->max_bssid) { 4846 wma_err("received invalid vdev_id %d", roam_pmkid_req_ev->vdev_id); 4847 return -EINVAL; 4848 } 4849 4850 num_entries = param_buf->num_pmkid_request; 4851 if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) { 4852 wma_err("num bssid entries:%d exceeds maximum value", 4853 num_entries); 4854 return -EINVAL; 4855 } 4856 4857 src_list = param_buf->pmkid_request; 4858 if (len < (sizeof(*roam_pmkid_req_ev) + 4859 (num_entries * sizeof(*src_list)))) { 4860 wma_err("Invalid length: %d", len); 4861 return -EINVAL; 4862 } 4863 4864 dst_list = qdf_mem_malloc(sizeof(struct roam_pmkid_req_event) + 4865 (sizeof(struct qdf_mac_addr) * num_entries)); 4866 if (!dst_list) 4867 return -ENOMEM; 4868 4869 for (i = 0; i < num_entries; i++) { 4870 roam_bsslist = &dst_list->ap_bssid[i]; 4871 WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid, 4872 roam_bsslist->bytes); 4873 if (qdf_is_macaddr_zero(roam_bsslist) || 4874 qdf_is_macaddr_broadcast(roam_bsslist) || 4875 qdf_is_macaddr_group(roam_bsslist)) { 4876 wma_err("Invalid bssid"); 4877 qdf_mem_free(dst_list); 4878 return -EINVAL; 4879 } 4880 wma_debug("Received pmkid fallback for bssid: "QDF_MAC_ADDR_FMT" vdev_id:%d", 4881 QDF_MAC_ADDR_REF(roam_bsslist->bytes), 4882 roam_pmkid_req_ev->vdev_id); 4883 src_list++; 4884 } 4885 dst_list->num_entries = num_entries; 4886 4887 status = cm_roam_pmkid_req_ind(wma->psoc, roam_pmkid_req_ev->vdev_id, 4888 dst_list); 4889 if (QDF_IS_STATUS_ERROR(status)) { 4890 wma_err("Pmkid request failed"); 4891 qdf_mem_free(dst_list); 4892 return -EINVAL; 4893 } 4894 4895 qdf_mem_free(dst_list); 4896 return 0; 4897 } 4898 #endif 4899