xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_sm.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
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("mlme state (%d) is invalid", state);
31 }
32 
33 void cm_set_substate(struct cnx_mgr *cm_ctx, enum wlan_cm_sm_state substate)
34 {
35 	if ((substate > WLAN_CM_S_MAX) && (substate < WLAN_CM_SS_MAX))
36 		cm_ctx->sm.cm_substate = substate;
37 	else
38 		mlme_err(" mlme sub state (%d) is invalid", substate);
39 }
40 
41 void cm_sm_state_update(struct cnx_mgr *cm_ctx,
42 			enum wlan_cm_sm_state state,
43 			enum wlan_cm_sm_state substate)
44 {
45 	if (!cm_ctx) {
46 		mlme_err("cm_ctx is NULL");
47 		return;
48 	}
49 
50 	cm_set_state(cm_ctx, state);
51 	cm_set_substate(cm_ctx, substate);
52 }
53 
54 /**
55  * cm_state_init_entry() - Entry API for init state for connection mgr
56  * @ctx: connection manager ctx
57  *
58  * API to perform operations on moving to init state
59  *
60  * Return: void
61  */
62 static void cm_state_init_entry(void *ctx)
63 {
64 	struct cnx_mgr *cm_ctx = ctx;
65 
66 	cm_sm_state_update(cm_ctx, WLAN_CM_S_INIT, WLAN_CM_SS_IDLE);
67 }
68 
69 /**
70  * cm_state_init_exit() - Exit API for init state for connection mgr
71  * @ctx: connection manager ctx
72  *
73  * API to perform operations on exiting from init state
74  *
75  * Return: void
76  */
77 static void cm_state_init_exit(void *ctx)
78 {
79 }
80 
81 /**
82  * cm_state_init_event() - Init State event handler for connection mgr
83  * @ctx: connection manager ctx
84  *
85  * API to handle events in INIT state
86  *
87  * Return: bool
88  */
89 static bool cm_state_init_event(void *ctx, uint16_t event,
90 				uint16_t data_len, void *data)
91 {
92 	struct cnx_mgr *cm_ctx = ctx;
93 	bool status;
94 
95 	switch (event) {
96 	case WLAN_CM_SM_EV_CONNECT_REQ:
97 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTING);
98 		cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_CONNECT_START,
99 				    data_len, data);
100 		status = true;
101 		break;
102 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
103 		cm_connect_complete(cm_ctx, data);
104 		status = true;
105 		break;
106 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
107 		cm_disconnect_complete(cm_ctx, data);
108 		status = true;
109 		break;
110 	default:
111 		status = false;
112 		break;
113 	}
114 
115 	return status;
116 }
117 
118 /**
119  * cm_state_connecting_entry() - Entry API for connecting state for
120  * connection mgr
121  * @ctx: connection manager ctx
122  *
123  * API to perform operations on moving to connecting state
124  *
125  * Return: void
126  */
127 static void cm_state_connecting_entry(void *ctx)
128 {
129 	struct cnx_mgr *cm_ctx = ctx;
130 
131 	cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTING, WLAN_CM_SS_IDLE);
132 }
133 
134 /**
135  * cm_state_connecting_exit() - Exit API for connecting state for
136  * connection mgr
137  * @ctx: connection manager ctx
138  *
139  * API to perform operations on exiting from connecting state
140  *
141  * Return: void
142  */
143 static void cm_state_connecting_exit(void *ctx)
144 {
145 }
146 
147 /**
148  * cm_state_connecting_event() - Connecting State event handler for
149  * connection mgr
150  * @ctx: connection manager ctx
151  *
152  * API to handle events in CONNECTING state
153  *
154  * Return: bool
155  */
156 static bool cm_state_connecting_event(void *ctx, uint16_t event,
157 				      uint16_t data_len, void *data)
158 {
159 	struct cnx_mgr *cm_ctx = ctx;
160 	bool status;
161 
162 	switch (event) {
163 	case WLAN_CM_SM_EV_CONNECT_START:
164 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
165 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
166 		status = true;
167 		break;
168 	default:
169 		status = false;
170 		break;
171 	}
172 
173 	return status;
174 }
175 
176 /**
177  * cm_state_connected_entry() - Entry API for connected state for
178  * connection mgr
179  * @ctx: connection manager ctx
180  *
181  * API to perform operations on moving to connected state
182  *
183  * Return: void
184  */
185 static void cm_state_connected_entry(void *ctx)
186 {
187 	struct cnx_mgr *cm_ctx = ctx;
188 
189 	cm_sm_state_update(cm_ctx, WLAN_CM_S_CONNECTED, WLAN_CM_SS_IDLE);
190 }
191 
192 /**
193  * cm_state_connected_exit() - Exit API for connected state for
194  * connection mgr
195  * @ctx: connection manager ctx
196  *
197  * API to perform operations on exiting from connected state
198  *
199  * Return: void
200  */
201 static void cm_state_connected_exit(void *ctx)
202 {
203 }
204 
205 /**
206  * cm_state_connected_event() - Connected State event handler for
207  * connection mgr
208  * @ctx: connection manager ctx
209  *
210  * API to handle events in CONNECTED state
211  *
212  * Return: bool
213  */
214 static bool cm_state_connected_event(void *ctx, uint16_t event,
215 				     uint16_t data_len, void *data)
216 {
217 	struct cnx_mgr *cm_ctx = ctx;
218 	bool status;
219 
220 	switch (event) {
221 	case WLAN_CM_SM_EV_CONNECT_SUCCESS:
222 		cm_connect_complete(cm_ctx, data);
223 		status = true;
224 		break;
225 	case WLAN_CM_SM_EV_DISCONNECT_REQ:
226 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
227 		cm_sm_deliver_event(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
228 				    data_len, data);
229 		status = true;
230 		break;
231 	default:
232 		status = false;
233 		break;
234 	}
235 
236 	return status;
237 }
238 
239 /**
240  * cm_state_disconnecting_entry() - Entry API for disconnecting state for
241  * connection mgr
242  * @ctx: connection manager ctx
243  *
244  * API to perform operations on moving to disconnecting state
245  *
246  * Return: void
247  */
248 static void cm_state_disconnecting_entry(void *ctx)
249 {
250 	struct cnx_mgr *cm_ctx = ctx;
251 
252 	cm_sm_state_update(cm_ctx, WLAN_CM_S_DISCONNECTING, WLAN_CM_SS_IDLE);
253 }
254 
255 /**
256  * cm_state_disconnecting_exit() - Exit API for disconnecting state for
257  * connection mgr
258  * @ctx: connection manager ctx
259  *
260  * API to perform operations on exiting from disconnecting state
261  *
262  * Return: void
263  */
264 static void cm_state_disconnecting_exit(void *ctx)
265 {
266 }
267 
268 /**
269  * cm_state_connected_event() - Disconnecting State event handler for
270  * connection mgr
271  * @ctx: connection manager ctx
272  *
273  * API to handle events in Disconnecting state
274  *
275  * Return: bool
276  */
277 static bool cm_state_disconnecting_event(void *ctx, uint16_t event,
278 					 uint16_t data_len, void *data)
279 {
280 	struct cnx_mgr *cm_ctx = ctx;
281 	bool status;
282 
283 	switch (event) {
284 	case WLAN_CM_SM_EV_DISCONNECT_START:
285 		cm_disconnect_start(cm_ctx, data);
286 		status = true;
287 		break;
288 	case WLAN_CM_SM_EV_DISCONNECT_ACTIVE:
289 		cm_disconnect_active(cm_ctx, data);
290 		status = true;
291 		break;
292 	case WLAN_CM_SM_EV_DISCONNECT_DONE:
293 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
294 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
295 		status = true;
296 		break;
297 	default:
298 		status = false;
299 		break;
300 	}
301 
302 	return status;
303 }
304 
305 /**
306  * cm_subst_join_pending_entry() - Entry API for join pending sub-state for
307  * connection mgr
308  * @ctx: connection manager ctx
309  *
310  * API to perform operations on moving to join pending sub-state
311  *
312  * Return: void
313  */
314 static void cm_subst_join_pending_entry(void *ctx)
315 {
316 	struct cnx_mgr *cm_ctx = ctx;
317 
318 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
319 		QDF_BUG(0);
320 
321 	cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
322 }
323 
324 /**
325  * cm_subst_join_pending_exit() - Exit API for join pending sub-state for
326  * connection mgr
327  * @ctx: connection manager ctx
328  *
329  * API to perform operations on exiting from join pending sub-state
330  *
331  * Return: void
332  */
333 static void cm_subst_join_pending_exit(void *ctx)
334 {
335 }
336 
337 /**
338  * cm_subst_join_pending_event() - Join pending sub-state event handler for
339  * connection mgr
340  * @ctx: connection manager ctx
341  *
342  * API to handle events in Join pending sub-state
343  *
344  * Return: bool
345  */
346 static bool cm_subst_join_pending_event(void *ctx, uint16_t event,
347 					uint16_t data_len, void *data)
348 {
349 	struct cnx_mgr *cm_ctx = ctx;
350 	bool status;
351 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
352 
353 	switch (event) {
354 	case WLAN_CM_SM_EV_CONNECT_START:
355 		cm_connect_start(cm_ctx, data);
356 		status = true;
357 		break;
358 	case WLAN_CM_SM_EV_CONNECT_ACTIVE:
359 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE);
360 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
361 		status = true;
362 		break;
363 	case WLAN_CM_SM_EV_SCAN:
364 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_SCAN);
365 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
366 		status = true;
367 		break;
368 	case WLAN_CM_SM_EV_SCAN_FAILURE:
369 		qdf_status = QDF_STATUS_E_FAILURE;
370 		/* Fall through after setting status failure */
371 	case WLAN_CM_SM_EV_SCAN_SUCCESS:
372 		cm_connect_scan_resp(cm_ctx, data, qdf_status);
373 		status = true;
374 		break;
375 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
376 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
377 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
378 		status = true;
379 		break;
380 	default:
381 		status = false;
382 		break;
383 	}
384 
385 	return status;
386 }
387 
388 /**
389  * cm_subst_scan_entry() - Entry API for scan sub-state for
390  * connection mgr
391  * @ctx: connection manager ctx
392  *
393  * API to perform operations on moving to scan sub-state
394  *
395  * Return: void
396  */
397 static void cm_subst_scan_entry(void *ctx)
398 {
399 	struct cnx_mgr *cm_ctx = ctx;
400 
401 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
402 		QDF_BUG(0);
403 
404 	cm_set_substate(cm_ctx, WLAN_CM_SS_SCAN);
405 }
406 
407 /**
408  * cm_subst_scan_exit() - Exit API for scan sub-state for
409  * connection mgr
410  * @ctx: connection manager ctx
411  *
412  * API to perform operations on exiting from scan sub-state
413  *
414  * Return: void
415  */
416 static void cm_subst_scan_exit(void *ctx)
417 {
418 }
419 
420 /**
421  * cm_subst_scan_event() - Scan sub-state event handler for
422  * connection mgr
423  * @ctx: connection manager ctx
424  *
425  * API to handle events in scan sub-state
426  *
427  * Return: bool
428  */
429 static bool cm_subst_scan_event(void *ctx, uint16_t event,
430 				uint16_t data_len, void *data)
431 {
432 	struct cnx_mgr *cm_ctx = ctx;
433 	bool status;
434 
435 	switch (event) {
436 	case WLAN_CM_SM_EV_SCAN:
437 		cm_connect_scan_start(cm_ctx, data);
438 		status = true;
439 		break;
440 	case WLAN_CM_SM_EV_SCAN_SUCCESS:
441 	case WLAN_CM_SM_EV_SCAN_FAILURE:
442 		cm_sm_transition_to(cm_ctx, WLAN_CM_SS_JOIN_PENDING);
443 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
444 		status = true;
445 		break;
446 	default:
447 		status = false;
448 		break;
449 	}
450 
451 	return status;
452 }
453 
454 /**
455  * cm_subst_join_active_entry() - Entry API for join active sub-state for
456  * connection mgr
457  * @ctx: connection manager ctx
458  *
459  * API to perform operations on moving to join active sub-state
460  *
461  * Return: void
462  */
463 static void cm_subst_join_active_entry(void *ctx)
464 {
465 	struct cnx_mgr *cm_ctx = ctx;
466 
467 	if (cm_get_state(cm_ctx) != WLAN_CM_S_CONNECTING)
468 		QDF_BUG(0);
469 
470 	cm_set_substate(cm_ctx, WLAN_CM_SS_JOIN_ACTIVE);
471 }
472 
473 /**
474  * cm_subst_join_active_exit() - Exit API for join active sub-state for
475  * connection mgr
476  * @ctx: connection manager ctx
477  *
478  * API to perform operations on exiting from join active sub-state
479  *
480  * Return: void
481  */
482 static void cm_subst_join_active_exit(void *ctx)
483 {
484 }
485 
486 /**
487  * cm_subst_join_active_event() - Join active sub-state event handler for
488  * connection mgr
489  * @ctx: connection manager ctx
490  *
491  * API to handle events in join active sub-state
492  *
493  * Return: bool
494  */
495 static bool cm_subst_join_active_event(void *ctx, uint16_t event,
496 				       uint16_t data_len, void *data)
497 {
498 	struct cnx_mgr *cm_ctx = ctx;
499 	bool status;
500 
501 	switch (event) {
502 	case WLAN_CM_SM_EV_CONNECT_ACTIVE:
503 		cm_connect_active(cm_ctx, data);
504 		status = true;
505 		break;
506 	case WLAN_CM_SM_EV_CONNECT_SUCCESS:
507 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_CONNECTED);
508 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
509 		status = true;
510 		break;
511 	case WLAN_CM_SM_EV_CONNECT_GET_NEXT_CANDIDATE:
512 		cm_try_next_candidate(cm_ctx, data);
513 		status = true;
514 		break;
515 	case WLAN_CM_SM_EV_CONNECT_FAILURE:
516 		cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
517 		cm_sm_deliver_event(cm_ctx, event, data_len, data);
518 		status = true;
519 		break;
520 	default:
521 		status = false;
522 		break;
523 	}
524 
525 	return status;
526 }
527 
528 struct wlan_sm_state_info cm_sm_info[] = {
529 	{
530 		(uint8_t)WLAN_CM_S_INIT,
531 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
532 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
533 		true,
534 		"INIT",
535 		cm_state_init_entry,
536 		cm_state_init_exit,
537 		cm_state_init_event
538 	},
539 	{
540 		(uint8_t)WLAN_CM_S_CONNECTING,
541 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
542 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
543 		true,
544 		"CONNECTING",
545 		cm_state_connecting_entry,
546 		cm_state_connecting_exit,
547 		cm_state_connecting_event
548 	},
549 	{
550 		(uint8_t)WLAN_CM_S_CONNECTED,
551 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
552 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
553 		true,
554 		"CONNECTED",
555 		cm_state_connected_entry,
556 		cm_state_connected_exit,
557 		cm_state_connected_event
558 	},
559 	{
560 		(uint8_t)WLAN_CM_S_DISCONNECTING,
561 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
562 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
563 		true,
564 		"DISCONNECTING",
565 		cm_state_disconnecting_entry,
566 		cm_state_disconnecting_exit,
567 		cm_state_disconnecting_event
568 	},
569 	{
570 		(uint8_t)WLAN_CM_S_ROAMING,
571 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
572 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
573 		true,
574 		"ROAMING",
575 		cm_state_roaming_entry,
576 		cm_state_roaming_exit,
577 		cm_state_roaming_event
578 	},
579 	{
580 		(uint8_t)WLAN_CM_S_MAX,
581 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
582 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
583 		false,
584 		"INVALID",
585 		NULL,
586 		NULL,
587 		NULL
588 	},
589 	{
590 		(uint8_t)WLAN_CM_SS_IDLE,
591 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
592 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
593 		false,
594 		"IDLE",
595 		NULL,
596 		NULL,
597 		NULL
598 	},
599 	{
600 		(uint8_t)WLAN_CM_SS_JOIN_PENDING,
601 		(uint8_t)WLAN_CM_S_CONNECTING,
602 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
603 		false,
604 		"JOIN_PENDING",
605 		cm_subst_join_pending_entry,
606 		cm_subst_join_pending_exit,
607 		cm_subst_join_pending_event
608 	},
609 	{
610 		(uint8_t)WLAN_CM_SS_SCAN,
611 		(uint8_t)WLAN_CM_S_CONNECTING,
612 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
613 		false,
614 		"SCAN",
615 		cm_subst_scan_entry,
616 		cm_subst_scan_exit,
617 		cm_subst_scan_event
618 	},
619 	{
620 		(uint8_t)WLAN_CM_SS_JOIN_ACTIVE,
621 		(uint8_t)WLAN_CM_S_CONNECTING,
622 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
623 		false,
624 		"JOIN_ACTIVE",
625 		cm_subst_join_active_entry,
626 		cm_subst_join_active_exit,
627 		cm_subst_join_active_event
628 	},
629 #ifdef WLAN_FEATURE_HOST_ROAM
630 	{
631 		(uint8_t)WLAN_CM_SS_PREAUTH,
632 		(uint8_t)WLAN_CM_S_ROAMING,
633 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
634 		false,
635 		"PREAUTH",
636 		cm_subst_preauth_entry,
637 		cm_subst_preauth_exit,
638 		cm_subst_preauth_event
639 	},
640 	{
641 		(uint8_t)WLAN_CM_SS_REASSOC,
642 		(uint8_t)WLAN_CM_S_ROAMING,
643 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
644 		false,
645 		"REASSOC",
646 		cm_subst_reassoc_entry,
647 		cm_subst_reassoc_exit,
648 		cm_subst_reassoc_event
649 	},
650 #endif
651 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
652 	{
653 		(uint8_t)WLAN_CM_SS_ROAM_STARTED,
654 		(uint8_t)WLAN_CM_S_ROAMING,
655 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
656 		false,
657 		"ROAM_START",
658 		cm_subst_roam_start_entry,
659 		cm_subst_roam_start_exit,
660 		cm_subst_roam_start_event
661 	},
662 	{
663 		(uint8_t)WLAN_CM_SS_ROAM_SYNC,
664 		(uint8_t)WLAN_CM_S_ROAMING,
665 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
666 		false,
667 		"ROAM_SYNC",
668 		cm_subst_roam_sync_entry,
669 		cm_subst_roam_sync_exit,
670 		cm_subst_roam_sync_event
671 	},
672 #endif
673 	{
674 		(uint8_t)WLAN_CM_SS_MAX,
675 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
676 		(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
677 		false,
678 		"INVALID",
679 		NULL,
680 		NULL,
681 		NULL
682 	},
683 };
684 
685 static const char *cm_sm_event_names[] = {
686 	"EV_CONNECT_REQ",
687 	"EV_SCAN",
688 	"EV_SCAN_SUCCESS",
689 	"EV_SCAN_FAILURE",
690 	"EV_CONNECT_START",
691 	"EV_CONNECT_ACTIVE",
692 	"EV_CONNECT_SUCCESS",
693 	"EV_CONNECT_GET_NXT_CANDIDATE",
694 	"EV_CONNECT_FAILURE",
695 	"EV_DISCONNECT_REQ",
696 	"EV_DISCONNECT_START",
697 	"EV_DISCONNECT_ACTIVE",
698 	"EV_DISCONNECT_DONE",
699 	"EV_ROAM_START",
700 	"EV_ROAM_SYNC",
701 	"EV_ROAM_INVOKE_FAIL",
702 	"EV_ROAM_HO_FAIL",
703 	"EV_PREAUTH_DONE",
704 	"EV_GET_NEXT_PREAUTH_AP",
705 	"EV_PREAUTH_FAIL",
706 	"EV_START_REASSOC",
707 	"EV_REASSOC_DONE",
708 	"EV_REASSOC_FAILURE",
709 	"EV_ROAM_COMPLETE",
710 };
711 
712 enum wlan_cm_sm_state cm_get_state(struct cnx_mgr *cm_ctx)
713 {
714 	enum QDF_OPMODE op_mode;
715 
716 	if (!cm_ctx || !cm_ctx->vdev)
717 		return WLAN_CM_S_MAX;
718 
719 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
720 
721 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
722 		return WLAN_CM_S_MAX;
723 
724 	return cm_ctx->sm.cm_state;
725 }
726 
727 enum wlan_cm_sm_state cm_get_sub_state(struct cnx_mgr *cm_ctx)
728 {
729 	enum QDF_OPMODE op_mode;
730 
731 	if (!cm_ctx || !cm_ctx->vdev)
732 		return WLAN_CM_SS_MAX;
733 
734 	op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
735 
736 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
737 		return WLAN_CM_SS_MAX;
738 
739 	return cm_ctx->sm.cm_substate;
740 }
741 
742 static void cm_sm_print_state_event(struct cnx_mgr *cm_ctx,
743 				    enum wlan_cm_sm_evt event)
744 {
745 	enum wlan_cm_sm_state state;
746 	enum wlan_cm_sm_state substate;
747 
748 	state = cm_get_state(cm_ctx);
749 	substate = cm_get_sub_state(cm_ctx);
750 
751 	mlme_nofl_debug("[%s]%s - %s, %s", cm_ctx->sm.sm_hdl->name,
752 			cm_sm_info[state].name, cm_sm_info[substate].name,
753 			cm_sm_event_names[event]);
754 }
755 
756 static void cm_sm_print_state(struct cnx_mgr *cm_ctx)
757 {
758 	enum wlan_cm_sm_state state;
759 	enum wlan_cm_sm_state substate;
760 
761 	state = cm_get_state(cm_ctx);
762 	substate = cm_get_sub_state(cm_ctx);
763 
764 	mlme_nofl_debug("[%s]%s - %s", cm_ctx->sm.sm_hdl->name,
765 			cm_sm_info[state].name, cm_sm_info[substate].name);
766 }
767 
768 QDF_STATUS wlan_cm_sm_deliver_evt(struct wlan_objmgr_vdev *vdev,
769 				  enum wlan_cm_sm_evt event,
770 				  uint16_t data_len, void *data)
771 {
772 	struct vdev_mlme_obj *vdev_mlme;
773 	QDF_STATUS status;
774 	enum wlan_cm_sm_state state_entry, state_exit;
775 	enum wlan_cm_sm_state substate_entry, substate_exit;
776 	enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev);
777 	struct cnx_mgr *cm_ctx;
778 
779 	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) {
780 		mlme_err("Invalid mode %d", op_mode);
781 		return QDF_STATUS_E_NOSUPPORT;
782 	}
783 
784 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
785 	if (!vdev_mlme || !vdev_mlme->cnx_mgr_ctx) {
786 		mlme_err("vdev mlme or cm ctx is NULL");
787 		return QDF_STATUS_E_FAILURE;
788 	}
789 	cm_ctx = vdev_mlme->cnx_mgr_ctx;
790 	cm_lock_acquire(cm_ctx);
791 
792 	/* store entry state and sub state for prints */
793 	state_entry = cm_get_state(cm_ctx);
794 	substate_entry = cm_get_sub_state(cm_ctx);
795 	cm_sm_print_state_event(cm_ctx, event);
796 
797 	status = cm_sm_deliver_event(cm_ctx, event, data_len, data);
798 	/* Take exit state, exit substate for prints */
799 	state_exit = cm_get_state(cm_ctx);
800 	substate_exit = cm_get_sub_state(cm_ctx);
801 	/* If no state and substate change, don't print */
802 	if (!((state_entry == state_exit) && (substate_entry == substate_exit)))
803 		cm_sm_print_state(cm_ctx);
804 	cm_lock_release(cm_ctx);
805 
806 	return status;
807 }
808 
809 QDF_STATUS cm_sm_create(struct cnx_mgr *cm_ctx)
810 {
811 	struct wlan_sm *sm;
812 	uint8_t name[WLAN_SM_ENGINE_MAX_NAME];
813 
814 	qdf_snprintf(name, sizeof(name), "CM-VDEV-%d",
815 		     wlan_vdev_get_id(cm_ctx->vdev));
816 	sm = wlan_sm_create(name, cm_ctx,
817 			    WLAN_CM_S_INIT,
818 			    cm_sm_info,
819 			    QDF_ARRAY_SIZE(cm_sm_info),
820 			    cm_sm_event_names,
821 			    QDF_ARRAY_SIZE(cm_sm_event_names));
822 	if (!sm) {
823 		mlme_err("CM MLME SM allocation failed");
824 		return QDF_STATUS_E_NOMEM;
825 	}
826 	cm_ctx->sm.sm_hdl = sm;
827 
828 	cm_lock_create(cm_ctx);
829 
830 	return QDF_STATUS_SUCCESS;
831 }
832 
833 QDF_STATUS cm_sm_destroy(struct cnx_mgr *cm_ctx)
834 {
835 	cm_lock_destroy(cm_ctx);
836 	wlan_sm_delete(cm_ctx->sm.sm_hdl);
837 
838 	return QDF_STATUS_SUCCESS;
839 }
840