xref: /wlan-driver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2011-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: Implements general Roam utils for connection manager
20  */
21 
22 #include "wlan_cm_main.h"
23 #include "wlan_cm_roam_sm.h"
24 #include "wlan_cm_sm.h"
25 #include "wlan_cm_main_api.h"
26 #include "wlan_cm_roam.h"
27 #include <wlan_scan_api.h>
28 
cm_free_roam_req_mem(struct cm_roam_req * roam_req)29 void cm_free_roam_req_mem(struct cm_roam_req *roam_req)
30 {
31 	if (roam_req->candidate_list)
32 		wlan_scan_purge_results(roam_req->candidate_list);
33 }
34 
35 #ifndef CONN_MGR_ADV_FEATURE
cm_fill_roam_vdev_crypto_params(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_req * req)36 static void cm_fill_roam_vdev_crypto_params(struct cnx_mgr *cm_ctx,
37 					    struct wlan_cm_connect_req *req)
38 {
39 	cm_fill_vdev_crypto_params(cm_ctx, req);
40 }
41 #else
cm_fill_roam_vdev_crypto_params(struct cnx_mgr * cm_ctx,struct wlan_cm_connect_req * req)42 static void cm_fill_roam_vdev_crypto_params(struct cnx_mgr *cm_ctx,
43 					    struct wlan_cm_connect_req *req)
44 {
45 }
46 #endif /* CONN_MGR_ADV_FEATURE */
47 
48 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
cm_check_and_prepare_roam_req(struct cnx_mgr * cm_ctx,struct cm_connect_req * connect_req,struct cm_req ** roam_req)49 QDF_STATUS cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx,
50 					 struct cm_connect_req *connect_req,
51 					 struct cm_req **roam_req)
52 {
53 	QDF_STATUS status;
54 	struct wlan_cm_connect_req *req;
55 	struct qdf_mac_addr bssid;
56 	struct qdf_mac_addr bss_mld_addr = {0};
57 	struct wlan_ssid ssid;
58 	struct cm_req *cm_req, *req_ptr;
59 	qdf_freq_t freq = 0;
60 
61 	/* Handle only if roam is enabled */
62 	if (!cm_is_roam_enabled(wlan_vdev_get_psoc(cm_ctx->vdev)))
63 		return QDF_STATUS_E_NOSUPPORT;
64 
65 	cm_req = qdf_container_of(connect_req, struct cm_req, connect_req);
66 	req = &connect_req->req;
67 
68 	if (req->chan_freq)
69 		freq = req->chan_freq;
70 	else if (req->chan_freq_hint)
71 		freq = req->chan_freq_hint;
72 	/*
73 	 * Reject re-assoc unless freq along with prev bssid and one
74 	 * of bssid or bssid hint is present.
75 	 */
76 	if (!cm_is_connect_req_reassoc(req))
77 		return QDF_STATUS_E_FAILURE;
78 
79 	wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);
80 	/* Reject re-assoc unless prev_bssid matches the current BSSID. */
81 	if (!qdf_is_macaddr_equal(&req->prev_bssid, &bssid)) {
82 		mlme_debug("BSSID didn't matched: bssid: "QDF_MAC_ADDR_FMT " prev bssid: " QDF_MAC_ADDR_FMT,
83 			   QDF_MAC_ADDR_REF(bssid.bytes),
84 			   QDF_MAC_ADDR_REF(req->prev_bssid.bytes));
85 		status = wlan_vdev_get_bss_peer_mld_mac(cm_ctx->vdev,
86 							&bss_mld_addr);
87 		if (!(QDF_IS_STATUS_SUCCESS(status) &&
88 		      qdf_is_macaddr_equal(&req->prev_bssid, &bss_mld_addr))) {
89 			mlme_debug("BSSID didn't matched: bss mld: "QDF_MAC_ADDR_FMT " prev bssid: " QDF_MAC_ADDR_FMT,
90 				   QDF_MAC_ADDR_REF(bss_mld_addr.bytes),
91 				   QDF_MAC_ADDR_REF(req->prev_bssid.bytes));
92 			return QDF_STATUS_E_FAILURE;
93 		}
94 	}
95 
96 	status = wlan_vdev_mlme_get_ssid(cm_ctx->vdev, ssid.ssid, &ssid.length);
97 	if (QDF_IS_STATUS_ERROR(status)) {
98 		mlme_err("failed to get ssid");
99 		return QDF_STATUS_E_FAILURE;
100 	}
101 
102 	/* Reject re-assoc unless ssid matches. */
103 	if (ssid.length != req->ssid.length ||
104 	    qdf_mem_cmp(ssid.ssid, req->ssid.ssid, ssid.length)) {
105 		mlme_debug("SSID didn't matched: self ssid: \"" QDF_SSID_FMT "\", ssid in req: \"" QDF_SSID_FMT "\"",
106 			   QDF_SSID_REF(ssid.length, ssid.ssid),
107 			   QDF_SSID_REF(req->ssid.length, req->ssid.ssid));
108 		return QDF_STATUS_E_FAILURE;
109 	}
110 
111 	/* fill roam_req for roaming and free cm_req */
112 	*roam_req = qdf_mem_malloc(sizeof(**roam_req));
113 	if (!*roam_req)
114 		return QDF_STATUS_E_NOMEM;
115 
116 	req_ptr = *roam_req;
117 	if (!qdf_is_macaddr_zero(&req->bssid))
118 		qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, &req->bssid);
119 	else
120 		qdf_copy_macaddr(&req_ptr->roam_req.req.bssid,
121 				 &req->bssid_hint);
122 
123 	qdf_copy_macaddr(&req_ptr->roam_req.req.prev_bssid, &req->prev_bssid);
124 	cm_fill_roam_vdev_crypto_params(cm_ctx, &connect_req->req);
125 	req_ptr->roam_req.req.chan_freq = freq;
126 	req_ptr->roam_req.req.source = CM_ROAMING_HOST;
127 
128 	/* Free the connect req, as reassoc is tried */
129 	cm_free_connect_req_mem(connect_req);
130 	qdf_mem_free(cm_req);
131 
132 	return QDF_STATUS_SUCCESS;
133 }
134 
cm_add_roam_req_to_list(struct cnx_mgr * cm_ctx,struct cm_req * cm_req)135 QDF_STATUS cm_add_roam_req_to_list(struct cnx_mgr *cm_ctx,
136 				   struct cm_req *cm_req)
137 {
138 	QDF_STATUS status;
139 
140 	cm_req->roam_req.cm_id =
141 			cm_get_cm_id(cm_ctx, cm_req->roam_req.req.source);
142 	cm_req->cm_id = cm_req->roam_req.cm_id;
143 	cm_req->roam_req.req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
144 	status =
145 	    cm_add_req_to_list_and_indicate_osif(cm_ctx, cm_req,
146 						 cm_req->roam_req.req.source);
147 
148 	return status;
149 }
150 
151 QDF_STATUS
cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr * cm_ctx,wlan_cm_id cm_id,struct wlan_cm_connect_resp * resp)152 cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
153 				      wlan_cm_id cm_id,
154 				      struct wlan_cm_connect_resp *resp)
155 {
156 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
157 	struct cm_req *cm_req;
158 	uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
159 	struct wlan_cm_roam_req *req;
160 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
161 	struct scan_cache_node *candidate;
162 	struct scan_cache_entry *entry;
163 
164 	if (prefix != ROAM_REQ_PREFIX)
165 		return QDF_STATUS_E_INVAL;
166 
167 	cm_req_lock_acquire(cm_ctx);
168 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
169 	while (cur_node) {
170 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
171 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
172 
173 		if (cm_req->cm_id != cm_id) {
174 			cur_node = next_node;
175 			next_node = NULL;
176 			continue;
177 		}
178 
179 		status = QDF_STATUS_SUCCESS;
180 
181 		req = &cm_req->roam_req.req;
182 		resp->freq = req->chan_freq;
183 		wlan_vdev_mlme_get_ssid(cm_ctx->vdev, resp->ssid.ssid,
184 					&resp->ssid.length);
185 
186 		if (qdf_is_macaddr_zero(&req->bssid))
187 			break;
188 
189 		candidate = cm_req->roam_req.cur_candidate;
190 		qdf_copy_macaddr(&resp->bssid, &req->bssid);
191 		if (candidate) {
192 			entry = candidate->entry;
193 			cm_connect_resp_fill_mld_addr_from_candidate(cm_ctx->vdev,
194 								     entry, resp);
195 		}
196 		break;
197 	}
198 	cm_req_lock_release(cm_ctx);
199 
200 	return status;
201 }
202 
cm_is_roam_enabled(struct wlan_objmgr_psoc * psoc)203 bool cm_is_roam_enabled(struct wlan_objmgr_psoc *psoc)
204 {
205 	if (cm_roam_offload_enabled(psoc) || cm_is_host_roam_enabled())
206 		return true;
207 
208 	mlme_rl_debug("All roam mode (offload %d, host %d) are disabled",
209 		      cm_roam_offload_enabled(psoc), cm_is_host_roam_enabled());
210 
211 	return false;
212 }
213 #endif
214 
215 #ifdef WLAN_FEATURE_HOST_ROAM
cm_get_active_reassoc_req(struct wlan_objmgr_vdev * vdev,struct wlan_cm_vdev_reassoc_req * req)216 bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
217 			       struct wlan_cm_vdev_reassoc_req *req)
218 {
219 	struct cnx_mgr *cm_ctx;
220 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
221 	struct cm_req *cm_req = NULL;
222 	bool status = false;
223 	uint32_t cm_id_prefix;
224 
225 	cm_ctx = cm_get_cm_ctx(vdev);
226 	if (!cm_ctx)
227 		return status;
228 
229 	cm_req_lock_acquire(cm_ctx);
230 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
231 	while (cur_node) {
232 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
233 
234 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
235 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
236 
237 		if (cm_req->cm_id == cm_ctx->active_cm_id &&
238 		    cm_id_prefix == ROAM_REQ_PREFIX) {
239 			req->vdev_id = wlan_vdev_get_id(vdev);
240 			req->cm_id = cm_req->roam_req.cm_id;
241 			qdf_copy_macaddr(&req->prev_bssid,
242 					 &cm_req->roam_req.req.prev_bssid);
243 			req->bss = cm_req->roam_req.cur_candidate;
244 			status = true;
245 			cm_req_lock_release(cm_ctx);
246 			return status;
247 		}
248 
249 		cur_node = next_node;
250 		next_node = NULL;
251 	}
252 	cm_req_lock_release(cm_ctx);
253 
254 	return status;
255 }
256 #endif
257 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
cm_get_first_roam_command(struct wlan_objmgr_vdev * vdev)258 struct cm_roam_req *cm_get_first_roam_command(struct wlan_objmgr_vdev *vdev)
259 {
260 	struct cnx_mgr *cm_ctx;
261 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
262 	struct cm_req *cm_req = NULL;
263 	uint32_t cm_id_prefix;
264 
265 	cm_ctx = cm_get_cm_ctx(vdev);
266 	if (!cm_ctx)
267 		return NULL;
268 
269 	cm_req_lock_acquire(cm_ctx);
270 	qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
271 	while (cur_node) {
272 		qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
273 
274 		cm_req = qdf_container_of(cur_node, struct cm_req, node);
275 		cm_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
276 
277 		if (cm_id_prefix == ROAM_REQ_PREFIX) {
278 			cm_req_lock_release(cm_ctx);
279 			return &cm_req->roam_req;
280 		}
281 
282 		cur_node = next_node;
283 		next_node = NULL;
284 	}
285 	cm_req_lock_release(cm_ctx);
286 
287 	return NULL;
288 }
289 #endif
290