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