1 /*
2  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  *
22  * This file lim_process_deauth_frame.cc contains the code
23  * for processing Deauthentication Frame.
24  * Author:        Chandra Modumudi
25  * Date:          03/24/02
26  * History:-
27  * Date           Modified by    Modification Information
28  * --------------------------------------------------------------------
29  *
30  */
31 #include "cds_api.h"
32 #include "ani_global.h"
33 
34 #include "utils_api.h"
35 #include "lim_types.h"
36 #include "lim_utils.h"
37 #include "lim_assoc_utils.h"
38 #include "lim_security_utils.h"
39 #include "lim_ser_des_utils.h"
40 #include "sch_api.h"
41 #include "lim_send_messages.h"
42 #include "wlan_connectivity_logging.h"
43 #include "cds_ieee80211_common.h"
44 
45 /**
46  * lim_process_deauth_frame
47  *
48  ***FUNCTION:
49  * This function is called by limProcessMessageQueue() upon
50  * Deauthentication frame reception.
51  *
52  ***LOGIC:
53  *
54  ***ASSUMPTIONS:
55  *
56  ***NOTE:
57  *
58  * @param  mac - Pointer to Global MAC structure
59  * @param  *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs
60  * @return None
61  */
62 
63 void
lim_process_deauth_frame(struct mac_context * mac,uint8_t * pRxPacketInfo,struct pe_session * pe_session)64 lim_process_deauth_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
65 			 struct pe_session *pe_session)
66 {
67 	uint8_t *pBody;
68 	uint16_t reasonCode;
69 	tpSirMacMgmtHdr pHdr;
70 	struct pe_session *pRoamSessionEntry = NULL;
71 	uint8_t roamSessionId;
72 	uint32_t frameLen;
73 	int32_t frame_rssi;
74 
75 	pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
76 
77 	pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo);
78 	frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo);
79 	frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
80 	if (frameLen < sizeof(reasonCode)) {
81 		pe_err("Deauth Frame length invalid %d", frameLen);
82 		return ;
83 	}
84 
85 	if (LIM_IS_STA_ROLE(pe_session) &&
86 	    wlan_drop_mgmt_frame_on_link_removal(pe_session->vdev)) {
87 		pe_debug("Received deauth Frame when link removed on vdev %d",
88 			 wlan_vdev_get_id(pe_session->vdev));
89 		return;
90 	}
91 
92 	if (LIM_IS_STA_ROLE(pe_session) &&
93 	    !(lim_is_sb_disconnect_allowed(pe_session) ||
94 	      (pe_session->limMlmState == eLIM_MLM_WT_SAE_AUTH_STATE &&
95 	       pe_session->limSmeState == eLIM_SME_WT_AUTH_STATE))) {
96 		/*Every 15th deauth frame will be logged in kmsg */
97 		if (!(mac->lim.deauthMsgCnt & 0xF)) {
98 			pe_debug("received Deauth frame in DEAUTH_WT_STATE"
99 				"(already processing previously received DEAUTH frame)"
100 				"Dropping this.. Deauth Failed %d",
101 				       ++mac->lim.deauthMsgCnt);
102 		} else {
103 			mac->lim.deauthMsgCnt++;
104 		}
105 		return;
106 	}
107 
108 	if (IEEE80211_IS_MULTICAST(pHdr->sa)) {
109 		/* Received Deauth frame from a BC/MC address */
110 		/* Log error and ignore it */
111 		pe_debug("received Deauth frame from a BC/MC address");
112 		return;
113 	}
114 
115 	if (IEEE80211_IS_MULTICAST(pHdr->da) &&
116 	    !QDF_IS_ADDR_BROADCAST(pHdr->da)) {
117 		/* Received Deauth frame for a MC address */
118 		/* Log error and ignore it */
119 		pe_debug("received Deauth frame for a MC address");
120 		return;
121 	}
122 	if (!lim_validate_received_frame_a1_addr(mac,
123 			pHdr->da, pe_session)) {
124 		pe_err("rx frame doesn't have valid a1 address, drop it");
125 		return;
126 	}
127 
128 	/* PMF: If this session is a PMF session, then ensure that this frame was protected */
129 	if (is_mgmt_protected(pe_session->vdev_id, (const uint8_t *)pHdr->sa) &&
130 	    (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) &
131 		DPU_FEEDBACK_UNPROTECTED_ERROR)) {
132 		pe_debug("received an unprotected deauth from AP");
133 		/*
134 		 * When 11w offload is enabled then
135 		 * firmware should not fwd this frame
136 		 */
137 		if (LIM_IS_STA_ROLE(pe_session) && mac->pmf_offload) {
138 			pe_err("11w offload is enable,unprotected deauth is not expected");
139 			return;
140 		}
141 
142 		/* If the frame received is unprotected, forward it to the supplicant to initiate */
143 		/* an SA query */
144 
145 		/* send the unprotected frame indication to SME */
146 		lim_send_sme_unprotected_mgmt_frame_ind(mac, pHdr->fc.subType,
147 							(uint8_t *) pHdr,
148 							(frameLen +
149 							 sizeof(tSirMacMgmtHdr)),
150 							pe_session->smeSessionId,
151 							pe_session);
152 		return;
153 	}
154 
155 	/* Get reasonCode from Deauthentication frame body */
156 	reasonCode = sir_read_u16(pBody);
157 
158 	pe_nofl_rl_info("Deauth RX: vdev %d from "QDF_MAC_ADDR_FMT" for "QDF_MAC_ADDR_FMT" RSSI = %d reason %d mlm state = %d, sme state = %d systemrole = %d ",
159 			pe_session->vdev_id, QDF_MAC_ADDR_REF(pHdr->sa),
160 			QDF_MAC_ADDR_REF(pHdr->da), frame_rssi,
161 			reasonCode, pe_session->limMlmState,
162 			pe_session->limSmeState,
163 			GET_LIM_SYSTEM_ROLE(pe_session));
164 
165 	lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_FRAME_EVENT,
166 		pe_session, 0, reasonCode);
167 
168 	lim_cp_stats_cstats_log_deauth_evt(pe_session, CSTATS_DIR_RX,
169 					   reasonCode);
170 
171 	if (lim_check_disassoc_deauth_ack_pending(mac, (uint8_t *) pHdr->sa)) {
172 		pe_debug("Ignore the Deauth received, while waiting for ack of "
173 			"disassoc/deauth");
174 		lim_clean_up_disassoc_deauth_req(mac, (uint8_t *) pHdr->sa, 1);
175 		wlan_connectivity_mgmt_event(mac->psoc, (struct wlan_frame_hdr *)pHdr,
176 					     pe_session->vdev_id, reasonCode,
177 					     0, frame_rssi, 0, 0, 0, 0,
178 					     WLAN_DEAUTH_RX);
179 		return;
180 	}
181 
182 	if (LIM_IS_AP_ROLE(pe_session)) {
183 		switch (reasonCode) {
184 		case REASON_UNSPEC_FAILURE:
185 		case REASON_DEAUTH_NETWORK_LEAVING:
186 			/* Valid reasonCode in received Deauthentication frame */
187 			break;
188 
189 		default:
190 			/* Invalid reasonCode in received Deauthentication frame */
191 			/* Log error and ignore the frame */
192 			pe_err("received Deauth frame with invalid reasonCode %d from "
193 				       QDF_MAC_ADDR_FMT, reasonCode,
194 				       QDF_MAC_ADDR_REF(pHdr->sa));
195 
196 			break;
197 		}
198 	} else if (LIM_IS_STA_ROLE(pe_session)) {
199 		switch (reasonCode) {
200 		case REASON_UNSPEC_FAILURE:
201 		case REASON_PREV_AUTH_NOT_VALID:
202 		case REASON_DEAUTH_NETWORK_LEAVING:
203 		case REASON_CLASS2_FRAME_FROM_NON_AUTH_STA:
204 		case REASON_CLASS3_FRAME_FROM_NON_ASSOC_STA:
205 		case REASON_STA_NOT_AUTHENTICATED:
206 			/* Valid reasonCode in received Deauth frame */
207 			break;
208 
209 		default:
210 			/* Invalid reasonCode in received Deauth frame */
211 			/* Log error and ignore the frame */
212 			pe_err("received Deauth frame with invalid reasonCode %d from "
213 				       QDF_MAC_ADDR_FMT, reasonCode,
214 				       QDF_MAC_ADDR_REF(pHdr->sa));
215 
216 			break;
217 		}
218 	} else {
219 		/* Received Deauth frame un-known role. Log and ignore it */
220 		pe_err("received Deauth frame with reasonCode %d in role %d from "
221 			QDF_MAC_ADDR_FMT, reasonCode,
222 			GET_LIM_SYSTEM_ROLE(pe_session),
223 			QDF_MAC_ADDR_REF(pHdr->sa));
224 
225 		return;
226 	}
227 
228 	/** If we are in the middle of ReAssoc, a few things could happen:
229 	 *  - STA is reassociating to current AP, and receives deauth from:
230 	 *         a) current AP
231 	 *         b) other AP
232 	 *  - STA is reassociating to a new AP, and receives deauth from:
233 	 *         c) current AP
234 	 *         d) reassoc AP
235 	 *         e) other AP
236 	 *
237 	 *  The logic is:
238 	 *  1) If rcv deauth from an AP other than the one we're trying to
239 	 *     reassociate with, then drop the deauth frame (case b, c, e)
240 	 *  2) If rcv deauth from the "new" reassoc AP (case d), then restore
241 	 *     context with previous AP and send SME_REASSOC_RSP failure.
242 	 *  3) If rcv deauth from the reassoc AP, which is also the same
243 	 *     AP we're currently associated with (case a), then proceed
244 	 *     with normal deauth processing.
245 	 */
246 	pRoamSessionEntry =
247 		pe_find_session_by_bssid(mac, pe_session->limReAssocbssId,
248 							&roamSessionId);
249 
250 	if (lim_is_reassoc_in_progress(mac, pe_session) ||
251 	    lim_is_reassoc_in_progress(mac, pRoamSessionEntry) ||
252 	    MLME_IS_ROAMING_IN_PROG(mac->psoc, pe_session->vdev_id)) {
253 		/*
254 		 * For LFR3, the roaming bssid is not known during ROAM_START,
255 		 * so check if the deauth is received from current AP when
256 		 * roaming is being done in the firmware
257 		 */
258 		if (MLME_IS_ROAMING_IN_PROG(mac->psoc, pe_session->vdev_id) &&
259 		    IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) {
260 			pe_debug("LFR3: Drop deauth frame from connected AP");
261 			/*
262 			 * recvd_deauth_while_roaming will be stored in the
263 			 * current AP session amd if roaming has been aborted
264 			 * for some reason and come back to same AP, then issue
265 			 * a disconnect internally if this flag is true. There
266 			 * is no need to reset this flag to false, because if
267 			 * roaming succeeds, then this session gets deleted and
268 			 * new session is created.
269 			 */
270 			pe_session->recvd_deauth_while_roaming = true;
271 			pe_session->deauth_disassoc_rc = reasonCode;
272 			return;
273 		}
274 		if (!IS_REASSOC_BSSID(mac, pHdr->sa, pe_session)) {
275 			pe_debug("Rcv Deauth from unknown/different "
276 				"AP while ReAssoc. Ignore " QDF_MAC_ADDR_FMT
277 				"limReAssocbssId : " QDF_MAC_ADDR_FMT,
278 				QDF_MAC_ADDR_REF(pHdr->sa),
279 				QDF_MAC_ADDR_REF(pe_session->limReAssocbssId));
280 			return;
281 		}
282 
283 		/** Received deauth from the new AP to which we tried to ReAssociate.
284 		 *  Drop ReAssoc and Restore the Previous context( current connected AP).
285 		 */
286 		if (!IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) {
287 			pe_debug("received DeAuth from the New AP to "
288 				"which ReAssoc is sent " QDF_MAC_ADDR_FMT
289 				"pe_session->bssId: " QDF_MAC_ADDR_FMT,
290 				QDF_MAC_ADDR_REF(pHdr->sa),
291 				QDF_MAC_ADDR_REF(pe_session->bssId));
292 
293 			lim_restore_pre_reassoc_state(mac,
294 						      eSIR_SME_REASSOC_REFUSED,
295 						      reasonCode,
296 						      pe_session);
297 			return;
298 		}
299 	}
300 
301 	/* If received DeAuth from AP other than the one we're trying to join with
302 	 * nor associated with, then ignore deauth and delete Pre-auth entry.
303 	 */
304 	if (!LIM_IS_AP_ROLE(pe_session)) {
305 		if (!IS_CURRENT_BSSID(mac, pHdr->bssId, pe_session)) {
306 			pe_err("received DeAuth from an AP other "
307 				"than we're trying to join. Ignore. "
308 				QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(pHdr->sa));
309 
310 			if (lim_search_pre_auth_list(mac, pHdr->sa)) {
311 				pe_debug("Preauth entry exist. Deleting");
312 				lim_delete_pre_auth_node(mac, pHdr->sa);
313 			}
314 			return;
315 		}
316 	}
317 
318 	lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr,
319 					WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
320 	wlan_connectivity_mgmt_event(mac->psoc, (struct wlan_frame_hdr *)pHdr,
321 				     pe_session->vdev_id, reasonCode,
322 				     0, frame_rssi, 0, 0, 0, 0,
323 				     WLAN_DEAUTH_RX);
324 
325 	lim_perform_deauth(mac, pe_session, reasonCode, pHdr->sa,
326 			   frame_rssi);
327 
328 	if (mac->mlme_cfg->gen.fatal_event_trigger &&
329 	    (reasonCode != REASON_UNSPEC_FAILURE &&
330 	    reasonCode != REASON_DEAUTH_NETWORK_LEAVING &&
331 	    reasonCode != REASON_DISASSOC_NETWORK_LEAVING)) {
332 		cds_flush_logs(WLAN_LOG_TYPE_FATAL,
333 			       WLAN_LOG_INDICATOR_HOST_DRIVER,
334 			       WLAN_LOG_REASON_DISCONNECT,
335 			       false, false);
336 	}
337 
338 } /*** end lim_process_deauth_frame() ***/
339 
340 #ifdef WLAN_FEATURE_SAE
341 /*
342  * lim_process_sae_auth_msg() - Process auth msg after receiving deauth
343  * @mac_ctx: Global MAC context
344  * @pe_session: PE session entry pointer
345  * @addr: peer address/ source address
346  *
347  * Return: None
348  */
lim_process_sae_auth_msg(struct mac_context * mac_ctx,struct pe_session * pe_session,tSirMacAddr addr)349 static void lim_process_sae_auth_msg(struct mac_context *mac_ctx,
350 				     struct pe_session *pe_session,
351 				     tSirMacAddr addr)
352 {
353 	struct sir_sae_msg *sae_msg;
354 
355 	sae_msg = qdf_mem_malloc(sizeof(*sae_msg));
356 	if (!sae_msg)
357 		return;
358 
359 	sae_msg->vdev_id = pe_session->vdev_id;
360 	sae_msg->sae_status = STATUS_UNSPECIFIED_FAILURE;
361 	sae_msg->result_code = eSIR_SME_AUTH_REFUSED;
362 	qdf_mem_copy(sae_msg->peer_mac_addr, addr, QDF_MAC_ADDR_SIZE);
363 	lim_process_sae_msg(mac_ctx, sae_msg);
364 
365 	qdf_mem_free(sae_msg);
366 }
367 #else
lim_process_sae_auth_msg(struct mac_context * mac_ctx,struct pe_session * pe_session,tSirMacAddr addr)368 static inline void lim_process_sae_auth_msg(struct mac_context *mac_ctx,
369 					    struct pe_session *pe_session,
370 					    tSirMacAddr addr)
371 {}
372 #endif
373 
lim_perform_deauth(struct mac_context * mac_ctx,struct pe_session * pe_session,uint16_t rc,tSirMacAddr addr,int32_t frame_rssi)374 void lim_perform_deauth(struct mac_context *mac_ctx, struct pe_session *pe_session,
375 			uint16_t rc, tSirMacAddr addr, int32_t frame_rssi)
376 {
377 	tLimMlmDeauthInd mlmDeauthInd;
378 	tLimMlmAssocCnf mlmAssocCnf;
379 	uint16_t aid;
380 	tpDphHashNode sta_ds;
381 	tpSirAssocRsp assoc_rsp;
382 
383 	sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid,
384 				       &pe_session->dph.dphHashTable);
385 	if (!sta_ds) {
386 		pe_debug("Hash entry not found");
387 		return;
388 	}
389 	/* Check for pre-assoc states */
390 	switch (GET_LIM_SYSTEM_ROLE(pe_session)) {
391 	case eLIM_STA_ROLE:
392 		switch (pe_session->limMlmState) {
393 		case eLIM_MLM_WT_AUTH_FRAME2_STATE:
394 			/**
395 			 * AP sent Deauth frame while waiting
396 			 * for Auth frame2. Report Auth failure
397 			 * to SME.
398 			 */
399 
400 			pe_debug("received Deauth frame state %X with failure "
401 				"code %d from " QDF_MAC_ADDR_FMT,
402 				pe_session->limMlmState, rc,
403 				QDF_MAC_ADDR_REF(addr));
404 
405 			lim_restore_from_auth_state(mac_ctx,
406 				eSIR_SME_DEAUTH_WHILE_JOIN,
407 				rc, pe_session);
408 
409 			return;
410 
411 		case eLIM_MLM_AUTHENTICATED_STATE:
412 			pe_debug("received Deauth frame state %X with "
413 				"reasonCode=%d from " QDF_MAC_ADDR_FMT,
414 				pe_session->limMlmState, rc,
415 				QDF_MAC_ADDR_REF(addr));
416 			/* / Issue Deauth Indication to SME. */
417 			qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr,
418 				addr, sizeof(tSirMacAddr));
419 				mlmDeauthInd.reasonCode = rc;
420 
421 			pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
422 			MTRACE(mac_trace
423 				(mac_ctx, TRACE_CODE_MLM_STATE,
424 				 pe_session->peSessionId,
425 				 pe_session->limMlmState));
426 
427 			lim_post_sme_message(mac_ctx,
428 					LIM_MLM_DEAUTH_IND,
429 					(uint32_t *) &mlmDeauthInd);
430 			return;
431 
432 		case eLIM_MLM_WT_ASSOC_RSP_STATE:
433 			/**
434 			 * AP may have 'aged-out' our Pre-auth
435 			 * context. Delete local pre-auth context
436 			 * if any and issue ASSOC_CNF to SME.
437 			 */
438 			pe_debug("received Deauth frame state %X with "
439 				"reasonCode=%d from " QDF_MAC_ADDR_FMT,
440 				pe_session->limMlmState, rc,
441 				QDF_MAC_ADDR_REF(addr));
442 			if (lim_search_pre_auth_list(mac_ctx, addr))
443 				lim_delete_pre_auth_node(mac_ctx, addr);
444 
445 			lim_stop_pmfcomeback_timer(pe_session);
446 			if (pe_session->pLimMlmJoinReq) {
447 				qdf_mem_free(pe_session->pLimMlmJoinReq);
448 				pe_session->pLimMlmJoinReq = NULL;
449 			}
450 
451 			mlmAssocCnf.resultCode = eSIR_SME_DEAUTH_WHILE_JOIN;
452 			mlmAssocCnf.protStatusCode = rc;
453 
454 			/* PE session Id */
455 			mlmAssocCnf.sessionId = pe_session->peSessionId;
456 
457 			pe_session->limMlmState =
458 			pe_session->limPrevMlmState;
459 			MTRACE(mac_trace
460 				(mac_ctx, TRACE_CODE_MLM_STATE,
461 				 pe_session->peSessionId,
462 				 pe_session->limMlmState));
463 
464 			/* Deactivate Association response timeout */
465 			lim_deactivate_and_change_timer(mac_ctx,
466 					eLIM_ASSOC_FAIL_TIMER);
467 
468 			lim_post_sme_message(mac_ctx,
469 					LIM_MLM_ASSOC_CNF,
470 			(uint32_t *) &mlmAssocCnf);
471 
472 			return;
473 
474 		case eLIM_MLM_WT_ADD_STA_RSP_STATE:
475 			pe_session->fDeauthReceived = true;
476 			pe_debug("Received Deauth frame in state %X with Reason "
477 				"Code %d from Peer" QDF_MAC_ADDR_FMT,
478 				pe_session->limMlmState, rc,
479 				QDF_MAC_ADDR_REF(addr));
480 			return;
481 
482 		case eLIM_MLM_IDLE_STATE:
483 		case eLIM_MLM_LINK_ESTABLISHED_STATE:
484 #ifdef FEATURE_WLAN_TDLS
485 			if ((sta_ds)
486 				&& (STA_ENTRY_TDLS_PEER == sta_ds->staType)) {
487 				pe_err("received Deauth frame in state %X with "
488 					"reason code %d from Tdls peer"
489 					QDF_MAC_ADDR_FMT,
490 					pe_session->limMlmState, rc,
491 					QDF_MAC_ADDR_REF(addr));
492 			lim_send_sme_tdls_del_sta_ind(mac_ctx, sta_ds,
493 							pe_session,
494 							rc);
495 			return;
496 			} else {
497 
498 			/*
499 			 * Delete all the TDLS peers only if Deauth
500 			 * is received from the AP
501 			 */
502 				if (IS_CURRENT_BSSID(mac_ctx, addr, pe_session))
503 					lim_delete_tdls_peers(mac_ctx, pe_session);
504 #endif
505 			/**
506 			 * This could be Deauthentication frame from
507 			 * a BSS with which pre-authentication was
508 			 * performed. Delete Pre-auth entry if found.
509 			 */
510 			if (lim_search_pre_auth_list(mac_ctx, addr))
511 				lim_delete_pre_auth_node(mac_ctx, addr);
512 #ifdef FEATURE_WLAN_TDLS
513 			}
514 #endif
515 			break;
516 
517 		case eLIM_MLM_WT_REASSOC_RSP_STATE:
518 			pe_err("received Deauth frame state %X with "
519 				"reasonCode=%d from " QDF_MAC_ADDR_FMT,
520 				pe_session->limMlmState, rc,
521 				QDF_MAC_ADDR_REF(addr));
522 			break;
523 
524 		case eLIM_MLM_WT_FT_REASSOC_RSP_STATE:
525 			pe_err("received Deauth frame in FT state %X with "
526 				"reasonCode=%d from " QDF_MAC_ADDR_FMT,
527 				pe_session->limMlmState, rc,
528 				QDF_MAC_ADDR_REF(addr));
529 			break;
530 
531 		case eLIM_MLM_WT_SAE_AUTH_STATE:
532 			pe_debug("received Deauth frame state %X with "
533 				 "reasonCode=%d from " QDF_MAC_ADDR_FMT,
534 				 pe_session->limMlmState, rc,
535 				 QDF_MAC_ADDR_REF(addr));
536 
537 			/* this will be treated as SAE authenticaton failure
538 			 * and connect failure to userspace.
539 			 */
540 			lim_process_sae_auth_msg(mac_ctx, pe_session, addr);
541 			return;
542 
543 		default:
544 			pe_err("received Deauth frame in state %X with "
545 				"reasonCode=%d from " QDF_MAC_ADDR_FMT,
546 				pe_session->limMlmState, rc,
547 				QDF_MAC_ADDR_REF(addr));
548 			return;
549 		}
550 		break;
551 
552 	case eLIM_AP_ROLE:
553 		break;
554 
555 	default:
556 		return;
557 	} /* end switch (mac->lim.gLimSystemRole) */
558 
559 	/**
560 	 * Extract 'associated' context for STA, if any.
561 	 * This is maintained by DPH and created by LIM.
562 	 */
563 	if (!sta_ds) {
564 		pe_err("sta_ds is NULL");
565 		return;
566 	}
567 
568 	if ((sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) ||
569 	    (sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) ||
570 	    sta_ds->sta_deletion_in_progress) {
571 		/**
572 		 * Already in the process of deleting context for the peer
573 		 * and received Deauthentication frame. Log and Ignore.
574 		 */
575 		pe_debug("Deletion is in progress (%d) for peer:"QDF_MAC_ADDR_FMT" in mlmState %d",
576 			 sta_ds->sta_deletion_in_progress,
577 			 QDF_MAC_ADDR_REF(addr),
578 			 sta_ds->mlmStaContext.mlmState);
579 		return;
580 	}
581 	sta_ds->mlmStaContext.disassocReason = rc;
582 	sta_ds->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DEAUTH;
583 	sta_ds->sta_deletion_in_progress = true;
584 
585 	/* / Issue Deauth Indication to SME. */
586 	qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr,
587 			sta_ds->staAddr, sizeof(tSirMacAddr));
588 	mlmDeauthInd.reasonCode =
589 		(uint8_t) sta_ds->mlmStaContext.disassocReason;
590 	mlmDeauthInd.deauthTrigger = eLIM_PEER_ENTITY_DEAUTH;
591 
592 	/*
593 	 * If we're in the middle of ReAssoc and received deauth from
594 	 * the ReAssoc AP, then notify SME by sending REASSOC_RSP with
595 	 * failure result code. SME will post the disconnect to the
596 	 * supplicant and the latter would start a fresh assoc.
597 	 */
598 	if (lim_is_reassoc_in_progress(mac_ctx, pe_session)) {
599 		/**
600 		 * AP may have 'aged-out' our Pre-auth
601 		 * context. Delete local pre-auth context
602 		 * if any and issue REASSOC_CNF to SME.
603 		 */
604 		if (lim_search_pre_auth_list(mac_ctx, addr))
605 			lim_delete_pre_auth_node(mac_ctx, addr);
606 
607 		if (pe_session->limAssocResponseData) {
608 			assoc_rsp = (tpSirAssocRsp) pe_session->
609 					limAssocResponseData;
610 			qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk);
611 			qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk);
612 			qdf_mem_free(pe_session->limAssocResponseData);
613 			pe_session->limAssocResponseData = NULL;
614 		}
615 
616 		pe_debug("Rcv Deauth from ReAssoc AP Issue REASSOC_CNF");
617 		/*
618 		 * TODO: Instead of overloading eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE
619 		 * it would have been good to define/use a different failure type.
620 		 * Using eSIR_SME_FT_REASSOC_FAILURE does not seem to clean-up
621 		 * properly and we end up seeing "transmit queue timeout".
622 		 */
623 		lim_post_reassoc_failure(mac_ctx,
624 				eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE,
625 				STATUS_UNSPECIFIED_FAILURE,
626 				pe_session);
627 		return;
628 	}
629 	/* reset the deauthMsgCnt here since we are able to Process
630 	 * the deauth frame and sending up the indication as well */
631 	if (mac_ctx->lim.deauthMsgCnt != 0) {
632 		mac_ctx->lim.deauthMsgCnt = 0;
633 	}
634 	if (LIM_IS_STA_ROLE(pe_session))
635 		wma_tx_abort(pe_session->smeSessionId);
636 
637 	lim_update_lost_link_info(mac_ctx, pe_session, frame_rssi);
638 
639 	/* / Deauthentication from peer MAC entity */
640 	if (LIM_IS_STA_ROLE(pe_session))
641 		lim_post_sme_message(mac_ctx, LIM_MLM_DEAUTH_IND,
642 				(uint32_t *) &mlmDeauthInd);
643 
644 	/* send eWNI_SME_DEAUTH_IND to SME */
645 	lim_send_sme_deauth_ind(mac_ctx, sta_ds, pe_session);
646 	return;
647 
648 }
649