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