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 struct wlan_objmgr_psoc *psoc; 451 452 psoc = wlan_vdev_get_psoc(vdev); 453 if (!psoc) 454 return QDF_STATUS_E_INVAL; 455 456 peer_obj = wlan_objmgr_get_peer_by_mac(psoc, 457 rsp->bssid.bytes, WLAN_OSIF_ID); 458 if (!peer_obj) 459 return QDF_STATUS_E_INVAL; 460 461 conn_rsp_params->ap_mld_addr = wlan_peer_mlme_get_mldaddr(peer_obj); 462 463 wlan_objmgr_peer_release_ref(peer_obj, WLAN_OSIF_ID); 464 465 return QDF_STATUS_SUCCESS; 466 } 467 468 static QDF_STATUS 469 osif_get_link_id_from_assoc_ml_ie(struct mlo_link_info *rsp_link_info, 470 struct mlo_partner_info *assoc_partner_info, 471 uint8_t *link_id) 472 { 473 int j; 474 475 for (j = 0; j < assoc_partner_info->num_partner_links; j++) { 476 if (!qdf_mem_cmp(rsp_link_info->link_addr.bytes, 477 assoc_partner_info->partner_link_info[j].link_addr.bytes, 478 QDF_MAC_ADDR_SIZE)) { 479 *link_id = assoc_partner_info->partner_link_info[j].link_id; 480 return QDF_STATUS_SUCCESS; 481 } 482 } 483 484 return QDF_STATUS_E_INVAL; 485 } 486 487 static struct cfg80211_bss * 488 osif_get_chan_bss_from_kernel(struct wlan_objmgr_vdev *vdev, 489 struct mlo_link_info *rsp_link_info, 490 struct wlan_cm_connect_resp *rsp) 491 { 492 struct vdev_osif_priv *osif_priv; 493 struct cfg80211_bss *partner_bss; 494 struct ieee80211_channel *chan; 495 496 osif_priv = wlan_vdev_get_ospriv(vdev); 497 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 498 rsp_link_info->chan_freq); 499 if (!chan) { 500 osif_err("Invalid partner channel"); 501 NULL; 502 } 503 504 partner_bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 505 rsp_link_info->link_addr.bytes, 506 rsp->ssid.ssid, rsp->ssid.length); 507 if (!partner_bss) { 508 osif_err("could not fetch partner bss from kernel"); 509 return NULL; 510 } 511 512 return partner_bss; 513 } 514 515 static void 516 osif_populate_partner_links_mlo_params(struct wlan_objmgr_pdev *pdev, 517 struct wlan_cm_connect_resp *rsp, 518 struct cfg80211_connect_resp_params *conn_rsp_params) 519 { 520 struct wlan_objmgr_vdev *partner_vdev; 521 struct mlo_link_info *rsp_partner_info; 522 struct mlo_partner_info assoc_partner_info = {0}; 523 struct cfg80211_bss *bss = NULL; 524 QDF_STATUS qdf_status; 525 uint8_t link_id = 0, num_links; 526 int i; 527 528 qdf_status = osif_get_partner_info_from_mlie(rsp, &assoc_partner_info); 529 if (QDF_IS_STATUS_ERROR(qdf_status)) 530 return; 531 532 num_links = rsp->ml_parnter_info.num_partner_links; 533 for (i = 0 ; i < num_links; i++) { 534 rsp_partner_info = &rsp->ml_parnter_info.partner_link_info[i]; 535 536 qdf_status = osif_get_link_id_from_assoc_ml_ie(rsp_partner_info, 537 &assoc_partner_info, 538 &link_id); 539 if (QDF_IS_STATUS_ERROR(qdf_status)) 540 continue; 541 542 partner_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, 543 rsp_partner_info->vdev_id, 544 WLAN_MLO_MGR_ID); 545 if (!partner_vdev) 546 continue; 547 548 bss = osif_get_chan_bss_from_kernel(partner_vdev, 549 rsp_partner_info, rsp); 550 if (!bss) { 551 wlan_objmgr_vdev_release_ref(partner_vdev, 552 WLAN_MLO_MGR_ID); 553 continue; 554 } 555 556 osif_populate_connect_response_for_link(partner_vdev, 557 conn_rsp_params, 558 link_id, bss); 559 wlan_objmgr_vdev_release_ref(partner_vdev, WLAN_MLO_MGR_ID); 560 } 561 } 562 563 static void osif_fill_connect_resp_mlo_params(struct wlan_objmgr_vdev *vdev, 564 struct wlan_cm_connect_resp *rsp, 565 struct cfg80211_bss *bss, 566 struct cfg80211_connect_resp_params *conn_rsp_params) 567 { 568 uint8_t assoc_link_id; 569 QDF_STATUS qdf_status; 570 571 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 572 return; 573 574 qdf_status = osif_fill_peer_mld_mac_connect_resp(vdev, rsp, 575 conn_rsp_params); 576 if (QDF_IS_STATUS_ERROR(qdf_status)) { 577 osif_err("Unable to fill peer mld address: %d", qdf_status); 578 return; 579 } 580 581 assoc_link_id = wlan_vdev_get_link_id(vdev); 582 osif_populate_connect_response_for_link(vdev, conn_rsp_params, 583 assoc_link_id, bss); 584 585 osif_populate_partner_links_mlo_params(wlan_vdev_get_pdev(vdev), rsp, 586 conn_rsp_params); 587 } 588 589 static void 590 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 591 { 592 } 593 #elif defined(CFG80211_IFTYPE_MLO_LINK_SUPPORT) && defined(WLAN_FEATURE_11BE_MLO) 594 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 595 static struct wlan_objmgr_vdev *osif_get_partner_vdev( 596 struct wlan_objmgr_vdev *vdev, 597 struct mlo_link_info rsp_partner_info) 598 { 599 return wlan_objmgr_get_vdev_by_id_from_pdev( 600 vdev->vdev_objmgr.wlan_pdev, 601 rsp_partner_info.vdev_id, 602 WLAN_MLO_MGR_ID); 603 } 604 #else 605 static struct wlan_objmgr_vdev *osif_get_partner_vdev( 606 struct wlan_objmgr_vdev *vdev, 607 struct mlo_link_info rsp_partner_info) 608 { 609 return mlo_get_vdev_by_link_id(vdev, rsp_partner_info.link_id); 610 } 611 #endif 612 static void osif_fill_connect_resp_mlo_params( 613 struct wlan_objmgr_vdev *vdev, 614 struct wlan_cm_connect_resp *rsp, 615 struct cfg80211_bss *bss, 616 struct cfg80211_connect_resp_params *conn_rsp_params) 617 { 618 uint8_t i, num_mlo_links = rsp->ml_parnter_info.num_partner_links + 1; 619 struct wlan_objmgr_vdev *ml_vdev = vdev; 620 struct vdev_osif_priv *osif_priv; 621 struct ieee80211_channel *chan; 622 struct cfg80211_mlo_link_params *ml_link_params; 623 struct mlo_link_info *rsp_partner_info; 624 625 if (num_mlo_links == 1) 626 return; 627 628 ml_link_params = qdf_mem_malloc( 629 num_mlo_links * sizeof(*ml_link_params)); 630 if (!ml_link_params) 631 return; 632 633 rsp_partner_info = rsp->ml_parnter_info.partner_link_info; 634 if (rsp->ml_parnter_info.num_partner_links) { 635 conn_rsp_params->n_mlo_links = num_mlo_links; 636 osif_priv = wlan_vdev_get_ospriv(ml_vdev); 637 for (i = 0; i < conn_rsp_params->n_mlo_links; i++) { 638 ml_link_params[i].wdev = osif_priv->wdev; 639 640 if (i != 0) { 641 chan = ieee80211_get_channel( 642 osif_priv->wdev->wiphy, 643 rsp_partner_info[i - 1].chan_freq); 644 if (!chan) { 645 osif_err("Invalid partner channel"); 646 goto end; 647 } 648 649 bss = wlan_cfg80211_get_bss( 650 osif_priv->wdev->wiphy, chan, 651 rsp_partner_info[i - 1].link_addr.bytes, 652 rsp->ssid.ssid, rsp->ssid.length); 653 if (!bss) { 654 osif_err("Partner bss is null"); 655 goto end; 656 } 657 } 658 qdf_mem_copy(ml_link_params[i].bssid, bss->bssid, 659 QDF_MAC_ADDR_SIZE); 660 661 if (i == rsp->ml_parnter_info.num_partner_links) 662 break; 663 664 ml_vdev = osif_get_partner_vdev(vdev, 665 rsp_partner_info[i]); 666 667 if (ml_vdev) { 668 osif_priv = wlan_vdev_get_ospriv(ml_vdev); 669 wlan_objmgr_vdev_release_ref(ml_vdev, 670 WLAN_MLO_MGR_ID); 671 } else { 672 osif_err("Partner vdev not found with vdev_id:%d", 673 rsp_partner_info[i].vdev_id); 674 goto end; 675 } 676 } 677 } 678 end: 679 conn_rsp_params->mlo_links = ml_link_params; 680 } 681 682 static void 683 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 684 { 685 struct cfg80211_mlo_link_params *ml_links; 686 687 ml_links = 688 (struct cfg80211_mlo_link_params *)conn_rsp_params->mlo_links; 689 if (ml_links) 690 qdf_mem_free(ml_links); 691 } 692 693 #else 694 static void osif_fill_connect_resp_mlo_params( 695 struct wlan_objmgr_vdev *vdev, 696 struct wlan_cm_connect_resp *rsp, 697 struct cfg80211_bss *bss, 698 struct cfg80211_connect_resp_params *conn_rsp_params) 699 { 700 } 701 702 static void 703 osif_free_ml_link_params(struct cfg80211_connect_resp_params *conn_rsp_params) 704 { 705 } 706 #endif 707 708 #ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT 709 static 710 void osif_copy_connected_info(struct cfg80211_connect_resp_params *conn_rsp, 711 struct wlan_cm_connect_resp *rsp, 712 struct cfg80211_bss *bss, 713 struct wlan_objmgr_vdev *vdev) 714 { 715 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 716 qdf_debug("MLO vdev fill everything in mlo fill params"); 717 return; 718 } 719 720 conn_rsp->links[0].bssid = rsp->bssid.bytes; 721 conn_rsp->links[0].bss = bss; 722 } 723 #else 724 static 725 void osif_copy_connected_info(struct cfg80211_connect_resp_params *conn_rsp, 726 struct wlan_cm_connect_resp *rsp, 727 struct cfg80211_bss *bss, 728 struct wlan_objmgr_vdev *vdev) 729 { 730 conn_rsp->bssid = rsp->bssid.bytes; 731 conn_rsp->bss = bss; 732 } 733 #endif 734 735 /** 736 * osif_connect_done() - Wrapper API to call cfg80211_connect_done 737 * @dev: network device 738 * @bss: bss info 739 * @rsp: Connection manager connect response 740 * @vdev: pointer to vdev 741 * 742 * This API is used as wrapper to send connect status and params to 743 * supplicant. 744 * 745 * Context: Any context. 746 * Return: 0 if success. Error code for failure 747 */ 748 static int osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, 749 struct wlan_cm_connect_resp *rsp, 750 struct wlan_objmgr_vdev *vdev) 751 { 752 struct cfg80211_connect_resp_params conn_rsp_params; 753 enum ieee80211_statuscode status; 754 755 osif_enter_dev(dev); 756 757 status = osif_get_connect_status_code(rsp); 758 qdf_mem_zero(&conn_rsp_params, sizeof(conn_rsp_params)); 759 760 conn_rsp_params.status = status; 761 osif_copy_connected_info(&conn_rsp_params, rsp, bss, vdev); 762 conn_rsp_params.timeout_reason = 763 osif_convert_timeout_reason(rsp->reason); 764 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 765 &conn_rsp_params.req_ie_len, 766 &conn_rsp_params.req_ie); 767 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 768 &conn_rsp_params.resp_ie_len, 769 &conn_rsp_params.resp_ie); 770 osif_populate_fils_params(&conn_rsp_params, &rsp->connect_ies); 771 osif_cm_save_gtk(vdev, rsp); 772 773 if (status == WLAN_STATUS_SUCCESS) 774 osif_fill_connect_resp_mlo_params(vdev, rsp, bss, 775 &conn_rsp_params); 776 777 osif_debug("Connect resp status %d", conn_rsp_params.status); 778 779 cfg80211_connect_done(dev, &conn_rsp_params, qdf_mem_malloc_flags()); 780 osif_cm_set_hlp_data(dev, vdev, rsp); 781 782 osif_free_ml_link_params(&conn_rsp_params); 783 784 return 0; 785 } 786 #else /* CFG80211_CONNECT_DONE */ 787 static inline int 788 osif_connect_done(struct net_device *dev, struct cfg80211_bss *bss, 789 struct wlan_cm_connect_resp *rsp, 790 struct wlan_objmgr_vdev *vdev) 791 { 792 return -EINVAL; 793 } 794 #endif 795 796 #if (defined(CFG80211_CONNECT_DONE) || \ 797 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))) 798 /** 799 * osif_update_connect_results() - API to send connection status to 800 * supplicant. 801 * @dev: network device 802 * @bss: bss info 803 * @connect_rsp: Connection manager connect response 804 * @vdev: pointer to vdev 805 * 806 * The API is a wrapper to send connection status to supplicant 807 * 808 * Context: Any context. 809 * Return: 0 if success else failure 810 */ 811 static int osif_update_connect_results(struct net_device *dev, 812 struct cfg80211_bss *bss, 813 struct wlan_cm_connect_resp *rsp, 814 struct wlan_objmgr_vdev *vdev) 815 { 816 return osif_connect_done(dev, bss, rsp, vdev); 817 } 818 #else /* CFG80211_CONNECT_DONE */ 819 820 static inline int osif_update_connect_results(struct net_device *dev, 821 struct cfg80211_bss *bss, 822 struct wlan_cm_connect_resp *rsp, 823 struct wlan_objmgr_vdev *vdev) 824 { 825 return -EINVAL; 826 } 827 #endif /* CFG80211_CONNECT_DONE */ 828 829 #ifdef WLAN_FEATURE_11BE_MLO 830 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 831 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 832 struct vdev_osif_priv *osif_priv, 833 struct wlan_cm_connect_resp *rsp) 834 { 835 struct cfg80211_bss *bss = NULL; 836 struct ieee80211_channel *chan; 837 838 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 839 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 840 rsp->freq); 841 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 842 rsp->bssid.bytes, 843 rsp->ssid.ssid, 844 rsp->ssid.length); 845 } 846 847 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 848 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 849 rsp, vdev)) 850 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 851 return; 852 } 853 854 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 855 if (osif_update_connect_results( 856 osif_priv->wdev->netdev, bss, 857 rsp, vdev)) 858 osif_connect_bss(osif_priv->wdev->netdev, 859 bss, rsp); 860 } 861 862 } 863 #else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 864 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 865 struct vdev_osif_priv *osif_priv, 866 struct wlan_cm_connect_resp *rsp) 867 { 868 struct cfg80211_bss *bss = NULL; 869 struct ieee80211_channel *chan; 870 struct wlan_objmgr_vdev *assoc_vdev = NULL; 871 struct vdev_osif_priv *tmp_osif_priv = NULL; 872 qdf_freq_t freq; 873 struct qdf_mac_addr macaddr = {0}; 874 struct wlan_cm_connect_resp resp = {0}; 875 876 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 877 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 878 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 879 rsp->freq); 880 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, 881 chan, 882 rsp->bssid.bytes, 883 rsp->ssid.ssid, 884 rsp->ssid.length); 885 } 886 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 887 rsp, vdev)) 888 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 889 return; 890 } 891 892 if ((QDF_IS_STATUS_SUCCESS(rsp->connect_status) && 893 ucfg_mlo_is_mld_connected(vdev)) || 894 (QDF_IS_STATUS_ERROR(rsp->connect_status) && 895 ucfg_mlo_is_mld_disconnected(vdev))) { 896 assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); 897 if (!assoc_vdev) 898 return; 899 qdf_mem_copy(&resp, rsp, sizeof(struct wlan_cm_connect_resp)); 900 tmp_osif_priv = wlan_vdev_get_ospriv(assoc_vdev); 901 freq = vdev->vdev_mlme.bss_chan->ch_freq; 902 wlan_vdev_get_bss_peer_mac(assoc_vdev, &macaddr); 903 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 904 chan = ieee80211_get_channel(tmp_osif_priv->wdev->wiphy, 905 freq); 906 bss = wlan_cfg80211_get_bss(tmp_osif_priv->wdev->wiphy, 907 chan, 908 macaddr.bytes, 909 rsp->ssid.ssid, 910 rsp->ssid.length); 911 } 912 qdf_mem_copy(resp.bssid.bytes, macaddr.bytes, 913 QDF_MAC_ADDR_SIZE); 914 resp.freq = freq; 915 resp.connect_ies.assoc_req.ptr = rsp->connect_ies.assoc_req.ptr; 916 resp.connect_ies.assoc_req.len = rsp->connect_ies.assoc_req.len; 917 resp.connect_ies.assoc_rsp.ptr = rsp->connect_ies.assoc_rsp.ptr; 918 resp.connect_ies.assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 919 if (osif_update_connect_results(tmp_osif_priv->wdev->netdev, bss, 920 &resp, assoc_vdev)) 921 osif_connect_bss(tmp_osif_priv->wdev->netdev, bss, &resp); 922 } 923 } 924 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 925 #else /* WLAN_FEATURE_11BE_MLO */ 926 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 927 struct vdev_osif_priv *osif_priv, 928 struct wlan_cm_connect_resp *rsp) 929 { 930 struct cfg80211_bss *bss = NULL; 931 struct ieee80211_channel *chan; 932 933 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { 934 chan = ieee80211_get_channel(osif_priv->wdev->wiphy, 935 rsp->freq); 936 bss = wlan_cfg80211_get_bss(osif_priv->wdev->wiphy, chan, 937 rsp->bssid.bytes, 938 rsp->ssid.ssid, 939 rsp->ssid.length); 940 } 941 942 if (osif_update_connect_results(osif_priv->wdev->netdev, bss, 943 rsp, vdev)) 944 osif_connect_bss(osif_priv->wdev->netdev, bss, rsp); 945 } 946 #endif /* WLAN_FEATURE_11BE_MLO */ 947 #else /* CFG80211_CONNECT_BSS */ 948 #ifdef WLAN_FEATURE_11BE_MLO 949 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 950 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 951 struct vdev_osif_priv *osif_priv, 952 struct wlan_cm_connect_resp *rsp) 953 { 954 enum ieee80211_statuscode status; 955 size_t req_len = 0; 956 const uint8_t *req_ptr = NULL; 957 size_t rsp_len = 0; 958 const uint8_t *rsp_ptr = NULL; 959 struct wlan_objmgr_vdev *assoc_vdev = NULL; 960 struct vdev_osif_priv *tmp_osif_priv = NULL; 961 962 status = osif_get_connect_status_code(rsp); 963 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 964 &req_len, &req_ptr); 965 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 966 &rsp_len, &rsp_ptr); 967 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 968 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 969 cfg80211_connect_result( 970 osif_priv->wdev->netdev, 971 rsp->bssid.bytes, req_ptr, req_len, 972 rsp_ptr, rsp_len, status, 973 qdf_mem_malloc_flags()); 974 } else { 975 cfg80211_connect_result(osif_priv->wdev->netdev, 976 rsp->bssid.bytes, req_ptr, req_len, 977 rsp_ptr, rsp_len, status, 978 qdf_mem_malloc_flags()); 979 } 980 } 981 #else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 982 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 983 struct vdev_osif_priv *osif_priv, 984 struct wlan_cm_connect_resp *rsp) 985 { 986 enum ieee80211_statuscode status; 987 size_t req_len = 0; 988 const uint8_t *req_ptr = NULL; 989 size_t rsp_len = 0; 990 const uint8_t *rsp_ptr = NULL; 991 struct wlan_objmgr_vdev *assoc_vdev = NULL; 992 struct vdev_osif_priv *tmp_osif_priv = NULL; 993 struct qdf_mac_addr macaddr = {0}; 994 995 status = osif_get_connect_status_code(rsp); 996 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 997 &req_len, &req_ptr); 998 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 999 &rsp_len, &rsp_ptr); 1000 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1001 if ((QDF_IS_STATUS_SUCCESS(rsp->connect_status) && 1002 ucfg_mlo_is_mld_connected(vdev)) || 1003 (QDF_IS_STATUS_ERROR(rsp->connect_status) && 1004 ucfg_mlo_is_mld_disconnected(vdev))) { 1005 assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); 1006 if (!assoc_vdev) 1007 return; 1008 tmp_osif_priv = wlan_vdev_get_ospriv(assoc_vdev); 1009 wlan_vdev_get_bss_peer_mac(assoc_vdev, &macaddr); 1010 cfg80211_connect_result(tmp_osif_priv->wdev->netdev, 1011 macaddr.bytes, req_ptr, 1012 req_len, rsp_ptr, rsp_len, 1013 status, qdf_mem_malloc_flags()); 1014 } 1015 } else { 1016 cfg80211_connect_result(osif_priv->wdev->netdev, 1017 rsp->bssid.bytes, req_ptr, req_len, 1018 rsp_ptr, rsp_len, status, 1019 qdf_mem_malloc_flags()); 1020 } 1021 } 1022 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 1023 #else /* WLAN_FEATURE_11BE_MLO */ 1024 static void osif_indcate_connect_results(struct wlan_objmgr_vdev *vdev, 1025 struct vdev_osif_priv *osif_priv, 1026 struct wlan_cm_connect_resp *rsp) 1027 { 1028 enum ieee80211_statuscode status; 1029 size_t req_len = 0; 1030 const uint8_t *req_ptr = NULL; 1031 size_t rsp_len = 0; 1032 const uint8_t *rsp_ptr = NULL; 1033 1034 status = osif_get_connect_status_code(rsp); 1035 osif_cm_get_assoc_req_ie_data(&rsp->connect_ies.assoc_req, 1036 &req_len, &req_ptr); 1037 osif_cm_get_assoc_rsp_ie_data(&rsp->connect_ies.assoc_rsp, 1038 &rsp_len, &rsp_ptr); 1039 cfg80211_connect_result(osif_priv->wdev->netdev, 1040 rsp->bssid.bytes, req_ptr, req_len, 1041 rsp_ptr, rsp_len, status, 1042 qdf_mem_malloc_flags()); 1043 } 1044 #endif /* WLAN_FEATURE_11BE_MLO */ 1045 #endif /* CFG80211_CONNECT_BSS */ 1046 1047 #ifdef CONN_MGR_ADV_FEATURE 1048 static inline 1049 bool osif_cm_is_unlink_bss_required(struct wlan_cm_connect_resp *rsp) 1050 { 1051 if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) 1052 return false; 1053 1054 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 1055 rsp->reason == CM_JOIN_TIMEOUT || 1056 rsp->reason == CM_AUTH_TIMEOUT || 1057 rsp->reason == CM_ASSOC_TIMEOUT) 1058 return true; 1059 1060 return false; 1061 } 1062 static inline void osif_check_and_unlink_bss(struct wlan_objmgr_vdev *vdev, 1063 struct vdev_osif_priv *osif_priv, 1064 struct wlan_cm_connect_resp *rsp) 1065 { 1066 if (osif_cm_is_unlink_bss_required(rsp)) 1067 osif_cm_unlink_bss(vdev, osif_priv, &rsp->bssid, rsp->ssid.ssid, 1068 rsp->ssid.length); 1069 } 1070 #else 1071 static inline void osif_check_and_unlink_bss(struct wlan_objmgr_vdev *vdev, 1072 struct vdev_osif_priv *osif_priv, 1073 struct wlan_cm_connect_resp *rsp) 1074 {} 1075 #endif 1076 1077 QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev, 1078 struct wlan_cm_connect_resp *rsp) 1079 { 1080 struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); 1081 QDF_STATUS status; 1082 1083 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", 1084 osif_priv->wdev->netdev->name, rsp->vdev_id, 1085 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 1086 QDF_MAC_ADDR_REF(rsp->bssid.bytes), 1087 rsp->ssid.length, rsp->ssid.ssid, 1088 rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id, 1089 rsp->reason, rsp->status_code, rsp->is_reassoc); 1090 1091 osif_check_and_unlink_bss(vdev, osif_priv, rsp); 1092 1093 status = osif_validate_connect_and_reset_src_id(osif_priv, rsp); 1094 if (QDF_IS_STATUS_ERROR(status)) { 1095 osif_cm_connect_comp_ind(vdev, rsp, OSIF_NOT_HANDLED); 1096 return status; 1097 } 1098 1099 osif_cm_connect_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE); 1100 if (rsp->is_reassoc) 1101 osif_indicate_reassoc_results(vdev, osif_priv, rsp); 1102 else 1103 osif_indcate_connect_results(vdev, osif_priv, rsp); 1104 osif_cm_connect_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE); 1105 1106 return QDF_STATUS_SUCCESS; 1107 } 1108 1109 QDF_STATUS osif_failed_candidate_handler(struct wlan_objmgr_vdev *vdev, 1110 struct wlan_cm_connect_resp *rsp) 1111 { 1112 struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); 1113 1114 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", 1115 osif_priv->wdev->netdev->name, rsp->vdev_id, 1116 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 1117 QDF_MAC_ADDR_REF(rsp->bssid.bytes), 1118 rsp->ssid.length, rsp->ssid.ssid, rsp->cm_id, 1119 rsp->reason, rsp->status_code); 1120 1121 /** 1122 * Do not unlink the BSS if it is an ML candidate. In case of ML, 1123 * failed candidate may be used as partner link while trying the 1124 * connection on other links. 1125 */ 1126 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 1127 osif_check_and_unlink_bss(vdev, osif_priv, rsp); 1128 1129 return QDF_STATUS_SUCCESS; 1130 } 1131