blob: 33a1c089d2322762c8d33cfd911b3bbe117be79c [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/*
29 *
30 * This file lim_process_disassoc_frame.cc contains the code
31 * for processing Disassocation Frame.
32 * Author: Chandra Modumudi
33 * Date: 03/24/02
34 * History:-
35 * Date Modified by Modification Information
36 * --------------------------------------------------------------------
37 *
38 */
39#include "cds_api.h"
40#include "wni_api.h"
41#include "sir_api.h"
42#include "ani_global.h"
43#include "wni_cfg.h"
44
45#include "utils_api.h"
46#include "lim_types.h"
47#include "lim_utils.h"
48#include "lim_assoc_utils.h"
49#include "lim_security_utils.h"
50#include "lim_ser_des_utils.h"
51#include "lim_send_messages.h"
52#include "sch_api.h"
53
54/**
55 * lim_process_disassoc_frame
56 *
57 ***FUNCTION:
58 * This function is called by limProcessMessageQueue() upon
59 * Disassociation frame reception.
60 *
61 ***LOGIC:
62 *
63 ***ASSUMPTIONS:
64 * DPH drops packets for STA with 'valid' bit in pStaDs set to '0'.
65 *
66 ***NOTE:
67 *
68 * @param pMac - Pointer to Global MAC structure
69 * @param *pRxPacketInfo - A pointer to Rx packet info structure
70 * @return None
71 */
72void
73lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo,
74 tpPESession psessionEntry)
75{
76 uint8_t *pBody;
77 uint16_t aid, reasonCode;
78 tpSirMacMgmtHdr pHdr;
79 tpDphHashNode pStaDs;
80 tLimMlmDisassocInd mlmDisassocInd;
81#ifdef WLAN_FEATURE_11W
82 uint32_t frameLen;
83#endif
84
85 pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
86 pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo);
87
88 if (lim_is_group_addr(pHdr->sa)) {
89 /* Received Disassoc frame from a BC/MC address */
90 /* Log error and ignore it */
91 PELOGE(lim_log(pMac, LOGE,
92 FL
93 ("received Disassoc frame from a BC/MC address"));
94 )
95
96 return;
97 }
98
99 if (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(pHdr->da)) {
100 /* Received Disassoc frame for a MC address */
101 /* Log error and ignore it */
102 PELOGE(lim_log(pMac, LOGE,
103 FL("received Disassoc frame for a MC address"));
104 )
105
106 return;
107 }
108 if (!lim_validate_received_frame_a1_addr(pMac,
109 pHdr->da, psessionEntry)) {
110 lim_log(pMac, LOGE,
111 FL("rx frame doesn't have valid a1 address, drop it"));
112 return;
113 }
114
115 if (LIM_IS_STA_ROLE(psessionEntry) &&
116 (eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState)) {
117 if (pHdr->fc.retry > 0) {
118 /*
119 * This can happen when first disassoc frame is received
120 * but ACK from this STA is lost, in this case 2nd
121 * disassoc frame is already in transmission queue
122 */
123 lim_log(pMac, LOGE,
124 FL("AP is sending disassoc after ACK lost..."));
125 return;
126 }
127 }
128#ifdef WLAN_FEATURE_11W
129 /* PMF: If this session is a PMF session, then ensure that this frame was protected */
130 if (psessionEntry->limRmfEnabled
131 && (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) &
132 DPU_FEEDBACK_UNPROTECTED_ERROR)) {
133 PELOGE(lim_log
134 (pMac, LOGE,
135 FL("received an unprotected disassoc from AP"));
136 )
137 /* If the frame received is unprotected, forward it to the supplicant to initiate */
138 /* an SA query */
139 frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
140 /* send the unprotected frame indication to SME */
141 lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType,
142 (uint8_t *) pHdr,
143 (frameLen +
144 sizeof(tSirMacMgmtHdr)),
145 psessionEntry->smeSessionId,
146 psessionEntry);
147 return;
148 }
149#endif
150
151 /* Get reasonCode from Disassociation frame body */
152 reasonCode = sir_read_u16(pBody);
153
154 PELOG2(lim_log(pMac, LOGE,
155 FL("Received Disassoc frame for Addr: " MAC_ADDRESS_STR
156 "(mlm state=%s, sme state=%d),"
157 "with reason code %d [%s] from " MAC_ADDRESS_STR),
158 MAC_ADDR_ARRAY(pHdr->da),
159 lim_mlm_state_str(psessionEntry->limMlmState),
160 psessionEntry->limSmeState, reasonCode,
161 lim_dot11_reason_str(reasonCode), MAC_ADDR_ARRAY(pHdr->sa));
162 )
163
164 /**
165 * Extract 'associated' context for STA, if any.
166 * This is maintained by DPH and created by LIM.
167 */
168 pStaDs =
169 dph_lookup_hash_entry(pMac, pHdr->sa, &aid,
170 &psessionEntry->dph.dphHashTable);
171
172 if (pStaDs == NULL) {
173 /**
174 * Disassociating STA is not associated.
175 * Log error.
176 */
177 PELOGE(lim_log(pMac, LOGE,
178 FL
179 ("received Disassoc frame from STA that does not have context "
180 "reasonCode=%d, addr " MAC_ADDRESS_STR),
181 reasonCode, MAC_ADDR_ARRAY(pHdr->sa));
182 )
183
184 return;
185 }
186
187 if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) {
188 PELOGE(lim_log(pMac, LOGE,
189 FL("Ignore the DisAssoc received, while waiting "
190 "for ack of disassoc/deauth"));
191 )
192 lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1);
193 return;
194 }
195
196 /** If we are in the Wait for ReAssoc Rsp state */
197 if (lim_is_reassoc_in_progress(pMac, psessionEntry)) {
198 /** If we had received the DisAssoc from,
199 * a. the Current AP during ReAssociate to different AP in same ESS
200 * b. Unknown AP
201 * drop/ignore the DisAssoc received
202 */
203 if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) {
204 PELOGE(lim_log
205 (pMac, LOGE,
206 FL("Ignore the DisAssoc received, while "
207 "Processing ReAssoc with different/unknown AP"));
208 )
209 return;
210 }
211 /** If the Disassoc is received from the new AP to which we tried to ReAssociate
212 * Drop ReAssoc and Restore the Previous context( current connected AP).
213 */
214 if (!IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) {
215 PELOGW(lim_log
216 (pMac, LOGW,
217 FL
218 ("received Disassoc from the New AP to which ReAssoc is sent "));
219 )
220 lim_restore_pre_reassoc_state(pMac,
221 eSIR_SME_REASSOC_REFUSED,
222 reasonCode,
223 psessionEntry);
224 return;
225 }
226 }
227
228 if (LIM_IS_AP_ROLE(psessionEntry) ||
229 LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) {
230 switch (reasonCode) {
231 case eSIR_MAC_UNSPEC_FAILURE_REASON:
232 case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON:
233 case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON:
234 case eSIR_MAC_MIC_FAILURE_REASON:
235 case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON:
236 case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON:
237 case eSIR_MAC_RSN_IE_MISMATCH_REASON:
238 case eSIR_MAC_1X_AUTH_FAILURE_REASON:
239 /* Valid reasonCode in received Disassociation frame */
240 break;
241
242 default:
243 /* Invalid reasonCode in received Disassociation frame */
244 PELOGE(lim_log(pMac, LOGE,
245 FL
246 ("received Disassoc frame with invalid reasonCode "
247 "%d from " MAC_ADDRESS_STR), reasonCode,
248 MAC_ADDR_ARRAY(pHdr->sa));
249 )
250 break;
251 }
252 } else if ((LIM_IS_STA_ROLE(psessionEntry) ||
253 LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) &&
254 ((psessionEntry->limSmeState != eLIM_SME_WT_JOIN_STATE) &&
255 (psessionEntry->limSmeState != eLIM_SME_WT_AUTH_STATE) &&
256 (psessionEntry->limSmeState != eLIM_SME_WT_ASSOC_STATE) &&
257 (psessionEntry->limSmeState != eLIM_SME_WT_REASSOC_STATE))) {
258 switch (reasonCode) {
259 case eSIR_MAC_UNSPEC_FAILURE_REASON:
260 case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON:
261 case eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON:
262 case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON:
263 case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON:
264 case eSIR_MAC_MIC_FAILURE_REASON:
265 case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON:
266 case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON:
267 case eSIR_MAC_RSN_IE_MISMATCH_REASON:
268 case eSIR_MAC_1X_AUTH_FAILURE_REASON:
269 case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON:
270 /* Valid reasonCode in received Disassociation frame */
271 break;
272
273 case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON:
274 case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON:
275 /* Valid reasonCode in received Disassociation frame */
276 /* as long as we're not about to channel switch */
277 if (psessionEntry->gLimChannelSwitch.state !=
278 eLIM_CHANNEL_SWITCH_IDLE) {
279 lim_log(pMac, LOGE,
280 FL
281 ("Ignoring disassoc frame due to upcoming "
282 "channel switch, from "
283 MAC_ADDRESS_STR),
284 MAC_ADDR_ARRAY(pHdr->sa));
285 return;
286 }
287 break;
288
289 default:
290 /* Invalid reasonCode in received Disassociation frame */
291 /* Log error and ignore the frame */
292 PELOGE(lim_log(pMac, LOGE,
293 FL
294 ("received Disassoc frame with invalid reasonCode "
295 "%d from " MAC_ADDRESS_STR), reasonCode,
296 MAC_ADDR_ARRAY(pHdr->sa));
297 )
298 return;
299 }
300 } else {
301 /* Received Disassociation frame in either IBSS */
302 /* or un-known role. Log and ignore it */
303 lim_log(pMac, LOGE,
304 FL
305 ("received Disassoc frame with invalid reasonCode %d in role "
306 "%d in sme state %d from " MAC_ADDRESS_STR), reasonCode,
307 GET_LIM_SYSTEM_ROLE(psessionEntry), psessionEntry->limSmeState,
308 MAC_ADDR_ARRAY(pHdr->sa));
309
310 return;
311 }
312
313 if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) ||
314 (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) {
315 /**
316 * Already in the process of deleting context for the peer
317 * and received Disassociation frame. Log and Ignore.
318 */
319 PELOGE(lim_log(pMac, LOGE,
320 FL("received Disassoc frame in state %d from "
321 MAC_ADDRESS_STR),
322 pStaDs->mlmStaContext.mlmState,
323 MAC_ADDR_ARRAY(pHdr->sa));
324 )
325
326 return;
327 }
328
329 if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) {
330 /**
331 * Requesting STA is in some 'transient' state?
332 * Log error.
333 */
334 if (pStaDs->mlmStaContext.mlmState ==
335 eLIM_MLM_WT_ASSOC_CNF_STATE)
336 pStaDs->mlmStaContext.updateContext = 1;
337
338 PELOGE(lim_log(pMac, LOGE,
339 FL
340 ("received Disassoc frame from peer that is in state %X, addr "
341 MAC_ADDRESS_STR), pStaDs->mlmStaContext.mlmState,
342 MAC_ADDR_ARRAY(pHdr->sa));
343 )
344
345 } /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */
346
347 pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC;
348 pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode;
349
350 /* Issue Disassoc Indication to SME. */
351 cdf_mem_copy((uint8_t *) &mlmDisassocInd.peerMacAddr,
352 (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr));
353 mlmDisassocInd.reasonCode =
354 (uint8_t) pStaDs->mlmStaContext.disassocReason;
355 mlmDisassocInd.disassocTrigger = eLIM_PEER_ENTITY_DISASSOC;
356
357 /* Update PE session Id */
358 mlmDisassocInd.sessionId = psessionEntry->peSessionId;
359
360 if (lim_is_reassoc_in_progress(pMac, psessionEntry)) {
361
362 /* If we're in the middle of ReAssoc and received disassoc from
363 * the ReAssoc AP, then notify SME by sending REASSOC_RSP with
364 * failure result code. By design, SME will then issue "Disassoc"
365 * and cleanup will happen at that time.
366 */
367 PELOGE(lim_log
368 (pMac, LOGE,
369 FL("received Disassoc from AP while waiting "
370 "for Reassoc Rsp"));
371 )
372
373 if (psessionEntry->limAssocResponseData) {
374 cdf_mem_free(psessionEntry->limAssocResponseData);
375 psessionEntry->limAssocResponseData = NULL;
376 }
377
378 lim_restore_pre_reassoc_state(pMac, eSIR_SME_REASSOC_REFUSED,
379 reasonCode, psessionEntry);
380 return;
381 }
382
383 lim_post_sme_message(pMac, LIM_MLM_DISASSOC_IND,
384 (uint32_t *) &mlmDisassocInd);
385
386 /* send eWNI_SME_DISASSOC_IND to SME */
387 lim_send_sme_disassoc_ind(pMac, pStaDs, psessionEntry);
388
389 return;
390} /*** end lim_process_disassoc_frame() ***/