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 *)¶ms->prev_bssid))
500 qdf_copy_macaddr(&req->prev_bssid,
501 (struct qdf_mac_addr *)¶ms->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