1 /* 2 * Copyright (c) 2012-2015, 2020-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: osif_cm_connect_rsp.c 20 * 21 * This file maintains definitaions of connect response apis. 22 */ 23 24 #include <linux/version.h> 25 #include <linux/nl80211.h> 26 #include <net/cfg80211.h> 27 #include "wlan_osif_priv.h" 28 #include "osif_cm_rsp.h" 29 #include "osif_cm_util.h" 30 #include "wlan_cfg80211.h" 31 #include "wlan_cfg80211_scan.h" 32 #include "wlan_mlo_mgr_sta.h" 33 #include "wlan_mlo_mgr_cmn.h" 34 #include "wlan_objmgr_vdev_obj.h" 35 #include "wlan_objmgr_peer_obj.h" 36 #include "utils_mlo.h" 37 38 #ifdef CONN_MGR_ADV_FEATURE 39 void osif_cm_get_assoc_req_ie_data(struct element_info *assoc_req, 40 size_t *ie_data_len, 41 const uint8_t **ie_data_ptr) 42 { 43 /* Validate IE and length */ 44 if (!assoc_req->len || !assoc_req->ptr || 45 assoc_req->len <= WLAN_ASSOC_REQ_IES_OFFSET) 46 return; 47 48 *ie_data_len = assoc_req->len - WLAN_ASSOC_REQ_IES_OFFSET; 49 *ie_data_ptr = assoc_req->ptr + WLAN_ASSOC_REQ_IES_OFFSET; 50 } 51 #else 52 void osif_cm_get_assoc_req_ie_data(struct element_info *assoc_req, 53 size_t *ie_data_len, 54 const uint8_t **ie_data_ptr) 55 { 56 /* Validate IE and length */ 57 if (!assoc_req->len || !assoc_req->ptr) 58 return; 59 60 *ie_data_len = assoc_req->len; 61 *ie_data_ptr = assoc_req->ptr; 62 } 63 #endif 64 65 void osif_cm_get_assoc_rsp_ie_data(struct element_info *assoc_rsp, 66 size_t *ie_data_len, 67 const uint8_t **ie_data_ptr) 68 { 69 /* Validate IE and length */ 70 if (!assoc_rsp->len || !assoc_rsp->ptr || 71 assoc_rsp->len <= WLAN_ASSOC_RSP_IES_OFFSET) 72 return; 73 74 *ie_data_len = assoc_rsp->len - WLAN_ASSOC_RSP_IES_OFFSET; 75 *ie_data_ptr = assoc_rsp->ptr + WLAN_ASSOC_RSP_IES_OFFSET; 76 } 77 78 /** 79 * osif_validate_connect_and_reset_src_id() - Validate connect response and 80 * resets source and id 81 * @osif_priv: Pointer to vdev osif priv 82 * @rsp: Connection manager connect response 83 * 84 * This function validates connect response and if the connect 85 * response is valid, resets the source and id of the command 86 * 87 * Context: Any context. Takes and releases cmd id spinlock. 88 * Return: QDF_STATUS 89 */ 90 static QDF_STATUS 91 osif_validate_connect_and_reset_src_id(struct vdev_osif_priv *osif_priv, 92 struct wlan_cm_connect_resp *rsp) 93 { 94 QDF_STATUS status = QDF_STATUS_SUCCESS; 95 96 /* 97 * Do not send to kernel if last osif cookie doesnt match or 98 * or source is CM_OSIF_CFG_CONNECT with success status. 99 * If cookie matches reset the cookie and source. 100 */ 101 qdf_spinlock_acquire(&osif_priv->cm_info.cmd_id_lock); 102 if (rsp->cm_id != osif_priv->cm_info.last_id || 103 (osif_priv->cm_info.last_source == CM_OSIF_CFG_CONNECT && 104 QDF_IS_STATUS_SUCCESS(rsp->connect_status))) { 105 osif_debug("Ignore as cm_id(0x%x)/src(%d) != cm_id(0x%x)/src(%d) OR source is CFG connect with status %d", 106 rsp->cm_id, CM_OSIF_CONNECT, 107 osif_priv->cm_info.last_id, 108 osif_priv->cm_info.last_source, 109 rsp->connect_status); 110 status = QDF_STATUS_E_INVAL; 111 goto rel_lock; 112 } 113 114 osif_cm_reset_id_and_src_no_lock(osif_priv); 115 rel_lock: 116 qdf_spinlock_release(&osif_priv->cm_info.cmd_id_lock); 117 118 return status; 119 } 120 121 static enum ieee80211_statuscode 122 osif_get_statuscode(enum wlan_status_code status) 123 { 124 return (enum ieee80211_statuscode)status; 125 } 126 127 static enum ieee80211_statuscode 128 osif_get_connect_status_code(struct wlan_cm_connect_resp *rsp) 129 { 130 enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; 131 132 if (QDF_IS_STATUS_ERROR(rsp->connect_status)) { 133 if (rsp->status_code) 134 status = osif_get_statuscode(rsp->status_code); 135 else 136 status = WLAN_STATUS_UNSPECIFIED_FAILURE; 137 } 138 139 return status; 140 } 141 142 /** 143 * osif_convert_timeout_reason() - Convert to kernel specific enum 144 * @timeout_reason: reason for connect timeout 145 * 146 * This function is used to convert host timeout 147 * reason enum to kernel specific enum. 148 * 149 * Context: Any context. 150 * Return: nl timeout enum 151 */ 152 153 static enum nl80211_timeout_reason 154 osif_convert_timeout_reason(enum wlan_cm_connect_fail_reason reason) 155 { 156 switch (reason) { 157 case CM_JOIN_TIMEOUT: 158 return NL80211_TIMEOUT_SCAN; 159 case CM_AUTH_TIMEOUT: 160 return NL80211_TIMEOUT_AUTH; 161 case CM_ASSOC_TIMEOUT: 162 return NL80211_TIMEOUT_ASSOC; 163 default: 164 return NL80211_TIMEOUT_UNSPECIFIED; 165 } 166 } 167 168 #if defined CFG80211_CONNECT_BSS || \ 169 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) 170 171 #if defined CFG80211_CONNECT_TIMEOUT_REASON_CODE || \ 172 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) 173 /** 174 * osif_connect_timeout() - API to send connection timeout reason 175 * @dev: network device 176 * @bssid: bssid to which we want to associate 177 * @reason: reason for connect timeout 178 * 179 * This API is used to send connection timeout reason to supplicant 180 * 181 * Context: Any context. 182 * Return: Void 183 */ 184 static void 185 osif_connect_timeout(struct net_device *dev, const u8 *bssid, 186 enum wlan_cm_connect_fail_reason reason) 187 { 188 enum nl80211_timeout_reason nl_timeout_reason; 189 190 nl_timeout_reason = osif_convert_timeout_reason(reason); 191 192 osif_debug("nl_timeout_reason %d", nl_timeout_reason); 193 194 cfg80211_connect_timeout(dev, bssid, NULL, 0, qdf_mem_malloc_flags(), 195 nl_timeout_reason); 196 } 197 198 /** 199 * __osif_connect_bss() - API to send connection status to supplicant 200 * @dev: network device 201 * @bss: bss info 202 * @connect_rsp: Connection manager connect response 203 * 204 * Context: Any context. 205 * Return: void 206 */ 207 static void __osif_connect_bss(struct net_device *dev, 208 struct cfg80211_bss *bss, 209 struct wlan_cm_connect_resp *rsp, 210 enum ieee80211_statuscode status) 211 { 212 enum nl80211_timeout_reason nl_timeout_reason; 213 size_t req_len = 0; 214 const uint8_t *req_ptr = NULL; 215 size_t rsp_len = 0; 216 const uint8_t *rsp_ptr = NULL; 217 218 nl_timeout_reason = osif_convert_timeout_reason(rsp->reason); 219 220 osif_debug("nl_timeout_reason %d", nl_timeout_reason); 221 222 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 223 &req_len, &req_ptr); 224 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 225 &rsp_len, &rsp_ptr); 226 227 cfg80211_connect_bss(dev, rsp->bssid.bytes, bss, 228 req_ptr, req_len, rsp_ptr, rsp_len, status, 229 qdf_mem_malloc_flags(), nl_timeout_reason); 230 } 231 #else /* CFG80211_CONNECT_TIMEOUT_REASON_CODE */ 232 233 #if defined CFG80211_CONNECT_TIMEOUT || \ 234 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) 235 static void osif_connect_timeout( 236 struct net_device *dev, 237 const u8 *bssid, 238 enum wlan_cm_connect_fail_reason reason) 239 { 240 cfg80211_connect_timeout(dev, bssid, NULL, 0, qdf_mem_malloc_flags()); 241 } 242 #endif 243 244 static void __osif_connect_bss(struct net_device *dev, 245 struct cfg80211_bss *bss, 246 struct wlan_cm_connect_resp *rsp, 247 ieee80211_statuscode status) 248 { 249 size_t req_len = 0; 250 const uint8_t *req_ptr = NULL; 251 size_t rsp_len = 0; 252 const uint8_t *rsp_ptr = NULL; 253 254 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 255 &req_len, &req_ptr); 256 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 257 &rsp_len, &rsp_ptr); 258 259 cfg80211_connect_bss(dev, rsp->bssid.bytes, bss, 260 req_ptr, req_len, rsp_ptr, rsp_len, 261 status, qdf_mem_malloc_flags()); 262 } 263 #endif /* CFG80211_CONNECT_TIMEOUT_REASON_CODE */ 264 265 /** 266 * osif_connect_bss() - API to send connection status to supplicant 267 * @dev: network device 268 * @bss: bss info 269 * @connect_rsp: Connection manager connect response 270 * 271 * The API is a wrapper to send connection status to supplicant 272 * 273 * Context: Any context. 274 * Return: Void 275 */ 276 #if defined CFG80211_CONNECT_TIMEOUT || \ 277 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) 278 static void osif_connect_bss(struct net_device *dev, struct cfg80211_bss *bss, 279 struct wlan_cm_connect_resp *rsp) 280 { 281 enum ieee80211_statuscode status = WLAN_STATUS_SUCCESS; 282 283 osif_enter_dev(dev); 284 285 if (rsp->reason == CM_JOIN_TIMEOUT || 286 rsp->reason == CM_AUTH_TIMEOUT || 287 rsp->reason == CM_ASSOC_TIMEOUT) { 288 osif_connect_timeout(dev, rsp->bssid.bytes, 289 rsp->reason); 290 } else { 291 status = osif_get_connect_status_code(rsp); 292 293 __osif_connect_bss(dev, bss, rsp, status); 294 } 295 } 296 #else /* CFG80211_CONNECT_TIMEOUT */ 297 static void osif_connect_bss(struct net_device *dev, struct cfg80211_bss *bss, 298 struct wlan_cm_connect_resp *rsp) 299 { 300 enum ieee80211_statuscode status; 301 302 osif_enter_dev(dev); 303 304 status = osif_get_connect_status_code(rsp); 305 __osif_connect_bss(dev, bss, rsp, status); 306 } 307 #endif /* CFG80211_CONNECT_TIMEOUT */ 308 309 #if defined(CFG80211_CONNECT_DONE) || \ 310 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) 311 312 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) 313 314 #if defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) 315 /** 316 * osif_populate_fils_params() - Populate FILS keys to connect response 317 * @conn_rsp_params: connect response to supplicant 318 * @connect_ies: Connect response IEs 319 * 320 * Context: Any context. 321 * Return: None 322 */ 323 static void 324 osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, 325 struct wlan_connect_rsp_ies *connect_ies) 326 { 327 if (!connect_ies->fils_ie) 328 return; 329 330 /* Increment seq number to be used for next FILS */ 331 rsp_params->fils_erp_next_seq_num = 332 connect_ies->fils_ie->fils_seq_num + 1; 333 rsp_params->update_erp_next_seq_num = true; 334 rsp_params->fils_kek = connect_ies->fils_ie->kek; 335 rsp_params->fils_kek_len = connect_ies->fils_ie->kek_len; 336 rsp_params->pmk = connect_ies->fils_ie->fils_pmk; 337 rsp_params->pmk_len = connect_ies->fils_ie->fils_pmk_len; 338 rsp_params->pmkid = connect_ies->fils_ie->fils_pmkid; 339 osif_debug("erp_next_seq_num:%d", rsp_params->fils_erp_next_seq_num); 340 } 341 #else /* CFG80211_FILS_SK_OFFLOAD_SUPPORT */ 342 static inline void 343 osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, 344 struct wlan_connect_rsp_ies *connect_ies) 345 { } 346 #endif /* CFG80211_FILS_SK_OFFLOAD_SUPPORT */ 347 348 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) 349 #if defined(WLAN_FEATURE_FILS_SK) 350 /** 351 * osif_populate_fils_params() - Populate FILS keys to connect response 352 * @conn_rsp_params: connect response to supplicant 353 * @connect_ies: Connect response IEs 354 * 355 * Context: Any context. 356 * Return: None 357 */ 358 static void 359 osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, 360 struct wlan_connect_rsp_ies *connect_ies) 361 362 { 363 if (!connect_ies->fils_ie) 364 return; 365 366 /* Increament seq number to be used for next FILS */ 367 rsp_params->fils.erp_next_seq_num = 368 connect_ies->fils_ie->fils_seq_num + 1; 369 rsp_params->fils.update_erp_next_seq_num = true; 370 rsp_params->fils.kek = connect_ies->fils_ie->kek; 371 rsp_params->fils.kek_len = connect_ies->fils_ie->kek_len; 372 rsp_params->fils.pmk = connect_ies->fils_ie->fils_pmk; 373 rsp_params->fils.pmk_len = connect_ies->fils_ie->fils_pmk_len; 374 rsp_params->fils.pmkid = connect_ies->fils_ie->fils_pmkid; 375 osif_debug("erp_next_seq_num:%d", rsp_params->fils.erp_next_seq_num); 376 } 377 #else /* WLAN_FEATURE_FILS_SK */ 378 static inline void 379 osif_populate_fils_params(struct cfg80211_connect_resp_params *rsp_params, 380 struct wlan_connect_rsp_ies *connect_ies) 381 { } 382 #endif /* WLAN_FEATURE_FILS_SK */ 383 #endif 384 385 #if defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT) && defined(WLAN_FEATURE_11BE_MLO) 386 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 387 static struct wlan_objmgr_vdev *osif_get_partner_vdev(struct wlan_objmgr_vdev *vdev, 388 struct mlo_link_info rsp_partner_info) 389 { 390 return mlo_get_vdev_by_link_id(vdev, rsp_partner_info.link_id); 391 } 392 #endif 393 394 static 395 void osif_populate_connect_response_for_link(struct wlan_objmgr_vdev *vdev, 396 struct cfg80211_connect_resp_params *conn_rsp_params, 397 uint8_t link_id, 398 struct cfg80211_bss *bss) 399 { 400 osif_debug("Link_id :%d", link_id); 401 conn_rsp_params->valid_links |= BIT(link_id); 402 conn_rsp_params->links[link_id].bssid = bss->bssid; 403 conn_rsp_params->links[link_id].bss = bss; 404 conn_rsp_params->links[link_id].addr = 405 wlan_vdev_mlme_get_macaddr(vdev); 406 } 407 408 static QDF_STATUS 409 osif_get_partner_info_from_mlie(struct wlan_cm_connect_resp *connect_rsp, 410 struct mlo_partner_info *partner_info) 411 { 412 qdf_size_t connect_resp_len = 0, ml_ie_len = 0; 413 const uint8_t *connect_resp_ptr = NULL; 414 QDF_STATUS qdf_status; 415 uint8_t *ml_ie = NULL; 416 417 osif_cm_get_assoc_rsp_ie_data(&connect_rsp->connect_ies.assoc_rsp, 418 &connect_resp_len, &connect_resp_ptr); 419 420 if (!connect_resp_len) { 421 osif_err("Connect response is null return error"); 422 return QDF_STATUS_E_INVAL; 423 } 424 425 qdf_status = util_find_mlie((uint8_t *)connect_resp_ptr, 426 connect_resp_len, &ml_ie, &ml_ie_len); 427 if (QDF_IS_STATUS_ERROR(qdf_status) || !ml_ie) { 428 osif_debug("ML IE not found %d", qdf_status); 429 return qdf_status; 430 } 431 432 osif_debug("ML IE found length %d", (int)ml_ie_len); 433 434 qdf_status = util_get_bvmlie_persta_partner_info(ml_ie, ml_ie_len, 435 partner_info); 436 if (QDF_IS_STATUS_ERROR(qdf_status)) { 437 osif_err("Unable to find per-sta profile in ML IE :%d"); 438 return qdf_status; 439 } 440 441 return qdf_status; 442 } 443 444 static QDF_STATUS 445 osif_fill_peer_mld_mac_connect_resp(struct wlan_objmgr_vdev *vdev, 446 struct wlan_cm_connect_resp *rsp, 447 struct cfg80211_connect_resp_params *conn_rsp_params) 448 { 449 struct wlan_objmgr_peer *peer_obj; 450 451 peer_obj = wlan_objmgr_get_peer_by_mac(wlan_vdev_get_psoc(vdev), 452 rsp->bssid.bytes, WLAN_OSIF_ID); 453 if (!peer_obj) 454 return QDF_STATUS_E_INVAL; 455 456 conn_rsp_params->ap_mld_addr = wlan_peer_mlme_get_mldaddr(peer_obj); 457 458 wlan_objmgr_peer_release_ref(peer_obj, WLAN_OSIF_ID); 459 460 return QDF_STATUS_SUCCESS; 461 } 462 463 static QDF_STATUS 464 osif_get_link_id_from_assoc_ml_ie(struct mlo_link_info *rsp_link_info, 465 struct mlo_partner_info *assoc_partner_info, 466 uint8_t *link_id) 467 { 468 int j; 469 470 for (j = 0; j < assoc_partner_info->num_partner_links; j++) { 471 if (!qdf_mem_cmp(rsp_link_info->link_addr.bytes, 472 assoc_partner_info->partner_link_info[j].link_addr.bytes, 473 QDF_MAC_ADDR_SIZE)) { 474 *link_id = assoc_partner_info->partner_link_info[j].link_id; 475 return QDF_STATUS_SUCCESS; 476 } 477 } 478 479 return QDF_STATUS_E_INVAL; 480 } 481 482 static struct cfg80211_bss * 483 osif_get_chan_bss_from_kernel(struct wlan_objmgr_vdev *vdev, 484 struct mlo_link_info *rsp_link_info, 485 struct wlan_cm_connect_resp *rsp) 486 { 487 struct vdev_osif_priv *osif_priv; 488 struct cfg80211_bss *partner_bss; 489 struct ieee80211_channel *chan; 490 491 osif_priv = wlan_vdev_get_ospriv(vdev); 492 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 493 rsp_link_info->chan_freq); 494 if (!chan) { 495 osif_err("Invalid partner channel"); 496 NULL; 497 } 498 499 partner_bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 500 rsp_link_info->link_addr.bytes, 501 rsp->ssid.ssid, rsp->ssid.length); 502 if (!partner_bss) { 503 osif_err("could not fetch partner bss from kernel"); 504 return NULL; 505 } 506 507 return partner_bss; 508 } 509 510 static void 511 osif_populate_partner_links_mlo_params(struct wlan_objmgr_pdev *pdev, 512 struct wlan_cm_connect_resp *rsp, 513 struct cfg80211_connect_resp_params *conn_rsp_params) 514 { 515 struct wlan_objmgr_vdev *partner_vdev; 516 struct mlo_link_info *rsp_partner_info; 517 struct mlo_partner_info assoc_partner_info = {0}; 518 struct cfg80211_bss *bss = NULL; 519 QDF_STATUS qdf_status; 520 uint8_t link_id = 0, num_links; 521 int i; 522 523 qdf_status = osif_get_partner_info_from_mlie(rsp, &assoc_partner_info); 524 if (QDF_IS_STATUS_ERROR(qdf_status)) 525 return; 526 527 num_links = rsp->ml_parnter_info.num_partner_links; 528 for (i = 0 ; i < num_links; i++) { 529 rsp_partner_info = &rsp->ml_parnter_info.partner_link_info[i]; 530 531 qdf_status = osif_get_link_id_from_assoc_ml_ie(rsp_partner_info, 532 &assoc_partner_info, 533 &link_id); 534 if (QDF_IS_STATUS_ERROR(qdf_status)) 535 continue; 536 537 partner_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, 538 rsp_partner_info->vdev_id, 539 WLAN_MLO_MGR_ID); 540 if (!partner_vdev) 541 continue; 542 543 bss = osif_get_chan_bss_from_kernel(partner_vdev, 544 rsp_partner_info, rsp); 545 if (!bss) { 546 wlan_objmgr_vdev_release_ref(partner_vdev, 547 WLAN_MLO_MGR_ID); 548 continue; 549 } 550 551 osif_populate_connect_response_for_link(partner_vdev, 552 conn_rsp_params, 553 link_id, bss); 554 wlan_objmgr_vdev_release_ref(partner_vdev, WLAN_MLO_MGR_ID); 555 } 556 } 557 558 static void osif_fill_connect_resp_mlo_params(struct wlan_objmgr_vdev *vdev, 559 struct wlan_cm_connect_resp *rsp, 560 struct cfg80211_bss *bss, 561 struct cfg80211_connect_resp_params *conn_rsp_params) 562 { 563 uint8_t assoc_link_id; 564 QDF_STATUS qdf_status; 565 566 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 567 return; 568 569 qdf_status = osif_fill_peer_mld_mac_connect_resp(vdev, rsp, 570 conn_rsp_params); 571 if (QDF_IS_STATUS_ERROR(qdf_status)) { 572 osif_err("Unable to fill peer mld address: %d", qdf_status); 573 return; 574 } 575 576 assoc_link_id = wlan_vdev_get_link_id(vdev); 577 osif_populate_connect_response_for_link(vdev, conn_rsp_params, 578 assoc_link_id, bss); 579 580 osif_populate_partner_links_mlo_params(wlan_vdev_get_pdev(vdev), rsp, 581 conn_rsp_params); 582 } 583 584 static void 585 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 586 { 587 } 588 #elif defined(CFG80211_IFTYPE_MLO_LINK_SUPPORT) && defined(WLAN_FEATURE_11BE_MLO) 589 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 590 static struct wlan_objmgr_vdev *osif_get_partner_vdev( 591 struct wlan_objmgr_vdev *vdev, 592 struct mlo_link_info rsp_partner_info) 593 { 594 return wlan_objmgr_get_vdev_by_id_from_pdev( 595 vdev->vdev_objmgr.wlan_pdev, 596 rsp_partner_info.vdev_id, 597 WLAN_MLO_MGR_ID); 598 } 599 #else 600 static struct wlan_objmgr_vdev *osif_get_partner_vdev( 601 struct wlan_objmgr_vdev *vdev, 602 struct mlo_link_info rsp_partner_info) 603 { 604 return mlo_get_vdev_by_link_id(vdev, rsp_partner_info.link_id); 605 } 606 #endif 607 static void osif_fill_connect_resp_mlo_params( 608 struct wlan_objmgr_vdev *vdev, 609 struct wlan_cm_connect_resp *rsp, 610 struct cfg80211_bss *bss, 611 struct cfg80211_connect_resp_params *conn_rsp_params) 612 { 613 uint8_t i, num_mlo_links = rsp->ml_parnter_info.num_partner_links + 1; 614 struct wlan_objmgr_vdev *ml_vdev = vdev; 615 struct vdev_osif_priv *osif_priv; 616 struct ieee80211_channel *chan; 617 struct cfg80211_mlo_link_params *ml_link_params; 618 struct mlo_link_info *rsp_partner_info; 619 620 if (num_mlo_links == 1) 621 return; 622 623 ml_link_params = qdf_mem_malloc( 624 num_mlo_links * sizeof(*ml_link_params)); 625 if (!ml_link_params) 626 return; 627 628 rsp_partner_info = rsp->ml_parnter_info.partner_link_info; 629 if (rsp->ml_parnter_info.num_partner_links) { 630 conn_rsp_params->n_mlo_links = num_mlo_links; 631 osif_priv = wlan_vdev_get_ospriv(ml_vdev); 632 for (i = 0; i < conn_rsp_params->n_mlo_links; i++) { 633 ml_link_params[i].wdev = osif_priv->wdev; 634 635 if (i != 0) { 636 chan = ieee80211_get_channel( 637 osif_priv->wdev->wiphy, 638 rsp_partner_info[i - 1].chan_freq); 639 if (!chan) { 640 osif_err("Invalid partner channel"); 641 goto end; 642 } 643 644 bss = wlan_cfg80211_get_bss( 645 osif_priv->wdev->wiphy, chan, 646 rsp_partner_info[i - 1].link_addr.bytes, 647 rsp->ssid.ssid, rsp->ssid.length); 648 if (!bss) { 649 osif_err("Partner bss is null"); 650 goto end; 651 } 652 } 653 qdf_mem_copy(ml_link_params[i].bssid, bss->bssid, 654 QDF_MAC_ADDR_SIZE); 655 656 if (i == rsp->ml_parnter_info.num_partner_links) 657 break; 658 659 ml_vdev = osif_get_partner_vdev(vdev, 660 rsp_partner_info[i]); 661 662 if (ml_vdev) { 663 osif_priv = wlan_vdev_get_ospriv(ml_vdev); 664 wlan_objmgr_vdev_release_ref(ml_vdev, 665 WLAN_MLO_MGR_ID); 666 } else { 667 osif_err("Partner vdev not found with vdev_id:%d", 668 rsp_partner_info[i].vdev_id); 669 goto end; 670 } 671 } 672 } 673 end: 674 conn_rsp_params->mlo_links = ml_link_params; 675 } 676 677 static void 678 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 679 { 680 struct cfg80211_mlo_link_params *ml_links; 681 682 ml_links = 683 (struct cfg80211_mlo_link_params *)conn_rsp_params->mlo_links; 684 if (ml_links) 685 qdf_mem_free(ml_links); 686 } 687 688 #else 689 static void osif_fill_connect_resp_mlo_params( 690 struct wlan_objmgr_vdev *vdev, 691 struct wlan_cm_connect_resp *rsp, 692 struct cfg80211_bss *bss, 693 struct cfg80211_connect_resp_params *conn_rsp_params) 694 { 695 } 696 697 static void 698 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 699 { 700 } 701 #endif 702 703 #ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT 704 static 705 void osif_copy_connected_info(struct cfg80211_connect_resp_params *conn_rsp, 706 struct wlan_cm_connect_resp *rsp, 707 struct cfg80211_bss *bss, 708 struct wlan_objmgr_vdev *vdev) 709 { 710 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 711 qdf_debug("MLO vdev fill everything in mlo fill params"); 712 return; 713 } 714 715 conn_rsp->links[0].bssid = rsp->bssid.bytes; 716 conn_rsp->links[0].bss = bss; 717 } 718 #else 719 static 720 void osif_copy_connected_info(struct cfg80211_connect_resp_params *conn_rsp, 721 struct wlan_cm_connect_resp *rsp, 722 struct cfg80211_bss *bss, 723 struct wlan_objmgr_vdev *vdev) 724 { 725 conn_rsp->bssid = rsp->bssid.bytes; 726 conn_rsp->bss = bss; 727 } 728 #endif 729 730 /** 731 * osif_connect_done() - Wrapper API to call cfg80211_connect_done 732 * @dev: network device 733 * @bss: bss info 734 * @rsp: Connection manager connect response 735 * @vdev: pointer to vdev 736 * 737 * This API is used as wrapper to send connect status and params to 738 * supplicant. 739 * 740 * Context: Any context. 741 * Return: 0 if success. Error code for failure 742 */ 743 static int osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, 744 struct wlan_cm_connect_resp *rsp, 745 struct wlan_objmgr_vdev *vdev) 746 { 747 struct cfg80211_connect_resp_params conn_rsp_params; 748 enum ieee80211_statuscode status; 749 750 osif_enter_dev(dev); 751 752 status = osif_get_connect_status_code(rsp); 753 qdf_mem_zero(&conn_rsp_params, sizeof(conn_rsp_params)); 754 755 conn_rsp_params.status = status; 756 osif_copy_connected_info(&conn_rsp_params, rsp, bss, vdev); 757 conn_rsp_params.timeout_reason = 758 osif_convert_timeout_reason(rsp->reason); 759 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 760 &conn_rsp_params.req_ie_len, 761 &conn_rsp_params.req_ie); 762 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 763 &conn_rsp_params.resp_ie_len, 764 &conn_rsp_params.resp_ie); 765 osif_populate_fils_params(&conn_rsp_params, &rsp->connect_ies); 766 osif_cm_save_gtk(vdev, rsp); 767 768 if (status == WLAN_STATUS_SUCCESS) 769 osif_fill_connect_resp_mlo_params(vdev, rsp, bss, 770 &conn_rsp_params); 771 772 osif_debug("Connect resp status %d", conn_rsp_params.status); 773 774 cfg80211_connect_done(dev, &conn_rsp_params, qdf_mem_malloc_flags()); 775 osif_cm_set_hlp_data(dev, vdev, rsp); 776 777 osif_free_ml_link_params(&conn_rsp_params); 778 779 return 0; 780 } 781 #else /* CFG80211_CONNECT_DONE */ 782 static inline int 783 osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, 784 struct wlan_cm_connect_resp *rsp, 785 struct wlan_objmgr_vdev *vdev) 786 { 787 return -EINVAL; 788 } 789 #endif 790 791 #if (defined(CFG80211_CONNECT_DONE) || \ 792 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))) 793 /** 794 * osif_update_connect_results() - API to send connection status to 795 * supplicant. 796 * @dev: network device 797 * @bss: bss info 798 * @connect_rsp: Connection manager connect response 799 * @vdev: pointer to vdev 800 * 801 * The API is a wrapper to send connection status to supplicant 802 * 803 * Context: Any context. 804 * Return: 0 if success else failure 805 */ 806 static int osif_update_connect_results(struct net_device *dev, 807 struct cfg80211_bss *bss, 808 struct wlan_cm_connect_resp *rsp, 809 struct wlan_objmgr_vdev *vdev) 810 { 811 return osif_connect_done(dev, bss, rsp, vdev); 812 } 813 #else /* CFG80211_CONNECT_DONE */ 814 815 static inline int osif_update_connect_results(struct net_device *dev, 816 struct cfg80211_bss *bss, 817 struct wlan_cm_connect_resp *rsp, 818 struct wlan_objmgr_vdev *vdev) 819 { 820 return -EINVAL; 821 } 822 #endif /* CFG80211_CONNECT_DONE */ 823 824 #ifdef WLAN_FEATURE_11BE_MLO 825 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 826 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 827 struct vdev_osif_priv *osif_priv, 828 struct wlan_cm_connect_resp *rsp) 829 { 830 struct cfg80211_bss *bss = NULL; 831 struct ieee80211_channel *chan; 832 833 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 834 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 835 rsp->freq); 836 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 837 rsp->bssid.bytes, 838 rsp->ssid.ssid, 839 rsp->ssid.length); 840 } 841 842 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 843 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 844 rsp, vdev)) 845 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 846 return; 847 } 848 849 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 850 if (osif_update_connect_results( 851 osif_priv->wdev->netdev, bss, 852 rsp, vdev)) 853 osif_connect_bss(osif_priv->wdev->netdev, 854 bss, rsp); 855 } 856 857 } 858 #else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 859 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 860 struct vdev_osif_priv *osif_priv, 861 struct wlan_cm_connect_resp *rsp) 862 { 863 struct cfg80211_bss *bss = NULL; 864 struct ieee80211_channel *chan; 865 struct wlan_objmgr_vdev *assoc_vdev = NULL; 866 struct vdev_osif_priv *tmp_osif_priv = NULL; 867 qdf_freq_t freq; 868 struct qdf_mac_addr macaddr = {0}; 869 struct wlan_cm_connect_resp resp = {0}; 870 871 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 872 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 873 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 874 rsp->freq); 875 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, 876 chan, 877 rsp->bssid.bytes, 878 rsp->ssid.ssid, 879 rsp->ssid.length); 880 } 881 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 882 rsp, vdev)) 883 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 884 return; 885 } 886 887 if ((QDF_IS_STATUS_SUCCESS(rsp->connect_status) && 888 ucfg_mlo_is_mld_connected(vdev)) || 889 (QDF_IS_STATUS_ERROR(rsp->connect_status) && 890 ucfg_mlo_is_mld_disconnected(vdev))) { 891 assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); 892 if (!assoc_vdev) 893 return; 894 qdf_mem_copy(&resp, rsp, sizeof(struct wlan_cm_connect_resp)); 895 tmp_osif_priv = wlan_vdev_get_ospriv(assoc_vdev); 896 freq = vdev->vdev_mlme.bss_chan->ch_freq; 897 wlan_vdev_get_bss_peer_mac(assoc_vdev, &macaddr); 898 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 899 chan = ieee80211_get_channel(tmp_osif_priv->wdev->wiphy, 900 freq); 901 bss = wlan_cfg80211_get_bss(tmp_osif_priv->wdev->wiphy, 902 chan, 903 macaddr.bytes, 904 rsp->ssid.ssid, 905 rsp->ssid.length); 906 } 907 qdf_mem_copy(resp.bssid.bytes, macaddr.bytes, 908 QDF_MAC_ADDR_SIZE); 909 resp.freq = freq; 910 resp.connect_ies.assoc_req.ptr = rsp->connect_ies.assoc_req.ptr; 911 resp.connect_ies.assoc_req.len = rsp->connect_ies.assoc_req.len; 912 resp.connect_ies.assoc_rsp.ptr = rsp->connect_ies.assoc_rsp.ptr; 913 resp.connect_ies.assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 914 if (osif_update_connect_results(tmp_osif_priv->wdev->netdev, bss, 915 &resp, assoc_vdev)) 916 osif_connect_bss(tmp_osif_priv->wdev->netdev, bss, &resp); 917 } 918 } 919 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 920 #else /* WLAN_FEATURE_11BE_MLO */ 921 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 922 struct vdev_osif_priv *osif_priv, 923 struct wlan_cm_connect_resp *rsp) 924 { 925 struct cfg80211_bss *bss = NULL; 926 struct ieee80211_channel *chan; 927 928 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 929 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 930 rsp->freq); 931 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 932 rsp->bssid.bytes, 933 rsp->ssid.ssid, 934 rsp->ssid.length); 935 } 936 937 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 938 rsp, vdev)) 939 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 940 } 941 #endif /* WLAN_FEATURE_11BE_MLO */ 942 #else /* CFG80211_CONNECT_BSS */ 943 #ifdef WLAN_FEATURE_11BE_MLO 944 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 945 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 946 struct vdev_osif_priv *osif_priv, 947 struct wlan_cm_connect_resp *rsp) 948 { 949 enum ieee80211_statuscode status; 950 size_t req_len = 0; 951 const uint8_t *req_ptr = NULL; 952 size_t rsp_len = 0; 953 const uint8_t *rsp_ptr = NULL; 954 struct wlan_objmgr_vdev *assoc_vdev = NULL; 955 struct vdev_osif_priv *tmp_osif_priv = NULL; 956 957 status = osif_get_connect_status_code(rsp); 958 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 959 &req_len, &req_ptr); 960 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 961 &rsp_len, &rsp_ptr); 962 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 963 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 964 cfg80211_connect_result( 965 osif_priv->wdev->netdev, 966 rsp->bssid.bytes, req_ptr, req_len, 967 rsp_ptr, rsp_len, status, 968 qdf_mem_malloc_flags()); 969 } else { 970 cfg80211_connect_result(osif_priv->wdev->netdev, 971 rsp->bssid.bytes, req_ptr, req_len, 972 rsp_ptr, rsp_len, status, 973 qdf_mem_malloc_flags()); 974 } 975 } 976 #else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 977 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 978 struct vdev_osif_priv *osif_priv, 979 struct wlan_cm_connect_resp *rsp) 980 { 981 enum ieee80211_statuscode status; 982 size_t req_len = 0; 983 const uint8_t *req_ptr = NULL; 984 size_t rsp_len = 0; 985 const uint8_t *rsp_ptr = NULL; 986 struct wlan_objmgr_vdev *assoc_vdev = NULL; 987 struct vdev_osif_priv *tmp_osif_priv = NULL; 988 struct qdf_mac_addr macaddr = {0}; 989 990 status = osif_get_connect_status_code(rsp); 991 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 992 &req_len, &req_ptr); 993 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 994 &rsp_len, &rsp_ptr); 995 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 996 if ((QDF_IS_STATUS_SUCCESS(rsp->connect_status) && 997 ucfg_mlo_is_mld_connected(vdev)) || 998 (QDF_IS_STATUS_ERROR(rsp->connect_status) && 999 ucfg_mlo_is_mld_disconnected(vdev))) { 1000 assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); 1001 if (!assoc_vdev) 1002 return; 1003 tmp_osif_priv = wlan_vdev_get_ospriv(assoc_vdev); 1004 wlan_vdev_get_bss_peer_mac(assoc_vdev, &macaddr); 1005 cfg80211_connect_result(tmp_osif_priv->wdev->netdev, 1006 macaddr.bytes, req_ptr, 1007 req_len, rsp_ptr, rsp_len, 1008 status, qdf_mem_malloc_flags()); 1009 } 1010 } else { 1011 cfg80211_connect_result(osif_priv->wdev->netdev, 1012 rsp->bssid.bytes, req_ptr, req_len, 1013 rsp_ptr, rsp_len, status, 1014 qdf_mem_malloc_flags()); 1015 } 1016 } 1017 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 1018 #else /* WLAN_FEATURE_11BE_MLO */ 1019 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 1020 struct vdev_osif_priv *osif_priv, 1021 struct wlan_cm_connect_resp *rsp) 1022 { 1023 enum ieee80211_statuscode status; 1024 size_t req_len = 0; 1025 const uint8_t *req_ptr = NULL; 1026 size_t rsp_len = 0; 1027 const uint8_t *rsp_ptr = NULL; 1028 1029 status = osif_get_connect_status_code(rsp); 1030 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 1031 &req_len, &req_ptr); 1032 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 1033 &rsp_len, &rsp_ptr); 1034 cfg80211_connect_result(osif_priv->wdev->netdev, 1035 rsp->bssid.bytes, req_ptr, req_len, 1036 rsp_ptr, rsp_len, status, 1037 qdf_mem_malloc_flags()); 1038 } 1039 #endif /* WLAN_FEATURE_11BE_MLO */ 1040 #endif /* CFG80211_CONNECT_BSS */ 1041 1042 #ifdef CONN_MGR_ADV_FEATURE 1043 static inline 1044 bool osif_cm_is_unlink_bss_required(struct wlan_cm_connect_resp *rsp) 1045 { 1046 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) 1047 return false; 1048 1049 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 1050 rsp->reason == CM_JOIN_TIMEOUT || 1051 rsp->reason == CM_AUTH_TIMEOUT || 1052 rsp->reason == CM_ASSOC_TIMEOUT) 1053 return true; 1054 1055 return false; 1056 } 1057 static inline void osif_check_and_unlink_bss(struct wlan_objmgr_vdev *vdev, 1058 struct vdev_osif_priv *osif_priv, 1059 struct wlan_cm_connect_resp *rsp) 1060 { 1061 if (osif_cm_is_unlink_bss_required(rsp)) 1062 osif_cm_unlink_bss(vdev, osif_priv, &rsp->bssid, rsp->ssid.ssid, 1063 rsp->ssid.length); 1064 } 1065 #else 1066 static inline void osif_check_and_unlink_bss(struct wlan_objmgr_vdev *vdev, 1067 struct vdev_osif_priv *osif_priv, 1068 struct wlan_cm_connect_resp *rsp) 1069 {} 1070 #endif 1071 1072 QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev, 1073 struct wlan_cm_connect_resp *rsp) 1074 { 1075 struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); 1076 QDF_STATUS status; 1077 1078 osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id 0x%x cm_reason %d status_code %d is_reassoc %d", 1079 osif_priv->wdev->netdev->name, rsp->vdev_id, 1080 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 1081 QDF_MAC_ADDR_REF(rsp->bssid.bytes), 1082 rsp->ssid.length, rsp->ssid.ssid, 1083 rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id, 1084 rsp->reason, rsp->status_code, rsp->is_reassoc); 1085 1086 osif_check_and_unlink_bss(vdev, osif_priv, rsp); 1087 1088 status = osif_validate_connect_and_reset_src_id(osif_priv, rsp); 1089 if (QDF_IS_STATUS_ERROR(status)) { 1090 osif_cm_connect_comp_ind(vdev, rsp, OSIF_NOT_HANDLED); 1091 return status; 1092 } 1093 1094 osif_cm_connect_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE); 1095 if (rsp->is_reassoc) 1096 osif_indicate_reassoc_results(vdev, osif_priv, rsp); 1097 else 1098 osif_indcate_connect_results(vdev, osif_priv, rsp); 1099 osif_cm_connect_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE); 1100 1101 return QDF_STATUS_SUCCESS; 1102 } 1103 1104 QDF_STATUS osif_failed_candidate_handler(struct wlan_objmgr_vdev *vdev, 1105 struct wlan_cm_connect_resp *rsp) 1106 { 1107 struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); 1108 1109 osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" FAILED cm_id 0x%x cm_reason %d reason_code %d", 1110 osif_priv->wdev->netdev->name, rsp->vdev_id, 1111 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 1112 QDF_MAC_ADDR_REF(rsp->bssid.bytes), 1113 rsp->ssid.length, rsp->ssid.ssid, rsp->cm_id, 1114 rsp->reason, rsp->status_code); 1115 1116 /** 1117 * Do not unlink the BSS if it is an ML candidate. In case of ML, 1118 * failed candidate may be used as partner link while trying the 1119 * connection on other links. 1120 */ 1121 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 1122 osif_check_and_unlink_bss(vdev, osif_priv, rsp); 1123 1124 return QDF_STATUS_SUCCESS; 1125 } 1126