xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/mlme/src/osif_cm_req.c (revision ea172ef154f8781b39809b88f37271c196c4c332)
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 " 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 *)&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_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 >= 2) {
583 			osif_err("Rejecting connect for 3 or more link MLD");
584 			return QDF_STATUS_E_FAILURE;
585 		}
586 
587 		wlan_vdev_set_link_id(vdev, linkid);
588 		wlan_vdev_mlme_set_mlo_vdev(vdev);
589 	}
590 
591 	qdf_mem_copy(&connect_req->ml_parnter_info,
592 		     &partner_info, sizeof(struct mlo_partner_info));
593 
594 	if (ml_ie_found) {
595 		mlo_clear_connect_req_links_bmap(vdev);
596 		mlo_update_connect_req_links(vdev, 1);
597 		osif_update_partner_vdev_info(vdev, partner_info);
598 		mlo_mlme_sta_op_class(vdev, ml_ie);
599 	}
600 
601 	return QDF_STATUS_SUCCESS;
602 }
603 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
604 #else
605 static inline
606 QDF_STATUS osif_update_mlo_partner_info(
607 			struct wlan_objmgr_vdev *vdev,
608 			struct wlan_cm_connect_req *connect_req,
609 			const struct cfg80211_connect_params *req)
610 {
611 	return QDF_STATUS_SUCCESS;
612 }
613 #endif
614 
615 int osif_cm_connect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
616 		    const struct cfg80211_connect_params *req,
617 		    const struct osif_connect_params *params)
618 {
619 	struct wlan_cm_connect_req *connect_req;
620 	const u8 *bssid_hint = req->bssid_hint;
621 	uint8_t vdev_id = vdev->vdev_objmgr.vdev_id;
622 	QDF_STATUS status;
623 	struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
624 	struct wlan_objmgr_vdev *temp_vdev;
625 
626 	if (req->bssid)
627 		qdf_mem_copy(bssid.bytes, req->bssid,
628 			     QDF_MAC_ADDR_SIZE);
629 	else if (bssid_hint)
630 		qdf_mem_copy(bssid.bytes, req->bssid_hint,
631 			     QDF_MAC_ADDR_SIZE);
632 
633 	temp_vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(
634 						wlan_vdev_get_pdev(vdev),
635 						bssid.bytes,
636 						WLAN_OSIF_CM_ID);
637 
638 	if (temp_vdev) {
639 		osif_err("vdev %d already exist with same mac address"
640 			 QDF_MAC_ADDR_FMT, wlan_vdev_get_id(temp_vdev),
641 			 QDF_MAC_ADDR_REF(bssid.bytes));
642 		wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_OSIF_CM_ID);
643 		return -EINVAL;
644 	}
645 	osif_cm_dump_connect_req(dev, vdev_id, req);
646 
647 	status = osif_cm_reset_id_and_src(vdev);
648 	if (QDF_IS_STATUS_ERROR(status))
649 		return qdf_status_to_os_return(status);
650 
651 	connect_req = qdf_mem_malloc(sizeof(*connect_req));
652 	if (!connect_req)
653 		return -ENOMEM;
654 
655 	connect_req->vdev_id = vdev_id;
656 	connect_req->source = CM_OSIF_CONNECT;
657 	if (req->bssid)
658 		qdf_mem_copy(connect_req->bssid.bytes, req->bssid,
659 			     QDF_MAC_ADDR_SIZE);
660 	else if (bssid_hint)
661 		qdf_mem_copy(connect_req->bssid_hint.bytes, req->bssid_hint,
662 			     QDF_MAC_ADDR_SIZE);
663 
664 	osif_cm_set_prev_bssid(connect_req, req);
665 
666 	connect_req->ssid.length = req->ssid_len;
667 	if (connect_req->ssid.length > WLAN_SSID_MAX_LEN) {
668 		osif_err("Invalid ssid len %zu", req->ssid_len);
669 		osif_cm_free_connect_req(connect_req);
670 		return -EINVAL;
671 	}
672 
673 	qdf_mem_copy(connect_req->ssid.ssid, req->ssid,
674 		     connect_req->ssid.length);
675 
676 	if (req->channel)
677 		connect_req->chan_freq = req->channel->center_freq;
678 
679 	if (req->channel_hint)
680 		connect_req->chan_freq_hint = req->channel_hint->center_freq;
681 
682 	status = osif_cm_set_crypto_params(connect_req, req);
683 	if (QDF_IS_STATUS_ERROR(status))
684 		goto connect_start_fail;
685 
686 	connect_req->ht_caps = req->ht_capa.cap_info;
687 	connect_req->ht_caps_mask = req->ht_capa_mask.cap_info;
688 	connect_req->vht_caps = req->vht_capa.vht_cap_info;
689 	connect_req->vht_caps_mask = req->vht_capa_mask.vht_cap_info;
690 
691 	/* Copy complete ie */
692 	if (req->ie_len) {
693 		connect_req->assoc_ie.len = req->ie_len;
694 		connect_req->assoc_ie.ptr = qdf_mem_malloc(req->ie_len);
695 		if (!connect_req->assoc_ie.ptr) {
696 			connect_req->assoc_ie.len = 0;
697 			status = QDF_STATUS_E_NOMEM;
698 				goto connect_start_fail;
699 		}
700 		qdf_mem_copy(connect_req->assoc_ie.ptr, req->ie,
701 			     connect_req->assoc_ie.len);
702 	}
703 
704 	status = osif_cm_set_fils_info(vdev, connect_req, req);
705 	if (QDF_IS_STATUS_ERROR(status))
706 		goto connect_start_fail;
707 
708 	osif_cm_fill_connect_params(connect_req, params);
709 
710 	status = osif_update_mlo_partner_info(vdev, connect_req, req);
711 	if (QDF_IS_STATUS_ERROR(status))
712 		goto connect_start_fail;
713 
714 	status = mlo_connect(vdev, connect_req);
715 	if (QDF_IS_STATUS_ERROR(status))
716 		osif_err("Connect failed with status %d", status);
717 
718 connect_start_fail:
719 	osif_cm_free_connect_req(connect_req);
720 
721 	return qdf_status_to_os_return(status);
722 }
723 
724 int osif_cm_disconnect(struct net_device *dev, struct wlan_objmgr_vdev *vdev,
725 		       uint16_t reason)
726 {
727 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
728 	QDF_STATUS status;
729 
730 	osif_info("%s(vdevid-%d): Received Disconnect reason:%d %s",
731 		  dev->name, vdev_id, reason,
732 		  ucfg_cm_reason_code_to_str(reason));
733 
734 	status = mlo_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
735 	if (QDF_IS_STATUS_ERROR(status))
736 		osif_err("Disconnect failed with status %d", status);
737 
738 	return qdf_status_to_os_return(status);
739 }
740 
741 int osif_cm_disconnect_sync(struct wlan_objmgr_vdev *vdev, uint16_t reason)
742 {
743 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
744 	QDF_STATUS status;
745 
746 	osif_info("vdevid-%d: Received Disconnect reason:%d %s",
747 		  vdev_id, reason, ucfg_cm_reason_code_to_str(reason));
748 
749 	status = mlo_sync_disconnect(vdev, CM_OSIF_DISCONNECT, reason, NULL);
750 
751 	return qdf_status_to_os_return(status);
752 }
753