xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf) !
1 /*
2  * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 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 SM framework for connection manager roaming sm
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 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
28 #include "wlan_mlo_mgr_roam.h"
29 #endif
30 
31 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
32 void cm_state_roaming_entry(void *ctx)
33 {
34 	struct cnx_mgr *cm_ctx = ctx;
35 
36 	cm_sm_state_update(cm_ctx, WLAN_CM_S_ROAMING, WLAN_CM_SS_IDLE);
37 }
38 
39 void cm_state_roaming_exit(void *ctx)
40 {
41 }
42 
43 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
44 static
45 bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event,
46 				uint16_t data_len, void *data)
47 {
48 	bool event_handled = true;
49 	QDF_STATUS status;
50 
51 	switch (event) {
52 	case WLAN_CM_SM_EV_ROAM_INVOKE:
53 		status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data);
54 		if (QDF_IS_STATUS_ERROR(status)) {
55 			event_handled = false;
56 			break;
57 		}
58 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
59 		cm_sm_deliver_event_sync(cm_ctx,
60 					 WLAN_CM_SM_EV_ROAM_INVOKE,
61 					 data_len, data);
62 		break;
63 	case WLAN_CM_SM_EV_ROAM_START:
64 		status = cm_add_fw_roam_cmd_to_list_n_ser(cm_ctx, data);
65 		if (QDF_IS_STATUS_ERROR(status)) {
66 			event_handled = false;
67 			break;
68 		}
69 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
70 		cm_sm_deliver_event_sync(cm_ctx,
71 					 WLAN_CM_SM_EV_ROAM_START,
72 					 0, NULL);
73 		break;
74 	case WLAN_CM_SM_EV_ROAM_ABORT:
75 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
76 		cm_sm_deliver_event_sync(cm_ctx, event,
77 					 data_len, data);
78 		break;
79 	case WLAN_CM_SM_EV_ROAM_SYNC:
80 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC);
81 		cm_sm_deliver_event_sync(cm_ctx, event,
82 					 data_len, data);
83 		break;
84 	default:
85 		event_handled = false;
86 		break;
87 	}
88 
89 	return event_handled;
90 }
91 #else
92 static inline
93 bool cm_handle_fw_roaming_event(struct cnx_mgr *cm_ctx, uint16_t event,
94 				uint16_t data_len, void *data)
95 {
96 	return false;
97 }
98 #endif
99 
100 bool cm_state_roaming_event(void *ctx, uint16_t event,
101 			    uint16_t data_len, void *data)
102 {
103 	struct cnx_mgr *cm_ctx = ctx;
104 	bool event_handled = true;
105 	struct wlan_objmgr_psoc *psoc;
106 
107 	switch (event) {
108 	case WLAN_CM_SM_EV_ROAM_REQ:
109 		psoc = wlan_vdev_get_psoc(cm_ctx->vdev);
110 		if (!psoc) {
111 			event_handled = false;
112 			break;
113 		}
114 		if (cm_roam_offload_enabled(psoc)) {
115 			cm_sm_deliver_event_sync(cm_ctx,
116 						 WLAN_CM_SM_EV_ROAM_INVOKE,
117 						 data_len, data);
118 		} else {
119 			cm_add_roam_req_to_list(cm_ctx, data);
120 			cm_sm_transition_to(cm_ctx, WLAN_CM_SS_PREAUTH);
121 			cm_sm_deliver_event_sync(cm_ctx,
122 						 WLAN_CM_SM_EV_ROAM_START,
123 						 data_len, data);
124 		}
125 		break;
126 	default:
127 		event_handled = cm_handle_fw_roaming_event(cm_ctx, event,
128 							   data_len, data);
129 		break;
130 	}
131 
132 	return event_handled;
133 }
134 
135 static bool cm_handle_connect_disconnect_in_roam(struct cnx_mgr *cm_ctx,
136 						 uint16_t event,
137 						 uint16_t data_len, void *data)
138 {
139 	QDF_STATUS status;
140 
141 	switch (event) {
142 	case WLAN_CM_SM_EV_CONNECT_REQ:
143 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
144 							WLAN_CM_S_ROAMING);
145 		if (QDF_IS_STATUS_ERROR(status))
146 			return false;
147 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING);
148 		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_START,
149 					 data_len, data);
150 		break;
151 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
152 		status = cm_handle_discon_req_in_non_connected_state(cm_ctx,
153 						data, WLAN_CM_S_ROAMING);
154 		if (QDF_IS_STATUS_ERROR(status))
155 			return false;
156 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
157 		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
158 					 data_len, data);
159 		break;
160 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
161 		cm_disconnect_active(cm_ctx, data);
162 		break;
163 	default:
164 		return false;
165 		break;
166 	}
167 
168 	return true;
169 }
170 #endif
171 
172 #ifdef WLAN_FEATURE_HOST_ROAM
173 void cm_subst_preauth_entry(void *ctx)
174 {
175 	struct cnx_mgr *cm_ctx = ctx;
176 
177 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
178 		QDF_BUG(0);
179 
180 	cm_set_substate(cm_ctx, WLAN_CM_SS_PREAUTH);
181 	/* set preauth to true when we enter preauth state */
182 	cm_ctx->preauth_in_progress = true;
183 }
184 
185 void cm_subst_preauth_exit(void *ctx)
186 {
187 }
188 
189 #ifdef WLAN_FEATURE_PREAUTH_ENABLE
190 static bool
191 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event,
192 			uint16_t data_len, void *data)
193 {
194 	bool event_handled = true;
195 
196 	switch (event) {
197 	case WLAN_CM_SM_EV_PREAUTH_ACTIVE:
198 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
199 			event_handled = false;
200 			break;
201 		}
202 		cm_preauth_active(cm_ctx, data);
203 		break;
204 	case WLAN_CM_SM_EV_PREAUTH_RESP:
205 		cm_preauth_done_resp(cm_ctx, data);
206 		break;
207 	case WLAN_CM_SM_EV_PREAUTH_DONE:
208 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC);
209 		cm_preauth_success(cm_ctx, data);
210 		break;
211 	case WLAN_CM_SM_EV_PREAUTH_FAIL:
212 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
213 		cm_preauth_fail(cm_ctx, data);
214 		break;
215 	default:
216 		event_handled = false;
217 	}
218 
219 	return event_handled;
220 }
221 #else
222 static inline bool
223 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event,
224 			uint16_t data_len, void *data)
225 {
226 	return false;
227 }
228 #endif
229 
230 bool cm_subst_preauth_event(void *ctx, uint16_t event,
231 			    uint16_t data_len, void *data)
232 {
233 	struct cnx_mgr *cm_ctx = ctx;
234 	bool event_handled = true;
235 
236 	switch (event) {
237 	case WLAN_CM_SM_EV_CONNECT_REQ:
238 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
239 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
240 		event_handled =
241 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
242 							     data_len, data);
243 		break;
244 	case WLAN_CM_SM_EV_ROAM_START:
245 		cm_host_roam_start_req(cm_ctx, data);
246 		break;
247 	case WLAN_CM_SM_EV_START_REASSOC:
248 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC);
249 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
250 		break;
251 	case WLAN_CM_SM_EV_REASSOC_FAILURE:
252 		cm_reassoc_complete(cm_ctx, data);
253 		break;
254 	default:
255 		event_handled = cm_handle_preauth_event(cm_ctx, event,
256 							data_len, data);
257 		break;
258 	}
259 
260 	return event_handled;
261 }
262 
263 void cm_subst_reassoc_entry(void *ctx)
264 {
265 	struct cnx_mgr *cm_ctx = ctx;
266 
267 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
268 		QDF_BUG(0);
269 
270 	cm_set_substate(cm_ctx, WLAN_CM_SS_REASSOC);
271 	/* set preauth to false as soon as we move to reassoc state */
272 	cm_ctx->preauth_in_progress = false;
273 }
274 
275 void cm_subst_reassoc_exit(void *ctx)
276 {
277 }
278 
279 #ifdef WLAN_FEATURE_PREAUTH_ENABLE
280 static bool
281 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event,
282 			uint16_t data_len, void *data)
283 {
284 	bool event_handled = true;
285 	QDF_STATUS status;
286 
287 	switch (event) {
288 	case WLAN_CM_SM_EV_REASSOC_TIMER:
289 		status = cm_handle_reassoc_timer(cm_ctx, data);
290 		if (QDF_IS_STATUS_ERROR(status))
291 			event_handled = false;
292 		break;
293 	default:
294 		event_handled = false;
295 	}
296 
297 	return event_handled;
298 }
299 #else
300 static inline bool
301 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event,
302 			uint16_t data_len, void *data)
303 {
304 	return false;
305 }
306 #endif
307 
308 bool cm_subst_reassoc_event(void *ctx, uint16_t event,
309 			    uint16_t data_len, void *data)
310 {
311 	struct cnx_mgr *cm_ctx = ctx;
312 	bool event_handled = true;
313 
314 	switch (event) {
315 	case WLAN_CM_SM_EV_CONNECT_REQ:
316 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
317 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
318 		event_handled =
319 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
320 							     data_len, data);
321 		break;
322 	case WLAN_CM_SM_EV_START_REASSOC:
323 		cm_reassoc_start(cm_ctx, data);
324 		break;
325 	case WLAN_CM_SM_EV_REASSOC_ACTIVE:
326 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
327 			event_handled = false;
328 			break;
329 		}
330 		cm_reassoc_active(cm_ctx, data);
331 		break;
332 	case WLAN_CM_SM_EV_HO_ROAM_DISCONNECT_DONE:
333 		cm_reassoc_disconnect_complete(cm_ctx, data);
334 		break;
335 	case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS:
336 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
337 			event_handled = false;
338 			break;
339 		}
340 		cm_resume_reassoc_after_peer_create(cm_ctx, data);
341 		break;
342 	case WLAN_CM_SM_EV_REASSOC_DONE:
343 		if (!cm_roam_resp_cmid_match_list_head(cm_ctx, data)) {
344 			event_handled = false;
345 			break;
346 		}
347 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
348 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
349 		break;
350 	case WLAN_CM_SM_EV_REASSOC_FAILURE:
351 		cm_reassoc_complete(cm_ctx, data);
352 		break;
353 	case WLAN_CM_SM_EV_HW_MODE_SUCCESS:
354 	case WLAN_CM_SM_EV_HW_MODE_FAILURE:
355 		/* check if cm id is valid for the current req */
356 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
357 			event_handled = false;
358 			break;
359 		}
360 		cm_handle_reassoc_hw_mode_change(cm_ctx, data, event);
361 		break;
362 	default:
363 		event_handled = cm_handle_reassoc_event(cm_ctx, event,
364 							data_len, data);
365 		break;
366 	}
367 
368 	return event_handled;
369 }
370 
371 #endif /* WLAN_FEATURE_HOST_ROAM */
372 
373 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
374 void cm_subst_roam_start_entry(void *ctx)
375 {
376 	struct cnx_mgr *cm_ctx = ctx;
377 
378 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
379 		QDF_BUG(0);
380 
381 	cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
382 }
383 
384 void cm_subst_roam_start_exit(void *ctx)
385 {
386 }
387 
388 bool cm_subst_roam_start_event(void *ctx, uint16_t event,
389 			       uint16_t data_len, void *data)
390 {
391 	bool event_handled = true;
392 	struct cnx_mgr *cm_ctx = ctx;
393 
394 	switch (event) {
395 	case WLAN_CM_SM_EV_CONNECT_REQ:
396 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
397 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
398 		event_handled =
399 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
400 							     data_len, data);
401 		break;
402 	case WLAN_CM_SM_EV_ROAM_START:
403 		cm_fw_roam_start(ctx);
404 		break;
405 	case WLAN_CM_SM_EV_ROAM_INVOKE:
406 		cm_send_roam_invoke_req(cm_ctx, data);
407 		break;
408 	case WLAN_CM_SM_EV_ROAM_ABORT:
409 	case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:
410 	case WLAN_CM_SM_EV_ROAM_HO_FAIL:
411 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
412 		cm_sm_deliver_event_sync(cm_ctx, event,
413 					 data_len, data);
414 		break;
415 	case WLAN_CM_SM_EV_ROAM_SYNC:
416 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC);
417 		cm_sm_deliver_event_sync(cm_ctx, event,
418 					 data_len, data);
419 		break;
420 	default:
421 		event_handled = false;
422 		break;
423 	}
424 
425 	return event_handled;
426 }
427 
428 void cm_subst_roam_sync_entry(void *ctx)
429 {
430 	struct cnx_mgr *cm_ctx = ctx;
431 
432 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
433 		QDF_BUG(0);
434 
435 	cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_SYNC);
436 }
437 
438 void cm_subst_roam_sync_exit(void *ctx)
439 {
440 }
441 
442 bool cm_subst_roam_sync_event(void *ctx, uint16_t event,
443 			      uint16_t data_len, void *data)
444 {
445 	bool event_handled = true;
446 	struct cnx_mgr *cm_ctx = ctx;
447 
448 	switch (event) {
449 	case WLAN_CM_SM_EV_CONNECT_REQ:
450 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
451 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
452 		event_handled =
453 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
454 							     data_len, data);
455 		break;
456 	case WLAN_CM_SM_EV_ROAM_SYNC:
457 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
458 		mlo_cm_roam_sync_cb(cm_ctx->vdev, data, data_len);
459 #endif
460 		cm_fw_send_vdev_roam_event(cm_ctx, data_len, data);
461 		break;
462 	case WLAN_CM_SM_EV_ROAM_DONE:
463 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
464 		cm_sm_deliver_event_sync(cm_ctx, event,
465 					 data_len, data);
466 		break;
467 	case WLAN_CM_SM_EV_ROAM_ABORT:
468 	case WLAN_CM_SM_EV_ROAM_HO_FAIL:
469 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
470 		cm_sm_deliver_event_sync(cm_ctx, event,
471 					 data_len, data);
472 		break;
473 	default:
474 		event_handled = false;
475 		break;
476 	}
477 
478 	return event_handled;
479 }
480 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
481