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