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