1 /* 2 * Copyright (c) 2012-2015,2020-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 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_req.c 20 * 21 * This file maintains definitaions of connect, disconnect, roam 22 * request apis. 23 */ 24 25 #include "wlan_osif_priv.h" 26 #include "osif_cm_req.h" 27 #include "wlan_cm_ucfg_api.h" 28 #include "wlan_nl_to_crypto_params.h" 29 #include <wlan_cfg80211.h> 30 #include "osif_cm_util.h" 31 #ifdef WLAN_FEATURE_FILS_SK 32 #include <wlan_mlme_ucfg_api.h> 33 #endif 34 #include <wlan_mlo_mgr_sta.h> 35 #include <utils_mlo.h> 36 #include <wlan_mgmt_txrx_rx_reo_utils_api.h> 37 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) 38 #include <wlan_mlo_mgr_setup.h> 39 #endif 40 41 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) && \ 42 LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) && \ 43 !defined(CFG80211_CRYPTO_WEP_KEYS_REMOVED) 44 static QDF_STATUS 45 osif_cm_update_wep_seq_info(struct wlan_cm_connect_req *connect_req, 46 const struct cfg80211_connect_params *req) 47 { 48 if (req->crypto.wep_keys->seq_len) { 49 connect_req->crypto.wep_keys.seq_len = 50 req->crypto.wep_keys->seq_len; 51 connect_req->crypto.wep_keys.seq = 52 qdf_mem_malloc(connect_req->crypto.wep_keys.seq_len); 53 if (!connect_req->crypto.wep_keys.seq) { 54 ucfg_cm_free_wep_key_params(connect_req); 55 return QDF_STATUS_E_NOMEM; 56 } 57 qdf_mem_copy(connect_req->crypto.wep_keys.seq, 58 req->crypto.wep_keys->seq, 59 connect_req->crypto.wep_keys.seq_len); 60 } 61 return QDF_STATUS_SUCCESS; 62 } 63 #else 64 static inline QDF_STATUS 65 osif_cm_update_wep_seq_info(struct wlan_cm_connect_req *connect_req, 66 const struct cfg80211_connect_params *req) 67 { 68 return QDF_STATUS_SUCCESS; 69 } 70 #endif 71 72 #if !defined(CFG80211_CRYPTO_WEP_KEYS_REMOVED) 73 static QDF_STATUS 74 osif_cm_set_wep_key_params(struct wlan_cm_connect_req *connect_req, 75 const struct cfg80211_connect_params *req) 76 { 77 if (!req->key_len) 78 return QDF_STATUS_SUCCESS; 79 80 connect_req->crypto.wep_keys.key_len = req->key_len; 81 connect_req->crypto.wep_keys.key_idx = req->key_idx; 82 83 connect_req->crypto.wep_keys.key = 84 qdf_mem_malloc(connect_req->crypto.wep_keys.key_len); 85 if (!connect_req->crypto.wep_keys.key) 86 return QDF_STATUS_E_NOMEM; 87 88 qdf_mem_copy(connect_req->crypto.wep_keys.key, req->key, 89 connect_req->crypto.wep_keys.key_len); 90 91 return osif_cm_update_wep_seq_info(connect_req, req); 92 } 93 #else 94 static QDF_STATUS 95 osif_cm_set_wep_key_params(struct wlan_cm_connect_req *connect_req, 96 const struct cfg80211_connect_params *req) 97 { 98 return QDF_STATUS_SUCCESS; 99 } 100 #endif 101 102 static void osif_cm_set_auth_type(struct wlan_cm_connect_req *connect_req, 103 const struct cfg80211_connect_params *req) 104 { 105 wlan_crypto_auth_mode crypto_auth_type = 106 osif_nl_to_crypto_auth_type(req->auth_type); 107 108 /* For auto check wpa version to decide WPA or RSNA */ 109 if (crypto_auth_type == WLAN_CRYPTO_AUTH_AUTO && 110 req->crypto.wpa_versions) { 111 if (req->crypto.wpa_versions & NL80211_WPA_VERSION_1) 112 crypto_auth_type = WLAN_CRYPTO_AUTH_WPA; 113 else 114 crypto_auth_type = WLAN_CRYPTO_AUTH_RSNA; 115 } else if (!req->crypto.n_ciphers_pairwise) { 116 crypto_auth_type = WLAN_CRYPTO_AUTH_OPEN; 117 } 118 119 QDF_SET_PARAM(connect_req->crypto.auth_type, crypto_auth_type); 120 } 121 122 static int 123 osif_cm_get_num_akm_suites(const struct cfg80211_connect_params *req) 124 { 125 return req->crypto.n_akm_suites; 126 } 127 128 static uint32_t* 129 osif_cm_get_akm_suites(const struct cfg80211_connect_params *req) 130 { 131 return (uint32_t *)req->crypto.akm_suites; 132 } 133 134 #ifdef CFG80211_MULTI_AKM_CONNECT_SUPPORT 135 #define MAX_AKM_SUITES WLAN_CM_MAX_CONNECT_AKMS 136 #else 137 #define MAX_AKM_SUITES NL80211_MAX_NR_AKM_SUITES 138 #endif 139 static void 140 osif_cm_set_akm_params(struct wlan_cm_connect_req *connect_req, 141 const struct cfg80211_connect_params *req) 142 { 143 uint32_t i; 144 wlan_crypto_key_mgmt akm; 145 146 /* Fill AKM suites */ 147 if (req->crypto.n_akm_suites) { 148 for (i = 0; i < req->crypto.n_akm_suites && 149 i < MAX_AKM_SUITES; i++) { 150 akm = osif_nl_to_crypto_akm_type( 151 req->crypto.akm_suites[i]); 152 QDF_SET_PARAM(connect_req->crypto.akm_suites, akm); 153 } 154 } else { 155 QDF_SET_PARAM(connect_req->crypto.akm_suites, 156 WLAN_CRYPTO_KEY_MGMT_NONE); 157 } 158 } 159 160 static inline 161 uint8_t osif_cm_get_rsn_cap_mfp(enum nl80211_mfp mfp_state) 162 { 163 switch (mfp_state) { 164 case NL80211_MFP_REQUIRED: 165 return RSN_CAP_MFP_REQUIRED; 166 case NL80211_MFP_OPTIONAL: 167 return RSN_CAP_MFP_CAPABLE; 168 default: 169 return RSN_CAP_MFP_DISABLED; 170 } 171 } 172 173 #ifdef CONNECTIVITY_DIAG_EVENT 174 /** 175 * osif_cm_populate_user_crypto_param() - API to cache crypto param 176 * received from the userspace. 177 * @connect_req: Connect request buffer to cache parameter 178 * @req: Connection request parameter received from userspace. 179 * 180 * Return: None 181 */ 182 static void 183 osif_cm_populate_user_crypto_param(struct wlan_cm_connect_req *connect_req, 184 const struct cfg80211_connect_params *req) 185 { 186 connect_req->crypto.user_cipher_pairwise = 187 req->crypto.ciphers_pairwise[0]; 188 connect_req->crypto.user_akm_suite = req->crypto.akm_suites[0]; 189 connect_req->crypto.user_auth_type = req->auth_type; 190 connect_req->crypto.user_grp_cipher = req->crypto.cipher_group; 191 } 192 #else 193 static void 194 osif_cm_populate_user_crypto_param(struct wlan_cm_connect_req *connect_req, 195 const struct cfg80211_connect_params *req) 196 { 197 } 198 #endif 199 200 static 201 QDF_STATUS osif_cm_set_crypto_params(struct wlan_cm_connect_req *connect_req, 202 const struct cfg80211_connect_params *req) 203 { 204 uint32_t i; 205 QDF_STATUS status; 206 wlan_crypto_cipher_type cipher = WLAN_CRYPTO_CIPHER_NONE; 207 208 connect_req->crypto.wpa_versions = req->crypto.wpa_versions; 209 210 osif_cm_set_auth_type(connect_req, req); 211 212 if (req->crypto.cipher_group) 213 cipher = 214 osif_nl_to_crypto_cipher_type(req->crypto.cipher_group); 215 216 QDF_SET_PARAM(connect_req->crypto.group_cipher, cipher); 217 218 /* Fill Pairwise ciphers */ 219 if (req->crypto.n_ciphers_pairwise) { 220 for (i = 0; i < req->crypto.n_ciphers_pairwise && 221 i < NL80211_MAX_NR_CIPHER_SUITES; i++) { 222 cipher = osif_nl_to_crypto_cipher_type( 223 req->crypto.ciphers_pairwise[i]); 224 QDF_SET_PARAM(connect_req->crypto.ciphers_pairwise, 225 cipher); 226 } 227 } else { 228 QDF_SET_PARAM(connect_req->crypto.ciphers_pairwise, 229 WLAN_CRYPTO_CIPHER_NONE); 230 } 231 232 /* Fill AKM suites */ 233 osif_cm_set_akm_params(connect_req, req); 234 235 /* Fill WEP Key information */ 236 status = osif_cm_set_wep_key_params(connect_req, req); 237 if (QDF_IS_STATUS_ERROR(status)) 238 osif_err("set wep key params failed"); 239 240 /* Copy user configured MFP capability */ 241 connect_req->crypto.user_mfp = osif_cm_get_rsn_cap_mfp(req->mfp); 242 243 osif_cm_populate_user_crypto_param(connect_req, req); 244 245 return status; 246 } 247 248 #ifdef WLAN_FEATURE_FILS_SK 249 static bool osif_cm_is_akm_suite_fils(uint32_t key_mgmt) 250 { 251 switch (key_mgmt) { 252 case WLAN_AKM_SUITE_FILS_SHA256: 253 case WLAN_AKM_SUITE_FILS_SHA384: 254 case WLAN_AKM_SUITE_FT_FILS_SHA256: 255 case WLAN_AKM_SUITE_FT_FILS_SHA384: 256 osif_debug("Fils AKM : %x", key_mgmt); 257 return true; 258 default: 259 return false; 260 } 261 } 262 263 static bool osif_cm_is_conn_type_fils(struct wlan_cm_connect_req *connect_req, 264 const struct cfg80211_connect_params *req) 265 { 266 int num_akm_suites; 267 uint32_t *akm_suites; 268 uint8_t i; 269 270 num_akm_suites = osif_cm_get_num_akm_suites(req); 271 akm_suites = osif_cm_get_akm_suites(req); 272 273 if (num_akm_suites <= 0) 274 return false; 275 276 /* 277 * Auth type will be either be OPEN or FILS type for a FILS connection 278 */ 279 if (connect_req->fils_info.auth_type == FILS_PK_MAX && 280 req->auth_type != NL80211_AUTHTYPE_OPEN_SYSTEM) 281 return false; 282 283 for (i = 0; i < num_akm_suites; i++) { 284 if (!osif_cm_is_akm_suite_fils(akm_suites[i])) 285 continue; 286 return true; 287 } 288 289 290 return false; 291 } 292 293 enum wlan_fils_auth_type 294 osif_cm_get_fils_auth_type(enum nl80211_auth_type auth) 295 { 296 switch (auth) { 297 case NL80211_AUTHTYPE_FILS_SK: 298 return FILS_SK_WITHOUT_PFS; 299 case NL80211_AUTHTYPE_FILS_SK_PFS: 300 return FILS_SK_WITH_PFS; 301 case NL80211_AUTHTYPE_FILS_PK: 302 return FILS_PK_AUTH; 303 default: 304 return FILS_PK_MAX; 305 } 306 } 307 308 static QDF_STATUS 309 osif_cm_set_fils_info(struct wlan_objmgr_vdev *vdev, 310 struct wlan_cm_connect_req *connect_req, 311 const struct cfg80211_connect_params *req) 312 { 313 bool value = 0; 314 QDF_STATUS status; 315 uint8_t *buf; 316 struct wlan_objmgr_psoc *psoc; 317 318 psoc = wlan_vdev_get_psoc(vdev); 319 if (!psoc) 320 return -QDF_STATUS_E_INVAL; 321 322 connect_req->fils_info.auth_type = 323 osif_cm_get_fils_auth_type(req->auth_type); 324 connect_req->fils_info.is_fils_connection = 325 osif_cm_is_conn_type_fils(connect_req, 326 req); 327 osif_debug("auth type %d is fils %d", 328 connect_req->fils_info.auth_type, 329 connect_req->fils_info.is_fils_connection); 330 if (!connect_req->fils_info.is_fils_connection) 331 return QDF_STATUS_SUCCESS; 332 333 status = ucfg_mlme_get_fils_enabled_info(psoc, &value); 334 if (QDF_IS_STATUS_ERROR(status) || !value) { 335 osif_err("get_fils_enabled status: %d fils_enabled: %d", 336 status, value); 337 return QDF_STATUS_E_INVAL; 338 } 339 340 /* 341 * The initial connection for FILS may happen with an OPEN 342 * auth type. Hence we need to allow the connection to go 343 * through in that case as well. 344 */ 345 if (req->auth_type != NL80211_AUTHTYPE_FILS_SK) { 346 osif_debug("set is fils false for initial connection"); 347 connect_req->fils_info.is_fils_connection = false; 348 return QDF_STATUS_SUCCESS; 349 } 350 351 connect_req->fils_info.realm_len = req->fils_erp_realm_len; 352 353 if (connect_req->fils_info.realm_len > WLAN_CM_FILS_MAX_REALM_LEN) { 354 osif_err("Invalid fils realm len %d", 355 connect_req->fils_info.realm_len); 356 return QDF_STATUS_E_INVAL; 357 } 358 qdf_mem_zero(connect_req->fils_info.realm, WLAN_CM_FILS_MAX_REALM_LEN); 359 qdf_mem_copy(connect_req->fils_info.realm, req->fils_erp_realm, 360 connect_req->fils_info.realm_len); 361 362 connect_req->fils_info.next_seq_num = req->fils_erp_next_seq_num + 1; 363 364 connect_req->fils_info.rrk_len = req->fils_erp_rrk_len; 365 366 if (connect_req->fils_info.rrk_len > WLAN_CM_FILS_MAX_RRK_LENGTH) { 367 osif_err("Invalid fils rrk len %d", 368 connect_req->fils_info.rrk_len); 369 return QDF_STATUS_E_INVAL; 370 } 371 qdf_mem_zero(connect_req->fils_info.rrk, WLAN_CM_FILS_MAX_RRK_LENGTH); 372 qdf_mem_copy(connect_req->fils_info.rrk, req->fils_erp_rrk, 373 connect_req->fils_info.rrk_len); 374 375 connect_req->fils_info.username_len = req->fils_erp_username_len + 376 sizeof(char) + req->fils_erp_realm_len; 377 osif_debug("usrname len %d = usrname recv len %zu + realm len %d + %zu", 378 connect_req->fils_info.username_len, 379 req->fils_erp_username_len, 380 connect_req->fils_info.realm_len, sizeof(char)); 381 382 if (connect_req->fils_info.username_len > 383 WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH) { 384 osif_err("Invalid fils username len %d", 385 connect_req->fils_info.username_len); 386 return QDF_STATUS_E_INVAL; 387 } 388 if (!req->fils_erp_username_len) { 389 osif_info("FILS_PMKSA: No ERP username, return success"); 390 return QDF_STATUS_SUCCESS; 391 } 392 buf = connect_req->fils_info.username; 393 qdf_mem_zero(connect_req->fils_info.username, 394 WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH); 395 qdf_mem_copy(buf, req->fils_erp_username, req->fils_erp_username_len); 396 buf += req->fils_erp_username_len; 397 *buf++ = '@'; 398 qdf_mem_copy(buf, req->fils_erp_realm, req->fils_erp_realm_len); 399 400 return QDF_STATUS_SUCCESS; 401 } 402 #else 403 static inline 404 QDF_STATUS osif_cm_set_fils_info(struct wlan_objmgr_vdev *vdev, 405 struct wlan_cm_connect_req *connect_req, 406 const struct cfg80211_connect_params *req) 407 { 408 return QDF_STATUS_SUCCESS; 409 } 410 #endif 411 412 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) 413 static inline void 414 osif_cm_set_prev_bssid(struct wlan_cm_connect_req *connect_req, 415 const struct cfg80211_connect_params *req) 416 { 417 if (req->prev_bssid) 418 qdf_mem_copy(connect_req->prev_bssid.bytes, req->prev_bssid, 419 QDF_MAC_ADDR_SIZE); 420 } 421 422 static inline 423 void osif_cm_dump_prev_bssid(const struct cfg80211_connect_params *req) 424 { 425 if (req->prev_bssid) 426 osif_nofl_debug("prev BSSID "QDF_MAC_ADDR_FMT, 427 QDF_MAC_ADDR_REF(req->prev_bssid)); 428 } 429 430 #else 431 static inline void 432 osif_cm_set_prev_bssid(struct wlan_cm_connect_req *connect_req, 433 const struct cfg80211_connect_params *req) 434 { 435 } 436 437 static inline 438 void osif_cm_dump_prev_bssid(const struct cfg80211_connect_params *req) 439 { 440 } 441 442 #endif 443 444 static inline void 445 osif_cm_dump_connect_req(struct net_device *dev, uint8_t vdev_id, 446 const struct cfg80211_connect_params *req) 447 { 448 uint32_t i; 449 uint32_t num_akm_suites; 450 uint32_t *akm_suites; 451 452 num_akm_suites = osif_cm_get_num_akm_suites(req); 453 akm_suites = osif_cm_get_akm_suites(req); 454 455 osif_nofl_debug("connect req for %s(vdevid-%d) freq %d SSID " QDF_SSID_FMT " auth type %d WPA ver %d n_akm %d n_cipher %d grp_cipher %x mfp %d freq hint %d", 456 dev->name, vdev_id, 457 req->channel ? req->channel->center_freq : 0, 458 QDF_SSID_REF((int)req->ssid_len, req->ssid), 459 req->auth_type, req->crypto.wpa_versions, 460 num_akm_suites, 461 req->crypto.n_ciphers_pairwise, 462 req->crypto.cipher_group, req->mfp, 463 req->channel_hint ? req->channel_hint->center_freq : 0); 464 if (req->bssid) 465 osif_nofl_debug("BSSID "QDF_MAC_ADDR_FMT, 466 QDF_MAC_ADDR_REF(req->bssid)); 467 if (req->bssid_hint) 468 osif_nofl_debug("BSSID hint "QDF_MAC_ADDR_FMT, 469 QDF_MAC_ADDR_REF(req->bssid_hint)); 470 osif_cm_dump_prev_bssid(req); 471 472 for (i = 0; i < num_akm_suites; i++) 473 osif_nofl_debug("akm[%d] = %x", i, akm_suites[i]); 474 475 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) 476 osif_nofl_debug("cipher_pairwise[%d] = %x", i, 477 req->crypto.ciphers_pairwise[i]); 478 } 479 480 static void 481 osif_cm_fill_connect_params(struct wlan_cm_connect_req *req, 482 const struct osif_connect_params *params) 483 { 484 if (!params) 485 return; 486 487 if (params->scan_ie.len) { 488 req->scan_ie.ptr = qdf_mem_malloc(params->scan_ie.len); 489 if (req->scan_ie.ptr) { 490 qdf_mem_copy(req->scan_ie.ptr, params->scan_ie.ptr, 491 params->scan_ie.len); 492 req->scan_ie.len = params->scan_ie.len; 493 } 494 } 495 req->dot11mode_filter = params->dot11mode_filter; 496 req->force_rsne_override = params->force_rsne_override; 497 req->sae_pwe = params->sae_pwe; 498 499 if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms->prev_bssid)) 500 qdf_copy_macaddr(&req->prev_bssid, 501 (struct qdf_mac_addr *)¶ms->prev_bssid); 502 } 503 504 #ifdef WLAN_FEATURE_11BE_MLO 505 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 506 static inline 507 QDF_STATUS osif_update_mlo_partner_info( 508 struct wlan_objmgr_vdev *vdev, 509 struct wlan_cm_connect_req *connect_req, 510 const struct cfg80211_connect_params *req) 511 { 512 return QDF_STATUS_SUCCESS; 513 } 514 #else 515 static inline 516 void osif_update_partner_vdev_info(struct wlan_objmgr_vdev *vdev, 517 struct mlo_partner_info partner_info) 518 { 519 struct wlan_objmgr_vdev *tmp_vdev; 520 struct wlan_mlo_dev_context *ml_dev = NULL; 521 uint8_t i; 522 uint8_t link_id; 523 524 if (!vdev) 525 return; 526 527 ml_dev = vdev->mlo_dev_ctx; 528 if (!ml_dev) 529 return; 530 531 for (i = 0; i < partner_info.num_partner_links; i++) { 532 tmp_vdev = mlo_get_ml_vdev_by_mac( 533 vdev, 534 &partner_info.partner_link_info[i].link_addr); 535 if (tmp_vdev) { 536 mlo_update_connect_req_links(tmp_vdev, 1); 537 wlan_vdev_mlme_set_mlo_vdev(tmp_vdev); 538 wlan_vdev_mlme_set_mlo_link_vdev(tmp_vdev); 539 /* Set link id for bridge sta vap */ 540 if (mlo_is_sta_bridge_vdev(tmp_vdev)) { 541 link_id = ml_dev->bridge_sta_ctx->bridge_link_id; 542 wlan_vdev_set_link_id(tmp_vdev, link_id); 543 } else 544 wlan_vdev_set_link_id( 545 tmp_vdev, 546 partner_info.partner_link_info[i].link_id); 547 osif_debug("link id %d", 548 tmp_vdev->vdev_mlme.mlo_link_id); 549 } 550 } 551 } 552 553 static inline 554 QDF_STATUS osif_update_mlo_partner_info( 555 struct wlan_objmgr_vdev *vdev, 556 struct wlan_cm_connect_req *connect_req, 557 const struct cfg80211_connect_params *req) 558 { 559 /* Update ml partner info from connect req*/ 560 uint8_t *ptr = NULL; 561 uint8_t *ml_ie = NULL; 562 qdf_size_t ml_ie_len = 0; 563 struct mlo_partner_info partner_info = {0}; 564 bool ml_ie_found = false, linkidfound = false; 565 uint8_t linkid = 0; 566 uint8_t aplinks = 0; 567 enum wlan_ml_variant variant; 568 QDF_STATUS status = QDF_STATUS_SUCCESS; 569 struct wlan_objmgr_pdev *pdev = NULL; 570 struct wlan_objmgr_psoc *psoc; 571 struct wlan_mlo_dev_context *ml_dev = NULL; 572 573 if (!vdev || !connect_req || !req) 574 return status; 575 576 ml_dev = vdev->mlo_dev_ctx; 577 if (!ml_dev) { 578 osif_debug("ML ctx is NULL, ignore ML IE"); 579 return QDF_STATUS_SUCCESS; 580 } 581 pdev = wlan_vdev_get_pdev(vdev); 582 583 if (!pdev) { 584 osif_debug("null pdev"); 585 return QDF_STATUS_SUCCESS; 586 } 587 psoc = wlan_pdev_get_psoc(pdev); 588 589 if (!psoc) { 590 osif_debug("null psoc"); 591 return QDF_STATUS_SUCCESS; 592 } 593 594 if (!wlan_mlo_get_psoc_capable(psoc)) 595 return QDF_STATUS_SUCCESS; 596 597 osif_debug("ML IE search start"); 598 if (req->ie_len) { 599 ptr = (uint8_t *)req->ie; 600 status = util_find_mlie(ptr, req->ie_len, &ml_ie, &ml_ie_len); 601 if (QDF_IS_STATUS_ERROR(status) || !ml_ie) { 602 osif_debug("ML IE not found"); 603 /* Return success since ML is not mandatory for a 604 * connect request 605 */ 606 return QDF_STATUS_SUCCESS; 607 } 608 609 osif_debug("ML IE found length %d", (int)ml_ie_len); 610 qdf_trace_hex_dump(QDF_MODULE_ID_OS_IF, QDF_TRACE_LEVEL_DEBUG, 611 ml_ie, (int)ml_ie_len); 612 ml_ie_found = true; 613 614 status = util_get_mlie_variant(ml_ie, ml_ie_len, 615 (int *)&variant); 616 if (status != QDF_STATUS_SUCCESS) { 617 osif_err("Unable to get Multi-Link element variant"); 618 return status; 619 } 620 621 if (variant != WLAN_ML_VARIANT_BASIC) { 622 osif_err("Invalid Multi-Link element variant %u", 623 variant); 624 return status; 625 } 626 627 status = util_get_bvmlie_primary_linkid(ml_ie, ml_ie_len, 628 &linkidfound, &linkid); 629 if (QDF_IS_STATUS_ERROR(status)) { 630 osif_err("Unable to find primary link ID in ML IE"); 631 return status; 632 } 633 634 status = util_get_bvmlie_persta_partner_info(ml_ie, ml_ie_len, 635 &partner_info); 636 if (QDF_IS_STATUS_ERROR(status)) { 637 osif_err("Unable to find per-sta profile in ML IE"); 638 return status; 639 } 640 641 if (partner_info.num_partner_links + 1 > 642 WLAN_UMAC_MLO_ASSOC_MAX_SUPPORTED_LINKS) { 643 osif_err("Rejecting connect for more than %d Assoc links", 644 WLAN_UMAC_MLO_ASSOC_MAX_SUPPORTED_LINKS); 645 return QDF_STATUS_E_FAILURE; 646 } 647 648 wlan_vdev_set_link_id(vdev, linkid); 649 wlan_vdev_mlme_set_mlo_vdev(vdev); 650 } 651 652 qdf_mem_copy(&connect_req->ml_parnter_info, 653 &partner_info, sizeof(struct mlo_partner_info)); 654 /* Get total number of links in association */ 655 aplinks = partner_info.num_partner_links + 1; 656 if (ml_ie_found) { 657 mlo_clear_connect_req_links_bmap(vdev); 658 /* Handle 4 LINK RDP Case*/ 659 if (mlo_check_topology(pdev, vdev, aplinks) != QDF_STATUS_SUCCESS) { 660 osif_err("Topology check failed prevent association\n"); 661 return QDF_STATUS_E_FAILURE; 662 } 663 664 if (mlo_sta_bridge_exists(vdev)) 665 mlo_update_partner_bridge_info(ml_dev, &partner_info); 666 667 mlo_update_connect_req_links(vdev, 1); 668 osif_update_partner_vdev_info(vdev, partner_info); 669 mlo_mlme_sta_op_class(vdev, ml_ie); 670 } 671 672 return QDF_STATUS_SUCCESS; 673 } 674 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 675 #else 676 static inline 677 QDF_STATUS osif_update_mlo_partner_info( 678 struct wlan_objmgr_vdev *vdev, 679 struct wlan_cm_connect_req *connect_req, 680 const struct cfg80211_connect_params *req) 681 { 682 return QDF_STATUS_SUCCESS; 683 } 684 #endif 685 686 int osif_cm_connect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, 687 const struct cfg80211_connect_params *req, 688 const struct osif_connect_params *params) 689 { 690 struct wlan_cm_connect_req *connect_req; 691 const u8 *bssid_hint = req->bssid_hint; 692 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 693 QDF_STATUS status; 694 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; 695 struct wlan_objmgr_vdev *temp_vdev; 696 697 if (req->bssid) 698 qdf_mem_copy(bssid.bytes, req->bssid, 699 QDF_MAC_ADDR_SIZE); 700 else if (bssid_hint) 701 qdf_mem_copy(bssid.bytes, req->bssid_hint, 702 QDF_MAC_ADDR_SIZE); 703 704 temp_vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev( 705 wlan_vdev_get_pdev(vdev), 706 bssid.bytes, 707 WLAN_OSIF_CM_ID); 708 709 if (temp_vdev) { 710 osif_err("vdev %d already exist with same mac address" 711 QDF_MAC_ADDR_FMT, wlan_vdev_get_id(temp_vdev), 712 QDF_MAC_ADDR_REF(bssid.bytes)); 713 wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_OSIF_CM_ID); 714 return -EINVAL; 715 } 716 osif_cm_dump_connect_req(dev, vdev_id, req); 717 718 status = osif_cm_reset_id_and_src(vdev); 719 if (QDF_IS_STATUS_ERROR(status)) 720 return qdf_status_to_os_return(status); 721 722 connect_req = qdf_mem_malloc(sizeof(*connect_req)); 723 if (!connect_req) 724 return -ENOMEM; 725 726 connect_req->vdev_id = vdev_id; 727 connect_req->source = CM_OSIF_CONNECT; 728 if (req->bssid) 729 qdf_mem_copy(connect_req->bssid.bytes, req->bssid, 730 QDF_MAC_ADDR_SIZE); 731 else if (bssid_hint) 732 qdf_mem_copy(connect_req->bssid_hint.bytes, req->bssid_hint, 733 QDF_MAC_ADDR_SIZE); 734 735 osif_cm_set_prev_bssid(connect_req, req); 736 737 connect_req->ssid.length = req->ssid_len; 738 if (connect_req->ssid.length > WLAN_SSID_MAX_LEN) { 739 osif_err("Invalid ssid len %zu", req->ssid_len); 740 ucfg_cm_free_connect_req(connect_req); 741 return -EINVAL; 742 } 743 744 qdf_mem_copy(connect_req->ssid.ssid, req->ssid, 745 connect_req->ssid.length); 746 747 if (req->channel) 748 connect_req->chan_freq = req->channel->center_freq; 749 750 if (req->channel_hint) 751 connect_req->chan_freq_hint = req->channel_hint->center_freq; 752 753 status = osif_cm_set_crypto_params(connect_req, req); 754 if (QDF_IS_STATUS_ERROR(status)) 755 goto connect_start_fail; 756 757 connect_req->ht_caps = req->ht_capa.cap_info; 758 connect_req->ht_caps_mask = req->ht_capa_mask.cap_info; 759 connect_req->vht_caps = req->vht_capa.vht_cap_info; 760 connect_req->vht_caps_mask = req->vht_capa_mask.vht_cap_info; 761 762 /* Copy complete ie */ 763 if (req->ie_len) { 764 connect_req->assoc_ie.len = req->ie_len; 765 connect_req->assoc_ie.ptr = qdf_mem_malloc(req->ie_len); 766 if (!connect_req->assoc_ie.ptr) { 767 connect_req->assoc_ie.len = 0; 768 status = QDF_STATUS_E_NOMEM; 769 goto connect_start_fail; 770 } 771 qdf_mem_copy(connect_req->assoc_ie.ptr, req->ie, 772 connect_req->assoc_ie.len); 773 } 774 775 status = osif_cm_set_fils_info(vdev, connect_req, req); 776 if (QDF_IS_STATUS_ERROR(status)) 777 goto connect_start_fail; 778 779 osif_cm_fill_connect_params(connect_req, params); 780 781 status = osif_update_mlo_partner_info(vdev, connect_req, req); 782 if (QDF_IS_STATUS_ERROR(status)) 783 goto connect_start_fail; 784 785 status = mlo_connect(vdev, connect_req); 786 if (QDF_IS_STATUS_ERROR(status)) 787 osif_err("Connect failed with status %d", status); 788 789 connect_start_fail: 790 ucfg_cm_free_connect_req(connect_req); 791 792 return qdf_status_to_os_return(status); 793 } 794 795 int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, 796 uint16_t reason) 797 { 798 uint8_t vdev_id = wlan_vdev_get_id(vdev); 799 QDF_STATUS status; 800 801 osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s", 802 dev->name, vdev_id, reason, 803 ucfg_cm_reason_code_to_str(reason)); 804 805 status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL); 806 if (QDF_IS_STATUS_ERROR(status)) 807 osif_err("Disconnect failed with status %d", status); 808 809 return qdf_status_to_os_return(status); 810 } 811 812 int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason) 813 { 814 uint8_t vdev_id = wlan_vdev_get_id(vdev); 815 QDF_STATUS status; 816 817 osif_info("vdevid-%d: Received Disconnect reason:%d %s", 818 vdev_id, reason, ucfg_cm_reason_code_to_str(reason)); 819 820 status = mlo_sync_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL); 821 822 return qdf_status_to_os_return(status); 823 } 824