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