1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * DOC: wlan_cm_roam_fw_sync.c 22 * 23 * Implementation for the FW based roaming sync api interfaces. 24 */ 25 #include "qdf_types.h" 26 #include "wlan_objmgr_psoc_obj.h" 27 #include "wlan_objmgr_pdev_obj.h" 28 #include "wlan_objmgr_vdev_obj.h" 29 #include "wlan_cm_roam_i.h" 30 #include "wlan_dlm_api.h" 31 #include "wlan_cm_roam_public_struct.h" 32 #include "wlan_utility.h" 33 #include "wlan_scan_api.h" 34 #include "wlan_crypto_global_api.h" 35 #include "wlan_cm_tgt_if_tx_api.h" 36 #include "wlan_cm_vdev_api.h" 37 #include "wlan_p2p_api.h" 38 #include "wlan_tdls_api.h" 39 #include "wlan_mlme_vdev_mgr_interface.h" 40 #include "wlan_pkt_capture_ucfg_api.h" 41 #include "cds_utils.h" 42 #include "wlan_roam_debug.h" 43 #include "wlan_mlme_twt_api.h" 44 #include "connection_mgr/core/src/wlan_cm_roam.h" 45 #include "connection_mgr/core/src/wlan_cm_main.h" 46 #include "connection_mgr/core/src/wlan_cm_sm.h" 47 #include <wlan_mlo_mgr_sta.h> 48 #include "wlan_mlo_mgr_roam.h" 49 #include "wlan_vdev_mgr_utils_api.h" 50 #include "wlan_mlo_link_force.h" 51 #include <wlan_psoc_mlme_api.h> 52 #include <wma.h> 53 54 /* 55 * cm_is_peer_preset_on_other_sta() - Check if peer exists on other STA 56 * @psoc: Pointer to psoc 57 * @vdev: pointer to vdev 58 * @vdev_id: vdev id 59 * @event: Roam sync event pointer 60 * 61 * Return: True is peer found on other STA else return false 62 */ 63 static bool 64 cm_is_peer_preset_on_other_sta(struct wlan_objmgr_psoc *psoc, 65 struct wlan_objmgr_vdev *vdev, 66 uint8_t vdev_id, void *event) 67 { 68 bool peer_exists_other_sta = false; 69 struct roam_offload_synch_ind *sync_ind; 70 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 71 uint8_t peer_vdev_id; 72 73 sync_ind = (struct roam_offload_synch_ind *)event; 74 75 if (wma_objmgr_peer_exist(wma, sync_ind->bssid.bytes, &peer_vdev_id)) { 76 if ((!wlan_vdev_mlme_is_mlo_vdev(vdev) && 77 vdev_id != peer_vdev_id) || 78 !mlo_check_is_given_vdevs_on_same_mld(psoc, vdev_id, 79 peer_vdev_id)) { 80 wma_debug("Peer " QDF_MAC_ADDR_FMT 81 " already exists on vdev %d, current vdev %d", 82 QDF_MAC_ADDR_REF(sync_ind->bssid.bytes), 83 peer_vdev_id, vdev_id); 84 peer_exists_other_sta = true; 85 } 86 } 87 88 return peer_exists_other_sta; 89 } 90 91 QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, 92 void *event, uint32_t event_data_len) 93 { 94 QDF_STATUS status; 95 struct wlan_objmgr_vdev *vdev; 96 97 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 98 WLAN_MLME_SB_ID); 99 100 if (!vdev) { 101 mlme_err("vdev object is NULL"); 102 return QDF_STATUS_E_NULL_VALUE; 103 } 104 105 if (mlo_is_mld_disconnecting_connecting(vdev) || 106 cm_is_vdev_connecting(vdev) || 107 cm_is_vdev_disconnecting(vdev) || 108 cm_is_peer_preset_on_other_sta(psoc, vdev, vdev_id, event)) { 109 mlme_err("vdev %d Roam sync not handled in connecting/disconnecting state", 110 vdev_id); 111 status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 112 vdev_id, 113 WLAN_ROAM_RSO_STOPPED, 114 REASON_ROAM_SYNCH_FAILED); 115 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 116 return status; 117 } 118 mlo_sta_stop_reconfig_timer(vdev); 119 wlan_clear_mlo_sta_link_removed_flag(vdev); 120 121 status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_SYNC, 122 event_data_len, event); 123 124 if (QDF_IS_STATUS_ERROR(status)) { 125 mlme_err("Roam sync was not handled"); 126 wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 127 vdev_id, WLAN_ROAM_RSO_STOPPED, 128 REASON_ROAM_SYNCH_FAILED); 129 } 130 131 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 132 133 return status; 134 } 135 136 QDF_STATUS 137 cm_fw_send_vdev_roam_event(struct cnx_mgr *cm_ctx, uint16_t data_len, 138 void *data) 139 { 140 QDF_STATUS status; 141 wlan_cm_id cm_id; 142 struct wlan_objmgr_psoc *psoc; 143 struct cm_roam_req *roam_req = NULL; 144 145 roam_req = cm_get_first_roam_command(cm_ctx->vdev); 146 if (!roam_req) { 147 mlme_err("Failed to find roam req from list"); 148 cm_id = CM_ID_INVALID; 149 status = QDF_STATUS_E_FAILURE; 150 goto error; 151 } 152 153 cm_id = roam_req->cm_id; 154 psoc = wlan_vdev_get_psoc(cm_ctx->vdev); 155 if (!psoc) { 156 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 157 CM_PREFIX_REF(roam_req->req.vdev_id, 158 roam_req->cm_id)); 159 status = QDF_STATUS_E_FAILURE; 160 goto error; 161 } 162 163 status = wlan_vdev_mlme_sm_deliver_evt(cm_ctx->vdev, 164 WLAN_VDEV_SM_EV_ROAM, 165 data_len, 166 data); 167 168 error: 169 170 return status; 171 } 172 173 QDF_STATUS 174 cm_fw_roam_sync_start_ind(struct wlan_objmgr_vdev *vdev, 175 struct roam_offload_synch_ind *sync_ind) 176 { 177 QDF_STATUS status = QDF_STATUS_SUCCESS; 178 struct wlan_objmgr_pdev *pdev; 179 struct qdf_mac_addr connected_bssid; 180 uint8_t vdev_id; 181 struct wlan_objmgr_psoc *psoc; 182 183 pdev = wlan_vdev_get_pdev(vdev); 184 vdev_id = wlan_vdev_get_id(vdev); 185 psoc = wlan_pdev_get_psoc(pdev); 186 187 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 188 if (!MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, 189 sync_ind->roamed_vdev_id)) 190 status = wlan_cm_roam_state_change(pdev, 191 sync_ind->roamed_vdev_id, 192 WLAN_ROAM_SYNCH_IN_PROG, 193 REASON_ROAM_HANDOFF_DONE); 194 195 status = wlan_cm_roam_state_change(pdev, 196 vdev_id, 197 WLAN_MLO_ROAM_SYNCH_IN_PROG, 198 REASON_ROAM_HANDOFF_DONE); 199 return status; 200 } 201 202 /* 203 * Get old bssid as, new AP is not updated yet and do cleanup 204 * for old bssid. 205 */ 206 wlan_mlme_get_bssid_vdev_id(pdev, vdev_id, 207 &connected_bssid); 208 209 /* Update the DLM that the previous profile has disconnected */ 210 wlan_dlm_update_bssid_connect_params(pdev, 211 connected_bssid, 212 DLM_AP_DISCONNECTED); 213 214 if (IS_ROAM_REASON_STA_KICKOUT(sync_ind->roam_reason)) { 215 struct reject_ap_info ap_info; 216 217 qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); 218 ap_info.bssid = connected_bssid; 219 ap_info.reject_ap_type = DRIVER_AVOID_TYPE; 220 ap_info.reject_reason = REASON_STA_KICKOUT; 221 ap_info.source = ADDED_BY_DRIVER; 222 wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); 223 } 224 225 cm_update_scan_mlme_on_roam(vdev, &connected_bssid, 226 SCAN_ENTRY_CON_STATE_NONE); 227 228 if (!MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) 229 status = wlan_cm_roam_state_change(pdev, 230 vdev_id, 231 WLAN_ROAM_SYNCH_IN_PROG, 232 REASON_ROAM_HANDOFF_DONE); 233 234 mlme_init_twt_context(wlan_pdev_get_psoc(pdev), &connected_bssid, 235 TWT_ALL_SESSIONS_DIALOG_ID); 236 237 mlme_cm_osif_roam_sync_ind(vdev); 238 239 return status; 240 } 241 242 void 243 cm_update_scan_mlme_on_roam(struct wlan_objmgr_vdev *vdev, 244 struct qdf_mac_addr *connected_bssid, 245 enum scan_entry_connection_state state) 246 { 247 struct wlan_objmgr_pdev *pdev; 248 struct bss_info bss_info; 249 struct mlme_info mlme; 250 struct wlan_channel *chan; 251 QDF_STATUS status; 252 253 pdev = wlan_vdev_get_pdev(vdev); 254 if (!pdev) { 255 mlme_err("failed to find pdev"); 256 return; 257 } 258 259 chan = wlan_vdev_get_active_channel(vdev); 260 if (!chan) { 261 mlme_err("failed to get active channel"); 262 return; 263 } 264 265 status = wlan_vdev_mlme_get_ssid(vdev, bss_info.ssid.ssid, 266 &bss_info.ssid.length); 267 268 if (QDF_IS_STATUS_ERROR(status)) { 269 mlme_err("failed to get ssid"); 270 return; 271 } 272 273 mlme.assoc_state = state; 274 qdf_copy_macaddr(&bss_info.bssid, connected_bssid); 275 276 bss_info.freq = chan->ch_freq; 277 278 wlan_scan_update_mlme_by_bssinfo(pdev, &bss_info, &mlme); 279 } 280 281 #ifdef WLAN_FEATURE_FILS_SK 282 static QDF_STATUS 283 cm_fill_fils_ie(struct wlan_connect_rsp_ies *connect_ies, 284 struct roam_offload_synch_ind *roam_synch_data) 285 { 286 struct fils_connect_rsp_params *fils_ie; 287 288 if (!roam_synch_data->hlp_data_len) 289 return QDF_STATUS_SUCCESS; 290 291 connect_ies->fils_ie = qdf_mem_malloc(sizeof(*fils_ie)); 292 if (!connect_ies->fils_ie) 293 return QDF_STATUS_E_NOMEM; 294 295 fils_ie = connect_ies->fils_ie; 296 cds_copy_hlp_info(&roam_synch_data->dst_mac, 297 &roam_synch_data->src_mac, 298 roam_synch_data->hlp_data_len, 299 roam_synch_data->hlp_data, 300 &fils_ie->dst_mac, 301 &fils_ie->src_mac, 302 &fils_ie->hlp_data_len, 303 fils_ie->hlp_data); 304 305 fils_ie->fils_seq_num = roam_synch_data->next_erp_seq_num; 306 307 return QDF_STATUS_SUCCESS; 308 } 309 #else 310 static inline QDF_STATUS 311 cm_fill_fils_ie(struct wlan_connect_rsp_ies *connect_ies, 312 struct roam_offload_synch_ind *roam_synch_data) 313 { 314 return QDF_STATUS_SUCCESS; 315 } 316 #endif 317 318 static QDF_STATUS 319 cm_populate_connect_ies(struct roam_offload_synch_ind *roam_synch_data, 320 struct cm_vdev_join_rsp *rsp) 321 { 322 struct wlan_connect_rsp_ies *connect_ies; 323 uint8_t *bcn_probe_rsp_ptr; 324 uint8_t *reassoc_rsp_ptr; 325 uint8_t *reassoc_req_ptr; 326 327 connect_ies = &rsp->connect_rsp.connect_ies; 328 329 /* Beacon/Probe Rsp frame */ 330 if (roam_synch_data->beacon_probe_resp_length) { 331 connect_ies->bcn_probe_rsp.len = 332 roam_synch_data->beacon_probe_resp_length; 333 bcn_probe_rsp_ptr = (uint8_t *)roam_synch_data + 334 roam_synch_data->beacon_probe_resp_offset; 335 336 connect_ies->bcn_probe_rsp.ptr = 337 qdf_mem_malloc(connect_ies->bcn_probe_rsp.len); 338 if (!connect_ies->bcn_probe_rsp.ptr) 339 return QDF_STATUS_E_NOMEM; 340 qdf_mem_copy(connect_ies->bcn_probe_rsp.ptr, bcn_probe_rsp_ptr, 341 connect_ies->bcn_probe_rsp.len); 342 } 343 344 /* Beacon/Probe Rsp frame */ 345 if (roam_synch_data->link_beacon_probe_resp_length) { 346 connect_ies->link_bcn_probe_rsp.len = 347 roam_synch_data->link_beacon_probe_resp_length; 348 bcn_probe_rsp_ptr = (uint8_t *)roam_synch_data + 349 roam_synch_data->link_beacon_probe_resp_offset; 350 351 connect_ies->link_bcn_probe_rsp.ptr = 352 qdf_mem_malloc(connect_ies->link_bcn_probe_rsp.len); 353 if (!connect_ies->link_bcn_probe_rsp.ptr) 354 return QDF_STATUS_E_NOMEM; 355 qdf_mem_copy(connect_ies->link_bcn_probe_rsp.ptr, 356 bcn_probe_rsp_ptr, 357 connect_ies->link_bcn_probe_rsp.len); 358 } 359 360 /* ReAssoc Rsp IE data */ 361 if (roam_synch_data->reassoc_resp_length > 362 sizeof(struct wlan_frame_hdr)) { 363 connect_ies->assoc_rsp.len = 364 roam_synch_data->reassoc_resp_length - 365 sizeof(struct wlan_frame_hdr); 366 reassoc_rsp_ptr = (uint8_t *)roam_synch_data + 367 roam_synch_data->reassoc_resp_offset + 368 sizeof(struct wlan_frame_hdr); 369 connect_ies->assoc_rsp.ptr = 370 qdf_mem_malloc(connect_ies->assoc_rsp.len); 371 if (!connect_ies->assoc_rsp.ptr) 372 return QDF_STATUS_E_NOMEM; 373 374 qdf_mem_copy(connect_ies->assoc_rsp.ptr, reassoc_rsp_ptr, 375 connect_ies->assoc_rsp.len); 376 } 377 378 /* ReAssoc Req IE data */ 379 if (roam_synch_data->reassoc_req_length > 380 sizeof(struct wlan_frame_hdr)) { 381 connect_ies->assoc_req.len = 382 roam_synch_data->reassoc_req_length - 383 sizeof(struct wlan_frame_hdr); 384 reassoc_req_ptr = (uint8_t *)roam_synch_data + 385 roam_synch_data->reassoc_req_offset + 386 sizeof(struct wlan_frame_hdr); 387 connect_ies->assoc_req.ptr = 388 qdf_mem_malloc(connect_ies->assoc_req.len); 389 if (!connect_ies->assoc_req.ptr) 390 return QDF_STATUS_E_NOMEM; 391 qdf_mem_copy(connect_ies->assoc_req.ptr, reassoc_req_ptr, 392 connect_ies->assoc_req.len); 393 } 394 rsp->connect_rsp.is_assoc = roam_synch_data->is_assoc; 395 396 cm_fill_fils_ie(connect_ies, roam_synch_data); 397 398 return QDF_STATUS_SUCCESS; 399 } 400 401 #ifdef FEATURE_WLAN_ESE 402 static QDF_STATUS 403 cm_copy_tspec_ie(struct cm_vdev_join_rsp *rsp, 404 struct roam_offload_synch_ind *roam_synch_data) 405 { 406 if (roam_synch_data->tspec_len) { 407 rsp->tspec_ie.len = roam_synch_data->tspec_len; 408 rsp->tspec_ie.ptr = 409 qdf_mem_malloc(rsp->tspec_ie.len); 410 if (!rsp->tspec_ie.ptr) 411 return QDF_STATUS_E_NOMEM; 412 413 qdf_mem_copy(rsp->tspec_ie.ptr, 414 roam_synch_data->ric_tspec_data + 415 roam_synch_data->ric_data_len, 416 rsp->tspec_ie.len); 417 } 418 419 return QDF_STATUS_SUCCESS; 420 } 421 #else 422 static inline QDF_STATUS 423 cm_copy_tspec_ie(struct cm_vdev_join_rsp *rsp, 424 struct roam_offload_synch_ind *roam_synch_data) 425 { 426 return QDF_STATUS_SUCCESS; 427 } 428 #endif 429 430 #ifdef WLAN_FEATURE_FILS_SK 431 static void 432 cm_fils_update_erp_seq_num(struct wlan_objmgr_vdev *vdev, 433 uint16_t next_erp_seq_num, 434 wlan_cm_id cm_id) 435 { 436 struct wlan_objmgr_psoc *psoc; 437 struct wlan_objmgr_pdev *pdev; 438 struct wlan_fils_connection_info *fils_info; 439 uint8_t vdev_id = wlan_vdev_get_id(vdev); 440 441 pdev = wlan_vdev_get_pdev(vdev); 442 if (!pdev) { 443 mlme_err(CM_PREFIX_FMT "Failed to find pdev", 444 CM_PREFIX_REF(vdev_id, cm_id)); 445 return; 446 } 447 448 psoc = wlan_pdev_get_psoc(pdev); 449 if (!psoc) { 450 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 451 CM_PREFIX_REF(vdev_id, cm_id)); 452 return; 453 } 454 455 fils_info = wlan_cm_get_fils_connection_info(psoc, vdev_id); 456 if (!fils_info) 457 return; 458 459 /* 460 * update the erp sequence number to the vdev level 461 * FILS cache. This will be sent in the next RSO 462 * command. 463 */ 464 fils_info->erp_sequence_number = next_erp_seq_num; 465 } 466 #else 467 static inline void 468 cm_fils_update_erp_seq_num(struct wlan_objmgr_vdev *vdev, 469 uint16_t next_erp_seq_num, wlan_cm_id cm_id) 470 {} 471 #endif 472 473 #ifdef WLAN_FEATURE_11BE_MLO 474 static void 475 cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev, 476 struct roam_offload_synch_ind *roam_synch_data) 477 { 478 struct wlan_channel channel = {0}; 479 struct ml_setup_link_param *ml_link; 480 uint8_t i; 481 482 if (!is_multi_link_roam(roam_synch_data)) 483 return; 484 485 mlo_mgr_reset_ap_link_info(vdev); 486 for (i = 0; i < roam_synch_data->num_setup_links; i++) { 487 ml_link = &roam_synch_data->ml_link[i]; 488 489 qdf_mem_zero(&channel, sizeof(channel)); 490 491 channel.ch_freq = ml_link->channel.mhz; 492 channel.ch_cfreq1 = ml_link->channel.band_center_freq1; 493 channel.ch_cfreq2 = ml_link->channel.band_center_freq2; 494 495 /* 496 * Update Link switch context for each vdev with roamed AP link 497 * address and self link address for each vdev 498 */ 499 mlo_mgr_roam_update_ap_link_info(vdev, ml_link, &channel); 500 } 501 } 502 503 static QDF_STATUS 504 cm_fill_bssid_freq_info(uint8_t vdev_id, 505 struct roam_offload_synch_ind *roam_synch_data, 506 struct cm_vdev_join_rsp *rsp) 507 { 508 uint8_t i; 509 struct ml_setup_link_param *ml_link; 510 511 /* The @bssid field in roam synch indication will 512 * contain MLD address in case of roaming to ML 513 * candidate or else legacy MAC address for non-ML 514 * roaming. 515 */ 516 if (is_multi_link_roam(roam_synch_data)) 517 qdf_copy_macaddr(&rsp->connect_rsp.mld_addr, 518 &roam_synch_data->bssid); 519 else 520 qdf_zero_macaddr(&rsp->connect_rsp.mld_addr); 521 522 for (i = 0; i < roam_synch_data->num_setup_links; i++) { 523 ml_link = &roam_synch_data->ml_link[i]; 524 if (vdev_id == ml_link->vdev_id) { 525 qdf_copy_macaddr(&rsp->connect_rsp.bssid, 526 &ml_link->link_addr); 527 rsp->connect_rsp.freq = ml_link->channel.mhz; 528 529 return QDF_STATUS_SUCCESS; 530 } 531 } 532 533 qdf_copy_macaddr(&rsp->connect_rsp.bssid, &roam_synch_data->bssid); 534 rsp->connect_rsp.freq = roam_synch_data->chan_freq; 535 536 return QDF_STATUS_SUCCESS; 537 } 538 539 static void 540 cm_mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp, 541 struct roam_offload_synch_ind *roam_synch_data) 542 { 543 mlo_roam_copy_partner_info(&connect_rsp->ml_parnter_info, 544 roam_synch_data, WLAN_INVALID_VDEV_ID, 545 true); 546 } 547 #else 548 static inline void 549 cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev, 550 struct roam_offload_synch_ind *roam_synch_data) 551 {} 552 static QDF_STATUS 553 cm_fill_bssid_freq_info(uint8_t vdev_id, 554 struct roam_offload_synch_ind *roam_synch_data, 555 struct cm_vdev_join_rsp *rsp) 556 { 557 qdf_copy_macaddr(&rsp->connect_rsp.bssid, &roam_synch_data->bssid); 558 rsp->connect_rsp.freq = roam_synch_data->chan_freq; 559 560 return QDF_STATUS_SUCCESS; 561 } 562 563 static void 564 cm_mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp, 565 struct roam_offload_synch_ind *roam_synch_data) 566 { 567 } 568 #endif 569 570 static void 571 cm_update_assoc_btm_cap(struct wlan_objmgr_vdev *vdev, 572 struct cm_vdev_join_rsp *rsp) 573 { 574 struct wlan_connect_rsp_ies *connect_ies; 575 const uint8_t *ext_cap_ie; 576 struct s_ext_cap *extcap; 577 uint8_t offset; 578 579 connect_ies = &rsp->connect_rsp.connect_ies; 580 /* 581 * Retain the btm cap from initial assoc if 582 * there is no assoc request 583 */ 584 if (!connect_ies->assoc_req.ptr || 585 !connect_ies->assoc_req.len) 586 return; 587 588 if (rsp->connect_rsp.is_assoc) 589 offset = WLAN_ASSOC_REQ_IES_OFFSET; 590 else 591 offset = WLAN_REASSOC_REQ_IES_OFFSET; 592 593 ext_cap_ie = 594 wlan_get_ie_ptr_from_eid(WLAN_ELEMID_XCAPS, 595 connect_ies->assoc_req.ptr + offset, 596 connect_ies->assoc_req.len - offset); 597 598 if (!ext_cap_ie) { 599 mlme_debug("Ext cap is not present, disable btm"); 600 wlan_cm_set_assoc_btm_cap(vdev, false); 601 return; 602 } 603 extcap = (struct s_ext_cap *)&ext_cap_ie[2]; 604 wlan_cm_set_assoc_btm_cap(vdev, extcap->bss_transition); 605 } 606 607 static QDF_STATUS 608 cm_fill_roam_info(struct wlan_objmgr_vdev *vdev, 609 struct roam_offload_synch_ind *roam_synch_data, 610 struct cm_vdev_join_rsp *rsp, wlan_cm_id cm_id) 611 { 612 struct wlan_roam_sync_info *roaming_info; 613 QDF_STATUS status = QDF_STATUS_SUCCESS; 614 615 rsp->connect_rsp.roaming_info = qdf_mem_malloc(sizeof(*roaming_info)); 616 if (!rsp->connect_rsp.roaming_info) 617 return QDF_STATUS_E_NOMEM; 618 619 rsp->connect_rsp.vdev_id = wlan_vdev_get_id(vdev); 620 status = cm_fill_bssid_freq_info(wlan_vdev_get_id(vdev), 621 roam_synch_data, rsp); 622 if (QDF_IS_STATUS_ERROR(status)) { 623 mlme_err(CM_PREFIX_FMT "Failed to get bssid and freq", 624 CM_PREFIX_REF(rsp->connect_rsp.vdev_id, cm_id)); 625 return QDF_STATUS_E_FAILURE; 626 } 627 628 if (!util_scan_is_null_ssid(&roam_synch_data->ssid)) 629 wlan_vdev_mlme_set_ssid(vdev, 630 roam_synch_data->ssid.ssid, 631 roam_synch_data->ssid.length); 632 633 status = wlan_vdev_mlme_get_ssid(vdev, 634 rsp->connect_rsp.ssid.ssid, 635 &rsp->connect_rsp.ssid.length); 636 if (QDF_IS_STATUS_ERROR(status)) { 637 mlme_err(CM_PREFIX_FMT "Failed to get ssid", 638 CM_PREFIX_REF(rsp->connect_rsp.vdev_id, cm_id)); 639 return QDF_STATUS_E_FAILURE; 640 } 641 642 rsp->connect_rsp.is_reassoc = true; 643 rsp->connect_rsp.connect_status = QDF_STATUS_SUCCESS; 644 rsp->connect_rsp.cm_id = cm_id; 645 rsp->nss = roam_synch_data->nss; 646 647 if (roam_synch_data->ric_data_len) { 648 rsp->ric_resp_ie.len = roam_synch_data->ric_data_len; 649 rsp->ric_resp_ie.ptr = 650 qdf_mem_malloc(rsp->ric_resp_ie.len); 651 if (!rsp->ric_resp_ie.ptr) 652 return QDF_STATUS_E_NOMEM; 653 654 qdf_mem_copy(rsp->ric_resp_ie.ptr, 655 roam_synch_data->ric_tspec_data, 656 rsp->ric_resp_ie.len); 657 } 658 cm_copy_tspec_ie(rsp, roam_synch_data); 659 660 status = cm_populate_connect_ies(roam_synch_data, rsp); 661 if (QDF_IS_STATUS_ERROR(status)) 662 return status; 663 664 roaming_info = rsp->connect_rsp.roaming_info; 665 roaming_info->auth_status = roam_synch_data->auth_status; 666 roaming_info->kck_len = roam_synch_data->kck_len; 667 if (roaming_info->kck_len) 668 qdf_mem_copy(roaming_info->kck, roam_synch_data->kck, 669 roam_synch_data->kck_len); 670 roaming_info->kek_len = roam_synch_data->kek_len; 671 if (roaming_info->kek_len) 672 qdf_mem_copy(roaming_info->kek, roam_synch_data->kek, 673 roam_synch_data->kek_len); 674 qdf_mem_copy(roaming_info->replay_ctr, roam_synch_data->replay_ctr, 675 REPLAY_CTR_LEN); 676 roaming_info->roam_reason = 677 roam_synch_data->roam_reason & ROAM_REASON_MASK; 678 roaming_info->subnet_change_status = 679 CM_GET_SUBNET_STATUS(roam_synch_data->roam_reason); 680 roaming_info->pmk_len = roam_synch_data->pmk_len; 681 if (roaming_info->pmk_len) 682 qdf_mem_copy(roaming_info->pmk, roam_synch_data->pmk, 683 roaming_info->pmk_len); 684 685 qdf_mem_copy(roaming_info->pmkid, roam_synch_data->pmkid, 686 PMKID_LEN); 687 roaming_info->update_erp_next_seq_num = 688 roam_synch_data->update_erp_next_seq_num; 689 roaming_info->next_erp_seq_num = roam_synch_data->next_erp_seq_num; 690 691 cm_fils_update_erp_seq_num(vdev, roaming_info->next_erp_seq_num, cm_id); 692 cm_update_assoc_btm_cap(vdev, rsp); 693 694 return status; 695 } 696 697 static QDF_STATUS cm_process_roam_keys(struct wlan_objmgr_vdev *vdev, 698 struct cm_vdev_join_rsp *rsp, 699 wlan_cm_id cm_id) 700 { 701 struct wlan_objmgr_psoc *psoc; 702 struct wlan_objmgr_pdev *pdev; 703 struct wlan_roam_sync_info *roaming_info; 704 uint8_t vdev_id = wlan_vdev_get_id(vdev); 705 struct cm_roam_values_copy config; 706 uint8_t mdie_present; 707 struct wlan_mlme_psoc_ext_obj *mlme_obj; 708 QDF_STATUS status = QDF_STATUS_SUCCESS; 709 int32_t akm; 710 711 pdev = wlan_vdev_get_pdev(vdev); 712 if (!pdev) { 713 mlme_err(CM_PREFIX_FMT "Failed to find pdev", 714 CM_PREFIX_REF(vdev_id, cm_id)); 715 status = QDF_STATUS_E_FAILURE; 716 goto end; 717 } 718 psoc = wlan_pdev_get_psoc(pdev); 719 if (!psoc) { 720 mlme_err(CM_PREFIX_FMT "Failed to find psoc", 721 CM_PREFIX_REF(vdev_id, cm_id)); 722 status = QDF_STATUS_E_FAILURE; 723 goto end; 724 } 725 mlme_obj = mlme_get_psoc_ext_obj(psoc); 726 if (!mlme_obj) { 727 mlme_err(CM_PREFIX_FMT "Failed to mlme psoc obj", 728 CM_PREFIX_REF(vdev_id, cm_id)); 729 status = QDF_STATUS_E_FAILURE; 730 goto end; 731 } 732 733 roaming_info = rsp->connect_rsp.roaming_info; 734 akm = wlan_crypto_get_param(vdev, 735 WLAN_CRYPTO_PARAM_KEY_MGMT); 736 737 /* 738 * Encryption keys for new connection are obtained as follows: 739 * auth_status = CSR_ROAM_AUTH_STATUS_AUTHENTICATED 740 * Open - No keys required. 741 * Static WEP - Firmware copies keys from old AP to new AP. 742 * Fast roaming authentications e.g. PSK, FT, CCKM - firmware 743 * supplicant obtains them through 4-way handshake. 744 * 745 * auth_status = CSR_ROAM_AUTH_STATUS_CONNECTED 746 * All other authentications - Host supplicant performs EAPOL 747 * with AP after this point and sends new keys to the driver. 748 * Driver starts wait_for_key timer for that purpose. 749 * Allow cm_lookup_pmkid_using_bssid() if akm is SAE/OWE since 750 * SAE/OWE roaming uses hybrid model and eapol is offloaded to 751 * supplicant unlike in WPA2 802.1x case, after 8 way handshake 752 * the __wlan_hdd_cfg80211_keymgmt_set_key ->sme_roam_set_psk_pmk() 753 * will get called after roam synch complete to update the 754 * session->psk_pmk, but in SAE/OWE roaming this sequence is not 755 * present and set_pmksa will come before roam synch indication & 756 * eapol. So the session->psk_pmk will be stale in PMKSA cached 757 * SAE/OWE roaming case. 758 */ 759 760 if (roaming_info->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED || 761 QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || 762 QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE) || 763 QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) { 764 struct wlan_crypto_pmksa *pmkid_cache, *pmksa; 765 766 cm_csr_set_ss_none(vdev_id); 767 /* 768 * If authStatus is AUTHENTICATED, then we have done successful 769 * 4 way handshake in FW using the cached PMKID. 770 * However, the session->psk_pmk has the PMK of the older AP 771 * as set_key is not received from supplicant. 772 * When any RSO command is sent for the current AP, the older 773 * AP's PMK is sent to the FW which leads to incorrect PMK and 774 * leads to 4 way handshake failure when roaming happens to 775 * this AP again. 776 * Check if a PMK cache exists for the roamed AP and update 777 * it into the session pmk. 778 */ 779 pmkid_cache = qdf_mem_malloc(sizeof(*pmkid_cache)); 780 if (!pmkid_cache) { 781 status = QDF_STATUS_E_NOMEM; 782 mlme_err(CM_PREFIX_FMT "Mem alloc failed", 783 CM_PREFIX_REF(vdev_id, cm_id)); 784 goto end; 785 } 786 wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, &pmkid_cache->bssid); 787 mlme_debug(CM_PREFIX_FMT "Trying to find PMKID for " 788 QDF_MAC_ADDR_FMT " AKM Type:%d", 789 CM_PREFIX_REF(vdev_id, cm_id), 790 QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes), akm); 791 792 wlan_cm_roam_cfg_get_value(psoc, vdev_id, 793 MOBILITY_DOMAIN, &config); 794 mdie_present = config.bool_value; 795 796 if (cm_lookup_pmkid_using_bssid(psoc, 797 vdev_id, 798 pmkid_cache)) { 799 /* 800 * Consider two APs: AP1, AP2 801 * Both APs configured with EAP 802.1x security mode 802 * and OKC is enabled in both APs by default. Initially 803 * DUT successfully associated with AP1, and generated 804 * PMK1 by performing full EAP and added an entry for 805 * AP1 in pmk table. At this stage, pmk table has only 806 * one entry for PMK1 (1. AP1-->PMK1). Now DUT try to 807 * roam to AP2 using PMK1 (as OKC is enabled) but 808 * session timeout happens on AP2 just before 4 way 809 * handshake completion in FW. At this point of time 810 * DUT not in authenticated state. Due to this DUT 811 * performs full EAP with AP2 and generates PMK2. As 812 * there is no previous entry of AP2 (AP2-->PMK1) in pmk 813 * table. When host gets pmk delete command for BSSID of 814 * AP2, the BSSID match fails. Hence host will not 815 * delete pmk entry of AP1 as well. 816 * At this point of time, the PMK table has two entry 817 * 1. AP1-->PMK1 and 2. AP2 --> PMK2. 818 * Ideally, if OKC is enabled then whenever timeout 819 * occurs in a mobility domain, then the driver should 820 * clear all APs cache entries related to that domain 821 * but as the BSSID doesn't exist yet in the driver 822 * cache there is no way of clearing the cache entries, 823 * without disturbing the legacy roaming. 824 * Now security profile for both APs changed to FT-RSN. 825 * DUT first disassociate with AP2 and successfully 826 * associated with AP2 and perform full EAP and 827 * generates PMK3. DUT first deletes PMK entry for AP2 828 * and then adds a new entry for AP2. 829 * At this point of time pmk table has two entry 830 * AP2--> PMK3 and AP1-->PMK1. Now DUT roamed to AP1 831 * using PMK3 but sends stale entry of AP1 (PMK1) to 832 * fw via RSO command. This override PMK for both APs 833 * with PMK1 (as FW uses mlme session PMK for both APs 834 * in case of FT roaming) and next time when FW try to 835 * roam to AP2 using PMK1, AP2 rejects PMK1 (As AP2 is 836 * expecting PMK3) and initiates full EAP with AP2, 837 * which is wrong. 838 * To address this issue update pmk table entry for 839 * roamed AP1 with pmk3 value comes to host via roam 840 * sync indication event. By this host override stale 841 * entry (if any) with the latest valid pmk for that AP 842 * at a point of time. 843 */ 844 if (roaming_info->pmk_len) { 845 pmksa = qdf_mem_malloc(sizeof(*pmksa)); 846 if (!pmksa) { 847 status = QDF_STATUS_E_NOMEM; 848 qdf_mem_zero(pmkid_cache, 849 sizeof(*pmkid_cache)); 850 qdf_mem_free(pmkid_cache); 851 goto end; 852 } 853 854 /* 855 * This pmksa buffer is to update the 856 * crypto table 857 */ 858 wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, 859 &pmksa->bssid); 860 qdf_mem_copy(pmksa->pmkid, 861 roaming_info->pmkid, PMKID_LEN); 862 qdf_mem_copy(pmksa->pmk, roaming_info->pmk, 863 roaming_info->pmk_len); 864 pmksa->pmk_len = roaming_info->pmk_len; 865 status = wlan_crypto_set_del_pmksa(vdev, 866 pmksa, true); 867 if (QDF_IS_STATUS_ERROR(status)) { 868 qdf_mem_zero(pmksa, sizeof(*pmksa)); 869 qdf_mem_free(pmksa); 870 } 871 872 /* update the pmkid_cache buffer to 873 * update the global session pmk 874 */ 875 qdf_mem_copy(pmkid_cache->pmkid, 876 roaming_info->pmkid, PMKID_LEN); 877 qdf_mem_copy(pmkid_cache->pmk, 878 roaming_info->pmk, 879 roaming_info->pmk_len); 880 pmkid_cache->pmk_len = roaming_info->pmk_len; 881 } 882 883 wlan_cm_set_psk_pmk(pdev, vdev_id, 884 pmkid_cache->pmk, 885 pmkid_cache->pmk_len); 886 mlme_debug(CM_PREFIX_FMT "pmkid found for " 887 QDF_MAC_ADDR_FMT " len %d", 888 CM_PREFIX_REF(vdev_id, cm_id), 889 QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes), 890 pmkid_cache->pmk_len); 891 } else { 892 mlme_debug(CM_PREFIX_FMT "PMKID Not found in cache for " 893 QDF_MAC_ADDR_FMT, 894 CM_PREFIX_REF(vdev_id, cm_id), 895 QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes)); 896 /* 897 * In FT roam when the CSR lookup fails then the PMK 898 * details from the roam sync indication will be 899 * updated to Session/PMK cache. This will result in 900 * having multiple PMK cache entries for the same MDID, 901 * So do not add the PMKSA cache entry in all the 902 * FT-Roam cases. 903 */ 904 if (!cm_is_auth_type_11r(mlme_obj, vdev, 905 mdie_present) && 906 roaming_info->pmk_len) { 907 /* 908 * This pmksa buffer is to update the 909 * crypto table 910 */ 911 pmksa = qdf_mem_malloc(sizeof(*pmksa)); 912 if (!pmksa) { 913 status = QDF_STATUS_E_NOMEM; 914 qdf_mem_zero(pmkid_cache, 915 sizeof(*pmkid_cache)); 916 qdf_mem_free(pmkid_cache); 917 goto end; 918 } 919 wlan_cm_set_psk_pmk(pdev, vdev_id, 920 roaming_info->pmk, 921 roaming_info->pmk_len); 922 wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, 923 &pmksa->bssid); 924 qdf_mem_copy(pmksa->pmkid, 925 roaming_info->pmkid, PMKID_LEN); 926 qdf_mem_copy(pmksa->pmk, 927 roaming_info->pmk, 928 roaming_info->pmk_len); 929 pmksa->pmk_len = roaming_info->pmk_len; 930 931 status = wlan_crypto_set_del_pmksa(vdev, 932 pmksa, 933 true); 934 if (QDF_IS_STATUS_ERROR(status)) { 935 qdf_mem_zero(pmksa, sizeof(*pmksa)); 936 qdf_mem_free(pmksa); 937 } 938 } 939 } 940 qdf_mem_zero(pmkid_cache, sizeof(*pmkid_cache)); 941 qdf_mem_free(pmkid_cache); 942 } 943 944 if (roaming_info->auth_status != ROAM_AUTH_STATUS_AUTHENTICATED) 945 cm_update_wait_for_key_timer(vdev, vdev_id, 946 WAIT_FOR_KEY_TIMEOUT_PERIOD); 947 end: 948 return status; 949 } 950 951 static void 952 cm_update_scan_db_on_roam_success(struct wlan_objmgr_vdev *vdev, 953 struct wlan_cm_connect_resp *resp, 954 struct roam_offload_synch_ind *roam_synch_ind, 955 wlan_cm_id cm_id) 956 { 957 struct cnx_mgr *cm_ctx; 958 qdf_freq_t frame_freq; 959 struct wlan_connect_rsp_ies *ies = &resp->connect_ies; 960 961 cm_ctx = cm_get_cm_ctx(vdev); 962 if (!cm_ctx) 963 return; 964 965 if (ies->link_bcn_probe_rsp.len) { 966 frame_freq = mlo_roam_get_link_freq_from_mac_addr( 967 roam_synch_ind, 968 wlan_mlme_get_src_addr_from_frame( 969 &ies->link_bcn_probe_rsp)); 970 cm_inform_bcn_probe(cm_ctx, 971 ies->link_bcn_probe_rsp.ptr, 972 ies->link_bcn_probe_rsp.len, 973 frame_freq, 974 roam_synch_ind->rssi, 975 cm_id); 976 } 977 978 frame_freq = mlo_roam_get_link_freq_from_mac_addr( 979 roam_synch_ind, 980 wlan_mlme_get_src_addr_from_frame( 981 &ies->bcn_probe_rsp)); 982 /* 983 * Firmware might have roamed to a link but got ML probe 984 * response from the other link. Then the link freq is not 985 * present in roam link info and it returns 0. No need to add 986 * the original probe rsp in such cases as roam sync indication 987 * handling would add it to scan db. Add the entry to scan 988 * db only if valid link freq is found. 989 */ 990 if (frame_freq) 991 cm_inform_bcn_probe(cm_ctx, 992 ies->bcn_probe_rsp.ptr, 993 ies->bcn_probe_rsp.len, 994 frame_freq, 995 roam_synch_ind->rssi, 996 cm_id); 997 998 cm_update_scan_mlme_on_roam(vdev, &resp->bssid, 999 SCAN_ENTRY_CON_STATE_ASSOC); 1000 1001 cm_standby_link_update_mlme_by_bssid(vdev, SCAN_ENTRY_CON_STATE_ASSOC, 1002 resp->ssid); 1003 } 1004 1005 #ifdef WLAN_FEATURE_11BE_MLO 1006 static void 1007 cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev) 1008 { 1009 struct wlan_mlo_dev_context *ml_dev; 1010 struct mlo_link_info *link_info; 1011 uint8_t i; 1012 1013 ml_dev = vdev->mlo_dev_ctx; 1014 if (!ml_dev || !ml_dev->link_ctx) 1015 return; 1016 1017 link_info = &ml_dev->link_ctx->links_info[0]; 1018 for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { 1019 if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) 1020 continue; 1021 1022 if (qdf_is_macaddr_zero(&link_info->link_addr)) 1023 continue; 1024 1025 wlan_crypto_free_key_by_link_id(wlan_vdev_get_psoc(vdev), 1026 &link_info->link_addr, 1027 link_info->link_id); 1028 link_info++; 1029 } 1030 } 1031 #else 1032 static void 1033 cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev) 1034 {} 1035 #endif 1036 1037 QDF_STATUS 1038 cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, 1039 struct roam_offload_synch_ind *roam_synch_data) 1040 { 1041 QDF_STATUS status; 1042 struct wlan_objmgr_vdev *vdev; 1043 struct cnx_mgr *cm_ctx; 1044 struct cm_roam_req *roam_req = NULL; 1045 struct cm_vdev_join_rsp *rsp = NULL; 1046 wlan_cm_id cm_id; 1047 struct wlan_objmgr_pdev *pdev; 1048 struct wlan_cm_connect_resp *connect_rsp; 1049 bool eht_capab = false; 1050 1051 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1052 WLAN_MLME_SB_ID); 1053 1054 if (!vdev) { 1055 mlme_err("vdev object is NULL"); 1056 return QDF_STATUS_E_NULL_VALUE; 1057 } 1058 1059 pdev = wlan_vdev_get_pdev(vdev); 1060 if (!pdev) { 1061 status = QDF_STATUS_E_FAILURE; 1062 goto rel_ref; 1063 } 1064 1065 cm_ctx = cm_get_cm_ctx(vdev); 1066 if (!cm_ctx) { 1067 status = QDF_STATUS_E_FAILURE; 1068 goto rel_ref; 1069 } 1070 1071 roam_req = cm_get_first_roam_command(vdev); 1072 if (!roam_req) { 1073 mlme_err("Failed to find roam req from list"); 1074 cm_id = CM_ID_INVALID; 1075 status = QDF_STATUS_E_FAILURE; 1076 goto error; 1077 } 1078 wlan_rec_conn_info(vdev_id, DEBUG_CONN_ROAMING, 1079 roam_synch_data->bssid.bytes, 0, 0); 1080 1081 cm_roam_update_mlo_mgr_info(vdev, roam_synch_data); 1082 cm_roam_ml_clear_prev_ap_keys(vdev); 1083 1084 cm_id = roam_req->cm_id; 1085 rsp = qdf_mem_malloc(sizeof(struct cm_vdev_join_rsp)); 1086 if (!rsp) { 1087 status = QDF_STATUS_E_NOMEM; 1088 goto error; 1089 } 1090 status = cm_fill_roam_info(vdev, roam_synch_data, rsp, cm_id); 1091 if (QDF_IS_STATUS_ERROR(status)) { 1092 mlme_err(CM_PREFIX_FMT " fail to prepare rsp", 1093 CM_PREFIX_REF(vdev_id, cm_id)); 1094 goto error; 1095 } 1096 1097 connect_rsp = &rsp->connect_rsp; 1098 cm_update_scan_db_on_roam_success(vdev, connect_rsp, 1099 roam_synch_data, cm_id); 1100 1101 status = cm_csr_connect_rsp(vdev, rsp); 1102 if (QDF_IS_STATUS_ERROR(status)) { 1103 mlme_err("Roam sync propagation failed, abort roaming"); 1104 goto error; 1105 } 1106 1107 cm_process_roam_keys(vdev, rsp, cm_id); 1108 /* 1109 * Re-enable the disabled link on roaming as decision 1110 * will be taken again to disable the link on roam sync completion. 1111 */ 1112 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) 1113 policy_mgr_move_vdev_from_disabled_to_connection_tbl(psoc, 1114 vdev_id); 1115 cm_mlo_roam_copy_partner_info(connect_rsp, roam_synch_data); 1116 mlo_roam_init_cu_bpcc(vdev, roam_synch_data); 1117 mlo_roam_set_link_id(vdev, roam_synch_data); 1118 1119 /** 1120 * Don't send roam_sync complete for MLO link vdevs. 1121 * Send only for legacy STA/MLO STA vdev. 1122 */ 1123 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 1124 cm_inform_dlm_connect_complete(cm_ctx->vdev, connect_rsp); 1125 wlan_p2p_status_connect(vdev); 1126 1127 if (!cm_csr_is_ss_wait_for_key(vdev_id)) { 1128 mlme_debug(CM_PREFIX_FMT "WLAN link up with AP = " 1129 QDF_MAC_ADDR_FMT, 1130 CM_PREFIX_REF(vdev_id, cm_id), 1131 QDF_MAC_ADDR_REF(connect_rsp->bssid.bytes)); 1132 cm_roam_start_init_on_connect(pdev, vdev_id); 1133 } 1134 wlan_cm_tgt_send_roam_sync_complete_cmd(psoc, vdev_id); 1135 mlo_roam_update_connected_links(vdev, connect_rsp); 1136 mlo_set_single_link_ml_roaming(psoc, vdev_id, 1137 false); 1138 } 1139 cm_connect_info(vdev, true, &connect_rsp->bssid, &connect_rsp->ssid, 1140 connect_rsp->freq); 1141 wlan_tdls_notify_sta_connect(vdev_id, 1142 mlme_get_tdls_chan_switch_prohibited(vdev), 1143 mlme_get_tdls_prohibited(vdev), vdev); 1144 1145 cm_update_associated_ch_info(vdev, true); 1146 1147 status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_ROAM_DONE, 1148 sizeof(*roam_synch_data), 1149 roam_synch_data); 1150 if (QDF_IS_STATUS_ERROR(status)) { 1151 mlme_err(CM_PREFIX_FMT " fail to post WLAN_CM_SM_EV_ROAM_DONE", 1152 CM_PREFIX_REF(vdev_id, cm_id)); 1153 goto error; 1154 } 1155 1156 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1157 mlo_roam_update_connected_links(vdev, connect_rsp); 1158 mlme_cm_osif_connect_complete(vdev, connect_rsp); 1159 mlme_cm_osif_roam_complete(vdev); 1160 1161 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) 1162 mlo_roam_copy_reassoc_rsp(vdev, connect_rsp); 1163 mlme_debug(CM_PREFIX_FMT, CM_PREFIX_REF(vdev_id, cm_id)); 1164 cm_remove_cmd(cm_ctx, &cm_id); 1165 1166 wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); 1167 if (eht_capab) { 1168 status = policy_mgr_current_connections_update( 1169 psoc, vdev_id, 1170 connect_rsp->freq, 1171 POLICY_MGR_UPDATE_REASON_LFR3_ROAM, 1172 POLICY_MGR_DEF_REQ_ID); 1173 if (status == QDF_STATUS_E_NOSUPPORT) 1174 status = QDF_STATUS_SUCCESS; 1175 else if (status == QDF_STATUS_E_FAILURE) 1176 mlme_err("Failed to take next action LFR3_ROAM"); 1177 } 1178 1179 error: 1180 if (rsp) 1181 wlan_cm_free_connect_rsp(rsp); 1182 1183 if (QDF_IS_STATUS_ERROR(status)) 1184 mlo_update_connected_links(vdev, 0); 1185 rel_ref: 1186 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1187 1188 return status; 1189 } 1190 1191 #ifdef WLAN_FEATURE_11BE_MLO 1192 static void 1193 cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc, 1194 uint8_t vdev_id, 1195 struct roam_offload_synch_ind *synch_data) 1196 { 1197 uint8_t i; 1198 struct wlan_objmgr_vdev *vdev; 1199 1200 for (i = 0; i < synch_data->num_setup_links; i++) { 1201 if (synch_data->ml_link[i].vdev_id == vdev_id && 1202 synch_data->ml_link[i].flags & CM_ROAM_LINK_FLAG_DISABLE) { 1203 mlme_info("Vdev %d: link id %d flags 0x%x, indicate link disable", 1204 vdev_id, synch_data->ml_link[i].link_id, 1205 synch_data->ml_link[i].flags); 1206 policy_mgr_move_vdev_from_connection_to_disabled_tbl( 1207 psoc, vdev_id); 1208 1209 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 1210 vdev_id, 1211 WLAN_MLME_SB_ID); 1212 if (!vdev) { 1213 mlme_debug("no vdev for id %d", vdev_id); 1214 break; 1215 } 1216 ml_nlink_set_curr_force_inactive_state( 1217 psoc, vdev, 1 << synch_data->ml_link[i].link_id, 1218 LINK_ADD); 1219 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1220 break; 1221 } 1222 } 1223 } 1224 #else 1225 static inline void 1226 cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc, 1227 uint8_t vdev_id, 1228 struct roam_offload_synch_ind *synch_data) 1229 {} 1230 #endif 1231 QDF_STATUS cm_fw_roam_complete(struct cnx_mgr *cm_ctx, void *data) 1232 { 1233 struct roam_offload_synch_ind *roam_synch_data; 1234 struct wlan_objmgr_pdev *pdev; 1235 struct wlan_objmgr_psoc *psoc; 1236 QDF_STATUS status = QDF_STATUS_SUCCESS; 1237 uint8_t vdev_id; 1238 1239 roam_synch_data = (struct roam_offload_synch_ind *)data; 1240 vdev_id = wlan_vdev_get_id(cm_ctx->vdev); 1241 1242 pdev = wlan_vdev_get_pdev(cm_ctx->vdev); 1243 if (!pdev) { 1244 mlme_err("Failed to find pdev"); 1245 status = QDF_STATUS_E_FAILURE; 1246 goto end; 1247 } 1248 1249 psoc = wlan_pdev_get_psoc(pdev); 1250 if (!pdev) { 1251 mlme_err("Failed to find psoc"); 1252 status = QDF_STATUS_E_FAILURE; 1253 goto end; 1254 } 1255 1256 /* Handle one race condition that if candidate is already 1257 *selected & FW has gone ahead with roaming or about to go 1258 * ahead when set_band comes, it will be complicated for FW 1259 * to stop the current roaming. Instead, host will check the 1260 * roam sync to make sure the new AP is not on disable freq 1261 * or disconnect the AP. 1262 */ 1263 if (wlan_reg_is_disable_for_pwrmode(pdev, roam_synch_data->chan_freq, 1264 REG_CURRENT_PWR_MODE)) { 1265 mlo_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT, 1266 REASON_OPER_CHANNEL_BAND_CHANGE, NULL); 1267 status = QDF_STATUS_E_FAILURE; 1268 goto end; 1269 } 1270 1271 /* 1272 * Following operations need to be done once roam sync 1273 * completion is sent to FW, hence called here: 1274 * 1) Firmware has already updated DBS policy. Update connection 1275 * table in the host driver. 1276 * 2) Force SCC switch if needed 1277 */ 1278 /* first update connection info from wma interface */ 1279 status = policy_mgr_update_connection_info(psoc, vdev_id); 1280 if (status == QDF_STATUS_NOT_INITIALIZED) 1281 policy_mgr_incr_active_session(psoc, QDF_STA_MODE, vdev_id); 1282 1283 /* Check if FW as indicated this link as disabled */ 1284 cm_get_and_disable_link_from_roam_ind(psoc, vdev_id, roam_synch_data); 1285 1286 /* then update remaining parameters from roam sync ctx */ 1287 if (roam_synch_data->hw_mode_trans_present) 1288 policy_mgr_hw_mode_transition_cb( 1289 roam_synch_data->hw_mode_trans_ind.old_hw_mode_index, 1290 roam_synch_data->hw_mode_trans_ind.new_hw_mode_index, 1291 roam_synch_data->hw_mode_trans_ind.num_vdev_mac_entries, 1292 roam_synch_data->hw_mode_trans_ind.vdev_mac_map, 1293 0, NULL, psoc); 1294 ml_nlink_conn_change_notify( 1295 psoc, vdev_id, 1296 ml_nlink_roam_sync_completion_evt, NULL); 1297 1298 if (roam_synch_data->pmk_len) { 1299 mlme_debug("Received pmk in roam sync. Length: %d", 1300 roam_synch_data->pmk_len); 1301 cm_check_and_set_sae_single_pmk_cap(psoc, vdev_id, 1302 roam_synch_data->pmk, 1303 roam_synch_data->pmk_len); 1304 } 1305 1306 cm_csr_send_set_ie(cm_ctx->vdev); 1307 1308 if (ucfg_pkt_capture_get_pktcap_mode(psoc)) 1309 ucfg_pkt_capture_record_channel(cm_ctx->vdev); 1310 1311 /* 1312 * Firmware will take care of checking hi_scan rssi delta, take care of 1313 * legacy -> legacy hi-rssi roam also if self mld roam supported. 1314 */ 1315 if (!wlan_cm_is_self_mld_roam_supported(psoc)) { 1316 if (WLAN_REG_IS_24GHZ_CH_FREQ(roam_synch_data->chan_freq)) { 1317 wlan_cm_set_disable_hi_rssi(pdev, 1318 vdev_id, false); 1319 } else { 1320 wlan_cm_set_disable_hi_rssi(pdev, 1321 vdev_id, true); 1322 mlme_debug("Disabling HI_RSSI, AP freq=%d rssi %d vdev id %d", 1323 roam_synch_data->chan_freq, 1324 roam_synch_data->rssi, vdev_id); 1325 } 1326 } 1327 policy_mgr_check_n_start_opportunistic_timer(psoc); 1328 1329 wlan_cm_handle_sta_sta_roaming_enablement(psoc, vdev_id); 1330 1331 if (wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) { 1332 status = wlan_cm_roam_state_change(pdev, 1333 vdev_id, 1334 WLAN_ROAM_DEINIT, 1335 REASON_ROAM_HANDOFF_DONE); 1336 } 1337 1338 if (roam_synch_data->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) 1339 wlan_cm_roam_state_change(pdev, vdev_id, 1340 WLAN_ROAM_RSO_ENABLED, 1341 REASON_CONNECT); 1342 else 1343 /* 1344 * STA is just in associated state here, RSO 1345 * enable will be sent once EAP & EAPOL will be done by 1346 * user-space and after set key response is received. 1347 * 1348 * When firmware roaming state is connected, EAP/EAPOL will be 1349 * done at the supplicant. If EAP/EAPOL fails and supplicant 1350 * sends disconnect, then the RSO state machine sends 1351 * deinit directly to firmware without RSO stop with roam 1352 * scan mode value 0. So to avoid this move state to RSO 1353 * stop. 1354 */ 1355 wlan_cm_roam_state_change(pdev, vdev_id, 1356 WLAN_ROAM_RSO_STOPPED, 1357 REASON_DISCONNECTED); 1358 policy_mgr_check_concurrent_intf_and_restart_sap(psoc, 1359 wlan_util_vdev_mgr_get_acs_mode_for_vdev(cm_ctx->vdev)); 1360 end: 1361 return status; 1362 } 1363 1364 static QDF_STATUS 1365 cm_disconnect_roam_invoke_fail(struct wlan_objmgr_vdev *vdev, 1366 wlan_cm_id cm_id) 1367 { 1368 QDF_STATUS status = QDF_STATUS_SUCCESS; 1369 struct wlan_mlme_psoc_ext_obj *mlme_obj; 1370 bool nud_disconnect; 1371 struct wlan_objmgr_psoc *psoc; 1372 uint8_t vdev_id = wlan_vdev_get_id(vdev); 1373 struct rso_config *rso_cfg; 1374 1375 psoc = wlan_vdev_get_psoc(vdev); 1376 if (!psoc) { 1377 mlme_err(CM_PREFIX_FMT "psoc not found", 1378 CM_PREFIX_REF(vdev_id, cm_id)); 1379 return QDF_STATUS_E_INVAL; 1380 } 1381 1382 mlme_obj = mlme_get_psoc_ext_obj(psoc); 1383 if (!mlme_obj) 1384 return QDF_STATUS_E_NULL_VALUE; 1385 1386 rso_cfg = wlan_cm_get_rso_config(vdev); 1387 if (!rso_cfg) { 1388 mlme_err(CM_PREFIX_FMT "rso cfg not found", 1389 CM_PREFIX_REF(vdev_id, cm_id)); 1390 return QDF_STATUS_E_NULL_VALUE; 1391 } 1392 1393 nud_disconnect = mlme_obj->cfg.lfr.disconnect_on_nud_roam_invoke_fail; 1394 mlme_debug(CM_PREFIX_FMT "disconnect on NUD %d, source %d forced roaming %d", 1395 CM_PREFIX_REF(vdev_id, cm_id), 1396 nud_disconnect, rso_cfg->roam_invoke_source, 1397 rso_cfg->is_forced_roaming); 1398 1399 /* 1400 * If reassoc MAC from user space is broadcast MAC as: 1401 * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0", 1402 * user space invoked roaming candidate selection will base on firmware 1403 * score algorithm, current connection will be kept if current AP has 1404 * highest score. It is requirement from customer which can avoid 1405 * ping-pong roaming. 1406 */ 1407 if (qdf_is_macaddr_broadcast(&rso_cfg->roam_invoke_bssid)) { 1408 qdf_zero_macaddr(&rso_cfg->roam_invoke_bssid); 1409 return status; 1410 } 1411 1412 if (rso_cfg->roam_invoke_source == CM_ROAMING_HOST || 1413 (rso_cfg->roam_invoke_source == CM_ROAMING_NUD_FAILURE && 1414 (nud_disconnect || rso_cfg->is_forced_roaming)) || 1415 rso_cfg->roam_invoke_source == CM_ROAMING_LINK_REMOVAL) { 1416 rso_cfg->roam_invoke_source = CM_SOURCE_INVALID; 1417 if (rso_cfg->is_forced_roaming) 1418 rso_cfg->is_forced_roaming = false; 1419 status = mlo_disconnect(vdev, CM_ROAM_DISCONNECT, 1420 REASON_USER_TRIGGERED_ROAM_FAILURE, 1421 NULL); 1422 } 1423 1424 return status; 1425 } 1426 1427 QDF_STATUS cm_fw_roam_invoke_fail(struct wlan_objmgr_psoc *psoc, 1428 uint8_t vdev_id) 1429 { 1430 QDF_STATUS status; 1431 struct wlan_objmgr_vdev *vdev; 1432 wlan_cm_id cm_id = CM_ID_INVALID; 1433 struct cnx_mgr *cm_ctx; 1434 struct cm_roam_req *roam_req = NULL; 1435 1436 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 1437 vdev_id, 1438 WLAN_MLME_SB_ID); 1439 if (!vdev) { 1440 mlme_err("vdev object is NULL"); 1441 return QDF_STATUS_E_NULL_VALUE; 1442 } 1443 1444 cm_ctx = cm_get_cm_ctx(vdev); 1445 if (!cm_ctx) { 1446 status = QDF_STATUS_E_NULL_VALUE; 1447 goto error; 1448 } 1449 1450 roam_req = cm_get_first_roam_command(vdev); 1451 if (roam_req) 1452 cm_id = roam_req->cm_id; 1453 1454 status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_INVOKE_FAIL, 1455 sizeof(wlan_cm_id), &cm_id); 1456 if (QDF_IS_STATUS_ERROR(status)) 1457 cm_remove_cmd(cm_ctx, &cm_id); 1458 1459 cm_disconnect_roam_invoke_fail(vdev, cm_id); 1460 error: 1461 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1462 return status; 1463 } 1464 1465 #ifdef FEATURE_WLAN_DIAG_SUPPORT 1466 static void cm_ho_fail_diag_event(void) 1467 { 1468 WLAN_HOST_DIAG_EVENT_DEF(roam_connection, 1469 host_event_wlan_status_payload_type); 1470 qdf_mem_zero(&roam_connection, 1471 sizeof(host_event_wlan_status_payload_type)); 1472 1473 roam_connection.eventId = DIAG_WLAN_STATUS_DISCONNECT; 1474 roam_connection.reason = DIAG_REASON_ROAM_HO_FAIL; 1475 WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS_V2); 1476 } 1477 #else 1478 static inline void cm_ho_fail_diag_event(void) {} 1479 #endif 1480 1481 #ifdef WLAN_FEATURE_11BE_MLO 1482 static bool 1483 cm_ho_fail_is_avoid_list_candidate(struct wlan_objmgr_vdev *vdev, 1484 struct cm_ho_fail_ind *ho_fail_ind) 1485 { 1486 uint8_t link_info_iter = 0; 1487 struct qdf_mac_addr peer_macaddr = {0}; 1488 struct mlo_link_info *mlo_link_info; 1489 uint32_t akm; 1490 1491 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1492 wlan_vdev_get_bss_peer_mac(vdev, &peer_macaddr); 1493 akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); 1494 if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) 1495 return true; 1496 1497 if (qdf_is_macaddr_equal(&peer_macaddr, &ho_fail_ind->bssid)) 1498 return false; 1499 else 1500 return true; 1501 } 1502 1503 mlo_link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 1504 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 1505 link_info_iter++, mlo_link_info++) { 1506 if (qdf_is_macaddr_equal(&mlo_link_info->ap_link_addr, 1507 &ho_fail_ind->bssid)) 1508 return false; 1509 } 1510 1511 return true; 1512 } 1513 #else 1514 static bool 1515 cm_ho_fail_is_avoid_list_candidate(struct wlan_objmgr_vdev *vdev, 1516 struct cm_ho_fail_ind *ho_fail_ind) 1517 { 1518 struct qdf_mac_addr peer_macaddr = {0}; 1519 uint32_t akm; 1520 1521 akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); 1522 if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) 1523 return true; 1524 1525 wlan_vdev_get_bss_peer_mac(vdev, &peer_macaddr); 1526 if (qdf_is_macaddr_equal(&peer_macaddr, &ho_fail_ind->bssid)) 1527 return false; 1528 else 1529 return true; 1530 } 1531 #endif 1532 1533 static QDF_STATUS cm_handle_ho_fail(struct scheduler_msg *msg) 1534 { 1535 QDF_STATUS status; 1536 struct cm_ho_fail_ind *ind = NULL; 1537 struct wlan_objmgr_vdev *vdev; 1538 struct wlan_objmgr_pdev *pdev; 1539 struct cnx_mgr *cm_ctx; 1540 wlan_cm_id cm_id = CM_ID_INVALID; 1541 struct reject_ap_info ap_info; 1542 struct cm_roam_req *roam_req = NULL; 1543 struct wlan_mlme_psoc_ext_obj *mlme_obj; 1544 struct wlan_objmgr_psoc *psoc; 1545 1546 if (!msg || !msg->bodyptr) 1547 return QDF_STATUS_E_FAILURE; 1548 1549 ind = msg->bodyptr; 1550 1551 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(ind->psoc, ind->vdev_id, 1552 WLAN_MLME_CM_ID); 1553 if (!vdev) { 1554 mlme_err("vdev_id: %d : vdev not found", ind->vdev_id); 1555 qdf_mem_free(ind); 1556 return QDF_STATUS_E_INVAL; 1557 } 1558 1559 pdev = wlan_vdev_get_pdev(vdev); 1560 if (!pdev) { 1561 mlme_err("pdev object is NULL"); 1562 status = QDF_STATUS_E_NULL_VALUE; 1563 goto error; 1564 } 1565 1566 psoc = wlan_pdev_get_psoc(pdev); 1567 if (!psoc) { 1568 mlme_err("psoc object is NULL"); 1569 status = QDF_STATUS_E_NULL_VALUE; 1570 goto error; 1571 } 1572 mlme_obj = mlme_get_psoc_ext_obj(psoc); 1573 if (!mlme_obj) { 1574 mlme_err("Failed to mlme psoc obj"); 1575 status = QDF_STATUS_E_FAILURE; 1576 goto error; 1577 } 1578 1579 cm_ctx = cm_get_cm_ctx(vdev); 1580 if (!cm_ctx) { 1581 status = QDF_STATUS_E_NULL_VALUE; 1582 goto error; 1583 } 1584 1585 roam_req = cm_get_first_roam_command(vdev); 1586 if (roam_req) { 1587 mlme_debug("Roam req found, get cm id to remove it, after disconnect"); 1588 cm_id = roam_req->cm_id; 1589 } 1590 /* CPU freq is boosted during roam sync to improve roam latency, 1591 * upon HO failure reset that request to restore cpu freq back to normal 1592 */ 1593 mlme_cm_osif_perfd_reset_cpufreq(); 1594 1595 qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); 1596 if (cm_ho_fail_is_avoid_list_candidate(vdev, ind)) { 1597 ap_info.bssid = ind->bssid; 1598 ap_info.reject_ap_type = DRIVER_AVOID_TYPE; 1599 ap_info.reject_reason = REASON_ROAM_HO_FAILURE; 1600 ap_info.source = ADDED_BY_DRIVER; 1601 wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); 1602 } 1603 1604 cm_ho_fail_diag_event(); 1605 wlan_roam_debug_log(ind->vdev_id, 1606 DEBUG_ROAM_SYNCH_FAIL, 1607 DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); 1608 1609 status = mlo_disconnect(vdev, CM_MLME_DISCONNECT, 1610 REASON_FW_TRIGGERED_ROAM_FAILURE, NULL); 1611 1612 if (mlme_obj->cfg.gen.fatal_event_trigger) 1613 cds_flush_logs(WLAN_LOG_TYPE_FATAL, 1614 WLAN_LOG_INDICATOR_HOST_DRIVER, 1615 WLAN_LOG_REASON_ROAM_HO_FAILURE, false, false); 1616 1617 cm_remove_cmd(cm_ctx, &cm_id); 1618 1619 error: 1620 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 1621 qdf_mem_free(ind); 1622 1623 return QDF_STATUS_SUCCESS; 1624 } 1625 1626 void cm_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, 1627 uint8_t vdev_id, struct qdf_mac_addr bssid) 1628 { 1629 QDF_STATUS status; 1630 struct scheduler_msg ind_msg = {0}; 1631 struct cm_ho_fail_ind *ind = NULL; 1632 1633 ind = qdf_mem_malloc(sizeof(*ind)); 1634 if (!ind) 1635 return; 1636 1637 ind->vdev_id = vdev_id; 1638 ind->psoc = psoc; 1639 ind->bssid = bssid; 1640 1641 ind_msg.bodyptr = ind; 1642 ind_msg.callback = cm_handle_ho_fail; 1643 1644 status = scheduler_post_message(QDF_MODULE_ID_MLME, QDF_MODULE_ID_OS_IF, 1645 QDF_MODULE_ID_OS_IF, &ind_msg); 1646 1647 if (QDF_IS_STATUS_ERROR(status)) { 1648 mlme_err("Failed to post HO fail indication on vdev_id %d", 1649 vdev_id); 1650 qdf_mem_free(ind); 1651 return; 1652 } 1653 } 1654 1655 QDF_STATUS wlan_cm_free_roam_synch_frame_ind(struct rso_config *rso_cfg) 1656 { 1657 struct roam_synch_frame_ind *frame_ind; 1658 1659 if (!rso_cfg) 1660 return QDF_STATUS_E_FAILURE; 1661 1662 frame_ind = &rso_cfg->roam_sync_frame_ind; 1663 1664 if (frame_ind->bcn_probe_rsp) { 1665 qdf_mem_free(frame_ind->bcn_probe_rsp); 1666 frame_ind->bcn_probe_rsp_len = 0; 1667 frame_ind->bcn_probe_rsp = NULL; 1668 } 1669 if (frame_ind->link_bcn_probe_rsp) { 1670 qdf_mem_free(frame_ind->link_bcn_probe_rsp); 1671 frame_ind->link_bcn_probe_rsp_len = 0; 1672 frame_ind->link_bcn_probe_rsp = NULL; 1673 } 1674 if (frame_ind->reassoc_req) { 1675 qdf_mem_free(frame_ind->reassoc_req); 1676 frame_ind->reassoc_req_len = 0; 1677 frame_ind->reassoc_req = NULL; 1678 } 1679 if (frame_ind->reassoc_rsp) { 1680 qdf_mem_free(frame_ind->reassoc_rsp); 1681 frame_ind->reassoc_rsp_len = 0; 1682 frame_ind->reassoc_rsp = NULL; 1683 } 1684 1685 return QDF_STATUS_SUCCESS; 1686 } 1687