xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_sm.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2012-2015, 2020, 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
19  */
20 
21 #include "wlan_cm_main_api.h"
22 #include "wlan_cm_sm.h"
23 #include "wlan_cm_roam_sm.h"
24 
25 void cm_set_state(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state state)
26 {
27 	if (state < WLAN_CM_S_MAX)
28 		cm_ctx->sm.cm_state = state;
29 	else
30 		mlme_err("vdev %d mlme state (%d) is invalid",
31 			 wlan_vdev_get_id(cm_ctx->vdev), state);
32 }
33 
34 void cm_set_substate(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state substate)
35 {
36 	if ((substate > WLAN_CM_S_MAX) && (substate < WLAN_CM_SS_MAX))
37 		cm_ctx->sm.cm_substate = substate;
38 	else
39 		mlme_err("vdev %d mlme sub state (%d) is invalid",
40 			 wlan_vdev_get_id(cm_ctx->vdev), substate);
41 }
42 
43 void cm_sm_state_update(struct cnx_mgr *cm_ctx,
44 			enum wlan_cm_sm_state state,
45 			enum wlan_cm_sm_state substate)
46 {
47 	if (!cm_ctx) {
48 		mlme_err("vdev %d cm_ctx is NULL",
49 			 wlan_vdev_get_id(cm_ctx->vdev));
50 		return;
51 	}
52 
53 	cm_set_state(cm_ctx, state);
54 	cm_set_substate(cm_ctx, substate);
55 }
56 
57 /**
58  * cm_state_init_entry() - Entry API for init state for connection mgr
59  * @ctx: connection manager ctx
60  *
61  * API to perform operations on moving to init state
62  *
63  * Return: void
64  */
65 static void cm_state_init_entry(void *ctx)
66 {
67 	struct cnx_mgr *cm_ctx = ctx;
68 
69 	cm_sm_state_update(cm_ctx, WLAN_CM_S_INIT, WLAN_CM_SS_IDLE);
70 }
71 
72 /**
73  * cm_state_init_exit() - Exit API for init state for connection mgr
74  * @ctx: connection manager ctx
75  *
76  * API to perform operations on exiting from init state
77  *
78  * Return: void
79  */
80 static void cm_state_init_exit(void *ctx)
81 {
82 }
83 
84 /**
85  * cm_state_init_event() - Init State event handler for connection mgr
86  * @ctx: connection manager ctx
87  *
88  * API to handle events in INIT state
89  *
90  * Return: bool
91  */
92 static bool cm_state_init_event(void *ctx, uint16_t event,
93 				uint16_t data_len, void *data)
94 {
95 	struct cnx_mgr *cm_ctx = ctx;
96 	bool event_handled;
97 	QDF_STATUS status;
98 	struct cm_disconnect_req *req;
99 
100 	switch (event) {
101 	case WLAN_CM_SM_EV_CONNECT_REQ:
102 		status = cm_add_connect_req_to_list(cm_ctx, data);
103 		if (QDF_IS_STATUS_ERROR(status)) {
104 			/* if fail to add req return failure */
105 			event_handled = false;
106 			break;
107 		}
108 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING);
109 		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_CONNECT_START,
110 					 data_len, data);
111 		event_handled = true;
112 		break;
113 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
114 		cm_connect_complete(cm_ctx, data);
115 		event_handled = true;
116 		break;
117 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
118 		cm_disconnect_complete(cm_ctx, data);
119 		event_handled = true;
120 		break;
121 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
122 		status = cm_add_disconnect_req_to_list(cm_ctx, data);
123 		if (QDF_IS_STATUS_ERROR(status)) {
124 			/* if fail to add req return failure */
125 			event_handled = false;
126 			break;
127 		}
128 
129 		req = data;
130 		cm_send_disconnect_resp(cm_ctx, req->cm_id);
131 		event_handled = true;
132 		break;
133 	default:
134 		event_handled = false;
135 		break;
136 	}
137 
138 	return event_handled;
139 }
140 
141 /**
142  * cm_state_connecting_entry() - Entry API for connecting state for
143  * connection mgr
144  * @ctx: connection manager ctx
145  *
146  * API to perform operations on moving to connecting state
147  *
148  * Return: void
149  */
150 static void cm_state_connecting_entry(void *ctx)
151 {
152 	struct cnx_mgr *cm_ctx = ctx;
153 
154 	cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTING, WLAN_CM_SS_IDLE);
155 }
156 
157 /**
158  * cm_state_connecting_exit() - Exit API for connecting state for
159  * connection mgr
160  * @ctx: connection manager ctx
161  *
162  * API to perform operations on exiting from connecting state
163  *
164  * Return: void
165  */
166 static void cm_state_connecting_exit(void *ctx)
167 {
168 }
169 
170 /**
171  * cm_state_connecting_event() - Connecting State event handler for
172  * connection mgr
173  * @ctx: connection manager ctx
174  *
175  * API to handle events in CONNECTING state
176  *
177  * Return: bool
178  */
179 static bool cm_state_connecting_event(void *ctx, uint16_t event,
180 				      uint16_t data_len, void *data)
181 {
182 	struct cnx_mgr *cm_ctx = ctx;
183 	bool event_handled;
184 
185 	switch (event) {
186 	case WLAN_CM_SM_EV_CONNECT_START:
187 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
188 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
189 		event_handled = true;
190 		break;
191 	default:
192 		event_handled = false;
193 		break;
194 	}
195 
196 	return event_handled;
197 }
198 
199 /**
200  * cm_state_connected_entry() - Entry API for connected state for
201  * connection mgr
202  * @ctx: connection manager ctx
203  *
204  * API to perform operations on moving to connected state
205  *
206  * Return: void
207  */
208 static void cm_state_connected_entry(void *ctx)
209 {
210 	struct cnx_mgr *cm_ctx = ctx;
211 
212 	cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTED, WLAN_CM_SS_IDLE);
213 }
214 
215 /**
216  * cm_state_connected_exit() - Exit API for connected state for
217  * connection mgr
218  * @ctx: connection manager ctx
219  *
220  * API to perform operations on exiting from connected state
221  *
222  * Return: void
223  */
224 static void cm_state_connected_exit(void *ctx)
225 {
226 }
227 
228 /**
229  * cm_state_connected_event() - Connected State event handler for
230  * connection mgr
231  * @ctx: connection manager ctx
232  *
233  * API to handle events in CONNECTED state
234  *
235  * Return: bool
236  */
237 static bool cm_state_connected_event(void *ctx, uint16_t event,
238 				     uint16_t data_len, void *data)
239 {
240 	struct cnx_mgr *cm_ctx = ctx;
241 	bool event_handled;
242 	QDF_STATUS status;
243 
244 	switch (event) {
245 	case WLAN_CM_SM_EV_CONNECT_REQ:
246 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
247 							WLAN_CM_S_CONNECTED);
248 		if (QDF_IS_STATUS_ERROR(status)) {
249 			event_handled = false;
250 			break;
251 		}
252 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING);
253 		cm_sm_deliver_event_sync(cm_ctx,
254 					 WLAN_CM_SM_EV_CONNECT_START,
255 					 data_len, data);
256 		event_handled = true;
257 		break;
258 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
259 		cm_disconnect_active(cm_ctx, data);
260 		event_handled = true;
261 		break;
262 	case WLAN_CM_SM_EV_CONNECT_SUCCESS:
263 		cm_connect_complete(cm_ctx, data);
264 		event_handled = true;
265 		break;
266 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
267 		status = cm_add_disconnect_req_to_list(cm_ctx, data);
268 		if (QDF_IS_STATUS_ERROR(status)) {
269 			/* if fail to add req return failure */
270 			event_handled = false;
271 			break;
272 		}
273 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
274 		cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
275 					 data_len, data);
276 		event_handled = true;
277 		break;
278 	default:
279 		event_handled = false;
280 		break;
281 	}
282 
283 	return event_handled;
284 }
285 
286 /**
287  * cm_state_disconnecting_entry() - Entry API for disconnecting state for
288  * connection mgr
289  * @ctx: connection manager ctx
290  *
291  * API to perform operations on moving to disconnecting state
292  *
293  * Return: void
294  */
295 static void cm_state_disconnecting_entry(void *ctx)
296 {
297 	struct cnx_mgr *cm_ctx = ctx;
298 
299 	cm_sm_state_update(cm_ctx, WLAN_CM_S_DISCONNECTING, WLAN_CM_SS_IDLE);
300 }
301 
302 /**
303  * cm_state_disconnecting_exit() - Exit API for disconnecting state for
304  * connection mgr
305  * @ctx: connection manager ctx
306  *
307  * API to perform operations on exiting from disconnecting state
308  *
309  * Return: void
310  */
311 static void cm_state_disconnecting_exit(void *ctx)
312 {
313 }
314 
315 /**
316  * cm_state_connected_event() - Disconnecting State event handler for
317  * connection mgr
318  * @ctx: connection manager ctx
319  *
320  * API to handle events in Disconnecting state
321  *
322  * Return: bool
323  */
324 static bool cm_state_disconnecting_event(void *ctx, uint16_t event,
325 					 uint16_t data_len, void *data)
326 {
327 	struct cnx_mgr *cm_ctx = ctx;
328 	bool event_handled;
329 	QDF_STATUS status;
330 
331 	switch (event) {
332 	case WLAN_CM_SM_EV_CONNECT_REQ:
333 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
334 						WLAN_CM_S_DISCONNECTING);
335 		if (QDF_IS_STATUS_ERROR(status)) {
336 			event_handled = false;
337 			break;
338 		}
339 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING);
340 		cm_sm_deliver_event_sync(cm_ctx,
341 					 WLAN_CM_SM_EV_CONNECT_START,
342 					 data_len, data);
343 		event_handled = true;
344 		break;
345 	case WLAN_CM_SM_EV_DISCONNECT_START:
346 		cm_disconnect_start(cm_ctx, data);
347 		event_handled = true;
348 		break;
349 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
350 		cm_disconnect_active(cm_ctx, data);
351 		event_handled = true;
352 		break;
353 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
354 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
355 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
356 		event_handled = true;
357 		break;
358 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
359 		status = cm_handle_discon_req_in_non_connected_state(cm_ctx,
360 						data, WLAN_CM_S_DISCONNECTING);
361 		if (QDF_IS_STATUS_ERROR(status)) {
362 			event_handled = false;
363 			break;
364 		}
365 		cm_sm_deliver_event_sync(cm_ctx,
366 					 WLAN_CM_SM_EV_DISCONNECT_START,
367 					 data_len, data);
368 		event_handled = true;
369 		break;
370 	default:
371 		event_handled = false;
372 		break;
373 	}
374 
375 	return event_handled;
376 }
377 
378 /**
379  * cm_subst_join_pending_entry() - Entry API for join pending sub-state for
380  * connection mgr
381  * @ctx: connection manager ctx
382  *
383  * API to perform operations on moving to join pending sub-state
384  *
385  * Return: void
386  */
387 static void cm_subst_join_pending_entry(void *ctx)
388 {
389 	struct cnx_mgr *cm_ctx = ctx;
390 
391 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
392 		QDF_BUG(0);
393 
394 	cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
395 }
396 
397 /**
398  * cm_subst_join_pending_exit() - Exit API for join pending sub-state for
399  * connection mgr
400  * @ctx: connection manager ctx
401  *
402  * API to perform operations on exiting from join pending sub-state
403  *
404  * Return: void
405  */
406 static void cm_subst_join_pending_exit(void *ctx)
407 {
408 }
409 
410 /**
411  * cm_subst_join_pending_event() - Join pending sub-state event handler for
412  * connection mgr
413  * @ctx: connection manager ctx
414  *
415  * API to handle events in Join pending sub-state
416  *
417  * Return: bool
418  */
419 static bool cm_subst_join_pending_event(void *ctx, uint16_t event,
420 					uint16_t data_len, void *data)
421 {
422 	struct cnx_mgr *cm_ctx = ctx;
423 	bool event_handled;
424 	QDF_STATUS status = QDF_STATUS_SUCCESS;
425 	struct wlan_cm_connect_resp *resp;
426 	struct cm_req *cm_req;
427 
428 	switch (event) {
429 	case WLAN_CM_SM_EV_CONNECT_REQ:
430 		status =
431 			cm_handle_connect_req_in_non_init_state(cm_ctx, data,
432 						WLAN_CM_SS_JOIN_PENDING);
433 		if (QDF_IS_STATUS_ERROR(status)) {
434 			event_handled = false;
435 			break;
436 		}
437 		cm_sm_deliver_event_sync(cm_ctx,
438 					 WLAN_CM_SM_EV_CONNECT_START,
439 					 data_len, data);
440 		event_handled = true;
441 		break;
442 	case WLAN_CM_SM_EV_CONNECT_START:
443 		cm_connect_start(cm_ctx, data);
444 		event_handled = true;
445 		break;
446 	case WLAN_CM_SM_EV_CONNECT_ACTIVE:
447 		/* check if cm id is valid for the current req */
448 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
449 			event_handled = false;
450 			break;
451 		}
452 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE);
453 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
454 		event_handled = true;
455 		break;
456 	case WLAN_CM_SM_EV_HW_MODE_SUCCESS:
457 	case WLAN_CM_SM_EV_HW_MODE_FAILURE:
458 		/* check if cm id is valid for the current req */
459 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
460 			event_handled = false;
461 			break;
462 		}
463 		cm_handle_hw_mode_change(cm_ctx, data, event);
464 		event_handled = true;
465 		break;
466 	case WLAN_CM_SM_EV_SCAN:
467 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_SCAN);
468 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
469 		event_handled = true;
470 		break;
471 	case WLAN_CM_SM_EV_SCAN_FAILURE:
472 		status = QDF_STATUS_E_FAILURE;
473 		/* Fall through after setting status failure */
474 		/* fallthrough */
475 	case WLAN_CM_SM_EV_SCAN_SUCCESS:
476 		cm_connect_scan_resp(cm_ctx, data, status);
477 		event_handled = true;
478 		break;
479 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
480 		/* check if connect resp cm id is valid for the current req */
481 		if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) {
482 			event_handled = false;
483 			break;
484 		}
485 		/*
486 		 * On connect req failure (before serialization), if there is a
487 		 * pending disconnect req then move to disconnecting state and
488 		 * wait for disconnect to complete before moving to INIT state.
489 		 * Else directly transition to INIT state.
490 		 *
491 		 * On disconnect completion or a new connect/disconnect req in
492 		 * disconnnecting state, the failed connect req will be flushed.
493 		 * This will ensure SM moves to INIT state after completion of
494 		 * all operation.
495 		 */
496 		if (cm_ctx->disconnect_count) {
497 			resp = data;
498 
499 			mlme_debug(CM_PREFIX_FMT "disconnect_count %d",
500 				   CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
501 						 resp->cm_id),
502 				   cm_ctx->disconnect_count);
503 			cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id);
504 			cm_req->failed_req = true;
505 			cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
506 			event_handled = true;
507 			break;
508 		}
509 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
510 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
511 		event_handled = true;
512 		break;
513 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
514 		cm_disconnect_active(cm_ctx, data);
515 		event_handled = true;
516 		break;
517 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
518 		cm_disconnect_complete(cm_ctx, data);
519 		event_handled = true;
520 		break;
521 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
522 		status = cm_handle_discon_req_in_non_connected_state(cm_ctx,
523 						data, WLAN_CM_SS_JOIN_PENDING);
524 		if (QDF_IS_STATUS_ERROR(status)) {
525 			event_handled = false;
526 			break;
527 		}
528 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
529 		cm_sm_deliver_event_sync(cm_ctx,
530 					 WLAN_CM_SM_EV_DISCONNECT_START,
531 					 data_len, data);
532 		event_handled = true;
533 		break;
534 	default:
535 		event_handled = false;
536 		break;
537 	}
538 
539 	return event_handled;
540 }
541 
542 /**
543  * cm_subst_scan_entry() - Entry API for scan sub-state for
544  * connection mgr
545  * @ctx: connection manager ctx
546  *
547  * API to perform operations on moving to scan sub-state
548  *
549  * Return: void
550  */
551 static void cm_subst_scan_entry(void *ctx)
552 {
553 	struct cnx_mgr *cm_ctx = ctx;
554 
555 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
556 		QDF_BUG(0);
557 
558 	cm_set_substate(cm_ctx, WLAN_CM_SS_SCAN);
559 }
560 
561 /**
562  * cm_subst_scan_exit() - Exit API for scan sub-state for
563  * connection mgr
564  * @ctx: connection manager ctx
565  *
566  * API to perform operations on exiting from scan sub-state
567  *
568  * Return: void
569  */
570 static void cm_subst_scan_exit(void *ctx)
571 {
572 }
573 
574 /**
575  * cm_subst_scan_event() - Scan sub-state event handler for
576  * connection mgr
577  * @ctx: connection manager ctx
578  *
579  * API to handle events in scan sub-state
580  *
581  * Return: bool
582  */
583 static bool cm_subst_scan_event(void *ctx, uint16_t event,
584 				uint16_t data_len, void *data)
585 {
586 	struct cnx_mgr *cm_ctx = ctx;
587 	bool event_handled;
588 	QDF_STATUS status;
589 
590 	switch (event) {
591 	case WLAN_CM_SM_EV_CONNECT_REQ:
592 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
593 							WLAN_CM_SS_SCAN);
594 		if (QDF_IS_STATUS_ERROR(status)) {
595 			event_handled = false;
596 			break;
597 		}
598 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
599 		cm_sm_deliver_event_sync(cm_ctx,
600 					 WLAN_CM_SM_EV_CONNECT_START,
601 					 data_len, data);
602 		event_handled = true;
603 		break;
604 	case WLAN_CM_SM_EV_SCAN:
605 		cm_connect_scan_start(cm_ctx, data);
606 		event_handled = true;
607 		break;
608 	case WLAN_CM_SM_EV_SCAN_SUCCESS:
609 	case WLAN_CM_SM_EV_SCAN_FAILURE:
610 		/* check if scan id is valid for the current req */
611 		if (!cm_check_scanid_match_list_head(cm_ctx, data)) {
612 			event_handled = false;
613 			break;
614 		}
615 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
616 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
617 		event_handled = true;
618 		break;
619 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
620 		cm_disconnect_active(cm_ctx, data);
621 		event_handled = true;
622 		break;
623 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
624 		cm_disconnect_complete(cm_ctx, data);
625 		event_handled = true;
626 		break;
627 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
628 		status = cm_handle_discon_req_in_non_connected_state(cm_ctx,
629 						data, WLAN_CM_SS_SCAN);
630 		if (QDF_IS_STATUS_ERROR(status)) {
631 			event_handled = false;
632 			break;
633 		}
634 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
635 		cm_sm_deliver_event_sync(cm_ctx,
636 					 WLAN_CM_SM_EV_DISCONNECT_START,
637 					 data_len, data);
638 		event_handled = true;
639 		break;
640 	default:
641 		event_handled = false;
642 		break;
643 	}
644 
645 	return event_handled;
646 }
647 
648 /**
649  * cm_subst_join_active_entry() - Entry API for join active sub-state for
650  * connection mgr
651  * @ctx: connection manager ctx
652  *
653  * API to perform operations on moving to join active sub-state
654  *
655  * Return: void
656  */
657 static void cm_subst_join_active_entry(void *ctx)
658 {
659 	struct cnx_mgr *cm_ctx = ctx;
660 
661 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
662 		QDF_BUG(0);
663 
664 	cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE);
665 }
666 
667 /**
668  * cm_subst_join_active_exit() - Exit API for join active sub-state for
669  * connection mgr
670  * @ctx: connection manager ctx
671  *
672  * API to perform operations on exiting from join active sub-state
673  *
674  * Return: void
675  */
676 static void cm_subst_join_active_exit(void *ctx)
677 {
678 }
679 
680 /**
681  * cm_subst_join_active_event() - Join active sub-state event handler for
682  * connection mgr
683  * @ctx: connection manager ctx
684  *
685  * API to handle events in join active sub-state
686  *
687  * Return: bool
688  */
689 static bool cm_subst_join_active_event(void *ctx, uint16_t event,
690 				       uint16_t data_len, void *data)
691 {
692 	struct cnx_mgr *cm_ctx = ctx;
693 	bool event_handled;
694 	QDF_STATUS status;
695 
696 	switch (event) {
697 	case WLAN_CM_SM_EV_CONNECT_REQ:
698 		status = cm_handle_connect_req_in_non_init_state(cm_ctx, data,
699 							WLAN_CM_SS_JOIN_ACTIVE);
700 		if (QDF_IS_STATUS_ERROR(status)) {
701 			event_handled = false;
702 			break;
703 		}
704 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
705 		cm_sm_deliver_event_sync(cm_ctx,
706 					 WLAN_CM_SM_EV_CONNECT_START,
707 					 data_len, data);
708 		event_handled = true;
709 		break;
710 	case WLAN_CM_SM_EV_CONNECT_ACTIVE:
711 		cm_connect_active(cm_ctx, data);
712 		event_handled = true;
713 		break;
714 	case WLAN_CM_SM_EV_CONNECT_SUCCESS:
715 		/* check if connect resp cm id is valid for the current req */
716 		if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) {
717 			event_handled = false;
718 			break;
719 		}
720 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
721 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
722 		event_handled = true;
723 		break;
724 	case WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE:
725 		/* check if connect resp cm id is valid for the current req */
726 		if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) {
727 			event_handled = false;
728 			break;
729 		}
730 		cm_try_next_candidate(cm_ctx, data);
731 		event_handled = true;
732 		break;
733 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
734 		/* check if connect resp cm id is valid for the current req */
735 		if (!cm_connect_resp_cmid_match_list_head(cm_ctx, data)) {
736 			event_handled = false;
737 			break;
738 		}
739 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
740 		cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
741 		event_handled = true;
742 		break;
743 	case WLAN_CM_SM_EV_BSS_SELECT_IND_SUCCESS:
744 		/* check if cm id is valid for the current req */
745 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
746 			event_handled = false;
747 			break;
748 		}
749 		cm_peer_create_on_bss_select_ind_resp(cm_ctx, data);
750 		event_handled = true;
751 		break;
752 	case WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS:
753 		/* check if cm id is valid for the current req */
754 		if (!cm_check_cmid_match_list_head(cm_ctx, data)) {
755 			event_handled = false;
756 			break;
757 		}
758 		cm_resume_connect_after_peer_create(cm_ctx, data);
759 		event_handled = true;
760 		break;
761 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
762 		status = cm_handle_discon_req_in_non_connected_state(cm_ctx,
763 						data, WLAN_CM_SS_JOIN_ACTIVE);
764 		if (QDF_IS_STATUS_ERROR(status)) {
765 			event_handled = false;
766 			break;
767 		}
768 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
769 		cm_sm_deliver_event_sync(cm_ctx,
770 					 WLAN_CM_SM_EV_DISCONNECT_START,
771 					 data_len, data);
772 		event_handled = true;
773 		break;
774 	default:
775 		event_handled = false;
776 		break;
777 	}
778 
779 	return event_handled;
780 }
781 
782 struct wlan_sm_state_info cm_sm_info[] = {
783 	{
784 		(uint8_t)WLAN_CM_S_INIT,
785 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
786 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
787 		true,
788 		"INIT",
789 		cm_state_init_entry,
790 		cm_state_init_exit,
791 		cm_state_init_event
792 	},
793 	{
794 		(uint8_t)WLAN_CM_S_CONNECTING,
795 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
796 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
797 		true,
798 		"CONNECTING",
799 		cm_state_connecting_entry,
800 		cm_state_connecting_exit,
801 		cm_state_connecting_event
802 	},
803 	{
804 		(uint8_t)WLAN_CM_S_CONNECTED,
805 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
806 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
807 		true,
808 		"CONNECTED",
809 		cm_state_connected_entry,
810 		cm_state_connected_exit,
811 		cm_state_connected_event
812 	},
813 	{
814 		(uint8_t)WLAN_CM_S_DISCONNECTING,
815 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
816 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
817 		true,
818 		"DISCONNECTING",
819 		cm_state_disconnecting_entry,
820 		cm_state_disconnecting_exit,
821 		cm_state_disconnecting_event
822 	},
823 	{
824 		(uint8_t)WLAN_CM_S_ROAMING,
825 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
826 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
827 		true,
828 		"ROAMING",
829 		cm_state_roaming_entry,
830 		cm_state_roaming_exit,
831 		cm_state_roaming_event
832 	},
833 	{
834 		(uint8_t)WLAN_CM_S_MAX,
835 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
836 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
837 		false,
838 		"INVALID",
839 		NULL,
840 		NULL,
841 		NULL
842 	},
843 	{
844 		(uint8_t)WLAN_CM_SS_IDLE,
845 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
846 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
847 		false,
848 		"IDLE",
849 		NULL,
850 		NULL,
851 		NULL
852 	},
853 	{
854 		(uint8_t)WLAN_CM_SS_JOIN_PENDING,
855 		(uint8_t)WLAN_CM_S_CONNECTING,
856 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
857 		false,
858 		"JOIN_PENDING",
859 		cm_subst_join_pending_entry,
860 		cm_subst_join_pending_exit,
861 		cm_subst_join_pending_event
862 	},
863 	{
864 		(uint8_t)WLAN_CM_SS_SCAN,
865 		(uint8_t)WLAN_CM_S_CONNECTING,
866 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
867 		false,
868 		"SCAN",
869 		cm_subst_scan_entry,
870 		cm_subst_scan_exit,
871 		cm_subst_scan_event
872 	},
873 	{
874 		(uint8_t)WLAN_CM_SS_JOIN_ACTIVE,
875 		(uint8_t)WLAN_CM_S_CONNECTING,
876 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
877 		false,
878 		"JOIN_ACTIVE",
879 		cm_subst_join_active_entry,
880 		cm_subst_join_active_exit,
881 		cm_subst_join_active_event
882 	},
883 	{
884 		(uint8_t)WLAN_CM_SS_PREAUTH,
885 		(uint8_t)WLAN_CM_S_ROAMING,
886 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
887 		false,
888 		"PREAUTH",
889 		cm_subst_preauth_entry,
890 		cm_subst_preauth_exit,
891 		cm_subst_preauth_event
892 	},
893 	{
894 		(uint8_t)WLAN_CM_SS_REASSOC,
895 		(uint8_t)WLAN_CM_S_ROAMING,
896 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
897 		false,
898 		"REASSOC",
899 		cm_subst_reassoc_entry,
900 		cm_subst_reassoc_exit,
901 		cm_subst_reassoc_event
902 	},
903 	{
904 		(uint8_t)WLAN_CM_SS_ROAM_STARTED,
905 		(uint8_t)WLAN_CM_S_ROAMING,
906 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
907 		false,
908 		"ROAM_START",
909 		cm_subst_roam_start_entry,
910 		cm_subst_roam_start_exit,
911 		cm_subst_roam_start_event
912 	},
913 	{
914 		(uint8_t)WLAN_CM_SS_ROAM_SYNC,
915 		(uint8_t)WLAN_CM_S_ROAMING,
916 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
917 		false,
918 		"ROAM_SYNC",
919 		cm_subst_roam_sync_entry,
920 		cm_subst_roam_sync_exit,
921 		cm_subst_roam_sync_event
922 	},
923 	{
924 		(uint8_t)WLAN_CM_SS_MAX,
925 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
926 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
927 		false,
928 		"INVALID",
929 		NULL,
930 		NULL,
931 		NULL
932 	},
933 };
934 
935 static const char *cm_sm_event_names[] = {
936 	"EV_CONNECT_REQ",
937 	"EV_SCAN",
938 	"EV_SCAN_SUCCESS",
939 	"EV_SCAN_FAILURE",
940 	"EV_HW_MODE_SUCCESS",
941 	"EV_HW_MODE_FAILURE",
942 	"EV_CONNECT_START",
943 	"EV_CONNECT_ACTIVE",
944 	"EV_CONNECT_SUCCESS",
945 	"EV_BSS_SELECT_IND_SUCCESS",
946 	"EV_BSS_CREATE_PEER_SUCCESS",
947 	"EV_CONNECT_GET_NXT_CANDIDATE",
948 	"EV_CONNECT_FAILURE",
949 	"EV_DISCONNECT_REQ",
950 	"EV_DISCONNECT_START",
951 	"EV_DISCONNECT_ACTIVE",
952 	"EV_DISCONNECT_DONE",
953 	"EV_ROAM_START",
954 	"EV_ROAM_SYNC",
955 	"EV_ROAM_INVOKE_FAIL",
956 	"EV_ROAM_HO_FAIL",
957 	"EV_PREAUTH_DONE",
958 	"EV_GET_NEXT_PREAUTH_AP",
959 	"EV_PREAUTH_FAIL",
960 	"EV_START_REASSOC",
961 	"EV_REASSOC_DONE",
962 	"EV_REASSOC_FAILURE",
963 	"EV_ROAM_COMPLETE",
964 };
965 
966 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx)
967 {
968 	enum QDF_OPMODE op_mode;
969 
970 	if (!cm_ctx || !cm_ctx->vdev)
971 		return WLAN_CM_S_MAX;
972 
973 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
974 
975 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
976 		return WLAN_CM_S_MAX;
977 
978 	return cm_ctx->sm.cm_state;
979 }
980 
981 enum wlan_cm_sm_state cm_get_sub_state(struct cnx_mgr *cm_ctx)
982 {
983 	enum QDF_OPMODE op_mode;
984 
985 	if (!cm_ctx || !cm_ctx->vdev)
986 		return WLAN_CM_SS_MAX;
987 
988 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
989 
990 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
991 		return WLAN_CM_SS_MAX;
992 
993 	return cm_ctx->sm.cm_substate;
994 }
995 
996 static void cm_sm_print_state_event(struct cnx_mgr *cm_ctx,
997 				    enum wlan_cm_sm_evt event)
998 {
999 	enum wlan_cm_sm_state state;
1000 	enum wlan_cm_sm_state substate;
1001 
1002 	state = cm_get_state(cm_ctx);
1003 	substate = cm_get_sub_state(cm_ctx);
1004 
1005 	mlme_nofl_debug("[%s]%s - %s, %s", cm_ctx->sm.sm_hdl->name,
1006 			cm_sm_info[state].name, cm_sm_info[substate].name,
1007 			cm_sm_event_names[event]);
1008 }
1009 
1010 static void cm_sm_print_state(struct cnx_mgr *cm_ctx)
1011 {
1012 	enum wlan_cm_sm_state state;
1013 	enum wlan_cm_sm_state substate;
1014 
1015 	state = cm_get_state(cm_ctx);
1016 	substate = cm_get_sub_state(cm_ctx);
1017 
1018 	mlme_nofl_debug("[%s]%s - %s", cm_ctx->sm.sm_hdl->name,
1019 			cm_sm_info[state].name, cm_sm_info[substate].name);
1020 }
1021 
1022 QDF_STATUS cm_sm_deliver_event(struct wlan_objmgr_vdev *vdev,
1023 			       enum wlan_cm_sm_evt event,
1024 			       uint16_t data_len, void *data)
1025 {
1026 	QDF_STATUS status;
1027 	enum wlan_cm_sm_state state_entry, state_exit;
1028 	enum wlan_cm_sm_state substate_entry, substate_exit;
1029 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
1030 	struct cnx_mgr *cm_ctx;
1031 
1032 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) {
1033 		mlme_err("vdev %d Invalid mode %d",
1034 			 wlan_vdev_get_id(vdev), op_mode);
1035 		return QDF_STATUS_E_NOSUPPORT;
1036 	}
1037 
1038 	cm_ctx = cm_get_cm_ctx(vdev);
1039 	if (!cm_ctx)
1040 		return QDF_STATUS_E_FAILURE;
1041 
1042 	cm_lock_acquire(cm_ctx);
1043 
1044 	/* store entry state and sub state for prints */
1045 	state_entry = cm_get_state(cm_ctx);
1046 	substate_entry = cm_get_sub_state(cm_ctx);
1047 	cm_sm_print_state_event(cm_ctx, event);
1048 
1049 	status = cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
1050 	/* Take exit state, exit substate for prints */
1051 	state_exit = cm_get_state(cm_ctx);
1052 	substate_exit = cm_get_sub_state(cm_ctx);
1053 	/* If no state and substate change, don't print */
1054 	if (!((state_entry == state_exit) && (substate_entry == substate_exit)))
1055 		cm_sm_print_state(cm_ctx);
1056 	cm_lock_release(cm_ctx);
1057 
1058 	return status;
1059 }
1060 
1061 QDF_STATUS cm_sm_create(struct cnx_mgr *cm_ctx)
1062 {
1063 	struct wlan_sm *sm;
1064 	uint8_t name[WLAN_SM_ENGINE_MAX_NAME];
1065 
1066 	qdf_scnprintf(name, sizeof(name), "CM-VDEV-%d",
1067 		      wlan_vdev_get_id(cm_ctx->vdev));
1068 	sm = wlan_sm_create(name, cm_ctx,
1069 			    WLAN_CM_S_INIT,
1070 			    cm_sm_info,
1071 			    QDF_ARRAY_SIZE(cm_sm_info),
1072 			    cm_sm_event_names,
1073 			    QDF_ARRAY_SIZE(cm_sm_event_names));
1074 	if (!sm) {
1075 		mlme_err("vdev %d CM State Machine allocation failed",
1076 			 wlan_vdev_get_id(cm_ctx->vdev));
1077 		return QDF_STATUS_E_NOMEM;
1078 	}
1079 	cm_ctx->sm.sm_hdl = sm;
1080 
1081 	cm_lock_create(cm_ctx);
1082 
1083 	return QDF_STATUS_SUCCESS;
1084 }
1085 
1086 QDF_STATUS cm_sm_destroy(struct cnx_mgr *cm_ctx)
1087 {
1088 	cm_lock_destroy(cm_ctx);
1089 	wlan_sm_delete(cm_ctx->sm.sm_hdl);
1090 
1091 	return QDF_STATUS_SUCCESS;
1092 }
1093 
1094 #ifdef SM_ENG_HIST_ENABLE
1095 void cm_sm_history_print(struct wlan_objmgr_vdev *vdev)
1096 {
1097 	struct cnx_mgr *cm_ctx;
1098 
1099 	cm_ctx = cm_get_cm_ctx(vdev);
1100 	if (!cm_ctx) {
1101 		mlme_err("cm_ctx is NULL");
1102 		return;
1103 	}
1104 
1105 	return wlan_sm_print_history(cm_ctx->sm.sm_hdl);
1106 }
1107 #endif
1108