xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.c (revision 00bcc8cbd3251495b2372fa547568b4656558e1c)
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 	default:
156 		return false;
157 		break;
158 	}
159 
160 	return true;
161 }
162 
163 #ifdef WLAN_FEATURE_HOST_ROAM
164 void cm_subst_preauth_entry(void *ctx)
165 {
166 	struct cnx_mgr *cm_ctx = ctx;
167 
168 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
169 		QDF_BUG(0);
170 
171 	cm_set_substate(cm_ctx, WLAN_CM_SS_PREAUTH);
172 	/* set preauth to true when we enter preauth state */
173 	cm_ctx->preauth_in_progress = true;
174 }
175 
176 void cm_subst_preauth_exit(void *ctx)
177 {
178 }
179 
180 #ifdef WLAN_FEATURE_PREAUTH_ENABLE
181 static bool
182 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event,
183 			uint16_t data_len, void *data)
184 {
185 	bool event_handled = true;
186 
187 	switch (event) {
188 	case WLAN_CM_SM_EV_PREAUTH_ACTIVE:
189 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
190 			event_handled = false;
191 			break;
192 		}
193 		cm_preauth_active(cm_ctx, data);
194 		break;
195 	case WLAN_CM_SM_EV_PREAUTH_RESP:
196 		cm_preauth_done_resp(cm_ctx, data);
197 		break;
198 	case WLAN_CM_SM_EV_PREAUTH_DONE:
199 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC);
200 		cm_preauth_success(cm_ctx, data);
201 		break;
202 	case WLAN_CM_SM_EV_PREAUTH_FAIL:
203 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
204 		cm_preauth_fail(cm_ctx, data);
205 		break;
206 	default:
207 		event_handled = false;
208 	}
209 
210 	return event_handled;
211 }
212 #else
213 static inline bool
214 cm_handle_preauth_event(struct cnx_mgr *cm_ctx, uint16_t event,
215 			uint16_t data_len, void *data)
216 {
217 	return false;
218 }
219 #endif
220 
221 bool cm_subst_preauth_event(void *ctx, uint16_t event,
222 			    uint16_t data_len, void *data)
223 {
224 	struct cnx_mgr *cm_ctx = ctx;
225 	bool event_handled = true;
226 
227 	switch (event) {
228 	case WLAN_CM_SM_EV_CONNECT_REQ:
229 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
230 		event_handled =
231 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
232 							     data_len, data);
233 		break;
234 	case WLAN_CM_SM_EV_ROAM_START:
235 		cm_host_roam_start_req(cm_ctx, data);
236 		break;
237 	case WLAN_CM_SM_EV_START_REASSOC:
238 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_REASSOC);
239 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
240 		break;
241 	case WLAN_CM_SM_EV_REASSOC_FAILURE:
242 		cm_reassoc_complete(cm_ctx, data);
243 		break;
244 	default:
245 		event_handled = cm_handle_preauth_event(cm_ctx, event,
246 							data_len, data);
247 		break;
248 	}
249 
250 	return event_handled;
251 }
252 
253 void cm_subst_reassoc_entry(void *ctx)
254 {
255 	struct cnx_mgr *cm_ctx = ctx;
256 
257 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
258 		QDF_BUG(0);
259 
260 	cm_set_substate(cm_ctx, WLAN_CM_SS_REASSOC);
261 	/* set preauth to false as soon as we move to reassoc state */
262 	cm_ctx->preauth_in_progress = false;
263 }
264 
265 void cm_subst_reassoc_exit(void *ctx)
266 {
267 }
268 
269 #ifdef WLAN_FEATURE_PREAUTH_ENABLE
270 static bool
271 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event,
272 			uint16_t data_len, void *data)
273 {
274 	bool event_handled = true;
275 	QDF_STATUS status;
276 
277 	switch (event) {
278 	case WLAN_CM_SM_EV_REASSOC_TIMER:
279 		status = cm_handle_reassoc_timer(cm_ctx, data);
280 		if (QDF_IS_STATUS_ERROR(status))
281 			event_handled = false;
282 		break;
283 	default:
284 		event_handled = false;
285 	}
286 
287 	return event_handled;
288 }
289 #else
290 static inline bool
291 cm_handle_reassoc_event(struct cnx_mgr *cm_ctx, uint16_t event,
292 			uint16_t data_len, void *data)
293 {
294 	return false;
295 }
296 #endif
297 
298 bool cm_subst_reassoc_event(void *ctx, uint16_t event,
299 			    uint16_t data_len, void *data)
300 {
301 	struct cnx_mgr *cm_ctx = ctx;
302 	bool event_handled = true;
303 
304 	switch (event) {
305 	case WLAN_CM_SM_EV_CONNECT_REQ:
306 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
307 		event_handled =
308 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
309 							     data_len, data);
310 		break;
311 	case WLAN_CM_SM_EV_START_REASSOC:
312 		cm_reassoc_start(cm_ctx, data);
313 		break;
314 	case WLAN_CM_SM_EV_REASSOC_ACTIVE:
315 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
316 			event_handled = false;
317 			break;
318 		}
319 		cm_reassoc_active(cm_ctx, data);
320 		break;
321 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
322 		cm_reassoc_disconnect_complete(cm_ctx, data);
323 		break;
324 	case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS:
325 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
326 			event_handled = false;
327 			break;
328 		}
329 		cm_resume_reassoc_after_peer_create(cm_ctx, data);
330 		break;
331 	case WLAN_CM_SM_EV_REASSOC_DONE:
332 		if (!cm_roam_resp_cmid_match_list_head(cm_ctx, data)) {
333 			event_handled = false;
334 			break;
335 		}
336 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
337 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
338 		break;
339 	case WLAN_CM_SM_EV_REASSOC_FAILURE:
340 		cm_reassoc_complete(cm_ctx, data);
341 		break;
342 	case WLAN_CM_SM_EV_HW_MODE_SUCCESS:
343 	case WLAN_CM_SM_EV_HW_MODE_FAILURE:
344 		/* check if cm id is valid for the current req */
345 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
346 			event_handled = false;
347 			break;
348 		}
349 		cm_handle_reassoc_hw_mode_change(cm_ctx, data, event);
350 		break;
351 	default:
352 		event_handled = cm_handle_reassoc_event(cm_ctx, event,
353 							data_len, data);
354 		break;
355 	}
356 
357 	return event_handled;
358 }
359 
360 #endif /* WLAN_FEATURE_HOST_ROAM */
361 
362 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
363 void cm_subst_roam_start_entry(void *ctx)
364 {
365 	struct cnx_mgr *cm_ctx = ctx;
366 
367 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
368 		QDF_BUG(0);
369 
370 	cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_STARTED);
371 }
372 
373 void cm_subst_roam_start_exit(void *ctx)
374 {
375 }
376 
377 bool cm_subst_roam_start_event(void *ctx, uint16_t event,
378 			       uint16_t data_len, void *data)
379 {
380 	bool event_handled = true;
381 	struct cnx_mgr *cm_ctx = ctx;
382 
383 	switch (event) {
384 	case WLAN_CM_SM_EV_CONNECT_REQ:
385 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
386 		event_handled =
387 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
388 							     data_len, data);
389 		break;
390 	case WLAN_CM_SM_EV_ROAM_START:
391 		cm_fw_roam_start(ctx);
392 		break;
393 	case WLAN_CM_SM_EV_ROAM_INVOKE:
394 		cm_send_roam_invoke_req(cm_ctx, data);
395 		break;
396 	case WLAN_CM_SM_EV_ROAM_ABORT:
397 	case WLAN_CM_SM_EV_ROAM_INVOKE_FAIL:
398 	case WLAN_CM_SM_EV_ROAM_HO_FAIL:
399 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
400 		cm_sm_deliver_event_sync(cm_ctx, event,
401 					 data_len, data);
402 		break;
403 	case WLAN_CM_SM_EV_ROAM_SYNC:
404 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_ROAM_SYNC);
405 		cm_sm_deliver_event_sync(cm_ctx, event,
406 					 data_len, data);
407 		break;
408 	default:
409 		event_handled = false;
410 		break;
411 	}
412 
413 	return event_handled;
414 }
415 
416 void cm_subst_roam_sync_entry(void *ctx)
417 {
418 	struct cnx_mgr *cm_ctx = ctx;
419 
420 	if (cm_get_state(cm_ctx) != WLAN_CM_S_ROAMING)
421 		QDF_BUG(0);
422 
423 	cm_set_substate(cm_ctx, WLAN_CM_SS_ROAM_SYNC);
424 }
425 
426 void cm_subst_roam_sync_exit(void *ctx)
427 {
428 }
429 
430 bool cm_subst_roam_sync_event(void *ctx, uint16_t event,
431 			      uint16_t data_len, void *data)
432 {
433 	bool event_handled = true;
434 	struct cnx_mgr *cm_ctx = ctx;
435 
436 	switch (event) {
437 	case WLAN_CM_SM_EV_CONNECT_REQ:
438 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
439 		event_handled =
440 			cm_handle_connect_disconnect_in_roam(cm_ctx, event,
441 							     data_len, data);
442 		break;
443 	case WLAN_CM_SM_EV_ROAM_SYNC:
444 		cm_fw_send_vdev_roam_event(cm_ctx, data_len, data);
445 		break;
446 	case WLAN_CM_SM_EV_ROAM_DONE:
447 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
448 		cm_sm_deliver_event_sync(cm_ctx, event,
449 					 data_len, data);
450 		break;
451 	case WLAN_CM_SM_EV_ROAM_ABORT:
452 	case WLAN_CM_SM_EV_ROAM_HO_FAIL:
453 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
454 		cm_sm_deliver_event_sync(cm_ctx, event,
455 					 data_len, data);
456 		break;
457 	default:
458 		event_handled = false;
459 		break;
460 	}
461 
462 	return event_handled;
463 }
464 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
465