| /* |
| ************************************************************************* |
| * Ralink Tech Inc. |
| * 5F., No.36, Taiyuan St., Jhubei City, |
| * Hsinchu County 302, |
| * Taiwan, R.O.C. |
| * |
| * (c) Copyright 2002-2007, Ralink Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 2 of the License, or * |
| * (at your option) any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the * |
| * Free Software Foundation, Inc., * |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| * * |
| ************************************************************************* |
| |
| Module Name: |
| auth.c |
| |
| Abstract: |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| John 2004-9-3 porting from RT2500 |
| */ |
| |
| #include "../rt_config.h" |
| |
| |
| /* |
| ========================================================================== |
| Description: |
| authenticate state machine init, including state transition and timer init |
| Parameters: |
| Sm - pointer to the auth state machine |
| Note: |
| The state machine looks like this |
| |
| AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 |
| MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth |
| MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action |
| MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ========================================================================== |
| */ |
| |
| void AuthStateMachineInit( |
| IN PRTMP_ADAPTER pAd, |
| IN STATE_MACHINE *Sm, |
| OUT STATE_MACHINE_FUNC Trans[]) |
| { |
| StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); |
| |
| // the first column |
| StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); |
| |
| // the second column |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); |
| |
| // the third column |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); |
| StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); |
| |
| RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| function to be executed at timer thread when auth timer expires |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID AuthTimeout( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; |
| |
| DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); |
| |
| // Do nothing if the driver is starting halt state. |
| // This might happen when timer already been fired before cancel timer with mlmehalt |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| return; |
| |
| // send a de-auth to reset AP's state machine (Patch AP-Dir635) |
| if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) |
| Cls2errAction(pAd, pAd->MlmeAux.Bssid); |
| |
| |
| MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); |
| RTMP_MLME_HANDLER(pAd); |
| } |
| |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeAuthReqAction( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| if (AUTH_ReqSend(pAd, Elem, &pAd->MlmeAux.AuthTimer, "AUTH", 1, NULL, 0)) |
| pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; |
| else |
| { |
| USHORT Status; |
| |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_INVALID_FORMAT; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID PeerAuthRspAtSeq2Action( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| UCHAR Addr2[MAC_ADDR_LEN]; |
| USHORT Seq, Status, RemoteStatus, Alg; |
| UCHAR ChlgText[CIPHER_TEXT_LEN]; |
| UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; |
| UCHAR Element[2]; |
| HEADER_802_11 AuthHdr; |
| BOOLEAN TimerCancelled; |
| PUCHAR pOutBuffer = NULL; |
| NDIS_STATUS NStatus; |
| ULONG FrameLen = 0; |
| USHORT Status2; |
| |
| if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, (PCHAR)ChlgText)) |
| { |
| if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); |
| RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); |
| |
| if (Status == MLME_SUCCESS) |
| { |
| // Authentication Mode "LEAP" has allow for CCX 1.X |
| if (pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) |
| { |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| else |
| { |
| // 2. shared key, need to be challenged |
| Seq++; |
| RemoteStatus = MLME_SUCCESS; |
| |
| // Get an unused nonpaged memory |
| NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); |
| if(NStatus != NDIS_STATUS_SUCCESS) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status2 = MLME_FAIL_NO_RESOURCE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); |
| return; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); |
| MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); |
| AuthHdr.FC.Wep = 1; |
| // Encrypt challenge text & auth information |
| RTMPInitWepEngine( |
| pAd, |
| pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, |
| pAd->StaCfg.DefaultKeyId, |
| pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, |
| CyperChlgText); |
| |
| Alg = cpu2le16(*(USHORT *)&Alg); |
| Seq = cpu2le16(*(USHORT *)&Seq); |
| RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); |
| |
| RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); |
| RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); |
| RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); |
| Element[0] = 16; |
| Element[1] = 128; |
| RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); |
| RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); |
| RTMPSetICV(pAd, CyperChlgText + 140); |
| MakeOutgoingFrame(pOutBuffer, &FrameLen, |
| sizeof(HEADER_802_11), &AuthHdr, |
| CIPHER_TEXT_LEN + 16, CyperChlgText, |
| END_OF_ARGS); |
| MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); |
| MlmeFreeMemory(pAd, pOutBuffer); |
| |
| RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; |
| } |
| } |
| else |
| { |
| pAd->StaCfg.AuthFailReason = Status; |
| COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| } |
| } |
| else |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); |
| } |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID PeerAuthRspAtSeq4Action( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| UCHAR Addr2[MAC_ADDR_LEN]; |
| USHORT Alg, Seq, Status; |
| CHAR ChlgText[CIPHER_TEXT_LEN]; |
| BOOLEAN TimerCancelled; |
| |
| if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) |
| { |
| if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); |
| RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); |
| |
| if (Status != MLME_SUCCESS) |
| { |
| pAd->StaCfg.AuthFailReason = Status; |
| COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); |
| } |
| |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| } |
| else |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); |
| } |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeDeauthReqAction( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| MLME_DEAUTH_REQ_STRUCT *pInfo; |
| HEADER_802_11 DeauthHdr; |
| PUCHAR pOutBuffer = NULL; |
| NDIS_STATUS NStatus; |
| ULONG FrameLen = 0; |
| USHORT Status; |
| |
| pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; |
| |
| NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory |
| if (NStatus != NDIS_STATUS_SUCCESS) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_FAIL_NO_RESOURCE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); |
| return; |
| } |
| |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); |
| MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); |
| MakeOutgoingFrame(pOutBuffer, &FrameLen, |
| sizeof(HEADER_802_11),&DeauthHdr, |
| 2, &pInfo->Reason, |
| END_OF_ARGS); |
| MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); |
| MlmeFreeMemory(pAd, pOutBuffer); |
| |
| pAd->StaCfg.DeauthReason = pInfo->Reason; |
| COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_SUCCESS; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); |
| |
| // send wireless event - for deauthentication |
| if (pAd->CommonCfg.bWirelessEvent) |
| RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID AuthTimeoutAction( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| USHORT Status; |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_REJ_TIMEOUT; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID InvalidStateWhenAuth( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| USHORT Status; |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_STATE_MACHINE_REJECT; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Some STA/AP |
| Note: |
| This action should never trigger AUTH state transition, therefore we |
| separate it from AUTH state machine, and make it as a standalone service |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID Cls2errAction( |
| IN PRTMP_ADAPTER pAd, |
| IN PUCHAR pAddr) |
| { |
| HEADER_802_11 DeauthHdr; |
| PUCHAR pOutBuffer = NULL; |
| NDIS_STATUS NStatus; |
| ULONG FrameLen = 0; |
| USHORT Reason = REASON_CLS2ERR; |
| |
| NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory |
| if (NStatus != NDIS_STATUS_SUCCESS) |
| return; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); |
| MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); |
| MakeOutgoingFrame(pOutBuffer, &FrameLen, |
| sizeof(HEADER_802_11),&DeauthHdr, |
| 2, &Reason, |
| END_OF_ARGS); |
| MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); |
| MlmeFreeMemory(pAd, pOutBuffer); |
| |
| pAd->StaCfg.DeauthReason = Reason; |
| COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); |
| } |
| |
| BOOLEAN AUTH_ReqSend( |
| IN PRTMP_ADAPTER pAd, |
| IN PMLME_QUEUE_ELEM pElem, |
| IN PRALINK_TIMER_STRUCT pAuthTimer, |
| IN PSTRING pSMName, |
| IN USHORT SeqNo, |
| IN PUCHAR pNewElement, |
| IN ULONG ElementLen) |
| { |
| USHORT Alg, Seq, Status; |
| UCHAR Addr[6]; |
| ULONG Timeout; |
| HEADER_802_11 AuthHdr; |
| BOOLEAN TimerCancelled; |
| NDIS_STATUS NStatus; |
| PUCHAR pOutBuffer = NULL; |
| ULONG FrameLen = 0, tmp = 0; |
| |
| // Block all authentication request durning WPA block period |
| if (pAd->StaCfg.bBlockAssoc == TRUE) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s - Block Auth request durning WPA block period!\n", pSMName)); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_STATE_MACHINE_REJECT; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| } |
| else if(MlmeAuthReqSanity(pAd, pElem->Msg, pElem->MsgLen, Addr, &Timeout, &Alg)) |
| { |
| /* reset timer */ |
| RTMPCancelTimer(pAuthTimer, &TimerCancelled); |
| |
| COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); |
| pAd->MlmeAux.Alg = Alg; |
| Seq = SeqNo; |
| Status = MLME_SUCCESS; |
| |
| NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory |
| if(NStatus != NDIS_STATUS_SUCCESS) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", pSMName, Alg)); |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| Status = MLME_FAIL_NO_RESOURCE; |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); |
| return FALSE; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("%s - Send AUTH request seq#1 (Alg=%d)...\n", pSMName, Alg)); |
| MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); |
| MakeOutgoingFrame(pOutBuffer, &FrameLen, |
| sizeof(HEADER_802_11),&AuthHdr, |
| 2, &Alg, |
| 2, &Seq, |
| 2, &Status, |
| END_OF_ARGS); |
| |
| if (pNewElement && ElementLen) |
| { |
| MakeOutgoingFrame(pOutBuffer+FrameLen, &tmp, |
| ElementLen, pNewElement, |
| END_OF_ARGS); |
| FrameLen += tmp; |
| } |
| |
| MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); |
| MlmeFreeMemory(pAd, pOutBuffer); |
| |
| RTMPSetTimer(pAuthTimer, Timeout); |
| return TRUE; |
| } |
| else |
| { |
| DBGPRINT_ERR(("%s - MlmeAuthReqAction() sanity check failed\n", pSMName)); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |