xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/mlme/src/osif_cm_req.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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_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 %.*s 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 			(int)req->ssid_len, req->ssid, req->auth_type,
415 			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 *)&params->prev_bssid))
456 		qdf_copy_macaddr(&req->prev_bssid,
457 				 (struct qdf_mac_addr *)&params->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_feat_ext2_cap_set(
505 					tmp_vdev, WLAN_VDEV_FEXT2_MLO_STA_LINK);
506 			wlan_vdev_set_link_id(
507 				tmp_vdev,
508 				partner_info.partner_link_info[i].link_id);
509 			osif_debug("link id %d",
510 				   tmp_vdev->vdev_mlme.mlo_link_id);
511 		}
512 	}
513 }
514 
515 static inline
516 QDF_STATUS osif_update_mlo_partner_info(
517 			struct wlan_objmgr_vdev *vdev,
518 			struct wlan_cm_connect_req *connect_req,
519 			const struct cfg80211_connect_params *req)
520 {
521 	/* Update ml partner info from connect req*/
522 	uint8_t *ptr = NULL;
523 	uint8_t *ml_ie = NULL;
524 	qdf_size_t ml_ie_len = 0;
525 	struct mlo_partner_info partner_info = {0};
526 	bool ml_ie_found = false, linkidfound = false;
527 	uint8_t linkid = 0;
528 	enum wlan_ml_variant variant;
529 	QDF_STATUS status = QDF_STATUS_SUCCESS;
530 
531 	if (!vdev || !connect_req || !req)
532 		return status;
533 
534 	if (!vdev->mlo_dev_ctx) {
535 		osif_debug("ML ctx is NULL, ignore ML IE");
536 		return QDF_STATUS_SUCCESS;
537 	}
538 
539 	osif_debug("ML IE search start");
540 	if (req->ie_len) {
541 		ptr = (uint8_t *)req->ie;
542 		status = util_find_mlie(ptr, req->ie_len, &ml_ie, &ml_ie_len);
543 		if (QDF_IS_STATUS_ERROR(status) || !ml_ie) {
544 			osif_debug("ML IE not found");
545 			/* Return success since ML is not mandatory for a
546 			 * connect request
547 			 */
548 			return QDF_STATUS_SUCCESS;
549 		}
550 
551 		osif_debug("ML IE found length %d", (int)ml_ie_len);
552 		qdf_trace_hex_dump(QDF_MODULE_ID_OS_IF, QDF_TRACE_LEVEL_DEBUG,
553 				   ml_ie, (int)ml_ie_len);
554 		ml_ie_found = true;
555 
556 		status = util_get_mlie_variant(ml_ie, ml_ie_len,
557 					       (int *)&variant);
558 		if (status != QDF_STATUS_SUCCESS) {
559 			osif_err("Unable to get Multi-Link element variant");
560 			return status;
561 		}
562 
563 		if (variant != WLAN_ML_VARIANT_BASIC) {
564 			osif_err("Invalid Multi-Link element variant %u",
565 				 variant);
566 			return status;
567 		}
568 
569 		status = util_get_bvmlie_primary_linkid(ml_ie, ml_ie_len,
570 							&linkidfound, &linkid);
571 		if (QDF_IS_STATUS_ERROR(status)) {
572 			osif_err("Unable to find primary link ID in ML IE");
573 			return status;
574 		}
575 
576 		status = util_get_bvmlie_persta_partner_info(ml_ie, ml_ie_len,
577 							     &partner_info);
578 		if (QDF_IS_STATUS_ERROR(status)) {
579 			osif_err("Unable to find per-sta profile in ML IE");
580 			return status;
581 		}
582 
583 		if (partner_info.num_partner_links >= 2) {
584 			osif_err("Rejecting connect for 3 or more link MLD");
585 			return QDF_STATUS_E_FAILURE;
586 		}
587 
588 		wlan_vdev_set_link_id(vdev, linkid);
589 		wlan_vdev_mlme_set_mlo_vdev(vdev);
590 	}
591 
592 	qdf_mem_copy(&connect_req->ml_parnter_info,
593 		     &partner_info, sizeof(struct mlo_partner_info));
594 
595 	if (ml_ie_found) {
596 		mlo_clear_connect_req_links_bmap(vdev);
597 		mlo_update_connect_req_links(vdev, 1);
598 		osif_update_partner_vdev_info(vdev, partner_info);
599 		mlo_mlme_sta_op_class(vdev, ml_ie);
600 	}
601 
602 	return QDF_STATUS_SUCCESS;
603 }
604 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
605 #else
606 static inline
607 QDF_STATUS osif_update_mlo_partner_info(
608 			struct wlan_objmgr_vdev *vdev,
609 			struct wlan_cm_connect_req *connect_req,
610 			const struct cfg80211_connect_params *req)
611 {
612 	return QDF_STATUS_SUCCESS;
613 }
614 #endif
615 
616 int osif_cm_connect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
617 		    const struct cfg80211_connect_params *req,
618 		    const struct osif_connect_params *params)
619 {
620 	struct wlan_cm_connect_req *connect_req;
621 	const u8 *bssid_hint = req->bssid_hint;
622 	uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
623 	QDF_STATUS status;
624 	struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
625 	struct wlan_objmgr_vdev *temp_vdev;
626 
627 	if (req->bssid)
628 		qdf_mem_copy(bssid.bytes, req->bssid,
629 			     QDF_MAC_ADDR_SIZE);
630 	else if (bssid_hint)
631 		qdf_mem_copy(bssid.bytes, req->bssid_hint,
632 			     QDF_MAC_ADDR_SIZE);
633 
634 	temp_vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(
635 						wlan_vdev_get_pdev(vdev),
636 						bssid.bytes,
637 						WLAN_OSIF_CM_ID);
638 
639 	if (temp_vdev) {
640 		osif_err("vdev %d already exist with same mac address"
641 			 QDF_MAC_ADDR_FMT, wlan_vdev_get_id(temp_vdev),
642 			 QDF_MAC_ADDR_REF(bssid.bytes));
643 		wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_OSIF_CM_ID);
644 		return -EINVAL;
645 	}
646 	osif_cm_dump_connect_req(dev, vdev_id, req);
647 
648 	status = osif_cm_reset_id_and_src(vdev);
649 	if (QDF_IS_STATUS_ERROR(status))
650 		return qdf_status_to_os_return(status);
651 
652 	connect_req = qdf_mem_malloc(sizeof(*connect_req));
653 	if (!connect_req)
654 		return -ENOMEM;
655 
656 	connect_req->vdev_id = vdev_id;
657 	connect_req->source = CM_OSIF_CONNECT;
658 	if (req->bssid)
659 		qdf_mem_copy(connect_req->bssid.bytes, req->bssid,
660 			     QDF_MAC_ADDR_SIZE);
661 	else if (bssid_hint)
662 		qdf_mem_copy(connect_req->bssid_hint.bytes, req->bssid_hint,
663 			     QDF_MAC_ADDR_SIZE);
664 
665 	osif_cm_set_prev_bssid(connect_req, req);
666 
667 	connect_req->ssid.length = req->ssid_len;
668 	if (connect_req->ssid.length > WLAN_SSID_MAX_LEN) {
669 		osif_err("Invalid ssid len %zu", req->ssid_len);
670 		osif_cm_free_connect_req(connect_req);
671 		return -EINVAL;
672 	}
673 
674 	qdf_mem_copy(connect_req->ssid.ssid, req->ssid,
675 		     connect_req->ssid.length);
676 
677 	if (req->channel)
678 		connect_req->chan_freq = req->channel->center_freq;
679 
680 	if (req->channel_hint)
681 		connect_req->chan_freq_hint = req->channel_hint->center_freq;
682 
683 	status = osif_cm_set_crypto_params(connect_req, req);
684 	if (QDF_IS_STATUS_ERROR(status))
685 		goto connect_start_fail;
686 
687 	connect_req->ht_caps = req->ht_capa.cap_info;
688 	connect_req->ht_caps_mask = req->ht_capa_mask.cap_info;
689 	connect_req->vht_caps = req->vht_capa.vht_cap_info;
690 	connect_req->vht_caps_mask = req->vht_capa_mask.vht_cap_info;
691 
692 	/* Copy complete ie */
693 	if (req->ie_len) {
694 		connect_req->assoc_ie.len = req->ie_len;
695 		connect_req->assoc_ie.ptr = qdf_mem_malloc(req->ie_len);
696 		if (!connect_req->assoc_ie.ptr) {
697 			connect_req->assoc_ie.len = 0;
698 			status = QDF_STATUS_E_NOMEM;
699 				goto connect_start_fail;
700 		}
701 		qdf_mem_copy(connect_req->assoc_ie.ptr, req->ie,
702 			     connect_req->assoc_ie.len);
703 	}
704 
705 	status = osif_cm_set_fils_info(vdev, connect_req, req);
706 	if (QDF_IS_STATUS_ERROR(status))
707 		goto connect_start_fail;
708 
709 	osif_cm_fill_connect_params(connect_req, params);
710 
711 	status = osif_update_mlo_partner_info(vdev, connect_req, req);
712 	if (QDF_IS_STATUS_ERROR(status))
713 		goto connect_start_fail;
714 
715 	status = mlo_connect(vdev, connect_req);
716 	if (QDF_IS_STATUS_ERROR(status))
717 		osif_err("Connect failed with status %d", status);
718 
719 connect_start_fail:
720 	osif_cm_free_connect_req(connect_req);
721 
722 	return qdf_status_to_os_return(status);
723 }
724 
725 int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
726 		       uint16_t reason)
727 {
728 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
729 	QDF_STATUS status;
730 
731 	osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s",
732 		  dev->name, vdev_id, reason,
733 		  ucfg_cm_reason_code_to_str(reason));
734 
735 	status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
736 	if (QDF_IS_STATUS_ERROR(status))
737 		osif_err("Disconnect failed with status %d", status);
738 
739 	return qdf_status_to_os_return(status);
740 }
741 
742 int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason)
743 {
744 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
745 	QDF_STATUS status;
746 
747 	osif_info("vdevid-%d: Received Disconnect reason:%d %s",
748 		  vdev_id, reason, ucfg_cm_reason_code_to_str(reason));
749 
750 	status = mlo_sync_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
751 
752 	return qdf_status_to_os_return(status);
753 }
754