• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *************************************************************************
3  * Ralink Tech Inc.
4  * 5F., No.36, Taiyuan St., Jhubei City,
5  * Hsinchu County 302,
6  * Taiwan, R.O.C.
7  *
8  * (c) Copyright 2002-2007, Ralink Technology, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify  *
11  * it under the terms of the GNU General Public License as published by  *
12  * the Free Software Foundation; either version 2 of the License, or     *
13  * (at your option) any later version.                                   *
14  *                                                                       *
15  * This program is distributed in the hope that it will be useful,       *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  * GNU General Public License for more details.                          *
19  *                                                                       *
20  * You should have received a copy of the GNU General Public License     *
21  * along with this program; if not, write to the                         *
22  * Free Software Foundation, Inc.,                                       *
23  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  *                                                                       *
25  *************************************************************************
26 
27 	Module Name:
28 	auth.c
29 
30 	Abstract:
31 
32 	Revision History:
33 	Who			When			What
34 	--------	----------		----------------------------------------------
35 	John		2004-9-3		porting from RT2500
36 */
37 #include "../rt_config.h"
38 
39 /*
40     ==========================================================================
41     Description:
42         authenticate state machine init, including state transition and timer init
43     Parameters:
44         Sm - pointer to the auth state machine
45     Note:
46         The state machine looks like this
47 
48                         AUTH_REQ_IDLE           AUTH_WAIT_SEQ2                   AUTH_WAIT_SEQ4
49     MT2_MLME_AUTH_REQ   mlme_auth_req_action    invalid_state_when_auth          invalid_state_when_auth
50     MT2_PEER_AUTH_EVEN  drop                    peer_auth_even_at_seq2_action    peer_auth_even_at_seq4_action
51     MT2_AUTH_TIMEOUT    Drop                    auth_timeout_action              auth_timeout_action
52 
53 	IRQL = PASSIVE_LEVEL
54 
55     ==========================================================================
56  */
57 
AuthStateMachineInit(IN PRTMP_ADAPTER pAd,IN STATE_MACHINE * Sm,OUT STATE_MACHINE_FUNC Trans[])58 void AuthStateMachineInit(
59     IN PRTMP_ADAPTER pAd,
60     IN STATE_MACHINE *Sm,
61     OUT STATE_MACHINE_FUNC Trans[])
62 {
63     StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE);
64 
65     // the first column
66     StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction);
67 
68     // the second column
69     StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth);
70     StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action);
71     StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction);
72 
73     // the third column
74     StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth);
75     StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action);
76     StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction);
77 
78 	RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE);
79 }
80 
81 /*
82     ==========================================================================
83     Description:
84         function to be executed at timer thread when auth timer expires
85 
86 	IRQL = DISPATCH_LEVEL
87 
88     ==========================================================================
89  */
AuthTimeout(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)90 VOID AuthTimeout(
91     IN PVOID SystemSpecific1,
92     IN PVOID FunctionContext,
93     IN PVOID SystemSpecific2,
94     IN PVOID SystemSpecific3)
95 {
96     RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
97 
98     DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n"));
99 
100 	// Do nothing if the driver is starting halt state.
101 	// This might happen when timer already been fired before cancel timer with mlmehalt
102 	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
103 		return;
104 
105 	// send a de-auth to reset AP's state machine (Patch AP-Dir635)
106 	if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2)
107 		Cls2errAction(pAd, pAd->MlmeAux.Bssid);
108 
109 
110     MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL);
111     RT28XX_MLME_HANDLER(pAd);
112 }
113 
114 
115 /*
116     ==========================================================================
117     Description:
118 
119 	IRQL = DISPATCH_LEVEL
120 
121     ==========================================================================
122  */
MlmeAuthReqAction(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)123 VOID MlmeAuthReqAction(
124     IN PRTMP_ADAPTER pAd,
125     IN MLME_QUEUE_ELEM *Elem)
126 {
127     UCHAR              Addr[6];
128     USHORT             Alg, Seq, Status;
129     ULONG              Timeout;
130     HEADER_802_11      AuthHdr;
131     BOOLEAN            TimerCancelled;
132     NDIS_STATUS        NStatus;
133     PUCHAR             pOutBuffer = NULL;
134     ULONG              FrameLen = 0;
135 
136 	// Block all authentication request durning WPA block period
137 	if (pAd->StaCfg.bBlockAssoc == TRUE)
138 	{
139         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n"));
140         pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
141         Status = MLME_STATE_MACHINE_REJECT;
142         MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
143 	}
144     else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg))
145     {
146         // reset timer
147         RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
148         COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr);
149         pAd->MlmeAux.Alg  = Alg;
150         Seq = 1;
151         Status = MLME_SUCCESS;
152 
153         NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
154         if(NStatus != NDIS_STATUS_SUCCESS)
155         {
156             DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg));
157             pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
158             Status = MLME_FAIL_NO_RESOURCE;
159             MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
160             return;
161         }
162 
163         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg));
164         MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid);
165         MakeOutgoingFrame(pOutBuffer,           &FrameLen,
166                           sizeof(HEADER_802_11),&AuthHdr,
167                           2,                    &Alg,
168                           2,                    &Seq,
169                           2,                    &Status,
170                           END_OF_ARGS);
171         MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
172     	MlmeFreeMemory(pAd, pOutBuffer);
173 
174         RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout);
175         pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2;
176     }
177     else
178     {
179         DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n"));
180         pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
181         Status = MLME_INVALID_FORMAT;
182         MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
183     }
184 }
185 
186 /*
187     ==========================================================================
188     Description:
189 
190 	IRQL = DISPATCH_LEVEL
191 
192     ==========================================================================
193  */
PeerAuthRspAtSeq2Action(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)194 VOID PeerAuthRspAtSeq2Action(
195     IN PRTMP_ADAPTER pAd,
196     IN MLME_QUEUE_ELEM *Elem)
197 {
198     UCHAR         Addr2[MAC_ADDR_LEN];
199     USHORT        Seq, Status, RemoteStatus, Alg;
200     UCHAR         ChlgText[CIPHER_TEXT_LEN];
201     UCHAR         CyperChlgText[CIPHER_TEXT_LEN + 8 + 8];
202     UCHAR         Element[2];
203     HEADER_802_11 AuthHdr;
204     BOOLEAN       TimerCancelled;
205     PUCHAR        pOutBuffer = NULL;
206     NDIS_STATUS   NStatus;
207     ULONG         FrameLen = 0;
208     USHORT        Status2;
209 
210     if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText))
211     {
212         if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2)
213         {
214             DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status));
215             RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
216 
217             if (Status == MLME_SUCCESS)
218             {
219                 // Authentication Mode "LEAP" has allow for CCX 1.X
220                 if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen)
221 #ifdef LEAP_SUPPORT
222 					|| (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP)
223 #endif // LEAP_SUPPORT //
224 				)
225                 {
226                     pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
227 #ifdef LEAP_SUPPORT
228                     pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE;
229 #endif // LEAP_SUPPORT //
230                     MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
231                 }
232                 else
233                 {
234                     // 2. shared key, need to be challenged
235                     Seq++;
236                     RemoteStatus = MLME_SUCCESS;
237 
238 					// Get an unused nonpaged memory
239                     NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
240                     if(NStatus != NDIS_STATUS_SUCCESS)
241                     {
242                         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n"));
243                         pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
244                         Status2 = MLME_FAIL_NO_RESOURCE;
245                         MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2);
246                         return;
247                     }
248 
249                     DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n"));
250                     MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid);
251                     AuthHdr.FC.Wep = 1;
252                     // Encrypt challenge text & auth information
253                     RTMPInitWepEngine(
254                     	pAd,
255                     	pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
256                     	pAd->StaCfg.DefaultKeyId,
257                     	pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen,
258                     	CyperChlgText);
259 
260 					Alg = cpu2le16(*(USHORT *)&Alg);
261 					Seq = cpu2le16(*(USHORT *)&Seq);
262 					RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus);
263 
264 					RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2);
265 					RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2);
266 					RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2);
267 					Element[0] = 16;
268 					Element[1] = 128;
269 					RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2);
270 					RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128);
271 					RTMPSetICV(pAd, CyperChlgText + 140);
272                     MakeOutgoingFrame(pOutBuffer,               &FrameLen,
273                                       sizeof(HEADER_802_11),    &AuthHdr,
274                                       CIPHER_TEXT_LEN + 16,     CyperChlgText,
275                                       END_OF_ARGS);
276                     MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
277                 	MlmeFreeMemory(pAd, pOutBuffer);
278 
279                     RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT);
280                     pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4;
281                 }
282             }
283             else
284             {
285 #ifdef LEAP_SUPPORT
286                 if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP)
287                 {
288                     //Invalid Authentication possible rogue AP
289                     //Add this Ap to Rogue AP.
290                     RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH);
291 				}
292 #endif // LEAP_SUPPORT //
293                 pAd->StaCfg.AuthFailReason = Status;
294                 COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2);
295                 pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
296                 MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
297             }
298         }
299     }
300     else
301     {
302         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n"));
303     }
304 }
305 
306 /*
307     ==========================================================================
308     Description:
309 
310 	IRQL = DISPATCH_LEVEL
311 
312     ==========================================================================
313  */
PeerAuthRspAtSeq4Action(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)314 VOID PeerAuthRspAtSeq4Action(
315     IN PRTMP_ADAPTER pAd,
316     IN MLME_QUEUE_ELEM *Elem)
317 {
318     UCHAR         Addr2[MAC_ADDR_LEN];
319     USHORT        Alg, Seq, Status;
320     CHAR          ChlgText[CIPHER_TEXT_LEN];
321     BOOLEAN       TimerCancelled;
322 
323     if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText))
324     {
325         if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4)
326         {
327             DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n"));
328             RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
329 
330             if (Status != MLME_SUCCESS)
331             {
332                 pAd->StaCfg.AuthFailReason = Status;
333                 COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2);
334             }
335 
336             pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
337             MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
338         }
339     }
340     else
341     {
342         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n"));
343     }
344 }
345 
346 /*
347     ==========================================================================
348     Description:
349 
350 	IRQL = DISPATCH_LEVEL
351 
352     ==========================================================================
353  */
MlmeDeauthReqAction(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)354 VOID MlmeDeauthReqAction(
355     IN PRTMP_ADAPTER pAd,
356     IN MLME_QUEUE_ELEM *Elem)
357 {
358     MLME_DEAUTH_REQ_STRUCT *pInfo;
359     HEADER_802_11 DeauthHdr;
360     PUCHAR        pOutBuffer = NULL;
361     NDIS_STATUS   NStatus;
362     ULONG         FrameLen = 0;
363     USHORT        Status;
364 
365     pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg;
366 
367     NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
368     if (NStatus != NDIS_STATUS_SUCCESS)
369     {
370         DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n"));
371         pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
372         Status = MLME_FAIL_NO_RESOURCE;
373         MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status);
374         return;
375     }
376 
377     DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason));
378     MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid);
379     MakeOutgoingFrame(pOutBuffer,           &FrameLen,
380                       sizeof(HEADER_802_11),&DeauthHdr,
381                       2,                    &pInfo->Reason,
382                       END_OF_ARGS);
383     MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
384 	MlmeFreeMemory(pAd, pOutBuffer);
385 
386     pAd->StaCfg.DeauthReason = pInfo->Reason;
387     COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr);
388     pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
389     Status = MLME_SUCCESS;
390     MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status);
391 
392 	// send wireless event - for deauthentication
393 	if (pAd->CommonCfg.bWirelessEvent)
394 		RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
395 }
396 
397 /*
398     ==========================================================================
399     Description:
400 
401 	IRQL = DISPATCH_LEVEL
402 
403     ==========================================================================
404  */
AuthTimeoutAction(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)405 VOID AuthTimeoutAction(
406     IN PRTMP_ADAPTER pAd,
407     IN MLME_QUEUE_ELEM *Elem)
408 {
409     USHORT Status;
410     DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n"));
411     pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
412     Status = MLME_REJ_TIMEOUT;
413     MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
414 }
415 
416 /*
417     ==========================================================================
418     Description:
419 
420 	IRQL = DISPATCH_LEVEL
421 
422     ==========================================================================
423  */
InvalidStateWhenAuth(IN PRTMP_ADAPTER pAd,IN MLME_QUEUE_ELEM * Elem)424 VOID InvalidStateWhenAuth(
425     IN PRTMP_ADAPTER pAd,
426     IN MLME_QUEUE_ELEM *Elem)
427 {
428     USHORT Status;
429     DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState));
430     pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
431     Status = MLME_STATE_MACHINE_REJECT;
432     MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
433 }
434 
435 /*
436     ==========================================================================
437     Description:
438         Some STA/AP
439     Note:
440         This action should never trigger AUTH state transition, therefore we
441         separate it from AUTH state machine, and make it as a standalone service
442 
443 	IRQL = DISPATCH_LEVEL
444 
445     ==========================================================================
446  */
Cls2errAction(IN PRTMP_ADAPTER pAd,IN PUCHAR pAddr)447 VOID Cls2errAction(
448     IN PRTMP_ADAPTER pAd,
449     IN PUCHAR pAddr)
450 {
451     HEADER_802_11 DeauthHdr;
452     PUCHAR        pOutBuffer = NULL;
453     NDIS_STATUS   NStatus;
454     ULONG         FrameLen = 0;
455     USHORT        Reason = REASON_CLS2ERR;
456 
457     NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
458     if (NStatus != NDIS_STATUS_SUCCESS)
459         return;
460 
461     DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n"));
462     MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid);
463     MakeOutgoingFrame(pOutBuffer,           &FrameLen,
464                       sizeof(HEADER_802_11),&DeauthHdr,
465                       2,                    &Reason,
466                       END_OF_ARGS);
467     MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
468 	MlmeFreeMemory(pAd, pOutBuffer);
469 
470     pAd->StaCfg.DeauthReason = Reason;
471     COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr);
472 }
473 
474 
475