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