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