1 /* 2 * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * DOC: osif_cm_req.c 19 * 20 * This file maintains definitaions of connect, disconnect, roam 21 * request apis. 22 */ 23 24 #include "wlan_osif_priv.h" 25 #include "osif_cm_req.h" 26 #include "wlan_cm_ucfg_api.h" 27 #include "wlan_nl_to_crypto_params.h" 28 #include <wlan_cfg80211.h> 29 #include "osif_cm_util.h" 30 #ifdef WLAN_FEATURE_FILS_SK 31 #include <wlan_mlme_ucfg_api.h> 32 #endif 33 #include <wlan_mlo_mgr_sta.h> 34 35 static void osif_cm_free_wep_key_params(struct wlan_cm_connect_req *connect_req) 36 { 37 if (connect_req->crypto.wep_keys.key) { 38 qdf_mem_zero(connect_req->crypto.wep_keys.key, 39 connect_req->crypto.wep_keys.key_len); 40 qdf_mem_free(connect_req->crypto.wep_keys.key); 41 connect_req->crypto.wep_keys.key = NULL; 42 } 43 if (connect_req->crypto.wep_keys.seq) { 44 qdf_mem_zero(connect_req->crypto.wep_keys.seq, 45 connect_req->crypto.wep_keys.seq_len); 46 qdf_mem_free(connect_req->crypto.wep_keys.seq); 47 connect_req->crypto.wep_keys.seq = NULL; 48 } 49 } 50 51 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) 52 static QDF_STATUS 53 osif_cm_update_wep_seq_info(struct wlan_cm_connect_req *connect_req, 54 const struct cfg80211_connect_params *req) 55 { 56 if (req->crypto.wep_keys->seq_len) { 57 connect_req->crypto.wep_keys.seq_len = 58 req->crypto.wep_keys->seq_len; 59 connect_req->crypto.wep_keys.seq = 60 qdf_mem_malloc(connect_req->crypto.wep_keys.seq_len); 61 if (!connect_req->crypto.wep_keys.seq) { 62 osif_cm_free_wep_key_params(connect_req); 63 return QDF_STATUS_E_NOMEM; 64 } 65 qdf_mem_copy(connect_req->crypto.wep_keys.seq, 66 req->crypto.wep_keys->seq, 67 connect_req->crypto.wep_keys.seq_len); 68 } 69 return QDF_STATUS_SUCCESS; 70 } 71 #else 72 static inline QDF_STATUS 73 osif_cm_update_wep_seq_info(struct wlan_cm_connect_req *connect_req, 74 const struct cfg80211_connect_params *req) 75 { 76 return QDF_STATUS_SUCCESS; 77 } 78 #endif 79 80 static QDF_STATUS 81 osif_cm_set_wep_key_params(struct wlan_cm_connect_req *connect_req, 82 const struct cfg80211_connect_params *req) 83 { 84 if (!req->key_len) 85 return QDF_STATUS_SUCCESS; 86 87 connect_req->crypto.wep_keys.key_len = req->key_len; 88 connect_req->crypto.wep_keys.key_idx = req->key_idx; 89 90 connect_req->crypto.wep_keys.key = 91 qdf_mem_malloc(connect_req->crypto.wep_keys.key_len); 92 if (!connect_req->crypto.wep_keys.key) 93 return QDF_STATUS_E_NOMEM; 94 95 qdf_mem_copy(connect_req->crypto.wep_keys.key, req->key, 96 connect_req->crypto.wep_keys.key_len); 97 98 return osif_cm_update_wep_seq_info(connect_req, req); 99 } 100 101 static void osif_cm_set_auth_type(struct wlan_cm_connect_req *connect_req, 102 const struct cfg80211_connect_params *req) 103 { 104 wlan_crypto_auth_mode crypto_auth_type = 105 osif_nl_to_crypto_auth_type(req->auth_type); 106 107 /* For auto check wpa version to decide WPA or RSNA */ 108 if (crypto_auth_type == WLAN_CRYPTO_AUTH_AUTO && 109 req->crypto.wpa_versions) { 110 if (req->crypto.wpa_versions & NL80211_WPA_VERSION_1) 111 crypto_auth_type = WLAN_CRYPTO_AUTH_WPA; 112 else 113 crypto_auth_type = WLAN_CRYPTO_AUTH_RSNA; 114 } else if (!req->crypto.n_ciphers_pairwise) { 115 crypto_auth_type = WLAN_CRYPTO_AUTH_OPEN; 116 } 117 118 QDF_SET_PARAM(connect_req->crypto.auth_type, crypto_auth_type); 119 } 120 121 static 122 QDF_STATUS osif_cm_set_crypto_params(struct wlan_cm_connect_req *connect_req, 123 const struct cfg80211_connect_params *req) 124 { 125 uint32_t i = 0; 126 QDF_STATUS status; 127 wlan_crypto_cipher_type cipher = WLAN_CRYPTO_CIPHER_NONE; 128 wlan_crypto_key_mgmt akm; 129 130 connect_req->crypto.wpa_versions = req->crypto.wpa_versions; 131 132 osif_cm_set_auth_type(connect_req, req); 133 134 if (req->crypto.cipher_group) 135 cipher = 136 osif_nl_to_crypto_cipher_type(req->crypto.cipher_group); 137 138 QDF_SET_PARAM(connect_req->crypto.group_cipher, cipher); 139 140 /* Fill Pairwise ciphers */ 141 if (req->crypto.n_ciphers_pairwise) { 142 for (i = 0; i < req->crypto.n_ciphers_pairwise && 143 i < NL80211_MAX_NR_CIPHER_SUITES; i++) { 144 cipher = osif_nl_to_crypto_cipher_type( 145 req->crypto.ciphers_pairwise[i]); 146 QDF_SET_PARAM(connect_req->crypto.ciphers_pairwise, 147 cipher); 148 } 149 } else { 150 QDF_SET_PARAM(connect_req->crypto.ciphers_pairwise, 151 WLAN_CRYPTO_CIPHER_NONE); 152 } 153 154 /* Fill AKM suites */ 155 if (req->crypto.n_akm_suites) { 156 for (i = 0; i < req->crypto.n_akm_suites && 157 i < NL80211_MAX_NR_AKM_SUITES; i++) { 158 akm = osif_nl_to_crypto_akm_type( 159 req->crypto.akm_suites[i]); 160 QDF_SET_PARAM(connect_req->crypto.akm_suites, akm); 161 } 162 } else { 163 QDF_SET_PARAM(connect_req->crypto.akm_suites, 164 WLAN_CRYPTO_KEY_MGMT_NONE); 165 } 166 167 /* Fill WEP Key information */ 168 status = osif_cm_set_wep_key_params(connect_req, req); 169 if (QDF_IS_STATUS_ERROR(status)) 170 osif_err("set wep key params failed"); 171 172 return status; 173 } 174 175 #ifdef WLAN_FEATURE_FILS_SK 176 static bool osif_cm_is_akm_suite_fils(uint32_t key_mgmt) 177 { 178 switch (key_mgmt) { 179 case WLAN_AKM_SUITE_FILS_SHA256: 180 case WLAN_AKM_SUITE_FILS_SHA384: 181 case WLAN_AKM_SUITE_FT_FILS_SHA256: 182 case WLAN_AKM_SUITE_FT_FILS_SHA384: 183 return true; 184 default: 185 return false; 186 } 187 } 188 189 static bool osif_cm_is_conn_type_fils(struct wlan_cm_connect_req *connect_req, 190 const struct cfg80211_connect_params *req) 191 { 192 int num_akm_suites = req->crypto.n_akm_suites; 193 uint32_t key_mgmt = req->crypto.akm_suites[0]; 194 195 if (num_akm_suites <= 0) 196 return false; 197 198 /* 199 * Auth type will be either be OPEN or FILS type for a FILS connection 200 */ 201 if (connect_req->fils_info.auth_type == FILS_PK_MAX && 202 req->auth_type != NL80211_AUTHTYPE_OPEN_SYSTEM) 203 return false; 204 205 if (!osif_cm_is_akm_suite_fils(key_mgmt)) 206 return false; 207 208 osif_debug("Fils Auth %d AKM %d", req->auth_type, key_mgmt); 209 210 return true; 211 } 212 213 enum wlan_fils_auth_type 214 osif_cm_get_fils_auth_type(enum nl80211_auth_type auth) 215 { 216 switch (auth) { 217 case NL80211_AUTHTYPE_FILS_SK: 218 return FILS_SK_WITHOUT_PFS; 219 case NL80211_AUTHTYPE_FILS_SK_PFS: 220 return FILS_SK_WITH_PFS; 221 case NL80211_AUTHTYPE_FILS_PK: 222 return FILS_PK_AUTH; 223 default: 224 return FILS_PK_MAX; 225 } 226 } 227 228 static QDF_STATUS 229 osif_cm_set_fils_info(struct wlan_objmgr_vdev *vdev, 230 struct wlan_cm_connect_req *connect_req, 231 const struct cfg80211_connect_params *req) 232 { 233 bool value = 0; 234 QDF_STATUS status; 235 uint8_t *buf; 236 struct wlan_objmgr_psoc *psoc; 237 238 psoc = wlan_vdev_get_psoc(vdev); 239 if (!psoc) 240 return -QDF_STATUS_E_INVAL; 241 242 connect_req->fils_info.auth_type = 243 osif_cm_get_fils_auth_type(req->auth_type); 244 connect_req->fils_info.is_fils_connection = 245 osif_cm_is_conn_type_fils(connect_req, 246 req); 247 osif_debug("auth type %d is fils %d", 248 connect_req->fils_info.auth_type, 249 connect_req->fils_info.is_fils_connection); 250 if (!connect_req->fils_info.is_fils_connection) 251 return QDF_STATUS_SUCCESS; 252 253 status = ucfg_mlme_get_fils_enabled_info(psoc, &value); 254 if (QDF_IS_STATUS_ERROR(status) || !value) { 255 osif_err("get_fils_enabled status: %d fils_enabled: %d", 256 status, value); 257 return QDF_STATUS_E_INVAL; 258 } 259 260 /* 261 * The initial connection for FILS may happen with an OPEN 262 * auth type. Hence we need to allow the connection to go 263 * through in that case as well. 264 */ 265 if (req->auth_type != NL80211_AUTHTYPE_FILS_SK) { 266 osif_debug("set is fils false for initial connection"); 267 connect_req->fils_info.is_fils_connection = false; 268 return QDF_STATUS_SUCCESS; 269 } 270 271 connect_req->fils_info.realm_len = req->fils_erp_realm_len; 272 273 if (connect_req->fils_info.realm_len > WLAN_CM_FILS_MAX_REALM_LEN) { 274 osif_err("Invalid fils realm len %d", 275 connect_req->fils_info.realm_len); 276 return QDF_STATUS_E_INVAL; 277 } 278 qdf_mem_zero(connect_req->fils_info.realm, WLAN_CM_FILS_MAX_REALM_LEN); 279 qdf_mem_copy(connect_req->fils_info.realm, req->fils_erp_realm, 280 connect_req->fils_info.realm_len); 281 282 connect_req->fils_info.next_seq_num = req->fils_erp_next_seq_num + 1; 283 284 connect_req->fils_info.rrk_len = req->fils_erp_rrk_len; 285 286 if (connect_req->fils_info.rrk_len > WLAN_CM_FILS_MAX_RRK_LENGTH) { 287 osif_err("Invalid fils rrk len %d", 288 connect_req->fils_info.rrk_len); 289 return QDF_STATUS_E_INVAL; 290 } 291 qdf_mem_zero(connect_req->fils_info.rrk, WLAN_CM_FILS_MAX_RRK_LENGTH); 292 qdf_mem_copy(connect_req->fils_info.rrk, req->fils_erp_rrk, 293 connect_req->fils_info.rrk_len); 294 295 connect_req->fils_info.username_len = req->fils_erp_username_len + 296 sizeof(char) + req->fils_erp_realm_len; 297 osif_debug("usrname len %d = usrname recv len %zu + realm len %d + %zu", 298 connect_req->fils_info.username_len, 299 req->fils_erp_username_len, 300 connect_req->fils_info.realm_len, sizeof(char)); 301 302 if (connect_req->fils_info.username_len > 303 WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH) { 304 osif_err("Invalid fils username len %d", 305 connect_req->fils_info.username_len); 306 return QDF_STATUS_E_INVAL; 307 } 308 if (!req->fils_erp_username_len) { 309 osif_info("FILS_PMKSA: No ERP username, return success"); 310 return QDF_STATUS_SUCCESS; 311 } 312 buf = connect_req->fils_info.username; 313 qdf_mem_zero(connect_req->fils_info.username, 314 WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH); 315 qdf_mem_copy(buf, req->fils_erp_username, req->fils_erp_username_len); 316 buf += req->fils_erp_username_len; 317 *buf++ = '@'; 318 qdf_mem_copy(buf, req->fils_erp_realm, req->fils_erp_realm_len); 319 320 return QDF_STATUS_SUCCESS; 321 } 322 #else 323 static inline 324 QDF_STATUS osif_cm_set_fils_info(struct wlan_objmgr_vdev *vdev, 325 struct wlan_cm_connect_req *connect_req, 326 const struct cfg80211_connect_params *req) 327 { 328 return QDF_STATUS_SUCCESS; 329 } 330 #endif 331 332 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) 333 static inline void 334 osif_cm_set_prev_bssid(struct wlan_cm_connect_req *connect_req, 335 const struct cfg80211_connect_params *req) 336 { 337 if (req->prev_bssid) 338 qdf_mem_copy(connect_req->prev_bssid.bytes, req->prev_bssid, 339 QDF_MAC_ADDR_SIZE); 340 } 341 342 static inline 343 void osif_cm_dump_prev_bssid(const struct cfg80211_connect_params *req) 344 { 345 if (req->prev_bssid) 346 osif_nofl_debug("prev BSSID "QDF_MAC_ADDR_FMT, 347 QDF_MAC_ADDR_REF(req->prev_bssid)); 348 } 349 350 #else 351 static inline void 352 osif_cm_set_prev_bssid(struct wlan_cm_connect_req *connect_req, 353 const struct cfg80211_connect_params *req) 354 { 355 } 356 357 static inline 358 void osif_cm_dump_prev_bssid(const struct cfg80211_connect_params *req) 359 { 360 } 361 362 #endif 363 364 static inline void 365 osif_cm_dump_connect_req(struct net_device *dev, uint8_t vdev_id, 366 const struct cfg80211_connect_params *req) 367 { 368 uint32_t i; 369 370 osif_nofl_debug("connect req for %s(vdevid-%d) freq %d SSID %.*s auth type %d WPA ver %d n_akm %d n_cipher %d grp_cipher %x mfp %d freq hint %d", 371 dev->name, vdev_id, 372 req->channel ? req->channel->center_freq : 0, 373 (int)req->ssid_len, req->ssid, req->auth_type, 374 req->crypto.wpa_versions, 375 req->crypto.n_akm_suites, 376 req->crypto.n_ciphers_pairwise, 377 req->crypto.cipher_group, req->mfp, 378 req->channel_hint ? req->channel_hint->center_freq : 0); 379 if (req->bssid) 380 osif_nofl_debug("BSSID "QDF_MAC_ADDR_FMT, 381 QDF_MAC_ADDR_REF(req->bssid)); 382 if (req->bssid_hint) 383 osif_nofl_debug("BSSID hint "QDF_MAC_ADDR_FMT, 384 QDF_MAC_ADDR_REF(req->bssid_hint)); 385 osif_cm_dump_prev_bssid(req); 386 387 for (i = 0; i < req->crypto.n_akm_suites; i++) 388 osif_nofl_debug("akm[%d] = %x", i, req->crypto.akm_suites[i]); 389 390 for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) 391 osif_nofl_debug("cipher_pairwise[%d] = %x", i, 392 req->crypto.ciphers_pairwise[i]); 393 } 394 395 static void 396 osif_cm_fill_connect_params(struct wlan_cm_connect_req *req, 397 const struct osif_connect_params *params) 398 { 399 if (!params) 400 return; 401 402 if (params->scan_ie.len) { 403 req->scan_ie.ptr = qdf_mem_malloc(params->scan_ie.len); 404 if (req->scan_ie.ptr) { 405 qdf_mem_copy(req->scan_ie.ptr, params->scan_ie.ptr, 406 params->scan_ie.len); 407 req->scan_ie.len = params->scan_ie.len; 408 } 409 } 410 req->dot11mode_filter = params->dot11mode_filter; 411 req->force_rsne_override = params->force_rsne_override; 412 req->sae_pwe = params->sae_pwe; 413 414 if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms->prev_bssid)) 415 qdf_copy_macaddr(&req->prev_bssid, 416 (struct qdf_mac_addr *)¶ms->prev_bssid); 417 } 418 419 static void osif_cm_free_connect_req(struct wlan_cm_connect_req *connect_req) 420 { 421 if (connect_req->scan_ie.ptr) { 422 qdf_mem_free(connect_req->scan_ie.ptr); 423 connect_req->scan_ie.ptr = NULL; 424 } 425 426 if (connect_req->assoc_ie.ptr) { 427 qdf_mem_free(connect_req->assoc_ie.ptr); 428 connect_req->assoc_ie.ptr = NULL; 429 } 430 431 osif_cm_free_wep_key_params(connect_req); 432 qdf_mem_free(connect_req); 433 } 434 435 #ifdef WLAN_FEATURE_11BE_MLO 436 static inline 437 void osif_update_mlo_partner_info(struct wlan_cm_connect_req *connect_req, 438 const struct cfg80211_connect_params *req) 439 { 440 //Update ml partner info in connect_req 441 } 442 #else 443 static inline 444 void osif_update_mlo_partner_info(struct wlan_cm_connect_req *connect_req, 445 const struct cfg80211_connect_params *req) 446 { 447 } 448 #endif 449 450 int osif_cm_connect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, 451 const struct cfg80211_connect_params *req, 452 const struct osif_connect_params *params) 453 { 454 struct wlan_cm_connect_req *connect_req; 455 const u8 *bssid_hint = req->bssid_hint; 456 uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; 457 QDF_STATUS status; 458 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; 459 struct wlan_objmgr_vdev *temp_vdev; 460 461 if (req->bssid) 462 qdf_mem_copy(bssid.bytes, req->bssid, 463 QDF_MAC_ADDR_SIZE); 464 else if (bssid_hint) 465 qdf_mem_copy(bssid.bytes, req->bssid_hint, 466 QDF_MAC_ADDR_SIZE); 467 468 temp_vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev( 469 wlan_vdev_get_pdev(vdev), 470 bssid.bytes, 471 WLAN_OSIF_CM_ID); 472 473 if (temp_vdev) { 474 osif_err("vdev %d already exist with same mac address" 475 QDF_MAC_ADDR_FMT, wlan_vdev_get_id(temp_vdev), 476 QDF_MAC_ADDR_REF(bssid.bytes)); 477 wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_OSIF_CM_ID); 478 return -EINVAL; 479 } 480 osif_cm_dump_connect_req(dev, vdev_id, req); 481 482 status = osif_cm_reset_id_and_src(vdev); 483 if (QDF_IS_STATUS_ERROR(status)) 484 return qdf_status_to_os_return(status); 485 486 connect_req = qdf_mem_malloc(sizeof(*connect_req)); 487 if (!connect_req) 488 return -ENOMEM; 489 490 connect_req->vdev_id = vdev_id; 491 connect_req->source = CM_OSIF_CONNECT; 492 if (req->bssid) 493 qdf_mem_copy(connect_req->bssid.bytes, req->bssid, 494 QDF_MAC_ADDR_SIZE); 495 else if (bssid_hint) 496 qdf_mem_copy(connect_req->bssid_hint.bytes, req->bssid_hint, 497 QDF_MAC_ADDR_SIZE); 498 499 osif_cm_set_prev_bssid(connect_req, req); 500 501 connect_req->ssid.length = req->ssid_len; 502 if (connect_req->ssid.length > WLAN_SSID_MAX_LEN) { 503 osif_err("Invalid ssid len %zu", req->ssid_len); 504 osif_cm_free_connect_req(connect_req); 505 return -EINVAL; 506 } 507 508 qdf_mem_copy(connect_req->ssid.ssid, req->ssid, 509 connect_req->ssid.length); 510 511 if (req->channel) 512 connect_req->chan_freq = req->channel->center_freq; 513 514 if (req->channel_hint) 515 connect_req->chan_freq_hint = req->channel_hint->center_freq; 516 517 status = osif_cm_set_crypto_params(connect_req, req); 518 if (QDF_IS_STATUS_ERROR(status)) 519 goto connect_start_fail; 520 521 connect_req->ht_caps = req->ht_capa.cap_info; 522 connect_req->ht_caps_mask = req->ht_capa_mask.cap_info; 523 connect_req->vht_caps = req->vht_capa.vht_cap_info; 524 connect_req->vht_caps_mask = req->vht_capa_mask.vht_cap_info; 525 526 /* Copy complete ie */ 527 if (req->ie_len) { 528 connect_req->assoc_ie.len = req->ie_len; 529 connect_req->assoc_ie.ptr = qdf_mem_malloc(req->ie_len); 530 if (!connect_req->assoc_ie.ptr) { 531 connect_req->assoc_ie.len = 0; 532 status = QDF_STATUS_E_NOMEM; 533 goto connect_start_fail; 534 } 535 qdf_mem_copy(connect_req->assoc_ie.ptr, req->ie, 536 connect_req->assoc_ie.len); 537 } 538 539 status = osif_cm_set_fils_info(vdev, connect_req, req); 540 if (QDF_IS_STATUS_ERROR(status)) 541 goto connect_start_fail; 542 543 osif_cm_fill_connect_params(connect_req, params); 544 545 osif_update_mlo_partner_info(connect_req, req); 546 547 status = mlo_connect(vdev, connect_req); 548 if (QDF_IS_STATUS_ERROR(status)) 549 osif_err("Connect failed with status %d", status); 550 551 connect_start_fail: 552 osif_cm_free_connect_req(connect_req); 553 554 return qdf_status_to_os_return(status); 555 } 556 557 static QDF_STATUS osif_cm_send_disconnect(struct wlan_objmgr_vdev *vdev, 558 uint16_t reason) 559 { 560 QDF_STATUS status; 561 562 status = osif_cm_reset_id_and_src(vdev); 563 if (QDF_IS_STATUS_ERROR(status)) 564 return qdf_status_to_os_return(status); 565 566 status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL); 567 568 return status; 569 } 570 571 int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev, 572 uint16_t reason) 573 { 574 uint8_t vdev_id = wlan_vdev_get_id(vdev); 575 QDF_STATUS status; 576 577 osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s", 578 dev->name, vdev_id, reason, 579 ucfg_cm_reason_code_to_str(reason)); 580 581 status = osif_cm_send_disconnect(vdev, reason); 582 if (QDF_IS_STATUS_ERROR(status)) 583 osif_err("Disconnect failed with status %d", status); 584 585 return qdf_status_to_os_return(status); 586 } 587 588 int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason) 589 { 590 uint8_t vdev_id = wlan_vdev_get_id(vdev); 591 QDF_STATUS status; 592 593 osif_info("vdevid-%d: Received Disconnect reason:%d %s", 594 vdev_id, reason, ucfg_cm_reason_code_to_str(reason)); 595 596 status = mlo_sync_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL); 597 598 return qdf_status_to_os_return(status); 599 } 600