diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/Kconfig linux-2.6.17-ra2/drivers/net/wireless/Kconfig --- linux-2.6.17-ra.orig/drivers/net/wireless/Kconfig 2006-06-18 03:49:35.000000000 +0200 +++ linux-2.6.17-ra2/drivers/net/wireless/Kconfig 2006-08-22 22:42:13.000000000 +0200 @@ -377,6 +377,8 @@ Enable support for PCI and mini-PCI cards containing the Atmel at76c506 chip. +source "drivers/net/wireless/rt2500/Kconfig" + # If Pcmcia is compiled in, offer Pcmcia cards... comment "Wireless 802.11b Pcmcia/Cardbus cards support" depends on NET_RADIO && PCMCIA diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/Makefile linux-2.6.17-ra2/drivers/net/wireless/Makefile --- linux-2.6.17-ra.orig/drivers/net/wireless/Makefile 2006-06-18 03:49:35.000000000 +0200 +++ linux-2.6.17-ra2/drivers/net/wireless/Makefile 2006-08-22 22:42:13.000000000 +0200 @@ -40,3 +40,4 @@ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o +obj-$(CONFIG_RT2500) += rt2500/ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/Kconfig linux-2.6.17-ra2/drivers/net/wireless/rt2500/Kconfig --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/Kconfig 2006-08-22 22:48:40.000000000 +0200 @@ -0,0 +1,8 @@ + +config RT2500 + tristate "RT2500 support" + depends on NET_RADIO && PCI && EXPERIMENTAL + default n + ---help--- + Driver for wireless cards that are based on the Ralink rt2500 chipsets. + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/Makefile linux-2.6.17-ra2/drivers/net/wireless/rt2500/Makefile --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/Makefile 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,6 @@ +RESMAN_CORE_OBJS := rtmp_main.o +RESMAN_GLUE_OBJS := mlme.o connect.o sync.o assoc.o auth.o auth_rsp.o rtmp_data.o rtmp_init.o sanity.o rtmp_wep.o wpa.o md5.o rtmp_tkip.o rtmp_info.o eeprom.o + +rt2500-objs:= $(RESMAN_CORE_OBJS) $(RESMAN_GLUE_OBJS) + +obj-$(CONFIG_RT2500):= rt2500.o diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/assoc.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/assoc.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/assoc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/assoc.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,893 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: assoc.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * MarkW 5th Jun 05 Fix no-SSID broadcasting assoc. + ***************************************************************************/ + +#include "rt_config.h" + +UCHAR CipherSuiteWpaTkip[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x02, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x02, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x01 // authentication + }; +UCHAR CipherSuiteWpaTkipLen = (sizeof(CipherSuiteWpaTkip) / sizeof(UCHAR)); + +UCHAR CipherSuiteWpaAes[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x04, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x04, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x01 // authentication + }; +UCHAR CipherSuiteWpaAesLen = (sizeof(CipherSuiteWpaAes) / sizeof(UCHAR)); + +UCHAR CipherSuiteWpaPskTkip[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x02, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x02, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x02 // authentication + }; +UCHAR CipherSuiteWpaPskTkipLen = (sizeof(CipherSuiteWpaPskTkip) / sizeof(UCHAR)); + +UCHAR CipherSuiteWpaPskAes[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x04, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x04, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x02 // authentication + }; +UCHAR CipherSuiteWpaPskAesLen = (sizeof(CipherSuiteWpaPskAes) / sizeof(UCHAR)); + +/* + ========================================================================== + Description: + association state machine init, including state transition and timer init + Parameters: + S - pointer to the association state machine + Note: + The state machine looks like the following + + ASSOC_IDLE ASSOC_WAIT_RSP REASSOC_WAIT_RSP DISASSOC_WAIT_RSP + MT2_MLME_ASSOC_REQ mlme_assoc_req_action invalid_state_when_assoc invalid_state_when_assoc invalid_state_when_assoc + MT2_MLME_REASSOC_REQ mlme_reassoc_req_action invalid_state_when_reassoc invalid_state_when_reassoc invalid_state_when_reassoc + MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action mlme_disassoc_req_action mlme_disassoc_req_action mlme_disassoc_req_action + MT2_PEER_DISASSOC_REQ peer_disassoc_action peer_disassoc_action peer_disassoc_action peer_disassoc_action + MT2_PEER_ASSOC_REQ drop drop drop drop + MT2_PEER_ASSOC_RSP drop peer_assoc_rsp_action drop drop + MT2_PEER_REASSOC_REQ drop drop drop drop + MT2_PEER_REASSOC_RSP drop drop peer_reassoc_rsp_action drop + MT2_CLS3ERR cls3err_action cls3err_action cls3err_action cls3err_action + MT2_ASSOC_TIMEOUT timer_nop assoc_timeout_action timer_nop timer_nop + MT2_REASSOC_TIMEOUT timer_nop timer_nop reassoc_timeout_action timer_nop + MT2_DISASSOC_TIMEOUT timer_nop timer_nop timer_nop disassoc_timeout_action + ========================================================================== + */ +VOID AssocStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + OUT STATE_MACHINE_FUNC Trans[]) +{ + StateMachineInit(S, (STATE_MACHINE_FUNC*)Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); + + // first column + StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); + StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); + StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); + StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); +// StateMachineSetAction(S, ASSOC_IDLE, MT2_CLS3ERR, (STATE_MACHINE_FUNC)Cls3errAction); + + // second column + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); +// StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_CLS3ERR, (STATE_MACHINE_FUNC)Cls3errAction); + StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); + + // third column + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); +// StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_CLS3ERR, (STATE_MACHINE_FUNC)Cls3errAction); + StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); + + // fourth column + StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); + StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); + StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); + StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); +// StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_CLS3ERR, (STATE_MACHINE_FUNC)Cls3errAction); + StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); + + // initialize the timer + RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.AssocTimer, AssocTimeout); + RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.ReassocTimer, ReassocTimeout); + RTMPInitTimer(pAd, &pAd->Mlme.AssocAux.DisassocTimer, DisassocTimeout); +} + +/* + ========================================================================== + Description: + Association timeout procedure. After association timeout, this function + will be called and it will put a message into the MLME queue + Parameters: + Standard timer parameters + ========================================================================== + */ +VOID AssocTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - enqueue MT2_ASSOC_TIMEOUT \n"); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + Reassociation timeout procedure. After reassociation timeout, this + function will be called and put a message into the MLME queue + Parameters: + Standard timer parameters + ========================================================================== + */ +VOID ReassocTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - enqueue MT2_REASSOC_TIMEOUT \n"); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + Disassociation timeout procedure. After disassociation timeout, this + function will be called and put a message into the MLME queue + Parameters: + Standard timer parameters + ========================================================================== + */ +VOID DisassocTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - enqueue MT2_DISASSOC_TIMEOUT \n"); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + mlme assoc req handling procedure + Parameters: + Adapter - Adapter pointer + Elem - MLME Queue Element + Pre: + the station has been authenticated and the following information is stored in the config + -# SSID + -# supported rates and their length + -# listen interval (Adapter->PortCfg.default_listen_count) + -# Transmit power (Adapter->PortCfg.tx_power) + Post : + -# An association request frame is generated and sent to the air + -# Association timer starts + -# Association state -> ASSOC_WAIT_RSP + ========================================================================== + */ +VOID MlmeAssocReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR ApAddr; + MACHDR AssocHdr; + UCHAR SsidIe = IE_SSID, RateIe = IE_SUPP_RATES,WpaIe = IE_WPA, ExtRateIe = IE_EXT_SUPP_RATES; + USHORT ListenIntv; + ULONG Timeout; + USHORT CapabilityInfo; + UCHAR *OutBuffer = NULL; + NDIS_STATUS NStatus; + ULONG FrameLen = 0; + ULONG tmp; + UCHAR VarIesOffset; + + // Block all authentication request durning WPA block period + if (pAd->PortCfg.bBlockAssoc == TRUE) + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Block Assoc request durning WPA block period!\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT); + } + // check sanity first + else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, &ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) + { + RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer); + COPY_MAC_ADDR(&pAd->Mlme.AssocAux.Addr, &ApAddr); + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; // pAd->PortCfg.SupportedCapabilityInfo; + pAd->Mlme.AssocAux.CapabilityInfo = CapabilityInfo; + pAd->Mlme.AssocAux.ListenIntv = ListenIntv; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeAssocReqAction() allocate memory failed \n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + // Add by James 03/06/27 + pAd->PortCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); //+ sizeof(NDIS_802_11_FIXED_IEs); // Filled in assoc request + pAd->PortCfg.AssocInfo.AvailableRequestFixedIEs = + NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL | NDIS_802_11_AI_REQFI_CURRENTAPADDRESS; + pAd->PortCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; + pAd->PortCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; + memcpy(pAd->PortCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, &AssocHdr, sizeof(NDIS_802_11_MAC_ADDRESS)); + pAd->PortCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); // No request Variables IEs + + // First add SSID + VarIesOffset = 0; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &pAd->PortCfg.SsidLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen); + VarIesOffset += pAd->PortCfg.SsidLen; + + // Second add Supported rates + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &RateIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &pAd->PortCfg.SupportedRatesLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, pAd->PortCfg.SupportedRates, pAd->PortCfg.SupportedRatesLen); + VarIesOffset += pAd->PortCfg.SupportedRatesLen; + // End Add by James + + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Send ASSOC request...\n"); + MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, &ApAddr, &ApAddr); + + // Build basic frame first + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &AssocHdr, + 2, &CapabilityInfo, + 2, &ListenIntv, + 1, &SsidIe, + 1, &pAd->Mlme.SyncAux.SsidLen, + pAd->Mlme.SyncAux.SsidLen, pAd->Mlme.SyncAux.Ssid, + 1, &RateIe, + 1, &pAd->PortCfg.SupRateLen, + pAd->PortCfg.SupRateLen, pAd->PortCfg.SupRate, + END_OF_ARGS); + if (pAd->PortCfg.ExtRateLen != 0) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &ExtRateIe, + 1, &pAd->PortCfg.ExtRateLen, + pAd->PortCfg.ExtRateLen, pAd->PortCfg.ExtRate, + END_OF_ARGS); + FrameLen += tmp; + } + + if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) && (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled)) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaTkipLen, + CipherSuiteWpaTkipLen, &CipherSuiteWpaTkip[0], + END_OF_ARGS); + FrameLen += tmp; + + // Add by James 03/06/27 + // Third add RSN + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &WpaIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &CipherSuiteWpaTkipLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherSuiteWpaTkip, CipherSuiteWpaTkipLen); + VarIesOffset += CipherSuiteWpaTkipLen; + + // Set Variable IEs Length + pAd->PortCfg.ReqVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset; + + // OffsetResponseIEs follow ReqVarIE + pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen; + // End Add by James + } + + else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) && (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled)) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaAesLen, + CipherSuiteWpaAesLen, &CipherSuiteWpaAes[0], + END_OF_ARGS); + FrameLen += tmp; + + // Add by James 03/06/27 + // Third add RSN + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &WpaIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &CipherSuiteWpaAesLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherSuiteWpaAes, CipherSuiteWpaAesLen); + VarIesOffset += CipherSuiteWpaAesLen; + + // Set Variable IEs Length + pAd->PortCfg.ReqVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset; + + // OffsetResponseIEs follow ReqVarIE + pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen; + // End Add by James + } + else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled)) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaPskTkipLen, + CipherSuiteWpaPskTkipLen, &CipherSuiteWpaPskTkip[0], + END_OF_ARGS); + FrameLen += tmp; + + // Add by James 03/06/27 + // Third add RSN + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &WpaIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &CipherSuiteWpaPskTkipLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherSuiteWpaPskTkip, CipherSuiteWpaPskTkipLen); + VarIesOffset += CipherSuiteWpaPskTkipLen; + + // Set Variable IEs Length + pAd->PortCfg.ReqVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset; + + // OffsetResponseIEs follow ReqVarIE + pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen; + // End Add by James + } + else if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled)) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaPskAesLen, + CipherSuiteWpaPskAesLen, &CipherSuiteWpaPskAes[0], + END_OF_ARGS); + FrameLen += tmp; + + // Add by James 03/06/27 + // Third add RSN + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &WpaIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, &CipherSuiteWpaPskAesLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ReqVarIEs + VarIesOffset, CipherSuiteWpaPskAes, CipherSuiteWpaPskAesLen); + VarIesOffset += CipherSuiteWpaPskAesLen; + + // Set Variable IEs Length + pAd->PortCfg.ReqVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset; + + // OffsetResponseIEs follow ReqVarIE + pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen; + // End Add by James + } + else + { + // Add by James 03/06/27 + // Set Variable IEs Length + pAd->PortCfg.ReqVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.RequestIELength = VarIesOffset; + + // OffsetResponseIEs follow ReqVarIE + pAd->PortCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->PortCfg.ReqVarIELen; + // End Add by James + } + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.AssocTimer, Timeout); + pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; + } + else + { + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_INVALID_FORMAT); + } + +} + +/* + ========================================================================== + Description: + mlme reassoc req handling procedure + Parameters: + Elem - + Pre: + -# SSID (Adapter->PortCfg.ssid[]) + -# BSSID (AP address, Adapter->PortCfg.bssid) + -# Supported rates (Adapter->PortCfg.supported_rates[]) + -# Supported rates length (Adapter->PortCfg.supported_rates_len) + -# Tx power (Adapter->PortCfg.tx_power) + ========================================================================== + */ +VOID MlmeReassocReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR ApAddr; + MACHDR ReassocHdr; + UCHAR SsidIe = IE_SSID, RateIe = IE_SUPP_RATES, ExtRateIe = IE_EXT_SUPP_RATES; + USHORT CapabilityInfo, ListenIntv; + ULONG Timeout; + ULONG FrameLen = 0; + NDIS_STATUS NStatus; + ULONG tmp; + UCHAR *OutBuffer = NULL; + + // Block all authentication request durning WPA block period + if (pAd->PortCfg.bBlockAssoc == TRUE) + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Block ReAssoc request durning WPA block period!\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT); + } + // the parameters are the same as the association + else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, &ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) + { + RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer); + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeReassocReqAction() allocate memory failed \n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; // pAd->PortCfg.SupportedCapabilityInfo; + pAd->Mlme.AssocAux.CapabilityInfo = CapabilityInfo; + COPY_MAC_ADDR(&pAd->Mlme.AssocAux.Addr, &ApAddr); + pAd->Mlme.AssocAux.ListenIntv = ListenIntv; + + // make frame, use bssid as the AP address?? + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Send RE-ASSOC request...\n"); + MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, &ApAddr, &ApAddr); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &ReassocHdr, + 2, &CapabilityInfo, + 2, &ListenIntv, + ETH_ALEN, &pAd->PortCfg.Bssid, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &RateIe, + 1, &pAd->PortCfg.SupRateLen, + pAd->PortCfg.SupRateLen, pAd->PortCfg.SupRate, + END_OF_ARGS); + if (pAd->PortCfg.ExtRateLen != 0) + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &ExtRateIe, + 1, &pAd->PortCfg.ExtRateLen, + pAd->PortCfg.ExtRateLen, pAd->PortCfg.ExtRate, + END_OF_ARGS); + FrameLen += tmp; + } + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.ReassocTimer, Timeout); /* in mSec */ + pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; + } + else + { + DBGPRINT(RT_DEBUG_TRACE,"ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_INVALID_FORMAT); + } +} + +/* + ========================================================================== + Description: + Upper layer issues disassoc request + Parameters: + Elem - + ========================================================================== + */ +VOID MlmeDisassocReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MLME_DISASSOC_REQ_STRUCT *DisassocReq; + MACHDR DisassocHdr; + CHAR *OutBuffer = NULL; + ULONG FrameLen = 0; + NDIS_STATUS NStatus; + ULONG Timeout = 0; + + // skip sanity check + DisassocReq = (MLME_DISASSOC_REQ_STRUCT *)(Elem->Msg); + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - MlmeDisassocReqAction() allocate memory failed\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer); + + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Send DISASSOC request\n"); + MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, &pAd->PortCfg.Bssid, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &DisassocHdr, + 2, &DisassocReq->Reason, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + memset(&(pAd->PortCfg.Bssid), 0, ETH_ALEN); + + pAd->PortCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; + COPY_MAC_ADDR(&pAd->PortCfg.DisassocSta, &DisassocReq->Addr); + + RTMPSetTimer(pAd, &pAd->Mlme.AssocAux.DisassocTimer, Timeout); /* in mSec */ + pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; +} + +/* + ========================================================================== + Description: + peer sends assoc rsp back + Parameters: + Elme - MLME message containing the received frame + ========================================================================== + */ +VOID PeerAssocRspAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT CapabilityInfo, Status, Aid; + UCHAR Rates[MAX_LEN_OF_SUPPORTED_RATES], RatesLen; + MACADDR Addr2; + BOOLEAN ExtendedRateIeExist; + + if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &CapabilityInfo, &Status, &Aid, Rates, &RatesLen, &ExtendedRateIeExist)) + { + // The frame is for me ? + if(MAC_ADDR_EQUAL(&Addr2, &pAd->Mlme.AssocAux.Addr)) + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status); + RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer); + if(Status == MLME_SUCCESS) + { + // go to procedure listed on page 376 + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; // pAd->PortCfg.SupportedCapabilityInfo; + AssocPostProc(pAd, &Addr2, CapabilityInfo, Aid, Rates, RatesLen, ExtendedRateIeExist); + } + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, Status); + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerAssocRspAction() sanity check fail\n"); + } +} + +/* + ========================================================================== + Description: + peer sends reassoc rsp + Parametrs: + Elem - MLME message cntaining the received frame + ========================================================================== + */ +VOID PeerReassocRspAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT CapabilityInfo; + USHORT Status; + USHORT Aid; + UCHAR Rates[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR RatesLen; + MACADDR Addr2; + BOOLEAN ExtendedRateIeExist; + + if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &CapabilityInfo, &Status, &Aid, Rates, &RatesLen, &ExtendedRateIeExist)) + { + if(MAC_ADDR_EQUAL(&Addr2, &pAd->Mlme.AssocAux.Addr)) // The frame is for me ? + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status); + RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer); + + if(Status == MLME_SUCCESS) + { + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; // pAd->PortCfg.SupportedCapabilityInfo; + // go to procedure listed on page 376 + AssocPostProc(pAd, &Addr2, CapabilityInfo, Aid, Rates, RatesLen, ExtendedRateIeExist); + } + + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, Status); + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerReassocRspAction() sanity check fail\n"); + } +} + +/* + ========================================================================== + Description: + procedures on IEEE 802.11/1999 p.376 + Parametrs: + ========================================================================== + */ +VOID AssocPostProc( + IN PRTMP_ADAPTER pAd, + IN PMACADDR Addr2, + IN USHORT CapabilityInfo, + IN USHORT Aid, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist) +{ + ULONG Idx; + UCHAR RateIe = IE_SUPP_RATES; + UCHAR VarIesOffset; + + // 2003/12/11 - skip the following because experiment show that we can not + // trust the "privacy" bit in AssocRsp. We can only trust "Privacy" bit specified in + // BEACON and ProbeRsp. + // pAd->PortCfg.PrivacyInvoked = CAP_IS_PRIVACY_ON(CapabilityInfo); + + pAd->PortCfg.Aid = Aid; + memcpy(pAd->PortCfg.SupportedRates, Rates, RatesLen); + pAd->PortCfg.SupportedRatesLen = RatesLen; + COPY_MAC_ADDR(&pAd->PortCfg.Bssid, Addr2); + AsicSetBssid(pAd, &pAd->PortCfg.Bssid); + + // set listen interval + pAd->PortCfg.DefaultListenCount = pAd->Mlme.AssocAux.ListenIntv; +// pAd->PortCfg.CurrListenCount = pAd->Mlme.AssocAux.ListenIntv; + + // Set New WPA information + Idx = BssTableSearch(&pAd->PortCfg.BssTab, Addr2); + if (Idx == BSS_NOT_FOUND) + { + DBGPRINT(RT_DEBUG_ERROR, "ASSOC - Can't find BSS after receiving Assoc response\n"); + } + else + { + // Mod by James to fix OID_802_11_ASSOCIATION_INFORMATION + pAd->PortCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); //+ sizeof(NDIS_802_11_FIXED_IEs); // Filled in assoc request + pAd->PortCfg.AssocInfo.AvailableResponseFixedIEs = + NDIS_802_11_AI_RESFI_CAPABILITIES | NDIS_802_11_AI_RESFI_STATUSCODE | NDIS_802_11_AI_RESFI_ASSOCIATIONID; + pAd->PortCfg.AssocInfo.ResponseFixedIEs.Capabilities = CapabilityInfo; + pAd->PortCfg.AssocInfo.ResponseFixedIEs.StatusCode = MLME_SUCCESS; // Should be success, add failed later + pAd->PortCfg.AssocInfo.ResponseFixedIEs.AssociationId = Aid; + + // Copy BSS VarIEs to PortCfg associnfo structure. + // First add Supported rates + VarIesOffset = 0; + memcpy(pAd->PortCfg.ResVarIEs + VarIesOffset, &RateIe, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ResVarIEs + VarIesOffset, &RatesLen, 1); + VarIesOffset += 1; + memcpy(pAd->PortCfg.ResVarIEs + VarIesOffset, Rates, RatesLen); + VarIesOffset += RatesLen; + + // Second add RSN + memcpy(pAd->PortCfg.ResVarIEs + VarIesOffset, pAd->PortCfg.BssTab.BssEntry[Idx].VarIEs, pAd->PortCfg.BssTab.BssEntry[Idx].VarIELen); + VarIesOffset += pAd->PortCfg.BssTab.BssEntry[Idx].VarIELen; + + // Set Variable IEs Length + pAd->PortCfg.ResVarIELen = VarIesOffset; + pAd->PortCfg.AssocInfo.ResponseIELength = VarIesOffset; + // End Mod by James + } +} + +/* + ========================================================================== + Description: + left part of IEEE 802.11/1999 p.374 + Parameters: + Elem - MLME message containing the received frame + ========================================================================== + */ +VOID PeerDisassocAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Addr2; + USHORT Reason; + + if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &Reason)) + { + if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, &Addr2)) + { + LinkDown(pAd); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + + pAd->RalinkCounters.BeenDisassociatedCount ++; + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Disassociated by AP, Auto Recovery attempt #%d\n", pAd->RalinkCounters.BeenDisassociatedCount); + MlmeAutoReconnectLastSSID(pAd); + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - PeerDisassocAction() sanity check fail\n"); + } +} + +/* + ========================================================================== + Description: + what the state machine will do after assoc timeout + Parameters: + Elme - + ========================================================================== + */ +VOID AssocTimeoutAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - AssocTimeoutAction\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_REJ_TIMEOUT); +} + +/* + ========================================================================== + Description: + what the state machine will do after reassoc timeout + ========================================================================== + */ +VOID ReassocTimeoutAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - ReassocTimeoutAction\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_REJ_TIMEOUT); +} + +/* + ========================================================================== + Description: + what the state machine will do after disassoc timeout + ========================================================================== + */ +VOID DisassocTimeoutAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - DisassocTimeoutAction\n"); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_SUCCESS); +} + +VOID InvalidStateWhenAssoc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenAssoc(state=%d), reset ASSOC state machine\n", + pAd->Mlme.AssocMachine.CurrState); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_ASSOC_CONF, MLME_STATE_MACHINE_REJECT); +} + +VOID InvalidStateWhenReassoc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenReassoc(state=%d), reset ASSOC state machine\n", + pAd->Mlme.AssocMachine.CurrState); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_REASSOC_CONF, MLME_STATE_MACHINE_REJECT); +} + +VOID InvalidStateWhenDisassociate( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - InvalidStateWhenDisassoc(state=%d), reset ASSOC state machine\n", + pAd->Mlme.AssocMachine.CurrState); + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + MlmeCntlConfirm(pAd, MT2_DISASSOC_CONF, MLME_STATE_MACHINE_REJECT); +} + +/* + ========================================================================== + Description: + right part of IEEE 802.11/1999 page 374 + Note: + This event should never cause ASSOC state machine perform state + transition, and has no relationship with CNTL machine. So we separate + this routine as a service outside of ASSOC state transition table. + ========================================================================== + */ +VOID Cls3errAction( + IN PRTMP_ADAPTER pAd, + IN PMACADDR pAddr) +{ + MACHDR DisassocHdr; + CHAR *OutBuffer = NULL; + ULONG FrameLen = 0; + NDIS_STATUS NStatus; + USHORT Reason = REASON_CLS3ERR; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + DBGPRINT(RT_DEBUG_TRACE, "ASSOC - Class 3 Error, Send DISASSOC frame\n"); + MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &DisassocHdr, + 2, &Reason, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + pAd->PortCfg.DisassocReason = REASON_CLS3ERR; + COPY_MAC_ADDR(&pAd->PortCfg.DisassocSta, pAddr); +} + + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/auth.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/auth.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/auth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/auth.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,407 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: auth.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#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_MLME_DEAUTH_REQ mlme_deauth_req_action mlme_deauth_req_action mlme_deauth_req_action + MT2_CLS2ERR cls2err_action cls2err_action cls2err_action + 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 + ========================================================================== + */ + +void AuthStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *Sm, + OUT STATE_MACHINE_FUNC Trans[]) +{ + StateMachineInit(Sm, (STATE_MACHINE_FUNC*)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); +// StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_DEAUTH_REQ, (STATE_MACHINE_FUNC)MlmeDeauthReqAction); +// StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_CLS2ERR, (STATE_MACHINE_FUNC)Cls2errAction); + + // the second column + StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); +// StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_DEAUTH_REQ, (STATE_MACHINE_FUNC)MlmeDeauthReqAction); +// StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_CLS2ERR, (STATE_MACHINE_FUNC)Cls2errAction); + 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_MLME_DEAUTH_REQ, (STATE_MACHINE_FUNC)MlmeDeauthReqAction); +// StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_CLS2ERR, (STATE_MACHINE_FUNC)Cls2errAction); + 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->Mlme.AuthAux.AuthTimer, AuthTimeout); +} + +/* + ========================================================================== + Description: + function to be executed at timer thread when auth timer expires + ========================================================================== + */ +VOID AuthTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + DBGPRINT(RT_DEBUG_TRACE,"AUTH - AuthTimeout\n"); + MlmeEnqueue(&pAd->Mlme.Queue, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID MlmeAuthReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Addr; + USHORT Alg, Seq, Status; + ULONG Timeout; + MACHDR AuthHdr; + NDIS_STATUS NStatus; + UCHAR *OutBuffer = NULL; + ULONG FrameLen = 0; + + // Block all authentication request durning WPA block period + if (pAd->PortCfg.bBlockAssoc == TRUE) + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Block Auth request durning WPA block period!\n"); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_STATE_MACHINE_REJECT); + } + else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr, &Timeout, &Alg)) + { + // reset timer + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + pAd->Mlme.AuthAux.Addr = Addr; + pAd->Mlme.AuthAux.Alg = Alg; + pAd->PortCfg.Mauth = FALSE; + Seq = 1; + Status = MLME_SUCCESS; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - MlmeAuthReqAction() allocate memory failed\n"); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg); + MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, &Addr, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + MAC_HDR_LEN, &AuthHdr, + 2, &Alg, + 2, &Seq, + 2, &Status, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + RTMPSetTimer(pAd, &pAd->Mlme.AuthAux.AuthTimer, Timeout); + pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; + } + else + { + printk(KERN_ERR DRV_NAME "AUTH - MlmeAuthReqAction() sanity check failed. BUG!!!!!\n"); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_INVALID_FORMAT); + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID PeerAuthRspAtSeq2Action( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Addr2; + USHORT Seq, Status, RemoteStatus, Alg; + UCHAR ChlgText[CIPHER_TEXT_LEN]; + UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; + UCHAR Element[2]; + MACHDR AuthHdr; + UCHAR *OutBuffer = NULL; + NDIS_STATUS NStatus; + ULONG FrameLen = 0; + + if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &Alg, &Seq, &Status, ChlgText)) + { + if (MAC_ADDR_EQUAL(&pAd->Mlme.AuthAux.Addr, &Addr2) && Seq == 2) + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status); + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + + if (Status == MLME_SUCCESS) + { + if (pAd->Mlme.AuthAux.Alg == Ndis802_11AuthModeOpen) + { + pAd->PortCfg.Mauth = TRUE; + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_SUCCESS); + } + else + { + // 2. shared key, need to be challenged + Seq++; + RemoteStatus = MLME_SUCCESS; + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n"); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Send AUTH request seq#3...\n"); + MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, &Addr2, &pAd->PortCfg.Bssid); + AuthHdr.Wep = 1; + // Encrypt challenge text & auth information + RTMPInitWepEngine( + pAd, + pAd->PortCfg.SharedKey[pAd->PortCfg.DefaultKeyId].Key, + pAd->PortCfg.DefaultKeyId, + pAd->PortCfg.SharedKey[pAd->PortCfg.DefaultKeyId].KeyLen, + CyperChlgText); +#ifdef BIG_ENDIAN + Alg = SWAP16(*(USHORT *)&Alg); + Seq = SWAP16(*(USHORT *)&Seq); + RemoteStatus= SWAP16(*(USHORT *)&RemoteStatus); + pAd->NeedSwapToLittleEndian = FALSE; +#endif + 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(OutBuffer, &FrameLen, + MAC_HDR_LEN, &AuthHdr, + CIPHER_TEXT_LEN + 16, CyperChlgText, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); +#ifdef BIG_ENDIAN + pAd->NeedSwapToLittleEndian = TRUE; +#endif + RTMPSetTimer(pAd, &pAd->Mlme.AuthAux.AuthTimer, AUTH_TIMEOUT); + pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; + } + } + else + { + pAd->PortCfg.AuthFailReason = Status; + COPY_MAC_ADDR(&pAd->PortCfg.AuthFailSta, &Addr2); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, Status); + } + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - PeerAuthSanity() sanity check fail\n"); + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID PeerAuthRspAtSeq4Action( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Addr2; + USHORT Alg, Seq, Status; + CHAR ChlgText[CIPHER_TEXT_LEN]; + + if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &Alg, &Seq, &Status, ChlgText)) + { + if(MAC_ADDR_EQUAL(&(pAd->Mlme.AuthAux.Addr), &Addr2) && Seq == 4) + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Receive AUTH_RSP seq#4 to me\n"); + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + + if(Status == MLME_SUCCESS) + { + pAd->PortCfg.Mauth = TRUE; + } + else + { + pAd->PortCfg.AuthFailReason = Status; + pAd->PortCfg.AuthFailSta = Addr2; + } + + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, Status); + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n"); + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID MlmeDeauthReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MLME_DEAUTH_REQ_STRUCT *Info; + MACHDR Hdr; + UCHAR *OutBuffer = NULL; + NDIS_STATUS NStatus; + ULONG FrameLen = 0; + + Info = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //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; + MlmeCntlConfirm(pAd, MT2_DEAUTH_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + DBGPRINT(RT_DEBUG_TRACE, "AUTH - Send DE-AUTH request...\n"); + MgtMacHeaderInit(pAd, &Hdr, SUBTYPE_DEAUTH, 0, &Info->Addr, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &Hdr, + 2, &Info->Reason, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + pAd->PortCfg.DeauthReason = Info->Reason; + COPY_MAC_ADDR(&pAd->PortCfg.DeauthSta, &Info->Addr); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_DEAUTH_CONF, MLME_SUCCESS); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AuthTimeoutAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "AUTH - AuthTimeoutAction\n"); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_REJ_TIMEOUT); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID InvalidStateWhenAuth( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "AUTH - InvalidStateWhenAuth (state=%d), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState); + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + MlmeCntlConfirm(pAd, MT2_AUTH_CONF, MLME_STATE_MACHINE_REJECT); +} + +/* + ========================================================================== + 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 + ========================================================================== + */ +VOID Cls2errAction( + IN PRTMP_ADAPTER pAd, + IN PMACADDR pAddr) +{ + MACHDR Hdr; + UCHAR *OutBuffer = NULL; + NDIS_STATUS NStatus; + ULONG FrameLen = 0; + USHORT Reason = REASON_CLS2ERR; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //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, &Hdr, SUBTYPE_DEAUTH, 0, pAddr, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &Hdr, + 2, &Reason, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + + pAd->PortCfg.DeauthReason = Reason; + COPY_MAC_ADDR(&pAd->PortCfg.DeauthSta, pAddr); +} + + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/auth_rsp.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/auth_rsp.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/auth_rsp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/auth_rsp.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,162 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: auth_rsp.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +/* + ========================================================================== + Description: + authentication state machine init procedure + Parameters: + Sm - the state machine + Note: + the state machine looks like the following + + AUTH_RSP_IDLE AUTH_RSP_WAIT_CHAL + MT2_AUTH_CHALLENGE_TIMEOUT auth_rsp_challenge_timeout_action auth_rsp_challenge_timeout_action + MT2_PEER_AUTH_ODD peer_auth_at_auth_rsp_idle_action peer_auth_at_auth_rsp_wait_action + MT2_PEER_DEAUTH peer_deauth_action peer_deauth_action + ========================================================================== + */ +VOID AuthRspStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN PSTATE_MACHINE Sm, + IN STATE_MACHINE_FUNC Trans[]) +{ + ULONG NOW; + + StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); + + // column 1 +// StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_AUTH_CHALLENGEG_TIMEOUT, (STATE_MACHINE_FUNC)AuthRspChallengeTimeoutAction); +// StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_AUTH_ODD, (STATE_MACHINE_FUNC)PeerAuthAtAuthRspIdleAction); + StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); + + // column 2 +// StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_AUTH_ODD, (STATE_MACHINE_FUNC)PeerAuthAtAuthRspWaitAction); +// StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_AUTH_CHALLENGE_TIMEOUT, (STATE_MACHINE_FUNC)AuthRspChallengeTimeoutAction); + StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); + + // initialize timer + RTMPInitTimer(pAd, &pAd->Mlme.AuthRspAux.AuthRspTimer, AuthRspChallengeTimeout); + + // initialize the random number generator + NOW = jiffies; + LfsrInit(pAd, NOW); +} + + +/* + ========================================================================== + Description: + challenge time out, called by timer thread + ========================================================================== + */ +VOID AuthRspChallengeTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + DBGPRINT(RT_DEBUG_TRACE,"AUTH_RSP - AuthRspChallengeTimeout \n"); + MlmeEnqueue(&pAd->Mlme.Queue, AUTH_RSP_STATE_MACHINE, MT2_AUTH_CHALLENGE_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID PeerAuthSimpleRspGenAndSend( + IN PRTMP_ADAPTER pAd, + IN PMACHDR Hdr, + IN USHORT Alg, + IN USHORT Seq, + IN USHORT Reason, + IN USHORT Status) +{ + MACHDR AuthHdr; + UINT FrameLen = 0; + UCHAR *OutBuffer = NULL; + NDIS_STATUS NStatus; + + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + if (Reason == MLME_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "Send AUTH response (seq#2)...\n"); + MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, &Hdr->Addr2, &pAd->PortCfg.Bssid); + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &AuthHdr, + 2, &Alg, + 2, &Seq, + 2, &Reason, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + } + else + { + MlmeFreeMemory(pAd, OutBuffer); + DBGPRINT(RT_DEBUG_TRACE, "Peer AUTH fail...\n"); + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID PeerDeauthAction( + IN PRTMP_ADAPTER pAd, + IN PMLME_QUEUE_ELEM Elem) +{ + MACADDR Addr2; + USHORT Reason; + + if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, &Reason)) + { + if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(&Addr2, &pAd->PortCfg.Bssid)) + { + RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer); + DBGPRINT(RT_DEBUG_TRACE,"AUTH_RSP - receive DE-AUTH from our AP, reason = %d\n", Reason); + LinkDown(pAd); + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE,"AUTH_RSP - PeerDeauthAction() sanity check fail\n"); + } +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/connect.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/connect.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/connect.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/connect.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1335 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: connect.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * Ivo (rt2400) 15th Dec 04 Timing ESSID set + ***************************************************************************/ + +#include "rt_config.h" + +UCHAR CipherSuiteWpaNoneTkip[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x02, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x00, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x00 // authentication + }; +UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); + +UCHAR CipherSuiteWpaNoneAes[] = { + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x04, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x00, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x00 // authentication + }; +UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID MlmeCntlInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + OUT STATE_MACHINE_FUNC Trans[]) +{ + // Control state machine differs from other state machines, the interface + // follows the standard interface + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID MlmeCntlMachinePerformAction( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + IN MLME_QUEUE_ELEM *Elem) +{ + switch (Elem->MsgType) + { + case OID_802_11_SSID: + CntlOidSsidProc(pAd, Elem); + return; + case OID_802_11_BSSID: + CntlOidRTBssidProc(pAd, Elem); + return; + case OID_802_11_BSSID_LIST_SCAN: + CntlOidScanProc(pAd, Elem); + return; + } + + switch(pAd->Mlme.CntlMachine.CurrState) + { + case CNTL_IDLE: + CntlIdleProc(pAd, Elem); + break; + case CNTL_WAIT_DISASSOC: + CntlWaitDisassocProc(pAd, Elem); + break; + case CNTL_WAIT_JOIN: + CntlWaitJoinProc(pAd, Elem); + break; + + // CNTL_WAIT_REASSOC is the only state in CNTL machine that does + // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". + // Therefore not protected by NDIS's "only one outstanding OID request" + // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. + // Current approach is to block new SET request at RTMPSetInformation() + // when CntlMachine.CurrState is not CNTL_IDLE + case CNTL_WAIT_REASSOC: + CntlWaitReassocProc(pAd, Elem); + break; + + case CNTL_WAIT_START: + CntlWaitStartProc(pAd, Elem); + break; + case CNTL_WAIT_AUTH: + CntlWaitAuthProc(pAd, Elem); + break; + case CNTL_WAIT_AUTH2: + CntlWaitAuthProc2(pAd, Elem); + break; + case CNTL_WAIT_ASSOC: + CntlWaitAssocProc(pAd, Elem); + break; + + case CNTL_WAIT_OID_LIST_SCAN: + if(Elem->MsgType == MT2_SCAN_CONF) + { + // Resume TxRing after SCANING complete. We hope the out-of-service time + // won't be too long to let upper layer time-out the waiting frames + RTMPResumeMsduTransmission(pAd); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + if (pAd->MediaState == NdisMediaStateDisconnected) + MlmeAutoReconnectLastSSID(pAd); + break; + + case CNTL_WAIT_OID_DISASSOC: + if (Elem->MsgType == MT2_DISASSOC_CONF) + { + LinkDown(pAd); + + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + break; + + default: + printk(KERN_ERR DRV_NAME "CNTL - Illegal message type(=%d)", Elem->MsgType); + break; + } +} + + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlIdleProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MLME_DISASSOC_REQ_STRUCT DisassocReq; + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + { + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + } + return; + } + + switch(Elem->MsgType) + { + case OID_802_11_DISASSOCIATE: + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; + // Set the control aux SSID to prevent it reconnect to old SSID + // Since calling this indicate user don't want to connect to that SSID anymore. + pAd->Mlme.CntlAux.SsidLen = 32; + memset(pAd->Mlme.CntlAux.Ssid, 0x00, pAd->Mlme.CntlAux.SsidLen); + break; + + case MT2_MLME_ROAMING_REQ: + CntlMlmeRoamingProc(pAd, Elem); + break; + + default: + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Illegal message in CntlIdleProc(MsgType=%d)\n",Elem->MsgType); + break; + } +} + +VOID CntlOidScanProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MLME_SCAN_REQ_STRUCT ScanReq; + CHAR BroadSsid[MAX_LEN_OF_SSID]; + ULONG BssIdx = BSS_NOT_FOUND; + BSS_ENTRY CurrBss; + + DBGPRINT(RT_DEBUG_INFO, "CNTL - SCAN starts\n"); + + // temporarily recover BBP from short-distance-low-sensibility mode during SCAN + // for best SCANNING reult; + AsicRestoreBbpSensibility(pAd); + + // record current BSS if network is connected. + // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. + if (pAd->MediaState == NdisMediaStateConnected) // if (INFRA_ON(pAd) || ADHOC_ON(pAd)) + { + BssIdx = BssTableSearch(&pAd->PortCfg.BssTab, &pAd->PortCfg.Bssid); + if (BssIdx != BSS_NOT_FOUND) + { + memcpy(&CurrBss, &pAd->PortCfg.BssTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); + + // 2003-2-20 reset this RSSI to a low value but not zero. In normal case, the coming SCAN + // should return a correct RSSI to overwrite this. If no BEEACON received after SCAN, + // at least we still report a "greater than 0" RSSI since we claim it's CONNECTED. + CurrBss.Rssi = 18; // about -82 dB + } + } + + // clean up previous SCAN result, add current BSS back to table if any + BssTableInit(&pAd->PortCfg.BssTab); + if (BssIdx != BSS_NOT_FOUND) + { + // DDK Note: If the NIC is associated with a particular BSSID and SSID + // that are not contained in the list of BSSIDs generated by this scan, the + // BSSID description of the currently associated BSSID and SSID should be + // appended to the list of BSSIDs in the NIC's database. + // To ensure this, we append this BSS as the first entry in SCAN result + memcpy(&pAd->PortCfg.BssTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); + pAd->PortCfg.BssTab.BssNr = 1; + } + + BroadSsid[0] = '\0'; + ScanParmFill(pAd, &ScanReq, BroadSsid, 0, BSS_ANY, SCAN_PASSIVE); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, + sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlOidSsidProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM * Elem) +{ + NDIS_802_11_SSID *OidSsid = (NDIS_802_11_SSID *)Elem->Msg; + MLME_DISASSOC_REQ_STRUCT DisassocReq; + ULONG Now; + + // Step 0. + // record the desired SSID and all matching BSSes into CntlAux.SsidBssTab for + // later-on iteration. Sort by RSSI order + memcpy(pAd->Mlme.CntlAux.Ssid, OidSsid->Ssid, OidSsid->SsidLength); + pAd->Mlme.CntlAux.SsidLen = (UCHAR)OidSsid->SsidLength; + BssTableSsidSort(pAd, &pAd->Mlme.CntlAux.SsidBssTab, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen); + pAd->Mlme.CntlAux.BssIdx = 0; + DBGPRINT(RT_DEBUG_INFO, "CNTL - %d BSS match the desire SSID %s\n",pAd->Mlme.CntlAux.SsidBssTab.BssNr, pAd->Mlme.CntlAux.Ssid); + + Now = jiffies; + + if ((pAd->MediaState == NdisMediaStateConnected) && + MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, &pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].Bssid)) + { + if (((pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && + (pAd->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) + { + // For WPA, WPA-PSK, if the 1x port is not secured, we have to redo + // connection process + DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP...\n"); + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, + sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; + } + else if (pAd->bConfigChanged == TRUE) + { + // Config has changed, we have to reconnect the same AP + DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP Because config changed...\n"); + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, + sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; + } + else + { + // We only check if same to the BSSID with highest RSSI. + // If roaming of same SSID required, we still do the reconnection. + // same BSSID, go back to idle state directly + DBGPRINT(RT_DEBUG_TRACE, "CNTL - already with this BSSID. ignore this SET_SSID request\n"); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + } + else if (INFRA_ON(pAd)) + { + // case 1. active association existent + // roaming is done within miniport driver, nothing to do with configuration + // utility. so upon a new SET(OID_802_11_SSID) is received, we just + // disassociate with the current (or previous) associated AP, if any, + // then perform a new association with this new SSID, no matter the + // new/old SSID are the same or npt. + DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP...\n"); + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, + sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; + } + else + { + if (ADHOC_ON(pAd)) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - drop current ADHOC\n"); + LinkDown(pAd); + pAd->MediaState = NdisMediaStateDisconnected; + DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event C!\n"); + } + + if ((pAd->Mlme.CntlAux.SsidBssTab.BssNr==0) && (pAd->PortCfg.AutoReconnect == TRUE) && (pAd->PortCfg.BssType == BSS_INFRA)) + { + MLME_SCAN_REQ_STRUCT ScanReq; + + DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new scan\n"); + // BroadSsid[0] = '\0'; + ScanParmFill(pAd, &ScanReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen, BSS_ANY, SCAN_ACTIVE); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; + // Reset Missed scan number + pAd->PortCfg.IgnoredScanNumber = 0; + pAd->PortCfg.LastScanTime = Now; + } + else + { + IterateOnBssTab(pAd); + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlOidRTBssidProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM * Elem) +{ + ULONG BssIdx; + MACADDR *pOidBssid = (MACADDR *)Elem->Msg; + MLME_DISASSOC_REQ_STRUCT DisassocReq; + MLME_JOIN_REQ_STRUCT JoinReq; + + COPY_MAC_ADDR(&pAd->Mlme.CntlAux.Bssid, pOidBssid); + BssIdx = BssTableSearch(&pAd->PortCfg.BssTab, pOidBssid); + + if (BssIdx == BSS_NOT_FOUND) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n"); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + return; + } + + // copy the matched BSS entry from PortCfg.BssTab to CntlAux.SsidBssTab + pAd->Mlme.CntlAux.BssIdx = 0; + pAd->Mlme.CntlAux.SsidBssTab.BssNr = 1; + memcpy(&pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0], &pAd->PortCfg.BssTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); + + // Add SSID into Mlme.CntlAux for site surey joining hidden SSID + pAd->Mlme.CntlAux.SsidLen = pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].SsidLen; + memcpy(pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidBssTab.BssEntry[0].Ssid, pAd->Mlme.CntlAux.SsidLen); + + // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP + // we just follow normal procedure. The reason of user doing this may because he/she changed + // AP to another channel, but we still received BEACON from it thus don't claim Link Down. + // Since user knows he's chnged AP channel, he'll re-connect again. By skipping the following + // checking, we'll disassociate then re-do normal association with this AP at the new channel. + // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do + // connection when setting the same BSSID. + if ( (pAd->MediaState == NdisMediaStateConnected) && //(INFRA_ON(pAd) || ADHOC_ON(pAd)) && + MAC_ADDR_EQUAL(&pAd->PortCfg.Bssid, pOidBssid)) + { + // same BSSID, go back to idle state directly + DBGPRINT(RT_DEBUG_TRACE, "CNTL - already in this BSSID. ignore this SET_BSSID request\n"); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + else + { + if (INFRA_ON(pAd)) + { + // disassoc from current AP first + DBGPRINT(RT_DEBUG_TRACE, "CNTL - disassociate with current AP ...\n"); + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_DISASSOC_STA_LEAVING); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, + sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; + } + else + { + if (ADHOC_ON(pAd)) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - drop current ADHOC\n"); + LinkDown(pAd); + pAd->MediaState = NdisMediaStateDisconnected; + DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event C!\n"); + } + + // No active association, join the BSS immediately + DBGPRINT(RT_DEBUG_TRACE, "CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", + pOidBssid->Octet[0],pOidBssid->Octet[1],pOidBssid->Octet[2], + pOidBssid->Octet[3],pOidBssid->Octet[4],pOidBssid->Octet[5]); + JoinParmFill(pAd, &JoinReq, pAd->Mlme.CntlAux.BssIdx); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; + } + } +} + +// Roaming is the only external request triggering CNTL state machine +// despite of other "SET OID" operation. All "SET OID" related oerations +// happen in sequence, because no other SET OID will be sent to this device +// until the the previous SET operation is complete (successful o failed). +// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? +// or been corrupted by other "SET OID"? +VOID CntlMlmeRoamingProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + // TODO: + // AP in different channel may show lower RSSI than actual value?? + // should we add a weighting factor to compensate it? + DBGPRINT(RT_DEBUG_TRACE,"CNTL - Roaming in CntlAux.RoamTab...\n"); + BssTableSortByRssi(&pAd->Mlme.CntlAux.RoamTab); + pAd->Mlme.CntlAux.RoamIdx=0; + IterateOnBssTab2(pAd); + +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitDisassocProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MLME_START_REQ_STRUCT StartReq; + + if (Elem->MsgType == MT2_DISASSOC_CONF) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Dis-associate successful\n"); + LinkDown(pAd); + + // case 1. no matching BSS, and user wants ADHOC, so we just start a new one + if ((pAd->Mlme.CntlAux.SsidBssTab.BssNr==0) && (pAd->PortCfg.BssType == BSS_INDEP)) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->Mlme.CntlAux.Ssid); + StartParmFill(pAd, &StartReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; + } + // case 2. try each matched BSS + else + { + IterateOnBssTab(pAd); + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitJoinProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Reason; + MLME_AUTH_REQ_STRUCT AuthReq; + + if (Elem->MsgType == MT2_JOIN_CONF) + { + memcpy(&Reason, Elem->Msg, sizeof(USHORT)); + if (Reason == MLME_SUCCESS) + { + // 1. joined an IBSS, we are pretty much done here + if (pAd->PortCfg.BssType == BSS_INDEP) + { + LinkUp(pAd, BSS_INDEP); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + // 2. joined a new INFRA network, start from authentication + else + { + // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first + if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeShared) || + (pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) + { + AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeShared); + } + else + { + AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen); + } + MlmeEnqueue(&pAd->Mlme.Queue, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, + sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; + } + } + else + { + // 3. failed, try next BSS + pAd->Mlme.CntlAux.BssIdx++; + IterateOnBssTab(pAd); + } + } +} + + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitStartProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Result; + + if (Elem->MsgType == MT2_START_CONF) + { + memcpy(&Result, Elem->Msg, sizeof(USHORT)); + if (Result == MLME_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - We have started a new ADHOC network\n"); + DBGPRINT(RT_DEBUG_TRACE, "CNTL - BSSID %02x:%02x:%02x:%02x:%02x:%02x ...\n", + pAd->PortCfg.Bssid.Octet[0], + pAd->PortCfg.Bssid.Octet[1], + pAd->PortCfg.Bssid.Octet[2], + pAd->PortCfg.Bssid.Octet[3], + pAd->PortCfg.Bssid.Octet[4], + pAd->PortCfg.Bssid.Octet[5]); + LinkUp(pAd, BSS_INDEP); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Start FAIL. BUG!!!!!\n"); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitAuthProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Reason; + MLME_ASSOC_REQ_STRUCT AssocReq; + MLME_AUTH_REQ_STRUCT AuthReq; + + if (Elem->MsgType == MT2_AUTH_CONF) + { + memcpy(&Reason, Elem->Msg, sizeof(USHORT)); + if (Reason == MLME_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH OK\n"); + AssocParmFill(pAd, &AssocReq, &pAd->PortCfg.Bssid, pAd->PortCfg.CapabilityInfo, + ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, + sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; + } + else + { + // This fail may because of the AP already keep us in its MAC table without + // ageing-out. The previous authentication attempt must have let it remove us. + // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. + DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, try again...\n"); + if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeShared) || + (pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) + { + // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first + AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeShared); + } + else + { + AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen); + } + + MlmeEnqueue(&pAd->Mlme.Queue, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, + sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitAuthProc2( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Reason; + MLME_ASSOC_REQ_STRUCT AssocReq; + MLME_AUTH_REQ_STRUCT AuthReq; + + if (Elem->MsgType == MT2_AUTH_CONF) + { + memcpy(&Reason, Elem->Msg, sizeof(USHORT)); + if (Reason == MLME_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH OK\n"); + AssocParmFill(pAd, &AssocReq, &pAd->PortCfg.Bssid, pAd->PortCfg.CapabilityInfo, + ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, + sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; + } + else + { + if ((pAd->PortCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && + (pAd->Mlme.AuthAux.Alg == Ndis802_11AuthModeShared)) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, try OPEN system...\n"); + AuthParmFill(pAd, &AuthReq, &pAd->PortCfg.Bssid, Ndis802_11AuthModeOpen); + MlmeEnqueue(&pAd->Mlme.Queue, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, + sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; + } + else + { + // not success, try next BSS + DBGPRINT(RT_DEBUG_TRACE, "CNTL - AUTH FAIL, give up; try next BSS\n"); + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? + pAd->Mlme.CntlAux.BssIdx++; + IterateOnBssTab(pAd); + } + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitAssocProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Reason; + + if (Elem->MsgType == MT2_ASSOC_CONF) + { + memcpy(&Reason, Elem->Msg, sizeof(USHORT)); + if (Reason == MLME_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Association successful on BSS #%d\n",pAd->Mlme.CntlAux.BssIdx); + LinkUp(pAd, BSS_INFRA); + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + else + { + // not success, try next BSS + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Association fails on BSS #%d\n",pAd->Mlme.CntlAux.BssIdx); + pAd->Mlme.CntlAux.BssIdx++; + IterateOnBssTab(pAd); + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID CntlWaitReassocProc( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + USHORT Result; + + if (Elem->MsgType == MT2_REASSOC_CONF) + { + memcpy(&Result, Elem->Msg, sizeof(USHORT)); + if (Result == MLME_SUCCESS) + { + BSS_ENTRY *pBss = &pAd->Mlme.CntlAux.RoamTab.BssEntry[pAd->Mlme.CntlAux.RoamIdx]; + + // COPY_MAC_ADDR(&pAd->PortCfg.Bssid, &pBss->Bssid); + // AsicSetBssid(pAd, &pAd->PortCfg.Bssid); + + // The following steps are supposed to be done after JOIN in normal procedure + // But since this RE-ASSOC skips the JOIN procedure, we have to do it after + // RE-ASSOC succeeds. If RE-ASSOC fails, then stay at original AP without any change + pAd->PortCfg.BeaconPeriod = pBss->BeaconPeriod; + pAd->PortCfg.Channel = pBss->Channel; + // The security setting should always follow upper layer definition, not from frame + //pAd->PortCfg.PrivacyInvoked = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); + pAd->PortCfg.SupportedRatesLen = pBss->RatesLen; + memcpy(pAd->PortCfg.SupportedRates, pBss->Rates, pBss->RatesLen); + + // Check for 802.11g information, if 802.11 b /g mixed mode. + pAd->PortCfg.CapabilityInfo = pBss->CapabilityInfo; + + pAd->PortCfg.CfpPeriod = pBss->CfpPeriod; + pAd->PortCfg.CfpMaxDuration = pBss->CfpMaxDuration; + pAd->PortCfg.CfpDurRemain = pBss->CfpDurRemaining; + pAd->PortCfg.CfpCount = pBss->CfpCount; + + // + // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC + // + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Re-assocition successful on BSS #%d\n", pAd->Mlme.CntlAux.RoamIdx); + LinkUp(pAd, BSS_INFRA); + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } + else + { + // reassoc failed, try to pick next BSS in the BSS Table + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Re-assocition fails on BSS #%d\n", pAd->Mlme.CntlAux.RoamIdx); + pAd->Mlme.CntlAux.RoamIdx++; + IterateOnBssTab2(pAd); + } + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID LinkUp( + IN PRTMP_ADAPTER pAd, + IN UCHAR BssType) +{ + ULONG Now; + + DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! LINK UP !!!\n"); + MlmeUpdateTxRates(pAd, TRUE); + memcpy(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11)); + memset(&pAd->DrsCounters, 0, sizeof(COUNTER_DRS)); + + Now = jiffies; + pAd->PortCfg.LastBeaconRxTime = Now; // last RX timestamp + + if ((pAd->PortCfg.WindowsTxPreamble != Rt802_11PreambleLong) && + CAP_IS_SHORT_PREAMBLE_ON(pAd->PortCfg.CapabilityInfo)) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! Set to short preamble!!!\n"); + MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); + } + + pAd->PortCfg.BssType = BssType; + if (BssType == BSS_INDEP) + { + pAd->PortCfg.Mibss = TRUE; + pAd->PortCfg.Massoc = FALSE; + MakeIbssBeacon(pAd); + AsicEnableIbssSync(pAd); + +#ifdef SINGLE_ADHOC_LINKUP + // Although this did not follow microsoft's recommendation. + //Change based on customer's request + pAd->MediaState = NdisMediaStateConnected; +#endif + + // Clear Key information when driver change to WPA-None mode + // which did not have any key set +#if 0 + if (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + INT i; + + for (i = 0; i < PAIRWISE_KEY_NO; i++) + { + pAd->PortCfg.PairwiseKey[i].KeyLen = 0; + } + + for (i = 0; i < GROUP_KEY_NO; i++) + { + pAd->PortCfg.GroupKey[i].KeyLen = 0; + } + } +#endif + } + else // BSS_INFRA + { + pAd->PortCfg.Massoc = TRUE; + pAd->PortCfg.Mibss = FALSE; + + // NOTE: + // the decision of using "short slot time" or not may change dynamically due to + // new STA association to the AP. so we have to decide that upon parsing BEACON, not here + + // NOTE: + // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically + // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here + + ComposePsPoll(pAd); + ComposeNullFrame(pAd); + AsicEnableBssSync(pAd); + + // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode + // should wait until at least 2 active nodes in this BSSID. + pAd->MediaState = NdisMediaStateConnected; + } + + DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_CONNECT Event B!\n"); + + if (pAd->PortCfg.LedMode != LED_MODE_SINGLE) + { + ASIC_LED_ACT_ON(pAd); + } + + AsicSetSlotTime(pAd, FALSE); + pAd->Mlme.PeriodicRound = 0; + // Reset config flag + pAd->bConfigChanged = FALSE; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID LinkDown( + IN PRTMP_ADAPTER pAd) +{ + DBGPRINT(RT_DEBUG_TRACE, "CNTL - !!! LINK DOWN !!!\n"); + + if (ADHOC_ON(pAd)) // Adhoc mode link down + { + pAd->PortCfg.Mibss = FALSE; + +#ifdef SINGLE_ADHOC_LINKUP + pAd->MediaState = NdisMediaStateDisconnected; + // clean up previous SCAN result, add current BSS back to table if any + BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid)); +#else + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + { + pAd->MediaState = NdisMediaStateDisconnected; + // clean up previous SCAN result, add current BSS back to table if any + BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid)); + } +#endif + } + else// Infra structure mode + { + pAd->PortCfg.Massoc = FALSE; + pAd->MediaState = NdisMediaStateDisconnected; + DBGPRINT(RT_DEBUG_TRACE, "NDIS_STATUS_MEDIA_DISCONNECT Event A!\n"); + BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid)); + + // restore back to - + // 1. long slot (20 us) or short slot (9 us) time + // 2. turn on/off RTS/CTS and/or CTS-to-self protection + // 3. short preamble + if (pAd->PortCfg.BGProtectionInUsed == TRUE) + { + pAd->PortCfg.BGProtectionInUsed = FALSE; + DBGPRINT(RT_DEBUG_TRACE, "Link down - turn off B/G protection\n"); + } + + } + + AsicSetSlotTime(pAd, FALSE); + AsicRestoreBbpSensibility(pAd); + + if (pAd->PortCfg.WindowsTxPreamble == Rt802_11PreambleShort) + MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); + else + MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); + + if ((pAd->PortCfg.LedMode != LED_MODE_SINGLE) && (pAd->PortCfg.LedMode != LED_MODE_ASUS)) + { + ASIC_LED_ACT_OFF(pAd); + } + else if ((pAd->PortCfg.LedMode == LED_MODE_ASUS) && (pAd->PortCfg.bRadio == TRUE)) + { + RTMP_IO_WRITE32(pAd, LEDCSR, 0x0002461E); + } + AsicDisableSync(pAd); + pAd->Mlme.PeriodicRound = 0; + + // Remove PortCfg Information after link down + memset(&(pAd->PortCfg.Bssid), 0, ETH_ALEN); + //memset(pAd->PortCfg.Ssid, 0, MAX_LEN_OF_SSID); + //pAd->PortCfg.SsidLen = 0; + + // Reset WPA-PSK state. Only reset when supplicant enabled + if (pAd->PortCfg.WpaState != SS_NOTUSE) + { + pAd->PortCfg.WpaState = SS_START; + // Clear Replay counter + memset(pAd->PortCfg.ReplayCounter, 0, 8); + } + + // Remove all WPA keys after link down + //RTMPWPARemoveAllKeys(pAd); + // 802.1x port control + pAd->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + pAd->PortCfg.MicErrCnt = 0; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID MlmeCntlConfirm( + IN PRTMP_ADAPTER pAd, + IN ULONG MsgType, + IN USHORT Msg) +{ + MlmeEnqueue(&pAd->Mlme.Queue, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID IterateOnBssTab( + IN PRTMP_ADAPTER pAd) +{ + MLME_START_REQ_STRUCT StartReq; + MLME_JOIN_REQ_STRUCT JoinReq; + ULONG BssIdx; + + BssIdx = pAd->Mlme.CntlAux.BssIdx; + if (BssIdx < pAd->Mlme.CntlAux.SsidBssTab.BssNr) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - Trying BSSID %02x:%02x:%02x:%02x:%02x:%02x ...\n", + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[0], + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[1], + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[2], + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[3], + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[4], + pAd->Mlme.CntlAux.SsidBssTab.BssEntry[BssIdx].Bssid.Octet[5]); + JoinParmFill(pAd, &JoinReq, BssIdx); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), + &JoinReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; + } + else if (pAd->PortCfg.BssType == BSS_INDEP) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->Mlme.CntlAux.Ssid); + StartParmFill(pAd, &StartReq, pAd->Mlme.CntlAux.Ssid, (UCHAR)pAd->Mlme.CntlAux.SsidLen); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; + } + else // no more BSS + { + if (pAd->Mlme.CntlAux.CurrReqIsFromNdis) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - All BSS fail; reply NDIS_STATUS_NOT_ACCEPTED\n"); + } + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } +} + +// for re-association only +VOID IterateOnBssTab2( + IN PRTMP_ADAPTER pAd) +{ + MLME_REASSOC_REQ_STRUCT ReassocReq; + ULONG BssIdx; + BSS_ENTRY *pBss; + + BssIdx = pAd->Mlme.CntlAux.RoamIdx; + pBss = &pAd->Mlme.CntlAux.RoamTab.BssEntry[BssIdx]; + + if (BssIdx < pAd->Mlme.CntlAux.RoamTab.BssNr) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - try BSS #%d %02x:%02x:%02x:%02x:%02x:%02x ...\n", + BssIdx, pBss->Bssid.Octet[0],pBss->Bssid.Octet[1],pBss->Bssid.Octet[2], + pBss->Bssid.Octet[3],pBss->Bssid.Octet[4],pBss->Bssid.Octet[5]); + + AsicSwitchChannel(pAd, pBss->Channel); + AsicLockChannel(pAd, pBss->Channel); + + // reassociate message has the same structure as associate message + AssocParmFill(pAd, &ReassocReq, &pBss->Bssid, pBss->CapabilityInfo, + ASSOC_TIMEOUT, pAd->PortCfg.DefaultListenCount); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, + sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; + } + else // no more BSS + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - All roaming failed, stay with original AP\n"); + AsicSwitchChannel(pAd, pAd->PortCfg.Channel); + AsicLockChannel(pAd, pAd->PortCfg.Channel); + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + } +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID JoinParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, + IN ULONG BssIdx) +{ + JoinReq->BssIdx = BssIdx; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID AssocParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, + IN MACADDR *Addr, + IN USHORT CapabilityInfo, + IN ULONG Timeout, + IN USHORT ListenIntv) +{ + COPY_MAC_ADDR(&AssocReq->Addr, Addr); + // Add mask to support 802.11b mode only + AssocReq->CapabilityInfo = CapabilityInfo & 0xfff3; // not cf-pollable, not cf-poll-request + AssocReq->Timeout = Timeout; + AssocReq->ListenIntv = ListenIntv; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID ScanParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN UCHAR ScanType) +{ + ScanReq->SsidLen = SsidLen; + memcpy(ScanReq->Ssid, Ssid, SsidLen); + ScanReq->BssType = BssType; + ScanReq->ScanType = ScanType; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID DisassocParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, + IN MACADDR *Addr, + IN USHORT Reason) +{ + COPY_MAC_ADDR(&DisassocReq->Addr, Addr); + DisassocReq->Reason = Reason; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID StartParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_START_REQ_STRUCT *StartReq, + IN CHAR Ssid[], + IN UCHAR SsidLen) +{ + memcpy(StartReq->Ssid, Ssid, SsidLen); + StartReq->SsidLen = SsidLen; +} + +/* + ========================================================================== + Description: + ========================================================================== +*/ +VOID AuthParmFill( + IN PRTMP_ADAPTER pAd, + IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, + IN MACADDR *Addr, + IN USHORT Alg) +{ + COPY_MAC_ADDR(&AuthReq->Addr, Addr); + AuthReq->Alg = Alg; + AuthReq->Timeout = AUTH_TIMEOUT; +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID ComposePsPoll( + IN PRTMP_ADAPTER pAd) +{ + memset(&pAd->Mlme.PsFr, 0, sizeof(PSPOLL_FRAME)); + pAd->Mlme.PsFr.Type = BTYPE_CNTL; + pAd->Mlme.PsFr.SubType = SUBTYPE_PS_POLL; + pAd->Mlme.PsFr.Aid = pAd->PortCfg.Aid | 0xC000; + COPY_MAC_ADDR(&(pAd->Mlme.PsFr.Bssid), &pAd->PortCfg.Bssid); + COPY_MAC_ADDR(&(pAd->Mlme.PsFr.Ta), &(pAd->CurrentAddress)); +} + +VOID ComposeNullFrame( + IN PRTMP_ADAPTER pAd) +{ + MgtMacHeaderInit(pAd, &pAd->Mlme.NullFr, SUBTYPE_NULL_FUNC, 1, &pAd->PortCfg.Bssid, &pAd->PortCfg.Bssid); + pAd->Mlme.NullFr.Duration = 0; + pAd->Mlme.NullFr.Type = BTYPE_DATA; +} + +/* + ========================================================================== + Description: + Pre-build a BEACON frame in the shared memory + ========================================================================== +*/ +ULONG MakeIbssBeacon( + IN PRTMP_ADAPTER pAd) +{ + UCHAR SsidIe = IE_SSID, DsIe = IE_DS_PARM, IbssIe = IE_IBSS_PARM, SuppIe = IE_SUPP_RATES, + DsLen = 1, IbssLen = 2; + UCHAR ExtRateIe = IE_EXT_SUPP_RATES, ExtRatesLen; + UCHAR ErpIe[3] = {IE_ERP, 1, 0x04}; + MACHDR BcnHdr; + USHORT CapabilityInfo; + LARGE_INTEGER FakeTimestamp; + ULONG FrameLen; + PTXD_STRUC pTxD = (PTXD_STRUC)pAd->BeaconRing.va_addr; + CHAR *pBeaconFrame = (CHAR *)pAd->BeaconRing.va_data_addr; + UCHAR SupportedRatesLen; + UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; + BOOLEAN Privacy; + + // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode + // make sure 1,2,5.5,11 are the firt 4 rates in PortCfg.SupportedRates[] array + if ((pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && (pAd->PortCfg.AdhocMode == 0)) + { + int i; + SupportedRatesLen=0; + for (i=0;iPortCfg.SupportedRatesLen;i++) + { + switch (pAd->PortCfg.SupportedRates[i] & 0x7f) + { + case 2: + case 4: + case 11: + case 22: + SupportedRates[SupportedRatesLen] = pAd->PortCfg.SupportedRates[i]; + SupportedRatesLen ++; + break; + default: + break; + } + } + // error handling - should never happen + if (SupportedRatesLen != 4) + { + SupportedRatesLen = 4; + SupportedRates[0] = 0x82; + SupportedRates[1] = 0x84; + SupportedRates[2] = 0x8b; + SupportedRates[3] = 0x96; + } + } + else + { + SupportedRatesLen = pAd->PortCfg.SupportedRatesLen; + memcpy(SupportedRates, pAd->PortCfg.SupportedRates, SupportedRatesLen); + } + + pAd->PortCfg.AtimWin = 0; // ?????? + + // compose IBSS beacon frame + MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, &pAd->PortCfg.Broadcast, &pAd->PortCfg.Bssid); + Privacy = (pAd->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) || + (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) || + (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled); + CapabilityInfo = CAP_GENERATE(0, 1, 0, 0, Privacy, (pAd->PortCfg.WindowsTxPreamble == Rt802_11PreambleShort)); + if (SupportedRatesLen <= 8) + { + MakeOutgoingFrame(pBeaconFrame, &FrameLen, + MAC_HDR_LEN, &BcnHdr, + TIMESTAMP_LEN, &FakeTimestamp, + 2, &pAd->PortCfg.BeaconPeriod, + 2, &CapabilityInfo, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &SuppIe, + 1, &SupportedRatesLen, + SupportedRatesLen, SupportedRates, + 1, &DsIe, + 1, &DsLen, + 1, &pAd->PortCfg.Channel, + 1, &IbssIe, + 1, &IbssLen, + 2, &pAd->PortCfg.AtimWin, + END_OF_ARGS); + } + else + { + ExtRatesLen = SupportedRatesLen - 8; + SupportedRatesLen = 8; + MakeOutgoingFrame(pBeaconFrame, &FrameLen, + MAC_HDR_LEN, &BcnHdr, + TIMESTAMP_LEN, &FakeTimestamp, + 2, &pAd->PortCfg.BeaconPeriod, + 2, &CapabilityInfo, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &SuppIe, + 1, &SupportedRatesLen, + SupportedRatesLen, SupportedRates, + 1, &DsIe, + 1, &DsLen, + 1, &pAd->PortCfg.Channel, + 1, &IbssIe, + 1, &IbssLen, + 2, &pAd->PortCfg.AtimWin, + 3, ErpIe, + 1, &ExtRateIe, + 1, &ExtRatesLen, + ExtRatesLen, &SupportedRates[SupportedRatesLen], + END_OF_ARGS); + } + // If adhoc secruity is set for WPA-None, append the cipher suite IE + if (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + ULONG tmp; + UCHAR WpaIe = IE_WPA; + + if (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) // Tkip + { + MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaNoneTkipLen, + CipherSuiteWpaNoneTkipLen, &CipherSuiteWpaNoneTkip[0], + END_OF_ARGS); + FrameLen += tmp; + } + else if (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) // Aes + { + MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaNoneAesLen, + CipherSuiteWpaNoneAesLen, &CipherSuiteWpaNoneAes[0], + END_OF_ARGS); + FrameLen += tmp; + } + } +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); +#endif + + RTMPWriteTxDescriptor(pTxD, FALSE, CIPHER_NONE, FALSE, FALSE, TRUE, SHORT_RETRY, IFS_NEW_BACKOFF, + pAd->PortCfg.MlmeRate, 4, FrameLen, pAd->PortCfg.TxPreambleInUsed, 0); + + DBGPRINT(RT_DEBUG_TRACE, "MakeIbssBeacon (len=%d)\n", FrameLen); + return FrameLen; +} + + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/eeprom.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/eeprom.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/eeprom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/eeprom.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,237 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: eeprom.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +VOID RaiseClock( + IN PRTMP_ADAPTER pAd, + IN ULONG *x) +{ + *x = *x | EESK; + RTMP_IO_WRITE32(pAd, CSR21, *x); + udelay(1); +} + +VOID LowerClock( + IN PRTMP_ADAPTER pAd, + IN ULONG *x) +{ + *x = *x & ~EESK; + RTMP_IO_WRITE32(pAd, CSR21, *x); + udelay(1); +} + +USHORT ShiftInBits( + IN PRTMP_ADAPTER pAd) +{ + ULONG x,i; + USHORT data=0; + + RTMP_IO_READ32(pAd, CSR21, &x); + + x &= ~( EEDO | EEDI); + + for(i=0; i<16; i++) + { + data = data << 1; + RaiseClock(pAd, &x); + + RTMP_IO_READ32(pAd, CSR21, &x); + + x &= ~(EEDI); + if(x & EEDO) + data |= 1; + + LowerClock(pAd, &x); + } + + return data; +} + +VOID ShiftOutBits( + IN PRTMP_ADAPTER pAd, + IN USHORT data, + IN USHORT count) +{ + ULONG x,mask; + + mask = 0x01 << (count - 1); + RTMP_IO_READ32(pAd, CSR21, &x); + + x &= ~(EEDO | EEDI); + + do + { + x &= ~EEDI; + if(data & mask) x |= EEDI; + + RTMP_IO_WRITE32(pAd, CSR21, x); + + RaiseClock(pAd, &x); + LowerClock(pAd, &x); + + mask = mask >> 1; + } while(mask); + + x &= ~EEDI; + RTMP_IO_WRITE32(pAd, CSR21, x); +} + +VOID EEpromCleanup( + IN PRTMP_ADAPTER pAd) +{ + ULONG x; + + RTMP_IO_READ32(pAd, CSR21, &x); + + x &= ~(EECS | EEDI); + RTMP_IO_WRITE32(pAd, CSR21, x); + + RaiseClock(pAd, &x); + LowerClock(pAd, &x); +} + +VOID EWEN( + IN PRTMP_ADAPTER pAd) +{ + ULONG x; + + // reset bits and set EECS + RTMP_IO_READ32(pAd, CSR21, &x); + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + RTMP_IO_WRITE32(pAd, CSR21, x); + + // kick a pulse + RaiseClock(pAd, &x); + LowerClock(pAd, &x); + + // output the read_opcode and six pulse in that order + ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); + ShiftOutBits(pAd, 0, 6); + + EEpromCleanup(pAd); +} + +VOID EWDS( + IN PRTMP_ADAPTER pAd) +{ + ULONG x; + + // reset bits and set EECS + RTMP_IO_READ32(pAd, CSR21, &x); + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + RTMP_IO_WRITE32(pAd, CSR21, x); + + // kick a pulse + RaiseClock(pAd, &x); + LowerClock(pAd, &x); + + // output the read_opcode and six pulse in that order + ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); + ShiftOutBits(pAd, 0, 6); + + EEpromCleanup(pAd); +} + +USHORT RTMP_EEPROM_READ16( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset) +{ + ULONG x; + USHORT data; + + Offset /= 2; + // reset bits and set EECS + RTMP_IO_READ32(pAd, CSR21, &x); + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + RTMP_IO_WRITE32(pAd, CSR21, x); + + // kick a pulse + RaiseClock(pAd, &x); + LowerClock(pAd, &x); + + // output the read_opcode and register number in that order + ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); + ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); + + // Now read the data (16 bits) in from the selected EEPROM word + data = ShiftInBits(pAd); + + EEpromCleanup(pAd); + + return data; +} //ReadEEprom + +VOID RTMP_EEPROM_WRITE16( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Data) +{ + ULONG i, x; + + Offset /= 2; + + EWEN(pAd); + + // reset bits and set EECS + RTMP_IO_READ32(pAd, CSR21, &x); + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + RTMP_IO_WRITE32(pAd, CSR21, x); + + // kick a pulse + RaiseClock(pAd, &x); + LowerClock(pAd, &x); + + // output the read_opcode ,register number and data in that order + ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); + ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); + ShiftOutBits(pAd, Data, 16); // 16-bit access + + // read DO status + RTMP_IO_READ32(pAd, CSR21, &x); + + EEpromCleanup(pAd); + + for(i=0; i<10; i++) + udelay(1000); //delay for twp(MAX)=10ms + + EWDS(pAd); + + EEpromCleanup(pAd); +} + + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/md5.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/md5.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/md5.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/md5.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1200 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + * This MD5 code is based on code from Dynamics -- HUT Mobile IP * + * Copyright (C) 1998-2001, Dynamics group * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: md5.c + * + * Abstract: contain MD5 and AES cipher algorithm + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * JanL 28th Oct 03 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +/** + * md5_mac: + * @key: pointer to the key used for MAC generation + * @key_len: length of the key in bytes + * @data: pointer to the data area for which the MAC is generated + * @data_len: length of the data in bytes + * @mac: pointer to the buffer holding space for the MAC; the buffer should + * have space for 128-bit (16 bytes) MD5 hash value + * + * md5_mac() determines the message authentication code by using secure hash + * MD5(key | data | key). + */ +void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) +{ + MD5_CTX context; + + rt2500_MD5Init(&context); + rt2500_MD5Update(&context, key, key_len); + rt2500_MD5Update(&context, data, data_len); + rt2500_MD5Update(&context, key, key_len); + rt2500_MD5Final(mac, &context); +} + +/** + * rt2500_hmac_md5: + * @key: pointer to the key used for MAC generation + * @key_len: length of the key in bytes + * @data: pointer to the data area for which the MAC is generated + * @data_len: length of the data in bytes + * @mac: pointer to the buffer holding space for the MAC; the buffer should + * have space for 128-bit (16 bytes) MD5 hash value + * + * rt2500_hmac_md5() determines the message authentication code using HMAC-MD5. + * This implementation is based on the sample code presented in RFC 2104. + */ +void rt2500_hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) +{ + MD5_CTX context; + u8 k_ipad[65]; /* inner padding - key XORd with ipad */ + u8 k_opad[65]; /* outer padding - key XORd with opad */ + u8 tk[16]; + int i; + + //assert(key != NULL && data != NULL && mac != NULL); + + /* if key is longer than 64 bytes reset it to key = MD5(key) */ + if (key_len > 64) { + MD5_CTX ttcontext; + + rt2500_MD5Init(&ttcontext); + rt2500_MD5Update(&ttcontext, key, key_len); + rt2500_MD5Final(tk, &ttcontext); + //key=(PUCHAR)ttcontext.buf; + key = tk; + key_len = 16; + } + + /* the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + //assert(key_len < sizeof(k_ipad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner MD5 */ + rt2500_MD5Init(&context); /* init context for 1st pass */ + rt2500_MD5Update(&context, k_ipad, 64); /* start with inner pad */ + rt2500_MD5Update(&context, data, data_len); /* then text of datagram */ + rt2500_MD5Final(mac, &context); /* finish up 1st pass */ + + /* perform outer MD5 */ + rt2500_MD5Init(&context); /* init context for 2nd pass */ + rt2500_MD5Update(&context, k_opad, 64); /* start with outer pad */ + rt2500_MD5Update(&context, mac, 16); /* then results of 1st hash */ + rt2500_MD5Final(mac, &context); /* finish up 2nd pass */ +} + + +/* ===== start - public domain MD5 implementation ===== */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to rt2500_MD5Init, call rt2500_MD5Update as + * needed on buffers full of bytes, and then call rt2500_MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#ifndef BIG_ENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); +void byteReverse(unsigned char *buf, unsigned longs) +{ + do { + *(ULONG *)buf = SWAP32(*(ULONG *)buf); + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void rt2500_MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void rt2500_MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void rt2500_MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +//#ifndef ASM_MD5 +#if 1 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w =( w<>(32-s))&0xffffffff, w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. rt2500_MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(u32 buf[4], u32 in[16]) +{ + register u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#endif + +void SHAInit(SHA_CTX *ctx) { + int i; + + ctx->lenW = 0; + ctx->sizeHi = ctx->sizeLo = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) + */ + ctx->H[0] = 0x67452301L; + ctx->H[1] = 0xefcdab89L; + ctx->H[2] = 0x98badcfeL; + ctx->H[3] = 0x10325476L; + ctx->H[4] = 0xc3d2e1f0L; + + for (i = 0; i < 80; i++) + ctx->W[i] = 0; + } + +#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) + +void SHAHashBlock(SHA_CTX *ctx) { + int t; + unsigned long A,B,C,D,E,TEMP; + + for (t = 16; t <= 79; t++) + ctx->W[t] = SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t = 0; t <= 19; t++) { + TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 20; t <= 39; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 40; t <= 59; t++) { + TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 60; t <= 79; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + +void SHAUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) +{ + int i; + + /* Read the data into W and process blocks as they get full + */ + for (i = 0; i < len; i++) { + ctx->W[ctx->lenW / 4] <<= 8; + ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i]; + if ((++ctx->lenW) % 64 == 0) { + SHAHashBlock(ctx); + ctx->lenW = 0; + } + ctx->sizeLo += 8; + ctx->sizeHi += (ctx->sizeLo < 8); + } +} + + +void SHAFinal(SHA_CTX *ctx, unsigned char hashout[20]) { + unsigned char pad0x80 = 0x80; + unsigned char pad0x00 = 0x00; + unsigned char padlen[8]; + int i; + + /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length + */ + padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); + padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); + padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); + padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); + padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); + padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); + padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); + padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); + SHAUpdate(ctx, &pad0x80, 1); + while (ctx->lenW != 56) + SHAUpdate(ctx, &pad0x00, 1); + SHAUpdate(ctx, padlen, 8); + + /* Output hash + */ + for (i = 0; i < 20; i++) { + hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); + ctx->H[i / 4] <<= 8; + } + + /* + * Re-initialize the context (also zeroizes contents) + */ + SHAInit(ctx); +} + +/* forward S-box */ + +static uint32 FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* forward table */ + +#define FT \ +\ + V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ + V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ + V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ + V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ + V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ + V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ + V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ + V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ + V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ + V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ + V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ + V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ + V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ + V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ + V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ + V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ + V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ + V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ + V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ + V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ + V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ + V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ + V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ + V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ + V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ + V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ + V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ + V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ + V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ + V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ + V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ + V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ + V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ + V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ + V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ + V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ + V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ + V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ + V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ + V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ + V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ + V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ + V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ + V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ + V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ + V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ + V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ + V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ + V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ + V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ + V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ + V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ + V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ + V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ + V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ + V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ + V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ + V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ + V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ + V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ + V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ + V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ + V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ + V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) + +#define V(a,b,c,d) 0x##a##b##c##d +static uint32 FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static uint32 FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static uint32 FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static uint32 FT3[256] = { FT }; +#undef V + +#undef FT + +/* reverse S-box */ + +static uint32 RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* reverse table */ + +#define RT \ +\ + V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ + V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ + V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ + V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ + V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ + V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ + V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ + V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ + V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ + V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ + V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ + V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ + V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ + V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ + V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ + V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ + V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ + V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ + V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ + V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ + V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ + V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ + V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ + V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ + V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ + V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ + V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ + V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ + V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ + V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ + V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ + V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ + V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ + V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ + V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ + V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ + V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ + V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ + V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ + V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ + V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ + V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ + V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ + V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ + V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ + V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ + V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ + V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ + V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ + V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ + V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ + V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ + V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ + V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ + V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ + V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ + V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ + V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ + V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ + V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ + V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ + V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ + V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ + V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) + +#define V(a,b,c,d) 0x##a##b##c##d +static uint32 RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static uint32 RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static uint32 RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static uint32 RT3[256] = { RT }; +#undef V + +#undef RT + +/* round constants */ + +static uint32 RCON[10] = +{ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 +}; + +/* key schedule tables */ + +static int KT_init = 1; + +static uint32 KT0[256]; +static uint32 KT1[256]; +static uint32 KT2[256]; +static uint32 KT3[256]; + +/* platform-independant 32-bit integer manipulation macros */ + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) ] << 24 ) \ + | ( (uint32) (b)[(i) + 1] << 16 ) \ + | ( (uint32) (b)[(i) + 2] << 8 ) \ + | ( (uint32) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8) ( (n) ); \ +} + +/* AES key scheduling routine */ + +int aes_set_key( aes_context *ctx, uint8 *key, int nbits ) +{ + int i; + uint32 *RK, *SK; + + switch( nbits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( 1 ); + } + + RK = ctx->erk; + + for( i = 0; i < (nbits >> 5); i++ ) + { + GET_UINT32( RK[i], key, i * 4 ); + } + + /* setup encryption round keys */ + + switch( nbits ) + { + case 128: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 192: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 256: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[11] ) ] ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + /* setup decryption round keys */ + + if( KT_init ) + { + for( i = 0; i < 256; i++ ) + { + KT0[i] = RT0[ FSb[i] ]; + KT1[i] = RT1[ FSb[i] ]; + KT2[i] = RT2[ FSb[i] ]; + KT3[i] = RT3[ FSb[i] ]; + } + + KT_init = 0; + } + + SK = ctx->drk; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + for( i = 1; i < ctx->nr; i++ ) + { + RK -= 8; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + } + + RK -= 8; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + return( 0 ); +} + +/* AES 128-bit block encryption routine */ + +void aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->erk; + GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; + GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; + GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; + GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y3 ) ]; \ + \ + X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y0 ) ]; \ + \ + X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y1 ) ]; \ + \ + X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y2 ) ]; \ +} + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ + + if( ctx->nr > 10 ) + { + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ + } + + if( ctx->nr > 12 ) + { + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y3 ) ] ); + + X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y0 ) ] ); + + X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y1 ) ] ); + + X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y2 ) ] ); + + PUT_UINT32( X0, output, 0 ); + PUT_UINT32( X1, output, 4 ); + PUT_UINT32( X2, output, 8 ); + PUT_UINT32( X3, output, 12 ); +} + +/* AES 128-bit block decryption routine */ + +void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->drk; + + GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; + GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; + GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; + GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y1 ) ]; \ + \ + X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y2 ) ]; \ + \ + X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y3 ) ]; \ + \ + X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y0 ) ]; \ +} + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ + + if( ctx->nr > 10 ) + { + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ + } + + if( ctx->nr > 12 ) + { + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y1 ) ] ); + + X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y2 ) ] ); + + X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y3 ) ] ); + + X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y0 ) ] ); + + PUT_UINT32( X0, output, 0 ); + PUT_UINT32( X1, output, 4 ); + PUT_UINT32( X2, output, 8 ); + PUT_UINT32( X3, output, 12 ); +} + +void hmac_sha1(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest) +{ + SHA_CTX context; + unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[65]; /* outer padding - key XORd with opad */ + int i; + + /* if key is longer than 64 bytes reset it to key=SHA1(key) */ + if (key_len > 64) + { + SHA_CTX tctx; + + SHAInit(&tctx); + SHAUpdate(&tctx, key, key_len); + SHAFinal(&tctx, key); + + key_len = 20; + } + + /* + * the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof k_ipad); + memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA1*/ + SHAInit(&context); /* init context for 1st pass */ + SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ + SHAUpdate(&context, text, text_len); /* then text of datagram */ + SHAFinal(&context, digest); /* finish up 1st pass */ + + /* perform outer SHA1 */ + SHAInit(&context); /* init context for 2nd pass */ + SHAUpdate(&context, k_opad, 64); /* start with outer pad */ + SHAUpdate(&context, digest, 20); /* then results of 1st hash */ + SHAFinal(&context, digest); /* finish up 2nd pass */ +} + +/* +* F(P, S, c, i) = U1 xor U2 xor ... Uc +* U1 = PRF(P, S || Int(i)) +* U2 = PRF(P, U1) +* Uc = PRF(P, Uc-1) +*/ + +void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) +{ + unsigned char digest[36], digest1[SHA_DIGEST_LEN]; + int i, j; + + /* U1 = PRF(P, S || int(i)) */ + memcpy(digest, ssid, ssidlength); + digest[ssidlength] = (unsigned char)((count>>24) & 0xff); + digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); + digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); + digest[ssidlength+3] = (unsigned char)(count & 0xff); + hmac_sha1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update + + /* output = U1 */ + memcpy(output, digest1, SHA_DIGEST_LEN); + + for (i = 1; i < iterations; i++) + { + /* Un = PRF(P, Un-1) */ + hmac_sha1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update + memcpy(digest1, digest, SHA_DIGEST_LEN); + + /* output = output xor Un */ + for (j = 0; j < SHA_DIGEST_LEN; j++) + { + output[j] ^= digest[j]; + } + } +} +/* +* password - ascii string up to 63 characters in length +* ssid - octet string up to 32 octets +* ssidlength - length of ssid in octets +* output must be 40 octets in length and outputs 256 bits of key +*/ +int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) +{ + if ((strlen(password) > 63) || (ssidlength > 32)) + return 0; + + F(password, ssid, ssidlength, 4096, 1, output); + F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); + return 1; +} diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/md5.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/md5.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/md5.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/md5.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,94 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + * This MD5 code is based on code from Dynamics -- HUT Mobile IP * + * Copyright (C) 1998-2001, Dynamics group * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: md5.h + * + * Abstract: contain MD5 and AES cipher algorithm + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef MD5_H +#define MD5_H + +#define MD5_MAC_LEN 16 +#define SHA_DIGEST_LEN 20 + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void rt2500_MD5Init(struct MD5Context *context); +void rt2500_MD5Update(struct MD5Context *context, unsigned char *buf, unsigned len); +void rt2500_MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(u32 buf[4], u32 in[16]); + +typedef struct MD5Context MD5_CTX; + + +void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); +void rt2500_hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); + +#endif /* MD5_H */ + +#ifndef _AES_H +#define _AES_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +typedef struct +{ + uint32 erk[64]; /* encryption round keys */ + uint32 drk[64]; /* decryption round keys */ + int nr; /* number of rounds */ +} +aes_context; + +int aes_set_key( aes_context *ctx, uint8 *key, int nbits ); +void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); +void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); + + +void SHAInit(SHA_CTX *ctx); +void SHAUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); +void SHAFinal(SHA_CTX *ctx, unsigned char hashout[20]); +void SHAHashBlock(SHA_CTX *ctx); +void hmac_sha1(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest); +void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); +int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); + +#endif /* aes.h */ + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/mlme.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/mlme.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/mlme.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/mlme.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,4091 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: mlme.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * MarkW 8th Dec 04 kmalloc ATOMIC fixes + * RobinC 10th Dec 04 RFMON Support + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + * Ivo (rt2400) 15th Dec 04 Uninitialised timer + * MarkW 17th Dec 04 Monitor mode through iwconfig + * BrunoH 3rd Feb 04 Fix for 802.11b adhoc association + * JohnC 19th Mar 04 Fixes for quality reporting + * MarkW 13th Jun 05 Fix to allow adhoc network creation + ***************************************************************************/ + +#include "rt_config.h" +#include + +// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than +// this value, then it's quaranteed capable of operating in 36 mbps TX rate in +// clean environment. +// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 +CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; + + // 1 2 5.5 11 +UCHAR Phy11BNextRateDownward[] = {RATE_1, RATE_1, RATE_2, RATE_5_5}; +UCHAR Phy11BNextRateUpward[] = {RATE_2, RATE_5_5, RATE_11, RATE_11}; + + // 1 2 5.5 11 6 9 12 18 24 36 48 54 +UCHAR Phy11BGNextRateDownward[]= {RATE_1, RATE_1, RATE_2, RATE_5_5,RATE_11, RATE_6, RATE_11, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48}; +UCHAR Phy11BGNextRateUpward[] = {RATE_2, RATE_5_5, RATE_11, RATE_12, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54}; + + // 1 2 5.5 11 6 9 12 18 24 36 48 54 +UCHAR Phy11ANextRateDownward[] = {RATE_6, RATE_6, RATE_6, RATE_6, RATE_6, RATE_6, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48}; +UCHAR Phy11ANextRateUpward[] = {RATE_9, RATE_9, RATE_9, RATE_9, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54, RATE_54}; + +// 2560D and after has implemented ASIC-based OFDM rate switching, but not +// 2560C and before. thus software use different PER for rate switching +// RATE_1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 +USHORT NewRateUpPER[] = { 40, 40, 35, 20, 20, 20, 20, 16, 10, 16, 10, 6 }; // in percentage +USHORT NewRateDownPER[] = { 50, 50, 45, 45, 35, 35, 35, 35, 25, 25, 25, 13 }; // in percentage + +USHORT OldRateUpPER[] = { 40, 40, 40, 40, 30, 30, 30, 30, 20, 20, 10, 10 }; // in percentage +USHORT OldRateDownPER[] = { 45, 45, 45, 45, 35, 35, 35, 35, 25, 25, 25, 12 }; // in percentage + +UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; +USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; + +RTMP_RF_REGS RF2522RegTable[] = { +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94002050, 0x940c1fda, 0x94000101, 0}, + {2, 0x94002050, 0x940c1fee, 0x94000101, 0}, + {3, 0x94002050, 0x940c2002, 0x94000101, 0}, + {4, 0x94002050, 0x940c2016, 0x94000101, 0}, + {5, 0x94002050, 0x940c202a, 0x94000101, 0}, + {6, 0x94002050, 0x940c203e, 0x94000101, 0}, + {7, 0x94002050, 0x940c2052, 0x94000101, 0}, + {8, 0x94002050, 0x940c2066, 0x94000101, 0}, + {9, 0x94002050, 0x940c207a, 0x94000101, 0}, + {10, 0x94002050, 0x940c208e, 0x94000101, 0}, + {11, 0x94002050, 0x940c20a2, 0x94000101, 0}, + {12, 0x94002050, 0x940c20b6, 0x94000101, 0}, + {13, 0x94002050, 0x940c20ca, 0x94000101, 0}, + {14, 0x94002050, 0x940c20fa, 0x94000101, 0} +}; +#define NUM_OF_2522_CHNL (sizeof(RF2522RegTable) / sizeof(RTMP_RF_REGS)) + +RTMP_RF_REGS RF2523RegTable[] = { +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94022010, 0x94000c9e, 0x940e0111, 0x94000a1b}, + {2, 0x94022010, 0x94000ca2, 0x940e0111, 0x94000a1b}, + {3, 0x94022010, 0x94000ca6, 0x940e0111, 0x94000a1b}, + {4, 0x94022010, 0x94000caa, 0x940e0111, 0x94000a1b}, + {5, 0x94022010, 0x94000cae, 0x940e0111, 0x94000a1b}, + {6, 0x94022010, 0x94000cb2, 0x940e0111, 0x94000a1b}, + {7, 0x94022010, 0x94000cb6, 0x940e0111, 0x94000a1b}, + {8, 0x94022010, 0x94000cba, 0x940e0111, 0x94000a1b}, + {9, 0x94022010, 0x94000cbe, 0x940e0111, 0x94000a1b}, + {10, 0x94022010, 0x94000d02, 0x940e0111, 0x94000a1b}, + {11, 0x94022010, 0x94000d06, 0x940e0111, 0x94000a1b}, + {12, 0x94022010, 0x94000d0a, 0x940e0111, 0x94000a1b}, + {13, 0x94022010, 0x94000d0e, 0x940e0111, 0x94000a1b}, + {14, 0x94022010, 0x94000d1a, 0x940e0111, 0x94000a03} +#if 0 + {1, 0x94022050, 0x940c1fda, 0x940e8101, 0}, + {2, 0x94022050, 0x940c1fee, 0x940e8101, 0}, + {3, 0x94022050, 0x940c2002, 0x940e8101, 0}, + {4, 0x94022050, 0x940c2016, 0x940e8101, 0}, + {5, 0x94022050, 0x940c202a, 0x940e8101, 0}, + {6, 0x94022050, 0x940c203e, 0x940e8101, 0}, + {7, 0x94022050, 0x940c2052, 0x940e8101, 0}, + {8, 0x94022050, 0x940c2066, 0x940e8101, 0}, + {9, 0x94022050, 0x940c207a, 0x940e8101, 0}, + {10, 0x94022050, 0x940c208e, 0x940e8101, 0}, + {11, 0x94022050, 0x940c20a2, 0x940e8101, 0}, + {12, 0x94022050, 0x940c20b6, 0x940e8101, 0}, + {13, 0x94022050, 0x940c20ca, 0x940e8101, 0}, + {14, 0x94022050, 0x940c20fa, 0x940e8101, 0} +#endif +}; +#define NUM_OF_2523_CHNL (sizeof(RF2523RegTable) / sizeof(RTMP_RF_REGS)) + +RTMP_RF_REGS RF2524RegTable[] = { +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94032020, 0x94000c9e, 0x94000101, 0x94000a1b}, + {2, 0x94032020, 0x94000ca2, 0x94000101, 0x94000a1b}, + {3, 0x94032020, 0x94000ca6, 0x94000101, 0x94000a1b}, + {4, 0x94032020, 0x94000caa, 0x94000101, 0x94000a1b}, + {5, 0x94032020, 0x94000cae, 0x94000101, 0x94000a1b}, + {6, 0x94032020, 0x94000cb2, 0x94000101, 0x94000a1b}, + {7, 0x94032020, 0x94000cb6, 0x94000101, 0x94000a1b}, + {8, 0x94032020, 0x94000cba, 0x94000101, 0x94000a1b}, + {9, 0x94032020, 0x94000cbe, 0x94000101, 0x94000a1b}, + {10, 0x94032020, 0x94000d02, 0x94000101, 0x94000a1b}, + {11, 0x94032020, 0x94000d06, 0x94000101, 0x94000a1b}, + {12, 0x94032020, 0x94000d0a, 0x94000101, 0x94000a1b}, + {13, 0x94032020, 0x94000d0e, 0x94000101, 0x94000a1b}, + {14, 0x94032020, 0x94000d1a, 0x94000101, 0x94000a03} +}; +#define NUM_OF_2524_CHNL (sizeof(RF2524RegTable) / sizeof(RTMP_RF_REGS)) + +RTMP_RF_REGS RF2525RegTable[] = { +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94022020, 0x94080c9e, 0x94060111, 0x94000a1b}, // {1, 0x94022010, 0x9408062e, 0x94060111, 0x94000a23}, + {2, 0x94022020, 0x94080ca2, 0x94060111, 0x94000a1b}, + {3, 0x94022020, 0x94080ca6, 0x94060111, 0x94000a1b}, + {4, 0x94022020, 0x94080caa, 0x94060111, 0x94000a1b}, + {5, 0x94022020, 0x94080cae, 0x94060111, 0x94000a1b}, + {6, 0x94022020, 0x94080cb2, 0x94060111, 0x94000a1b}, + {7, 0x94022020, 0x94080cb6, 0x94060111, 0x94000a1b}, + {8, 0x94022020, 0x94080cba, 0x94060111, 0x94000a1b}, + {9, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b}, + {10, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b}, + {11, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b}, // {11, 0x94022010, 0x94080682, 0x94060111, 0x94000a23}, + {12, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b}, + {13, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b}, // {13, 0x94022010, 0x94080686, 0x94060111, 0x94000a23}, + {14, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a03} +}; +#define NUM_OF_2525_CHNL (sizeof(RF2525RegTable) / sizeof(RTMP_RF_REGS)) + +RTMP_RF_REGS RF2525HBOffsetRegTable[] = { + {1, 0x94022020, 0x94080cbe, 0x94060111, 0x94000a1b}, + {2, 0x94022020, 0x94080d02, 0x94060111, 0x94000a1b}, + {3, 0x94022020, 0x94080d06, 0x94060111, 0x94000a1b}, + {4, 0x94022020, 0x94080d0a, 0x94060111, 0x94000a1b}, + {5, 0x94022020, 0x94080d0e, 0x94060111, 0x94000a1b}, + {6, 0x94022020, 0x94080d12, 0x94060111, 0x94000a1b}, + {7, 0x94022020, 0x94080d16, 0x94060111, 0x94000a1b}, + {8, 0x94022020, 0x94080d1a, 0x94060111, 0x94000a1b}, + {9, 0x94022020, 0x94080d1e, 0x94060111, 0x94000a1b}, + {10, 0x94022020, 0x94080d22, 0x94060111, 0x94000a1b}, + {11, 0x94022020, 0x94080d26, 0x94060111, 0x94000a1b}, + {12, 0x94022020, 0x94080d2a, 0x94060111, 0x94000a1b}, + {13, 0x94022020, 0x94080d2e, 0x94060111, 0x94000a1b}, + {14, 0x94022020, 0x94080d3a, 0x94060111, 0x94000a03} +}; + +RTMP_RF_REGS RF2525eRegTable[] = { +#if 1 +// using 5 Mhz reference clock +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94022020, 0x94081136, 0x94060111, 0x94000a0b}, + {2, 0x94022020, 0x9408113a, 0x94060111, 0x94000a0b}, + {3, 0x94022020, 0x9408113e, 0x94060111, 0x94000a0b}, + {4, 0x94022020, 0x94081182, 0x94060111, 0x94000a0b}, + {5, 0x94022020, 0x94081186, 0x94060111, 0x94000a0b}, + {6, 0x94022020, 0x9408118a, 0x94060111, 0x94000a0b}, + {7, 0x94022020, 0x9408118e, 0x94060111, 0x94000a0b}, + {8, 0x94022020, 0x94081192, 0x94060111, 0x94000a0b}, + {9, 0x94022020, 0x94081196, 0x94060111, 0x94000a0b}, + {10, 0x94022020, 0x9408119a, 0x94060111, 0x94000a0b}, + {11, 0x94022020, 0x9408119e, 0x94060111, 0x94000a0b}, + {12, 0x94022020, 0x940811a2, 0x94060111, 0x94000a0b}, + {13, 0x94022020, 0x940811a6, 0x94060111, 0x94000a0b}, + {14, 0x94022020, 0x940811ae, 0x94060111, 0x94000a1b} +#else +// using 10 Mhz reference clock +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94022010, 0x9408089a, 0x94060111, 0x94000a1b}, + {2, 0x94022010, 0x9408089e, 0x94060111, 0x94000a07}, + {3, 0x94022010, 0x9408089e, 0x94060111, 0x94000a1b}, + {4, 0x94022010, 0x940808a2, 0x94060111, 0x94000a07}, + {5, 0x94022010, 0x940808a2, 0x94060111, 0x94000a1b}, + {6, 0x94022010, 0x940808a6, 0x94060111, 0x94000a07}, + {7, 0x94022010, 0x940808a6, 0x94060111, 0x94000a1b}, + {8, 0x94022010, 0x940808aa, 0x94060111, 0x94000a07}, + {9, 0x94022010, 0x940808aa, 0x94060111, 0x94000a1b}, + {10, 0x94022010, 0x940808ae, 0x94060111, 0x94000a07}, + {11, 0x94022010, 0x940808ae, 0x94060111, 0x94000a1b}, + {12, 0x94022010, 0x940808b2, 0x94060111, 0x94000a07}, + {13, 0x94022010, 0x940808b2, 0x94060111, 0x94000a1b}, + {14, 0x94022010, 0x940808b6, 0x94060111, 0x94000a23} +#endif +}; +#define NUM_OF_2525E_CHNL (sizeof(RF2525eRegTable) / sizeof(RTMP_RF_REGS)) + +RTMP_RF_REGS RF5222RegTable[] = { +// ch R1 R2 R3(TX0~4=0) R4 + {1, 0x94022020, 0x94001136, 0x94000101, 0x94000a0b}, + {2, 0x94022020, 0x9400113a, 0x94000101, 0x94000a0b}, + {3, 0x94022020, 0x9400113e, 0x94000101, 0x94000a0b}, + {4, 0x94022020, 0x94001182, 0x94000101, 0x94000a0b}, + {5, 0x94022020, 0x94001186, 0x94000101, 0x94000a0b}, + {6, 0x94022020, 0x9400118a, 0x94000101, 0x94000a0b}, + {7, 0x94022020, 0x9400118e, 0x94000101, 0x94000a0b}, + {8, 0x94022020, 0x94001192, 0x94000101, 0x94000a0b}, + {9, 0x94022020, 0x94001196, 0x94000101, 0x94000a0b}, + {10, 0x94022020, 0x9400119a, 0x94000101, 0x94000a0b}, + {11, 0x94022020, 0x9400119e, 0x94000101, 0x94000a0b}, + {12, 0x94022020, 0x940011a2, 0x94000101, 0x94000a0b}, + {13, 0x94022020, 0x940011a6, 0x94000101, 0x94000a0b}, + {14, 0x94022020, 0x940011ae, 0x94000101, 0x94000a1b}, + + // still lack of MMAC(Japan) ch 34,38,42,46 + + {36, 0x94022010, 0x94018896, 0x94000101, 0x94000a1f}, + {40, 0x94022010, 0x9401889a, 0x94000101, 0x94000a1f}, + {44, 0x94022010, 0x9401889e, 0x94000101, 0x94000a1f}, + {48, 0x94022010, 0x940188a2, 0x94000101, 0x94000a1f}, + {52, 0x94022010, 0x940188a6, 0x94000101, 0x94000a1f}, + {66, 0x94022010, 0x940188aa, 0x94000101, 0x94000a1f}, + {60, 0x94022010, 0x940188ae, 0x94000101, 0x94000a1f}, + {64, 0x94022010, 0x940188b2, 0x94000101, 0x94000a1f}, + + {100, 0x94022010, 0x94008802, 0x94000101, 0x94000a0f}, + {104, 0x94022010, 0x94008806, 0x94000101, 0x94000a0f}, + {108, 0x94022010, 0x9400880a, 0x94000101, 0x94000a0f}, + {112, 0x94022010, 0x9400880e, 0x94000101, 0x94000a0f}, + {116, 0x94022010, 0x94008812, 0x94000101, 0x94000a0f}, + {120, 0x94022010, 0x94008816, 0x94000101, 0x94000a0f}, + {124, 0x94022010, 0x9400881a, 0x94000101, 0x94000a0f}, + {128, 0x94022010, 0x9400881e, 0x94000101, 0x94000a0f}, + {132, 0x94022010, 0x94008822, 0x94000101, 0x94000a0f}, + {136, 0x94022010, 0x94008826, 0x94000101, 0x94000a0f}, + {140, 0x94022010, 0x9400882a, 0x94000101, 0x94000a0f}, + + {149, 0x94022020, 0x940090a6, 0x94000101, 0x94000a07}, + {153, 0x94022020, 0x940090ae, 0x94000101, 0x94000a07}, + {157, 0x94022020, 0x940090b6, 0x94000101, 0x94000a07}, + {161, 0x94022020, 0x940090be, 0x94000101, 0x94000a07} +}; +#define NUM_OF_5222_CHNL (sizeof(RF5222RegTable) / sizeof(RTMP_RF_REGS)) + +/* + ========================================================================== + Description: + initialize the MLME task and its data structure (queue, spinlock, + timer, state machines). + Return: + always return NDIS_STATUS_SUCCESS + ========================================================================== +*/ +NDIS_STATUS MlmeInit( + IN PRTMP_ADAPTER pAd) +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + if(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_INITIALIZED)) + return Status; + + DBGPRINT(RT_DEBUG_TRACE, "--> MLME Initialize\n"); + + do + { + pAd->Mlme.Running = FALSE; + spin_lock_init(&pAd->Mlme.TaskLock); + + // initialize the two tables + // MacTableInit(pAd); + BssTableInit(&pAd->PortCfg.BssTab); + + // init state machines + ASSERT(ASSOC_FUNC_SIZE == MAX_ASSOC_MSG * MAX_ASSOC_STATE); + AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); + + ASSERT(AUTH_FUNC_SIZE == MAX_AUTH_MSG * MAX_AUTH_STATE); + AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); + + ASSERT(AUTH_RSP_FUNC_SIZE == MAX_AUTH_RSP_MSG * MAX_AUTH_RSP_STATE); + AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); + + ASSERT(SYNC_FUNC_SIZE == MAX_SYNC_MSG * MAX_SYNC_STATE); + SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); + + ASSERT(WPA_PSK_FUNC_SIZE == MAX_WPA_PSK_MSG * MAX_WPA_PSK_STATE); + WpaPskStateMachineInit(pAd,&pAd->Mlme.WpaPskMachine,pAd->Mlme.WpaPskFunc); + + // Since we are using switch/case to implement it, the init is different from the above + // state machine init + MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); + + // Init mlme periodic timer + RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, MlmePeriodicExec); + // Set mlme periodic timer + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); + + RTMPInitTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, AsicLedPeriodicExec); + if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY) + { + // Set blink timer + RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70); + } + + // software-based RX Antenna diversity + RTMPInitTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, AsicRxAntEvalTimeout); + } while (FALSE); + + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MLME_INITIALIZED); + + DBGPRINT(RT_DEBUG_TRACE, "<-- MLME Initialize\n"); + + return Status; +} + + +/* + ========================================================================== + Description: + main loop of the MLME + Pre: + Mlme has to be initialized, and there are something inside the queue + Note: + This function is invoked from MPSetInformation and MPReceive; + This task guarantee only one MlmeHandler will run. + ========================================================================== + */ +VOID MlmeHandler( + IN PRTMP_ADAPTER pAd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + schedule_work(&pAd->mlme_work); +} + +VOID MlmeWork(void *vpAd) +{ + PRTMP_ADAPTER pAd = vpAd; +#endif + MLME_QUEUE_ELEM *Elem = NULL; + unsigned long flags; + int loops = 0; + + // Only accept MLME and Frame from peer side, no other (control/data) frame should + // get into this state machine + + spin_lock_irqsave(&pAd->Mlme.TaskLock,flags); + if(pAd->Mlme.Running) + { + spin_unlock_irqrestore(&pAd->Mlme.TaskLock,flags); + return; + } + else + { + pAd->Mlme.Running = TRUE; + } + spin_unlock_irqrestore(&pAd->Mlme.TaskLock,flags); + + while (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) + { + //From message type, determine which state machine I should drive + if (pAd->PortCfg.BssType != BSS_MONITOR) + { + // if dequeue success + switch (Elem->Machine) + { + case ASSOC_STATE_MACHINE: + StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); + break; + case AUTH_STATE_MACHINE: + StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); + break; + case AUTH_RSP_STATE_MACHINE: + StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); + break; + case SYNC_STATE_MACHINE: + StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); + break; + case MLME_CNTL_STATE_MACHINE: + MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); + break; + case WPA_PSK_STATE_MACHINE: + StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); + break; + default: + DBGPRINT(RT_DEBUG_TRACE, "ERROR: Illegal machine in MlmeHandler()\n"); + break; + } // end of switch + + // free MLME element + Elem->Occupied = FALSE; + Elem->MsgLen = 0; + + } + else + { + printk(KERN_ERR DRV_NAME "ERROR: empty Elem in MlmeQueue\n"); + } + loops++; + if (loops > 50) + /* something wrong - avoid locking up the computer solid */ + break; + } + + spin_lock_irqsave(&pAd->Mlme.TaskLock,flags); + pAd->Mlme.Running = FALSE; + spin_unlock_irqrestore(&pAd->Mlme.TaskLock,flags); +} + +/* + ========================================================================== + Description: + Destructor of MLME (Destroy queue, state machine, spin lock and timer) + Parameters: + Adapter - NIC Adapter pointer + Post: + The MLME task will no longer work properly + ========================================================================== + */ +VOID MlmeHalt( + IN PRTMP_ADAPTER pAd) +{ + MLME_DISASSOC_REQ_STRUCT DisReq; + MLME_QUEUE_ELEM *MsgElem; + + if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_INITIALIZED)) + return; + + MsgElem = kmalloc(sizeof(MLME_QUEUE_ELEM), GFP_KERNEL); + if(!MsgElem) + return; + + DBGPRINT(RT_DEBUG_TRACE, "==> MlmeHalt\n"); + + if (INFRA_ON(pAd) && !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) + { + COPY_MAC_ADDR(&DisReq.Addr, &pAd->PortCfg.Bssid); + DisReq.Reason = REASON_DISASSOC_STA_LEAVING; + + MsgElem->Machine = ASSOC_STATE_MACHINE; + MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; + MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); + memcpy(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); + + MlmeDisassocReqAction(pAd, MsgElem); + + udelay(1000); + } + + if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) + { + // disable BEACON generation and other BEACON related hardware timers + AsicDisableSync(pAd); + } + + // Cancel pending timers + RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer); + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + RTMPCancelTimer(&pAd->Mlme.PeriodicTimer); + // RTMPCancelTimer(&pAd->PortCfg.MacTab.AgedOutTimer); + + if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) + { + RTMPCancelTimer(&pAd->PortCfg.LedCntl.BlinkTimer); + ASIC_LED_ACT_OFF(pAd); + } + + RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer); + udelay(1000); + + MlmeQueueDestroy(&pAd->Mlme.Queue); + StateMachineDestroy(&pAd->Mlme.AssocMachine); + StateMachineDestroy(&pAd->Mlme.AuthMachine); + StateMachineDestroy(&pAd->Mlme.AuthRspMachine); + StateMachineDestroy(&pAd->Mlme.SyncMachine); + // StateMachineDestroy(&pAd->Mlme.CntlMachine); + //NdisFreeSpinLock(&pAd->Mlme.Queue.Lock); + //NdisFreeSpinLock(&pAd->Mlme.TaskLock); + // NdisFreeSpinLock(&pAd->PortCfg.MacTab.Lock); + + MlmeFreeMemoryHandler(pAd); //Free MLME memory handler + + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MLME_INITIALIZED); + + DBGPRINT(RT_DEBUG_TRACE, "<== MlmeHalt\n"); + kfree(MsgElem); +} + +/* + ========================================================================== + Description: + This routine is executed periodically to - + 1. Decide if it's a right time to turn on PwrMgmt bit of all + outgoiing frames + 2. Calculate ChannelQuality based on statistics of the last + period, so that TX rate won't toggling very frequently between a + successful TX and a failed TX. + 3. If the calculated ChannelQuality indicated current connection not + healthy, then a ROAMing attempt is tried here. + ========================================================================== + */ +#define ADHOC_BEACON_LOST_TIME (10*HZ) // 4 sec +VOID MlmePeriodicExec( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + ULONG Now32; + CSR15_STRUC Csr15; + + if (pAd->PortCfg.BssType == BSS_MONITOR) + { + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); + return; + } + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + { + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); + return; + } + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) + { + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); + return; + } + + // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a + // valid indication of the distance between this AP and its clients. + if (pAd->MediaState == NdisMediaStateConnected) + { + if (pAd->PortCfg.NumOfAvgRssiSample < 3) + { + pAd->PortCfg.RxAnt.AvgRssi[0] = (-95 + 120) << 3; // reset Ant-A's RSSI history + pAd->PortCfg.RxAnt.AvgRssi[1] = (-95 + 120) << 3; // reset Ant-B's RSSI history + pAd->PortCfg.AvgRssi = pAd->PortCfg.LastR17Value; + DBGPRINT(RT_DEBUG_TRACE, "MlmePeriodicExec: no traffic, reset Avg RSSI= %d dbm\n", pAd->PortCfg.AvgRssi); + } + else + pAd->PortCfg.NumOfAvgRssiSample = 0; + } + + Now32 = jiffies; + + if (pAd->RalinkCounters.MgmtRingFullCount >= 2) + { + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); + } + else + { + pAd->RalinkCounters.MgmtRingFullCount = 0; + } + + if ((pAd->PortCfg.bBlockAssoc == TRUE) && (pAd->PortCfg.LastMicErrorTime + (60 * HZ) < Now32)) + { + pAd->PortCfg.bBlockAssoc = FALSE; + } + + // if Rx Antenna is DIVERSITY ON, then perform Software-based diversity evaluation + if ((pAd->PortCfg.CurrentRxAntenna == 0xff) && (pAd->Mlme.PeriodicRound % 2 == 1)) + { + SHORT realavgrssi = (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt] >> 3) - pAd->PortCfg.RssiToDbm; + DBGPRINT(RT_DEBUG_TRACE, "MlmePeriodicExec:(%d), Primary AvgRssi(%d), LastAvgRssi(%d)\n", pAd->PortCfg.RxAnt.PrimaryRxAnt, realavgrssi, pAd->PortCfg.LastAvgRssi); + DBGPRINT(RT_DEBUG_TRACE, "Primary AvgRssi(%d), Second AvgRssi(%d)\n", pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt], pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt]); + if ((realavgrssi > pAd->PortCfg.LastAvgRssi + 5) || (realavgrssi < pAd->PortCfg.LastAvgRssi - 5)) + { + //DBGPRINT(RT_DEBUG_TRACE, ("AsicEvaluateSecondaryRxAnt ===> start evaluate second antenna!!!\n")); + pAd->PortCfg.LastAvgRssi = realavgrssi; + AsicEvaluateSecondaryRxAnt(pAd); + } + } + + +#ifndef WIFI_TEST + // danamic tune BBP R17 to find a balance between sensibility and noise isolation + // 2003-12-05 For 2560C and before, to avoid collision with MAC ASIC, limit + // BBP R17 tuning to be within 20 seconds after LINK UP. 2560D (R0=4) and + // after can always enable R17 tuning + if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D) + AsicBbpTuning(pAd); + else if ((pAd->MediaState == NdisMediaStateConnected) && (pAd->Mlme.PeriodicRound <= 20)) + AsicBbpTuning(pAd); +#endif + + if (pAd->MediaState == NdisMediaStateConnected) + { + // update channel quality for Roaming and UI LinkQuality display + MlmeCheckChannelQuality(pAd, Now32); +#if 0 + // periodic VCO tuning when there's no traffic. + // RF guys suspected VCO will shift away upon temperature change along the time + if (((pAd->Mlme.PeriodicRound % 16) == 2) && + ((pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount)==0)) + { + DBGPRINT(RT_DEBUG_TRACE,("Periodic VCO tuning...\n")); + AsicSwitchChannel(pAd, pAd->PortCfg.Channel); + AsicLockChannel(pAd, pAd->PortCfg.Channel); + } +#endif + // perform dynamic tx rate switching based on past TX history + MlmeCheckDynamicTxRateSwitching(pAd); + } + + AsicAdjustTxPower(pAd); + + if (INFRA_ON(pAd)) + { + // Is PSM bit consistent with user power management policy? + // This is the only place that will set PSM bit ON. + MlmeCheckForPsmChange(pAd, Now32); + + // Check for EAPOL frame sent after MIC countermeasures + if (pAd->PortCfg.MicErrCnt >= 3) + { + MLME_DISASSOC_REQ_STRUCT DisassocReq; + + // disassoc from current AP first + DBGPRINT(RT_DEBUG_TRACE, "MLME - disassociate with current AP after sending second continuous EAPOL frame\n"); + DisassocParmFill(pAd, &DisassocReq, &pAd->PortCfg.Bssid, REASON_MIC_FAILURE); + MlmeEnqueue(&pAd->Mlme.Queue, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, + sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); + + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; + pAd->PortCfg.bBlockAssoc = TRUE; + } + + else + { + // send out a NULL frame every 10 sec. for what??? inform "PwrMgmt" bit? + if ((pAd->Mlme.PeriodicRound % 10) == 8) + EnqueueNullFrame(pAd, pAd->PortCfg.TxRate); + + if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) + { + pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Bad CQI. Auto Recovery attempt #%d\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount); + MlmeAutoReconnectLastSSID(pAd); + } + + else if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) || CQI_IS_POOR(pAd->Mlme.ChannelQuality)) + { + // perform aggresive roaming only when SECURITY OFF or WEP64/128; + // WPA and WPA-PSK has no aggresive roaming because re-negotiation + // between 802.1x supplicant and authenticator/AAA server is required + // but can't be guaranteed. + if (pAd->PortCfg.AuthMode < Ndis802_11AuthModeWPA) + MlmeCheckForRoaming(pAd, Now32); + } + } + } + else if (ADHOC_ON(pAd)) + { + if ((pAd->Mlme.PeriodicRound % 2) == 1) + { + // So that even when ASIC's BEACONgen engine been blocked + // by peer's BEACON due to slower system clock, this STA still can send out + // minimum BEACON to tell the peer I'm alive. + // drawback is that this BEACON won't well align at TBTT boundary. + RTMP_IO_READ32(pAd, CSR15, &Csr15.word); // read-n-clear "BcnSent" bit + if (Csr15.field.BeaconSent == 0) + EnqueueBeaconFrame(pAd); // software send BEACON + } + else + { + // if all 11b peers leave this BSS more than 5 seconds, update Tx rate + if ((pAd->PortCfg.Channel <= 14) && + (pAd->PortCfg.MaxTxRate <= RATE_11) && + (pAd->PortCfg.MaxDesiredRate > RATE_11) && + ((pAd->PortCfg.Last11bBeaconRxTime + (5 * HZ)) < Now32)) + { + DBGPRINT(RT_DEBUG_TRACE, "last 11B peer left, update Tx rates\n"); + memcpy(pAd->PortCfg.SupportedRates, pAd->PortCfg.IbssConfig.SupportedRates, MAX_LEN_OF_SUPPORTED_RATES); + pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen; + MlmeUpdateTxRates(pAd, FALSE); + MakeIbssBeacon(pAd); // supported rates changed + } + } + +#ifndef SINGLE_ADHOC_LINKUP + // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState + // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can + // join later. + if ((pAd->PortCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < Now32) && + (pAd->MediaState == NdisMediaStateConnected)) + { + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"); + + pAd->MediaState = NdisMediaStateDisconnected; + // clean up previous SCAN result, add current BSS back to table if any + BssTableDeleteEntry(&pAd->PortCfg.BssTab, &(pAd->PortCfg.Bssid)); + + pAd->PortCfg.LastScanTime = Now32; + } +#endif + + } + else + { + DBGPRINT(RT_DEBUG_INFO, "MLME periodic exec, no association so far\n"); + if (pAd->PortCfg.AutoReconnect == TRUE) + { + if ((pAd->PortCfg.BssTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) + { + MLME_SCAN_REQ_STRUCT ScanReq; + + if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32) + { + DBGPRINT(RT_DEBUG_TRACE, "CNTL - No matching BSS, start a new scan\n"); + // BroadSsid[0] = '\0'; + ScanParmFill(pAd, &ScanReq, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen, BSS_ANY, SCAN_ACTIVE); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); + pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; + // Reset Missed scan number + pAd->PortCfg.IgnoredScanNumber = 0; + pAd->PortCfg.LastScanTime = Now32; + } + else if (pAd->PortCfg.BssType == BSS_INDEP) // Quit the forever scan when in a very clean room + MlmeAutoRecoverNetwork(pAd); + //MlmeAutoReconnectLastSSID(pAd); + } + else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) + { + if ((pAd->Mlme.PeriodicRound % 10) == 7) + { + if ((pAd->PortCfg.LastScanTime + 10 * HZ) < Now32) + { + MlmeAutoScan(pAd); + pAd->PortCfg.LastScanTime = Now32; + } + } + else + MlmeAutoReconnectLastSSID(pAd); + + DBGPRINT(RT_DEBUG_INFO, "pAd->PortCfg.AutoReconnect is TRUE\n"); + } + } + } + pAd->Mlme.PeriodicRound ++; + MlmeHandler(pAd); + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + NICCheckForHang(pAd); + + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); +} + +VOID MlmeAutoScan( + IN PRTMP_ADAPTER pAd) +{ + // check CntlMachine.CurrState to avoid collision with NDIS SetOID request + if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) + { + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto scan\n"); + + // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by driver itself. + pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAd->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_BSSID_LIST_SCAN, + 0, + NULL); + MlmeHandler(pAd); + } +} + +VOID MlmeAutoRecoverNetwork( + IN PRTMP_ADAPTER pAd) +{ + // check CntlMachine.CurrState to avoid collision with NDIS SetOID request + if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) + { + NDIS_802_11_SSID OidSsid; + OidSsid.SsidLength = pAd->PortCfg.SsidLen; + memcpy(OidSsid.Ssid, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen); + + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Driver auto recovering network - %s\n", pAd->PortCfg.Ssid); + + // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by driver itself. + pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAd->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_SSID, + sizeof(NDIS_802_11_SSID), + &OidSsid); + MlmeHandler(pAd); + } + +} + +VOID MlmeAutoReconnectLastSSID( + IN PRTMP_ADAPTER pAd) +{ + // check CntlMachine.CurrState to avoid collision with NDIS SetOID request + if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) + { + NDIS_802_11_SSID OidSsid; + OidSsid.SsidLength = pAd->Mlme.CntlAux.SsidLen; + memcpy(OidSsid.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->Mlme.CntlAux.SsidLen); + + DBGPRINT(RT_DEBUG_TRACE, "Driver auto reconnect to last OID_802_11_SSID setting - %s\n", pAd->Mlme.CntlAux.Ssid); + + // We will only try this attemp once, therefore change the AutoReconnect flag afterwards. + pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAd->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_SSID, + sizeof(NDIS_802_11_SSID), + &OidSsid); + MlmeHandler(pAd); + } +} + +/* + ========================================================================== + Description: + This routine checks if there're other APs out there capable for + roaming. Caller should call this routine only when Massoc=TRUE and + channel quality is below CQI_GOOD_THRESHOLD. + Output: + ========================================================================== + */ +VOID MlmeCheckForRoaming( + IN PRTMP_ADAPTER pAd, + IN ULONG Now32) +{ + USHORT i; + BSS_TABLE *pBssTab = &pAd->Mlme.CntlAux.SsidBssTab; + BSS_TABLE *pRoamTab = &pAd->Mlme.CntlAux.RoamTab; + BSS_ENTRY *pBss; + + // put all roaming candidates into RoamTab, and sort in RSSI order + BssTableInit(pRoamTab); + for (i = 0; i < pBssTab->BssNr; i++) + { + pBss = &pBssTab->BssEntry[i]; + + if ((pBssTab->BssEntry[i].LastBeaconRxTime + BEACON_LOST_TIME) < Now32) + continue; // AP disappear + if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) + continue; // RSSI too weak. forget it. + if (MAC_ADDR_EQUAL(&pBssTab->BssEntry[i].Bssid, &pAd->PortCfg.Bssid)) + continue; // skip current AP + if (CQI_IS_FAIR(pAd->Mlme.ChannelQuality) && (pAd->PortCfg.LastRssi + RSSI_DELTA > pBss->Rssi)) + continue; // we're still okay, only AP with stronger RSSI is eligible for roaming + + // AP passing all above rules is put into roaming candidate table + memcpy(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); + pRoamTab->BssNr += 1; + } + + if (pRoamTab->BssNr > 0) + { + // check CntlMachine.CurrState to avoid collision with NDIS SetOID request + if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) + { + // tell CNTL state machine NOT to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by driver itself, not from NDIS. + pAd->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + pAd->RalinkCounters.PoorCQIRoamingCount ++; + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - Roaming attempt #%d\n", pAd->RalinkCounters.PoorCQIRoamingCount); + MlmeEnqueue(&pAd->Mlme.Queue, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); + MlmeHandler(pAd); + } + } + +} + +/* + ========================================================================== + Description: + This routine calculates TxPER, RxPER of the past N-sec period. And + according to the calculation result, ChannelQuality is calculated here + to decide if current AP is still doing the job. + + If ChannelQuality is not good, a ROAMing attempt may be tried later. + Output: + PortCfg.ChannelQuality - 0..100 + ========================================================================== + */ +VOID MlmeCheckChannelQuality( + IN PRTMP_ADAPTER pAd, + IN ULONG Now32) +{ + ULONG TxFailCnt, TxOkCnt, TxRetryCnt, TxCnt; + ULONG RxFailCnt, RxOkCnt, RxCnt, Cnt0, OldFcsCount; + static ULONG TxPER = 0, TxPRR = 0, RxPER = 0; + + // + // monitor TX counters change for the past period + // + TxFailCnt = pAd->WlanCounters.FailedCount.vv.LowPart - + pAd->Mlme.PrevWlanCounters.FailedCount.vv.LowPart; + TxRetryCnt = pAd->WlanCounters.RetryCount.vv.LowPart - + pAd->Mlme.PrevWlanCounters.RetryCount.vv.LowPart; + TxOkCnt = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart - + pAd->Mlme.PrevWlanCounters.TransmittedFragmentCount.vv.LowPart; + TxCnt = TxOkCnt + TxFailCnt; + + if (TxCnt > 5) // if too few TX samples, skip TX related statistics + { + TxPER = (TxFailCnt * 100) / TxCnt; + TxPRR = ((TxRetryCnt + TxFailCnt) * 100) / TxCnt; + } + + // + // calculate RX PER + // + + // Update FCS counters + RTMP_IO_READ32(pAd, CNT0, &Cnt0); + OldFcsCount= pAd->WlanCounters.FCSErrorCount.vv.LowPart; + pAd->WlanCounters.FCSErrorCount.vv.LowPart += ((Cnt0 & 0x0000ffff) >> 7); + if (pAd->WlanCounters.FCSErrorCount.vv.LowPart < OldFcsCount) + pAd->WlanCounters.FCSErrorCount.vv.HighPart++; + + // Add FCS error count to private counters + OldFcsCount = pAd->RalinkCounters.RealFcsErrCount.vv.LowPart; + pAd->RalinkCounters.RealFcsErrCount.vv.LowPart += Cnt0; + if (pAd->RalinkCounters.RealFcsErrCount.vv.LowPart < OldFcsCount) + pAd->RalinkCounters.RealFcsErrCount.vv.HighPart++; + + RxOkCnt = pAd->WlanCounters.ReceivedFragmentCount.vv.LowPart - + pAd->Mlme.PrevWlanCounters.ReceivedFragmentCount.vv.LowPart; + RxFailCnt = pAd->RalinkCounters.RealFcsErrCount.vv.LowPart - + pAd->Mlme.PrevWlanCounters.FCSErrorCount.vv.LowPart; + RxCnt = RxOkCnt + RxFailCnt; + + if (RxCnt > 5) + RxPER = (RxFailCnt * 100) / RxCnt; +//printk("!! WiFi: Ok: %d, Fail: %d, PER: %d\n", RxOkCnt, RxFailCnt, RxPER); + // + // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER + // + // This value also decides when all roaming fails (or no roaming candidates at + // all), should this STA stay with original AP, or a LinkDown signal + // is indicated to NDIS + // + if (INFRA_ON(pAd) && + (pAd->PortCfg.LastBeaconRxTime + BEACON_LOST_TIME < Now32)) // BEACON starving? + { + // Ignore lost beacon when NIC in reset state + // Ignore lost beacon if traffic still goes well + if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) && (TxOkCnt < 2)) + { + DBGPRINT(RT_DEBUG_TRACE, "BEACON lost for more than %d sec with TxOkCnt=%d, let CQI = 0\n", BEACON_LOST_TIME/HZ, TxOkCnt); + pAd->Mlme.ChannelQuality = 0; + // Lost AP, send disconnect & link down event + LinkDown(pAd); + } + } + else + { + // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) + pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * pAd->PortCfg.LastRssi + + TX_WEIGHTING * (100 - TxPRR) + + RX_WEIGHTING* (100 - RxPER)) / 100; + if (pAd->Mlme.ChannelQuality >= 100) + pAd->Mlme.ChannelQuality = 100; + } + + // latch current WLAN counters for next check-for-roaming usage + memcpy(&pAd->Mlme.PrevWlanCounters, &pAd->WlanCounters, sizeof(COUNTER_802_11)); + // make sure copy the real FCS counts into previous mlme counter structure. + pAd->Mlme.PrevWlanCounters.FCSErrorCount = pAd->RalinkCounters.RealFcsErrCount; + + DBGPRINT(RT_DEBUG_INFO, "MMCHK - CQI= %d, (Tx Fail=%d/Retry=%d/Total=%d, Rx Fail=%d/Total=%d, RSSI=%d dbm)\n", + pAd->Mlme.ChannelQuality, TxFailCnt, TxRetryCnt, TxCnt, RxFailCnt, RxCnt, pAd->PortCfg.LastRssi - pAd->PortCfg.RssiToDbm); + +} + +/* + ========================================================================== + Description: + This routine calculates the acumulated TxPER of eaxh TxRate. And + according to the calculation result, change PortCfg.TxRate which + is the stable TX Rate we expect the Radio situation could sustained. + + PortCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} + Output: + PortCfg.TxRate - + NOTE: + call this routine every second + ========================================================================== + */ +VOID MlmeCheckDynamicTxRateSwitching( + IN PRTMP_ADAPTER pAd) +{ + UCHAR UpRate, DownRate, CurrRate; + USHORT TxTotalCnt = pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount; + USHORT TxErrorRatio; + BOOLEAN fUpgradeQuality = FALSE; + USHORT *pRateUpPER, *pRateDownPER; + + pAd->DrsCounters.CurrTxRateStableTime ++; + CurrRate = pAd->PortCfg.TxRate; + do + { + if (pAd->PortCfg.EnableAutoRateSwitching == FALSE) + break; + + // if no traffic in the past 1-sec period, don't change TX rate, + // but clear all bad history. because the bad history may affect the next + // Chariot throughput test + if (TxTotalCnt == 0) + { + pAd->DrsCounters.TxRateUpPenalty = 0; + memset(pAd->DrsCounters.TxQuality, 0, MAX_LEN_OF_SUPPORTED_RATES); + memset(pAd->DrsCounters.PER, 0, MAX_LEN_OF_SUPPORTED_RATES); + break; + } + + // decide the next upgrade rate and downgrade rate, if any + if (pAd->PortCfg.PhyMode == PHY_11BG_MIXED) + { + UpRate = Phy11BGNextRateUpward[CurrRate]; + DownRate = Phy11BGNextRateDownward[CurrRate]; + } + else if (pAd->PortCfg.PhyMode == PHY_11B) + { + UpRate = Phy11BNextRateUpward[CurrRate]; + DownRate = Phy11BNextRateDownward[CurrRate]; + } + else if (pAd->PortCfg.PhyMode == PHY_11A) + { + UpRate = Phy11ANextRateUpward[CurrRate]; + DownRate = Phy11ANextRateDownward[CurrRate]; + } + else // PHY_11ABG_MIXED + { + if (pAd->PortCfg.Channel > 14) + { + UpRate = Phy11ANextRateUpward[CurrRate]; + DownRate = Phy11ANextRateDownward[CurrRate]; + } + else + { + UpRate = Phy11BGNextRateUpward[CurrRate]; + DownRate = Phy11BGNextRateDownward[CurrRate]; + } + } + + if (UpRate > pAd->PortCfg.MaxTxRate) + UpRate = pAd->PortCfg.MaxTxRate; + + // decide TX quality based on Tx PER when enough samples are available + if (TxTotalCnt > 15) + { + TxErrorRatio = ((pAd->DrsCounters.OneSecTxRetryOkCount + pAd->DrsCounters.OneSecTxFailCount) *100) / TxTotalCnt; + + // 2560D and after has implemented ASIC-based OFDM rate switching, + // but not 2560C & before. thus software use different PER for rate switching + if (pAd->PortCfg.Rt2560Version >= RT2560_VER_D) + { + pRateUpPER = &NewRateUpPER[0]; + pRateDownPER = &NewRateDownPER[0]; + } + else + { + pRateUpPER = &OldRateUpPER[0]; + pRateDownPER = &OldRateDownPER[0]; + } + + // downgrade TX quality if PER >= Rate-Down threshold + if (TxErrorRatio >= pRateDownPER[CurrRate]) + { + pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND; + } + // upgrade TX quality if PER <= Rate-Up threshold + else if (TxErrorRatio <= pRateUpPER[CurrRate]) + { + fUpgradeQuality = TRUE; + if (pAd->DrsCounters.TxQuality[CurrRate]) + pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate + + if (pAd->DrsCounters.TxRateUpPenalty) + pAd->DrsCounters.TxRateUpPenalty --; + else if (pAd->DrsCounters.TxQuality[UpRate]) + pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality + } + + } + + // if not enough TX samples, decide by heuristic rules + else + { + TxErrorRatio = 0; + + // Downgrade TX quality upon any TX failure in the past second + if (pAd->DrsCounters.OneSecTxFailCount) + { + if ((pAd->DrsCounters.OneSecTxFailCount <= 1) && + (pAd->DrsCounters.OneSecTxOkCount + pAd->DrsCounters.OneSecTxRetryOkCount)) + { + pAd->DrsCounters.TxQuality[CurrRate] += 2; // degrade quality + if (pAd->DrsCounters.TxQuality[CurrRate] > DRS_TX_QUALITY_WORST_BOUND) + pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND; + } + else // more than 2 failure, or no TX ok cases + { + pAd->DrsCounters.TxQuality[CurrRate] = DRS_TX_QUALITY_WORST_BOUND; + } + } + // upgrade TX quality if - + // 1. no TX failure but do have TX ok case, and + // 2. there's more one-time-ok cases than retry-ok cases in the past second + else if ((pAd->DrsCounters.OneSecTxOkCount > pAd->DrsCounters.OneSecTxRetryOkCount)) + { + fUpgradeQuality = TRUE; + if (pAd->DrsCounters.TxQuality[CurrRate]) + pAd->DrsCounters.TxQuality[CurrRate] --; // quality very good in CurrRate + + if (pAd->DrsCounters.TxRateUpPenalty) + pAd->DrsCounters.TxRateUpPenalty --; + else if (pAd->DrsCounters.TxQuality[UpRate]) + pAd->DrsCounters.TxQuality[UpRate] --; // may improve next UP rate's quality + } + } + + pAd->DrsCounters.PER[CurrRate] = (UCHAR)TxErrorRatio; + + if (pAd->DrsCounters.fNoisyEnvironment) + { + DBGPRINT(RT_DEBUG_TRACE,"DRS(noisy):"); + } + else + { + DBGPRINT(RT_DEBUG_TRACE,"DRS:"); + } + DBGPRINT(RT_DEBUG_TRACE, "Qty[%d]=%d PER=%d%% %d-sec, Qty[%d]=%d, Pty=%d\n", + RateIdToMbps[CurrRate], pAd->DrsCounters.TxQuality[CurrRate], + TxErrorRatio, + pAd->DrsCounters.CurrTxRateStableTime, + RateIdToMbps[UpRate], pAd->DrsCounters.TxQuality[UpRate], + pAd->DrsCounters.TxRateUpPenalty); + + // 2004-3-13 special case: Claim noisy environment + // decide if there was a false "rate down" in the past 2 sec due to noisy + // environment. if so, we would rather switch back to the higher TX rate. + // criteria - + // 1. there's a higher rate available, AND + // 2. there was a rate-down happened, AND + // 3. current rate has 75% > PER > 20%, AND + // 4. comparing to UpRate, current rate didn't improve PER more than 5 % + if ((UpRate != CurrRate) && + (pAd->DrsCounters.LastSecTxRateChangeAction == 2) && + (TxTotalCnt > 15) && // this line is to prevent the case that not enough TX sample causing PER=0% + (pAd->DrsCounters.PER[CurrRate] < 75) && + ((pAd->DrsCounters.PER[CurrRate] > 20) || (pAd->DrsCounters.fNoisyEnvironment)) && + ((pAd->DrsCounters.PER[CurrRate]+5) > pAd->DrsCounters.PER[UpRate])) + { + // we believe this is a noisy environment. better stay at UpRate + DBGPRINT(RT_DEBUG_TRACE,"DRS: #### enter Noisy environment ####\n"); + pAd->DrsCounters.fNoisyEnvironment = TRUE; + + // 2004-3-14 when claiming noisy environment, we're not only switch back + // to UpRate, but can be more aggressive to use one more rate up + UpRate++; +// if (UpRate>RATE_54) UpRate=RATE_54; + if ((UpRate==RATE_6) || (UpRate==RATE_9)) UpRate=RATE_12; + if (UpRate > pAd->PortCfg.MaxTxRate) + UpRate = pAd->PortCfg.MaxTxRate; + pAd->PortCfg.TxRate = UpRate; + break; + } + + // 2004-3-12 special case: Leave noisy environment + // The interference has gone suddenly. reset TX rate to + // the theoritical value according to RSSI. Criteria - + // 1. it's currently in noisy environment + // 2. PER drops to be below 12% + if ((pAd->DrsCounters.fNoisyEnvironment == TRUE) && + (TxTotalCnt > 15) && (pAd->DrsCounters.PER[CurrRate] <= 12)) + { + UCHAR JumpUpRate; + + pAd->DrsCounters.fNoisyEnvironment = FALSE; + for (JumpUpRate = RATE_54; JumpUpRate > RATE_1; JumpUpRate--) + { + if (pAd->PortCfg.AvgRssi > (RssiSafeLevelForTxRate[JumpUpRate] + pAd->PortCfg.RssiToDbm)) + + break; + } + + if (JumpUpRate > pAd->PortCfg.MaxTxRate) + JumpUpRate = pAd->PortCfg.MaxTxRate; + + DBGPRINT(RT_DEBUG_TRACE,"DRS: #### leave Noisy environment ####, RSSI=%d, JumpUpRate=%d\n", + + pAd->PortCfg.AvgRssi - RSSI_TO_DBM_OFFSET, RateIdToMbps[JumpUpRate]); + + + if (JumpUpRate > CurrRate) + { + pAd->PortCfg.TxRate = JumpUpRate; + break; + } + } + + // we're going to upgrade CurrRate to UpRate at next few seconds, + // but before that, we'd better try a NULL frame @ UpRate and + // see if UpRate is stable or not. If this NULL frame fails, it will + // downgrade TxQuality[CurrRate], so that STA won't switch to + // to UpRate in the next second + // 2004-04-07 requested by David Tung - sent test frames only in OFDM rates + if (fUpgradeQuality && + INFRA_ON(pAd) && + (UpRate != CurrRate) && + (UpRate > RATE_11) && + (pAd->DrsCounters.TxQuality[CurrRate] <= 1) && + (pAd->DrsCounters.TxQuality[UpRate] <= 1)) + { + DBGPRINT(RT_DEBUG_TRACE,"DRS: 2 NULL frames at UpRate = %d Mbps\n",RateIdToMbps[UpRate]); + EnqueueNullFrame(pAd, UpRate); + EnqueueNullFrame(pAd, UpRate); + } + + // perform DRS - consider TxRate Down first, then rate up. + // 1. rate down, if current TX rate's quality is not good + // 2. rate up, if UPRate's quality is very good + if ((pAd->DrsCounters.TxQuality[CurrRate] >= DRS_TX_QUALITY_WORST_BOUND) && + (CurrRate != DownRate)) + { +#ifdef WIFI_TEST + if (DownRate <= RATE_2) break; // never goes lower than 5.5 Mbps TX rate +#endif + pAd->PortCfg.TxRate = DownRate; + } + else if ((pAd->DrsCounters.TxQuality[CurrRate] <= 0) && + (pAd->DrsCounters.TxQuality[UpRate] <=0) && + (CurrRate != UpRate)) + { + pAd->PortCfg.TxRate = UpRate; + } + + }while (FALSE); + + + // if rate-up happen, clear all bad history of all TX rates + if (pAd->PortCfg.TxRate > CurrRate) + { + DBGPRINT(RT_DEBUG_TRACE,"DRS: ++TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]); + pAd->DrsCounters.CurrTxRateStableTime = 0; + pAd->DrsCounters.TxRateUpPenalty = 0; + pAd->DrsCounters.LastSecTxRateChangeAction = 1; // rate UP + memset(pAd->DrsCounters.TxQuality, 0, MAX_LEN_OF_SUPPORTED_RATES); + memset(pAd->DrsCounters.PER, 0, MAX_LEN_OF_SUPPORTED_RATES); + } + // if rate-down happen, only clear DownRate's bad history + else if (pAd->PortCfg.TxRate < CurrRate) + { + DBGPRINT(RT_DEBUG_TRACE,"DRS: --TX rate from %d to %d Mbps\n", RateIdToMbps[CurrRate],RateIdToMbps[pAd->PortCfg.TxRate]); + // shorter stable time require more penalty in next rate UP criteria + if (pAd->DrsCounters.CurrTxRateStableTime < 4) // less then 4 sec + pAd->DrsCounters.TxRateUpPenalty = DRS_PENALTY; // add 8 sec penalty + else if (pAd->DrsCounters.CurrTxRateStableTime < 8) // less then 8 sec + pAd->DrsCounters.TxRateUpPenalty = 2; // add 2 sec penalty + else // >= 8 sec + pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty + + pAd->DrsCounters.CurrTxRateStableTime = 0; + pAd->DrsCounters.LastSecTxRateChangeAction = 2; // rate DOWN + pAd->DrsCounters.TxQuality[pAd->PortCfg.TxRate] = 0; + pAd->DrsCounters.PER[pAd->PortCfg.TxRate] = 0; + } + else + pAd->DrsCounters.LastSecTxRateChangeAction = 0; // rate no change + + // reset all OneSecxxx counters + pAd->DrsCounters.OneSecTxFailCount = 0; + pAd->DrsCounters.OneSecTxOkCount = 0; + pAd->DrsCounters.OneSecTxRetryOkCount = 0; +} + +/* + ========================================================================== + Description: + This routine is executed periodically inside MlmePeriodicExec() after + association with an AP. + It checks if PortCfg.Psm is consistent with user policy (recorded in + PortCfg.WindowsPowerMode). If not, enforce user policy. However, + there're some conditions to consider: + 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all + the time when Mibss==TRUE + 2. When Massoc==TRUE (INFRA mode), Psm should not be switch to PWR_SAVE + if outgoing traffic available in TxRing or PrioRing. + Output: + 1. change pAd->PortCfg.Psm to PWR_SAVE or leave it untouched + ========================================================================== + */ +VOID MlmeCheckForPsmChange( + IN PRTMP_ADAPTER pAd, + IN ULONG Now32) +{ + ULONG PowerMode; + // condition - + // 1. Psm maybe ON only happen in INFRASTRUCTURE mode + // 2. user wants either MAX_PSP or FAST_PSP + // 3. but current psm is not in PWR_SAVE + // 4. CNTL state machine is not doing SCANning + // 5. no TX SUCCESS event for the past period + PowerMode = pAd->PortCfg.WindowsPowerMode; + + if (INFRA_ON(pAd) && + (PowerMode != Ndis802_11PowerModeCAM) && + (pAd->PortCfg.Psm == PWR_ACTIVE) && + (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && + (pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart == pAd->Mlme.PrevTxCnt)) + { + MlmeSetPsmBit(pAd, PWR_SAVE); + EnqueueNullFrame(pAd, pAd->PortCfg.TxRate); + } + + // latch current count for next-time comparison + pAd->Mlme.PrevTxCnt = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart; + +} + +VOID MlmeSetPsmBit( + IN PRTMP_ADAPTER pAd, + IN USHORT psm) +{ + TXCSR7_STRUC txcsr7; + + txcsr7.word = 0; + pAd->PortCfg.Psm = psm; + + DBGPRINT(RT_DEBUG_TRACE, "MMCHK - change PSM bit to %d <<<\n", psm); + if (psm == PWR_SAVE) + { + txcsr7.field.ARPowerManage = 1; + RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word); + } + else + { + txcsr7.field.ARPowerManage = 0; + RTMP_IO_WRITE32(pAd, TXCSR7, txcsr7.word); + } +} + +VOID MlmeSetTxPreamble( + IN PRTMP_ADAPTER pAd, + IN USHORT TxPreamble) +{ + ULONG Plcp1MCsr = 0x00700400; // 0x13c, ACK/CTS PLCP at 1 Mbps + ULONG Plcp2MCsr = 0x00380401; // 0x140, ACK/CTS PLCP at 2 Mbps + ULONG Plcp5MCsr = 0x00150402; // 0x144, ACK/CTS PLCP at 5.5 Mbps + ULONG Plcp11MCsr = 0x000b8403; // 0x148, ACK/CTS PLCP at 11 Mbps + + if (TxPreamble == Rt802_11PreambleShort) + { + DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= SHORT PREAMBLE)\n"); +// Plcp1MCsr |= 0x00000008; // 1Mbps should always use long preamble + Plcp2MCsr |= 0x00000008; + Plcp5MCsr |= 0x00000008; + Plcp11MCsr |= 0x00000008; + pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleShort; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "MlmeSetTxPreamble (= LONG PREAMBLE)\n"); + pAd->PortCfg.TxPreambleInUsed = Rt802_11PreambleLong; + } + + RTMP_IO_WRITE32(pAd, PLCP1MCSR, Plcp1MCsr); + RTMP_IO_WRITE32(pAd, PLCP2MCSR, Plcp2MCsr); + RTMP_IO_WRITE32(pAd, PLCP5MCSR, Plcp5MCsr); + RTMP_IO_WRITE32(pAd, PLCP11MCSR, Plcp11MCsr); +} + +VOID MlmeUpdateTxRates( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN bLinkUp) +{ + int i, num; + UCHAR Rate, MaxDesire = RATE_1, MaxSupport = RATE_1; + ULONG BasicRateBitmap = 0; + UCHAR CurrBasicRate = RATE_1; + + // find max desired rate + num = 0; + for (i=0; iPortCfg.DesiredRates[i] & 0x7f) + { + case 2: Rate = RATE_1; num++; break; + case 4: Rate = RATE_2; num++; break; + case 11: Rate = RATE_5_5; num++; break; + case 22: Rate = RATE_11; num++; break; + case 12: Rate = RATE_6; num++; break; + case 18: Rate = RATE_9; num++; break; + case 24: Rate = RATE_12; num++; break; + case 36: Rate = RATE_18; num++; break; + case 48: Rate = RATE_24; num++; break; + case 72: Rate = RATE_36; num++; break; + case 96: Rate = RATE_48; num++; break; + case 108: Rate = RATE_54; num++; break; + default: Rate = RATE_1; break; + } + if (MaxDesire < Rate) MaxDesire = Rate; + } + + // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode + if ((pAd->PortCfg.BssType == BSS_INDEP) && + (pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && + (pAd->PortCfg.AdhocMode == 0) && + (MaxDesire > RATE_11)) + MaxDesire = RATE_11; + + pAd->PortCfg.MaxDesiredRate = MaxDesire; + + // Auto rate switching is enabled only if more than one DESIRED RATES are + // specified; otherwise disabled + if (num <= 1) + pAd->PortCfg.EnableAutoRateSwitching = FALSE; + else + pAd->PortCfg.EnableAutoRateSwitching = TRUE; + + // find max supported rate + for (i=0; iPortCfg.SupportedRatesLen; i++) + { + switch (pAd->PortCfg.SupportedRates[i] & 0x7f) + { + case 2: Rate = RATE_1; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0001; + break; + case 4: Rate = RATE_2; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0002; + break; + case 11: + Rate = RATE_5_5; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0004; + break; + case 22: + Rate = RATE_11; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0008; + break; + case 12: + Rate = RATE_6; +// if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0010; + break; + case 18: + Rate = RATE_9; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0020; + break; + case 24: + Rate = RATE_12; +// if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0040; + break; + case 36: + Rate = RATE_18; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0080; + break; + case 48: + Rate = RATE_24; +// if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0100; + break; + case 72: + Rate = RATE_36; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0200; + break; + case 96: + Rate = RATE_48; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0400; + break; + case 108: + Rate = RATE_54; + if (pAd->PortCfg.SupportedRates[i] & 0x80) + BasicRateBitmap |= 0x0800; + break; + default: + Rate = RATE_1; + break; + } + if (MaxSupport < Rate) MaxSupport = Rate; + } + RTMP_IO_WRITE32(pAd, ARCSR1, BasicRateBitmap); + + // calculate the expected ACK rate for each TX rate. This info is used to caculate + // the DURATION field of outgoing unicast DATA/MGMT frame + for (i=0; iPortCfg.ExpectedACKRate[i] = CurrBasicRate; + DBGPRINT(RT_DEBUG_INFO,"Expected ACK rate[%d] = %d Mbps\n", RateIdToMbps[i], RateIdToMbps[CurrBasicRate]); + } + + // max tx rate = min {max desire rate, max supported rate} + if (MaxSupport < MaxDesire) + pAd->PortCfg.MaxTxRate = MaxSupport; + else + pAd->PortCfg.MaxTxRate = MaxDesire; + + // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success + // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending + // on average RSSI + // 1. RSSI >= -70db, start at 54 Mbps (short distance) + // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) + // 3. -75 > RSSI, start at 11 Mbps (long distance) + if (pAd->PortCfg.EnableAutoRateSwitching) + { + if (pAd->PortCfg.Channel > 14) + pAd->PortCfg.TxRate = RATE_6; // 802.11a + else + { + short dbm = pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm; + if (bLinkUp == TRUE && pAd->PortCfg.MaxTxRate >= RATE_24) + pAd->PortCfg.TxRate = RATE_24; + else + pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate; + if (dbm < -75) + pAd->PortCfg.TxRate = RATE_11; + else if ((dbm < -70) && (pAd->PortCfg.TxRate > RATE_24)) + pAd->PortCfg.TxRate = RATE_24; + DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (Rssi=%d, init TX rate = %d Mbps)\n", dbm, RateIdToMbps[pAd->PortCfg.TxRate]); + } + } + else + pAd->PortCfg.TxRate = pAd->PortCfg.MaxTxRate; + + switch (pAd->PortCfg.PhyMode) { + case PHY_11BG_MIXED: + case PHY_11B: + pAd->PortCfg.MlmeRate = RATE_2; +#ifdef WIFI_TEST + pAd->PortCfg.RtsRate = RATE_11; +#else + pAd->PortCfg.RtsRate = RATE_2; +#endif + break; + case PHY_11A: + pAd->PortCfg.MlmeRate = RATE_6; + pAd->PortCfg.RtsRate = RATE_6; + break; + case PHY_11ABG_MIXED: + if (pAd->PortCfg.Channel <= 14) + { + pAd->PortCfg.MlmeRate = RATE_2; + pAd->PortCfg.RtsRate = RATE_2; + } + else + { + pAd->PortCfg.MlmeRate = RATE_6; + pAd->PortCfg.RtsRate = RATE_6; + } + break; + default: // error + pAd->PortCfg.MlmeRate = RATE_2; + pAd->PortCfg.RtsRate = RATE_2; + break; + } + + DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, Rate Switching =%d)\n", + RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->PortCfg.MaxTxRate], pAd->PortCfg.EnableAutoRateSwitching); + DBGPRINT(RT_DEBUG_TRACE, " MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04x)\n", + RateIdToMbps[pAd->PortCfg.TxRate], RateIdToMbps[pAd->PortCfg.RtsRate], BasicRateBitmap); +} + +VOID MlmeRadioOff( + IN PRTMP_ADAPTER pAd) +{ + // Set Radio off flag + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); + + // Link down first if any association exists + if (INFRA_ON(pAd) || ADHOC_ON(pAd)) + LinkDown(pAd); + + // Abort Tx + RTMP_IO_WRITE32(pAd, TXCSR0, 0x08); + // Disable Rx + RTMP_IO_WRITE32(pAd, RXCSR0, 0x01); + // Turn off radio + RTMP_IO_WRITE32(pAd, PWRCSR0, 0x00000000); + + if (pAd->PortCfg.LedMode == LED_MODE_ASUS) + { + ASIC_LED_ACT_OFF(pAd); + } + + // Clean up old bss table + BssTableInit(&pAd->PortCfg.BssTab); +} + +VOID MlmeRadioOn( + IN PRTMP_ADAPTER pAd) +{ + // Turn on radio + RTMP_IO_WRITE32(pAd, PWRCSR0, 0x3f3b3100); + + // Abort Tx + RTMP_IO_WRITE32(pAd, TXCSR0, 0x08); + // Disable Rx + RTMP_IO_WRITE32(pAd, RXCSR0, 0x01); + + RTMPRingCleanUp(pAd, TX_RING); + RTMPRingCleanUp(pAd, PRIO_RING); + RTMPRingCleanUp(pAd, RX_RING); + + NICResetFromError(pAd); + // Clear Radio off flag + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); + + if (pAd->PortCfg.LedMode == LED_MODE_ASUS) + { + RTMP_IO_WRITE32(pAd, LEDCSR, 0x0002461E); + } +} + +// =========================================================================================== +// bss_table.c +// =========================================================================================== + + +/*! \brief initialize BSS table + * \param p_tab pointer to the table + * \return none + * \pre + * \post + */ +VOID BssTableInit( + IN BSS_TABLE *Tab) +{ + int i; + + Tab->BssNr = 0; + for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) + { + memset(&Tab->BssEntry[i], 0, sizeof(BSS_ENTRY)); + } +} + +/*! \brief search the BSS table by SSID + * \param p_tab pointer to the bss table + * \param ssid SSID string + * \return index of the table, BSS_NOT_FOUND if not in the table + * \pre + * \post + * \note search by sequential search + */ +ULONG BssTableSearch( + IN BSS_TABLE *Tab, + IN PMACADDR Bssid) +{ + UCHAR i; + + for (i = 0; i < Tab->BssNr; i++) + { + //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid); + if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid)) + { + return i; + } + } + return (ULONG)BSS_NOT_FOUND; +} + +VOID BssTableDeleteEntry( + IN OUT BSS_TABLE *Tab, + IN PMACADDR Bssid) +{ + UCHAR i, j; + + for (i = 0; i < Tab->BssNr; i++) + { + //printf("comparing %s and %s\n", p_tab->bss[i].ssid, ssid); + if (MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid)) + { + for (j = i; j < Tab->BssNr - 1; j++) + { + memcpy(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); + } + Tab->BssNr -= 1; + return; + } + } +} + +UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; +/*! \brief + * \param + * \return + * \pre + * \post + */ +VOID BssEntrySet( + IN PRTMP_ADAPTER pAd, + OUT BSS_ENTRY *pBss, + IN MACADDR *pBssid, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN USHORT BeaconPeriod, + IN BOOLEAN CfExist, + IN CF_PARM *pCfParm, + IN USHORT AtimWin, + IN USHORT CapabilityInfo, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist, + IN UCHAR Channel, + IN UCHAR Rssi, + IN UCHAR Noise, + IN LARGE_INTEGER TimeStamp, + IN PNDIS_802_11_VARIABLE_IEs pVIE) +{ + COPY_MAC_ADDR(&pBss->Bssid, pBssid); + // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID + pBss->Hidden = 1; + if (SsidLen > 0) + { + // For hidden SSID AP, it might send beacon with SSID len equal to 0 + // Or send beacon /probe response with SSID len matching real SSID length, + // but SSID is all zero. such as "00-00-00-00" with length 4. + // We have to prevent this case overwrite correct table + if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) + { + memcpy(pBss->Ssid, Ssid, SsidLen); + pBss->SsidLen = SsidLen; + pBss->Hidden = 0; + } + } + pBss->BssType = BssType; + pBss->BeaconPeriod = BeaconPeriod; + if (BssType == BSS_INFRA) + { + if (CfExist) + { + pBss->CfpCount = pCfParm->CfpCount; + pBss->CfpPeriod = pCfParm->CfpPeriod; + pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; + pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; + } + } + else + { + pBss->AtimWin = AtimWin; + } + + pBss->CapabilityInfo = CapabilityInfo; + // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES + // Combine with AuthMode, they will decide the connection methods. + pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); + memcpy(pBss->Rates, Rates, RatesLen); + pBss->RatesLen = RatesLen; + pBss->ExtendedRateIeExist = ExtendedRateIeExist; + pBss->Channel = Channel; + pBss->Rssi = Rssi; + pBss->Noise = Noise; + + // New for microsoft Fixed IEs + memcpy(pBss->FixIEs.Timestamp, &TimeStamp, 8); + pBss->FixIEs.BeaconInterval = BeaconPeriod; + pBss->FixIEs.Capabilities = CapabilityInfo; + + // New for microsoft Variable IEs + if (pVIE->Length != 0) + { + pBss->VarIELen = pVIE->Length + 2; + memcpy(pBss->VarIEs, pVIE, pBss->VarIELen); + pBss->WepStatus = BssCipherParse(pBss->VarIEs); + } + else + { + pBss->VarIELen = 0; + // No SSN ID, if security is on, this is WEP algorithm + if (pBss->Privacy) + pBss->WepStatus = Ndis802_11WEPEnabled; + // No SSN ID, security is also off. + else + pBss->WepStatus = Ndis802_11WEPDisabled; + } +} + +/*! + * \brief insert an entry into the bss table + * \param p_tab The BSS table + * \param Bssid BSSID + * \param ssid SSID + * \param ssid_len Length of SSID + * \param bss_type + * \param beacon_period + * \param timestamp + * \param p_cf + * \param atim_win + * \param cap + * \param rates + * \param rates_len + * \param channel_idx + * \return none + * \pre + * \post + * \note If SSID is identical, the old entry will be replaced by the new one + */ +ULONG BssTableSetEntry( + IN PRTMP_ADAPTER pAd, + OUT BSS_TABLE *Tab, + IN MACADDR *Bssid, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN USHORT BeaconPeriod, + IN BOOLEAN CfExist, + IN CF_PARM *CfParm, + IN USHORT AtimWin, + IN USHORT CapabilityInfo, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist, + IN UCHAR ChannelNo, + IN UCHAR Rssi, + IN UCHAR Noise, + IN LARGE_INTEGER TimeStamp, + IN PNDIS_802_11_VARIABLE_IEs pVIE) +{ + ULONG Idx; + Idx = BssTableSearch(Tab, Bssid); + if (Idx == BSS_NOT_FOUND) + { + if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) + return BSS_NOT_FOUND; + + Idx = Tab->BssNr; + BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod, + CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist, + ChannelNo, Rssi, Noise, TimeStamp, pVIE); + Tab->BssNr++; + } + else + { + BssEntrySet(pAd, &Tab->BssEntry[Idx], Bssid, Ssid, SsidLen, BssType, BeaconPeriod, + CfExist, CfParm, AtimWin, CapabilityInfo, Rates, RatesLen, ExtendedRateIeExist, + ChannelNo, Rssi, Noise, TimeStamp, pVIE); + } + + return Idx; +} + +VOID BssTableSsidSort( + IN PRTMP_ADAPTER pAd, + OUT BSS_TABLE *OutTab, + IN CHAR Ssid[], + IN UCHAR SsidLen) +{ + INT i; + BssTableInit(OutTab); + + for (i = 0; i < pAd->PortCfg.BssTab.BssNr; i++) + { + BSS_ENTRY *pInBss = &pAd->PortCfg.BssTab.BssEntry[i]; + + if ((pInBss->BssType == pAd->PortCfg.BssType) && + ((pInBss->SsidLen==SsidLen) && RTMPEqualMemory(pInBss->Ssid, Ssid, (ULONG) SsidLen))) + { + BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; + + // Bss Type matched, SSID matched. + // We will check wepstatus for qualification Bss + if (pAd->PortCfg.WepStatus != pInBss->WepStatus) + continue; + + // Since the AP is using hidden SSID, and we are trying to connect to ANY + // It definitely will fail. So, skip it. + // CCX also require not even try to connect it!! + if (SsidLen == 0) + continue; + + // copy matching BSS from InTab to OutTab + memcpy(pOutBss, pInBss, sizeof(BSS_ENTRY)); + + OutTab->BssNr++; + } + else if ((pInBss->BssType == pAd->PortCfg.BssType) && (SsidLen == 0)) + { + BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; + + // Bss Type matched, SSID matched. + // We will check wepstatus for qualification Bss + if (pAd->PortCfg.WepStatus != pInBss->WepStatus) + continue; + + // copy matching BSS from InTab to OutTab + memcpy(pOutBss, pInBss, sizeof(BSS_ENTRY)); + + OutTab->BssNr++; + } +#if 0 + else if ((pInBss->BssType == pAd->PortCfg.BssType) && (pInBss->SsidLen == 0)) + { + // Add for hidden SSID. But we have to verify the security suite too. + BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; + + // Bss Type matched, SSID matched. + // We will check wepstatus for qualification Bss + if (pAd->PortCfg.WepStatus != pInBss->WepStatus) + continue; + + // copy matching BSS from InTab to OutTab + memcpy(pOutBss, pInBss, sizeof(BSS_ENTRY)); + + OutTab->BssNr++; + } +#endif + if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) + break; + + } + + BssTableSortByRssi(OutTab); +} + +VOID BssTableSortByRssi( + IN OUT BSS_TABLE *OutTab) +{ + INT i, j; + BSS_ENTRY TmpBss; + + for (i = 0; i < OutTab->BssNr - 1; i++) + { + for (j = i+1; j < OutTab->BssNr; j++) + { + if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) + { + memcpy(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); + memcpy(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); + memcpy(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); + } + } + } +} + +NDIS_802_11_WEP_STATUS BssCipherParse( + IN PUCHAR pCipher) +{ + PBEACON_EID_STRUCT pEid; + PUCHAR pTmp; + + pEid = (PBEACON_EID_STRUCT) pCipher; + + // Double check sanity information, although it should be done at peer beacon sanity check already. + if (pEid->Eid != IE_WPA) + return (Ndis802_11WEPDisabled); + + // Double check Var IE length, it must be no less than 0x16 + if (pEid->Len < 0x16) + return (Ndis802_11WEPDisabled); + + // Skip OUI, version, and multicast suite + // This part should be improved in the future when AP supported multiple cipher suite. + // For now, it's OK since almost all APs have fixed cipher suite supported. + pTmp = (PUCHAR) pEid->Octet; + pTmp += 9; + + if (*pTmp == 4) // AES + return (Ndis802_11Encryption3Enabled); + else if (*pTmp == 2) // TKIP + return (Ndis802_11Encryption2Enabled); + + return (Ndis802_11WEPDisabled); +} + +// =========================================================================================== +// mac_table.c +// =========================================================================================== + +/*! \brief generates a random mac address value for IBSS BSSID + * \param Addr the bssid location + * \return none + * \pre + * \post + */ +VOID MacAddrRandomBssid( + IN PRTMP_ADAPTER pAd, + OUT MACADDR *Addr) +{ + INT i; + + for (i = 0; i < ETH_ALEN; i++) + { + Addr->Octet[i] = RandomByte(pAd); + } + + Addr->Octet[0] = (Addr->Octet[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx +} + +/*! \brief init the management mac frame header + * \param p_hdr mac header + * \param subtype subtype of the frame + * \param p_ds destination address, don't care if it is a broadcast address + * \return none + * \pre the station has the following information in the pAd->PortCfg + * - bssid + * - station address + * \post + * \note this function initializes the following field + */ +VOID MgtMacHeaderInit( + IN PRTMP_ADAPTER pAd, + IN OUT PMACHDR Hdr, + IN UCHAR Subtype, + IN UCHAR ToDs, + IN PMACADDR Ds, + IN PMACADDR Bssid) +{ + memset(Hdr, 0, sizeof(MACHDR)); + Hdr->Type = BTYPE_MGMT; + Hdr->SubType = Subtype; + Hdr->Tods = ToDs; + COPY_MAC_ADDR(&Hdr->Addr1, Ds); + COPY_MAC_ADDR(&Hdr->Addr2, &pAd->CurrentAddress); + COPY_MAC_ADDR(&Hdr->Addr3, Bssid); +} + +// =========================================================================================== +// mem_mgmt.c +// =========================================================================================== + +/*!*************************************************************************** + * This routine build an outgoing frame, and fill all information specified + * in argument list to the frame body. The actual frame size is the summation + * of all arguments. + * input params: + * Buffer - pointer to a pre-allocated memory segment + * args - a list of pairs. + * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this + * function will FAIL!!! + * return: + * Size of the buffer + * usage: + * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); + ****************************************************************************/ +ULONG MakeOutgoingFrame( + OUT CHAR *Buffer, + OUT ULONG *FrameLen, ...) +{ + CHAR *p; + int leng; + ULONG TotLeng; + va_list Args; + + // calculates the total length + TotLeng = 0; + va_start(Args, FrameLen); + do + { + leng = va_arg(Args, int); + if (leng == END_OF_ARGS) + { + break; + } + p = va_arg(Args, PVOID); + memcpy(&Buffer[TotLeng], p, leng); + TotLeng = TotLeng + leng; + } while(TRUE); + + va_end(Args); /* clean up */ + *FrameLen = TotLeng; + return TotLeng; +} + +// =========================================================================================== +// mlme_queue.c +// =========================================================================================== + +/*! \brief Initialize The MLME Queue, used by MLME Functions + * \param *Queue The MLME Queue + * \return Always Return NDIS_STATE_SUCCESS in this implementation + * \pre + * \post + * \note Because this is done only once (at the init stage), no need to be locked + */ +NDIS_STATUS MlmeQueueInit( + IN MLME_QUEUE *Queue) +{ + INT i; + + spin_lock_init(&Queue->Lock); + + Queue->Num = 0; + Queue->Head = 0; + Queue->Tail = 0; + + for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) + { + Queue->Entry[i].Occupied = FALSE; + Queue->Entry[i].MsgLen = 0; + memset(Queue->Entry[i].Msg, 0, MAX_LEN_OF_MLME_BUFFER); + } + + return NDIS_STATUS_SUCCESS; +} + + +/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread + * \param *Queue The MLME Queue + * \param Machine The State Machine Id + * \param MsgType The Message Type + * \param MsgLen The Message length + * \param *Msg The message pointer + * \return TRUE if enqueue is successful, FALSE if the queue is full + * \pre + * \post + * \note The message has to be initialized + */ +BOOLEAN MlmeEnqueue( + OUT MLME_QUEUE *Queue, + IN ULONG Machine, + IN ULONG MsgType, + IN ULONG MsgLen, + IN VOID *Msg) +{ + INT Tail; + unsigned long flags; + // First check the size, it MUST not exceed the mlme queue size + if (MsgLen > MAX_LEN_OF_MLME_BUFFER) + { + DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen); + return FALSE; + } + + spin_lock_irqsave(&(Queue->Lock), flags); + if (MlmeQueueFull(Queue)) + { + printk(KERN_ERR DRV_NAME "MlmeEnqueue full, msg dropped and may corrupt MLME\n"); + spin_unlock_irqrestore(&(Queue->Lock), flags); + return FALSE; + } + + Tail = Queue->Tail; + Queue->Tail++; + Queue->Num++; + if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) + { + Queue->Tail = 0; + } + DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueue, num=%d\n",Queue->Num); + + Queue->Entry[Tail].Occupied = TRUE; + Queue->Entry[Tail].Machine = Machine; + Queue->Entry[Tail].MsgType = MsgType; + Queue->Entry[Tail].MsgLen = MsgLen; + memcpy(Queue->Entry[Tail].Msg, Msg, MsgLen); + spin_unlock_irqrestore(&(Queue->Lock), flags); + return TRUE; +} + +/*! \brief This function is used when Recv gets a MLME message + * \param *Queue The MLME Queue + * \param TimeStampHigh The upper 32 bit of timestamp + * \param TimeStampLow The lower 32 bit of timestamp + * \param Rssi The receiving RSSI strength + * \param MsgLen The length of the message + * \param *Msg The message pointer + * \return TRUE if everything ok, FALSE otherwise (like Queue Full) + * \pre + * \post + */ +BOOLEAN MlmeEnqueueForRecv( + IN PRTMP_ADAPTER pAd, + OUT MLME_QUEUE *Queue, + IN ULONG TimeStampHigh, + IN ULONG TimeStampLow, + IN UCHAR Rssi, + IN UCHAR Noise, + IN ULONG MsgLen, + IN VOID *Msg) +{ + INT Tail, Machine; + MACFRAME *Fr = (MACFRAME *)Msg; + ULONG MsgType; + unsigned long flags; + + // First check the size, it MUST not exceed the mlme queue size + if (MsgLen > MAX_LEN_OF_MLME_BUFFER) + { + DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv mlme frame too large, size = %d \n", MsgLen); + return FALSE; + } + + + if (!MsgTypeSubst(Fr, &Machine, &MsgType)) + { + DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (drop mgmt->subtype=%d)\n",Fr->Hdr.SubType); + return FALSE; + } + + spin_lock_irqsave(&(Queue->Lock), flags); + if (MlmeQueueFull(Queue)) + { + DBGPRINT(RT_DEBUG_ERROR, "MlmeEnqueueForRecv (queue full error) \n"); + spin_unlock_irqrestore(&(Queue->Lock), flags); + return FALSE; + } + + // OK, we got all the informations, it is time to put things into queue + Tail = Queue->Tail; + Queue->Tail++; + Queue->Num++; + if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) + { + Queue->Tail = 0; + } + + DBGPRINT(RT_DEBUG_INFO, "MlmeEnqueueForRecv, num=%d\n",Queue->Num); + + Queue->Entry[Tail].Occupied = TRUE; + Queue->Entry[Tail].Machine = Machine; + Queue->Entry[Tail].MsgType = MsgType; + Queue->Entry[Tail].MsgLen = MsgLen; + Queue->Entry[Tail].TimeStamp.vv.LowPart = TimeStampLow; + Queue->Entry[Tail].TimeStamp.vv.HighPart = TimeStampHigh; + Queue->Entry[Tail].Rssi = Rssi; + Queue->Entry[Tail].Noise = (Noise > BBP_R17_DYNAMIC_UP_BOUND) ? BBP_R17_DYNAMIC_UP_BOUND : ((ULONG) Noise); + memcpy(Queue->Entry[Tail].Msg, Msg, MsgLen); + spin_unlock_irqrestore(&(Queue->Lock), flags); + + MlmeHandler(pAd); + + return TRUE; +} + +/*! \brief Dequeue a message from the MLME Queue + * \param *Queue The MLME Queue + * \param *Elem The message dequeued from MLME Queue + * \return TRUE if the Elem contains something, FALSE otherwise + * \pre + * \post + */ +BOOLEAN MlmeDequeue( + IN MLME_QUEUE *Queue, + OUT MLME_QUEUE_ELEM **Elem) +{ + unsigned long flags; + spin_lock_irqsave(&(Queue->Lock), flags); + if (Queue->Num == 0) { + spin_unlock_irqrestore(&(Queue->Lock),flags); + return FALSE; + } + *Elem = &(Queue->Entry[Queue->Head]); + Queue->Num--; + Queue->Head++; + if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) + { + Queue->Head = 0; + } + spin_unlock_irqrestore(&(Queue->Lock), flags); + DBGPRINT(RT_DEBUG_INFO, "MlmeDequeue, num=%d\n",Queue->Num); + + return TRUE; +} + +VOID MlmeRestartStateMachine( + IN PRTMP_ADAPTER pAd) +{ + MLME_QUEUE_ELEM *Elem = NULL; + unsigned long flags; + + if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_INITIALIZED)){ + DBGPRINT(RT_DEBUG_INFO, "MLME not yet initialized...\n"); + if(MlmeInit(pAd)) + DBGPRINT(RT_DEBUG_ERROR, "Failure to initialize mlme.\n"); + // Continue the reset procedure... + } + + spin_lock_irqsave(&pAd->Mlme.TaskLock, flags); + if(pAd->Mlme.Running) + { + spin_unlock_irqrestore(&pAd->Mlme.TaskLock, flags); + return; + } + else + { + pAd->Mlme.Running = TRUE; + } + spin_unlock_irqrestore(&pAd->Mlme.TaskLock, flags); + + // Remove all Mlme queues elements + while (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) + { + //From message type, determine which state machine I should drive + + // free MLME element + Elem->Occupied = FALSE; + Elem->MsgLen = 0; + + } + + // Cancel all timer events + // Be careful to cancel new added timer + RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer); + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer); + + // Change back to original channel in case of doing scan + AsicSwitchChannel(pAd, pAd->PortCfg.Channel); + AsicLockChannel(pAd, pAd->PortCfg.Channel); + + // Resume MSDU which is turned off durning scan + RTMPResumeMsduTransmission(pAd); + + // Set all state machines back IDLE + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; + pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; + pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + + // Remove running state + spin_lock_irqsave(&pAd->Mlme.TaskLock, flags); + pAd->Mlme.Running = FALSE; + spin_unlock_irqrestore(&pAd->Mlme.TaskLock, flags); +} + +/*! \brief test if the MLME Queue is empty + * \param *Queue The MLME Queue + * \return TRUE if the Queue is empty, FALSE otherwise + * \pre + * \post + */ +BOOLEAN MlmeQueueEmpty( + IN MLME_QUEUE *Queue) +{ + BOOLEAN Ans; + + Ans = (Queue->Num == 0); + + return Ans; +} + +/*! \brief test if the MLME Queue is full + * \param *Queue The MLME Queue + * \return TRUE if the Queue is empty, FALSE otherwise + * \pre + * \post + */ +BOOLEAN MlmeQueueFull( + IN MLME_QUEUE *Queue) +{ + BOOLEAN Ans; + + Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE); + + return Ans; +} + +/*! \brief The destructor of MLME Queue + * \param + * \return + * \pre + * \post + * \note Clear Mlme Queue, Set Queue->Num to Zero. + */ +VOID MlmeQueueDestroy( + IN MLME_QUEUE *Queue) +{ + unsigned long flags; + spin_lock_irqsave(&(Queue->Lock), flags); + Queue->Num = 0; + Queue->Head = 0; + Queue->Tail = 0; + spin_unlock_irqrestore(&(Queue->Lock), flags); +} + +/*! \brief To substitute the message type if the message is coming from external + * \param *Fr The frame received + * \param *Machine The state machine + * \param *MsgType the message type for the state machine + * \return TRUE if the substitution is successful, FALSE otherwise + * \pre + * \post + */ +BOOLEAN MsgTypeSubst( + IN MACFRAME *Fr, + OUT INT *Machine, + OUT INT *MsgType) +{ + USHORT Seq; + UCHAR EAPType; + + // The only data type will pass to this function is EAPOL frame + if (Fr->Hdr.Type == BTYPE_DATA) + { + *Machine = WPA_PSK_STATE_MACHINE; + EAPType = *((UCHAR*)Fr + LENGTH_802_11 + LENGTH_802_1_H + 1); + return(WpaMsgTypeSubst(EAPType, MsgType)); + } + + switch (Fr->Hdr.SubType) + { + case SUBTYPE_ASSOC_REQ: + *Machine = ASSOC_STATE_MACHINE; + *MsgType = MT2_PEER_ASSOC_REQ; + break; + case SUBTYPE_ASSOC_RSP: + *Machine = ASSOC_STATE_MACHINE; + *MsgType = MT2_PEER_ASSOC_RSP; + break; + case SUBTYPE_REASSOC_REQ: + *Machine = ASSOC_STATE_MACHINE; + *MsgType = MT2_PEER_REASSOC_REQ; + break; + case SUBTYPE_REASSOC_RSP: + *Machine = ASSOC_STATE_MACHINE; + *MsgType = MT2_PEER_REASSOC_RSP; + break; + case SUBTYPE_PROBE_REQ: + *Machine = SYNC_STATE_MACHINE; + *MsgType = MT2_PEER_PROBE_REQ; + break; + case SUBTYPE_PROBE_RSP: + *Machine = SYNC_STATE_MACHINE; + *MsgType = MT2_PEER_PROBE_RSP; + break; + case SUBTYPE_BEACON: + *Machine = SYNC_STATE_MACHINE; + *MsgType = MT2_PEER_BEACON; + break; + case SUBTYPE_ATIM: + *Machine = SYNC_STATE_MACHINE; + *MsgType = MT2_PEER_ATIM; + break; + case SUBTYPE_DISASSOC: + *Machine = ASSOC_STATE_MACHINE; + *MsgType = MT2_PEER_DISASSOC_REQ; + break; + case SUBTYPE_AUTH: + // get the sequence number from payload 24 Mac Header + 2 bytes algorithm + memcpy(&Seq, &Fr->Octet[2], sizeof(USHORT)); + if (Seq == 1 || Seq == 3) + { + *Machine = AUTH_RSP_STATE_MACHINE; + *MsgType = MT2_PEER_AUTH_ODD; + } + else if (Seq == 2 || Seq == 4) + { + *Machine = AUTH_STATE_MACHINE; + *MsgType = MT2_PEER_AUTH_EVEN; + } + else + { + return FALSE; + } + break; + case SUBTYPE_DEAUTH: + *Machine = AUTH_RSP_STATE_MACHINE; + *MsgType = MT2_PEER_DEAUTH; + break; + default: + return FALSE; + break; + } + + return TRUE; +} + +// =========================================================================================== +// state_machine.c +// =========================================================================================== + +/*! \brief Initialize the state machine. + * \param *S pointer to the state machine + * \param Trans State machine transition function + * \param StNr number of states + * \param MsgNr number of messages + * \param DefFunc default function, when there is invalid state/message combination + * \param InitState initial state of the state machine + * \param Base StateMachine base, internal use only + * \pre p_sm should be a legal pointer + * \post + */ + +VOID StateMachineInit( + IN STATE_MACHINE *S, + IN STATE_MACHINE_FUNC Trans[], + IN ULONG StNr, + IN ULONG MsgNr, + IN STATE_MACHINE_FUNC DefFunc, + IN ULONG InitState, + IN ULONG Base) +{ + ULONG i, j; + + // set number of states and messages + S->NrState = StNr; + S->NrMsg = MsgNr; + S->Base = Base; + + S->TransFunc = Trans; + + // init all state transition to default function + for (i = 0; i < StNr; i++) + { + for (j = 0; j < MsgNr; j++) + { + S->TransFunc[i * MsgNr + j] = DefFunc; + } + } + + // set the starting state + S->CurrState = InitState; + +} + +/*! \brief This function fills in the function pointer into the cell in the state machine + * \param *S pointer to the state machine + * \param St state + * \param Msg incoming message + * \param f the function to be executed when (state, message) combination occurs at the state machine + * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state + * \post + */ +VOID StateMachineSetAction( + IN STATE_MACHINE *S, + IN ULONG St, + IN ULONG Msg, + IN STATE_MACHINE_FUNC Func) +{ + ULONG MsgIdx; + + MsgIdx = Msg - S->Base; + + if (St < S->NrState && MsgIdx < S->NrMsg) + { + // boundary checking before setting the action + S->TransFunc[St * S->NrMsg + MsgIdx] = Func; + } +} + +/*! \brief The destructor of the state machine + * \param *S the statemachine + * \note doing nothing at this moment, may need to do something if the implementation changed + */ +VOID +StateMachineDestroy(IN STATE_MACHINE *S) +{ +} + +/*! \brief This function does the state transition + * \param *Adapter the NIC adapter pointer + * \param *S the state machine + * \param *Elem the message to be executed + * \return None + */ +VOID StateMachinePerformAction( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + IN MLME_QUEUE_ELEM *Elem) +{ + (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); +} + +/* + ========================================================================== + Description: + The drop function, when machine executes this, the message is simply + ignored. This function does nothing, the message is freed in + StateMachinePerformAction() + ========================================================================== + */ +VOID Drop( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ +#if 0 + if ((Elem->MsgType == MT2_PEER_BEACON) || + (Elem->MsgType == MT2_PEER_PROBE_REQ) || + (Elem->MsgType == MT2_PEER_PROBE_RSP)) + ; + else + { + DBGPRINT(RT_DEBUG_TRACE, ("Warn:>>Drop Msg=%d<<\n",Elem->MsgType)); + } +#endif +} + +// =========================================================================================== +// lfsr.c +// =========================================================================================== + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID LfsrInit( + IN PRTMP_ADAPTER pAd, + IN ULONG Seed) +{ + if (Seed == 0) + pAd->Mlme.ShiftReg = 1; + else + pAd->Mlme.ShiftReg = Seed; +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +UCHAR RandomByte( + IN PRTMP_ADAPTER pAd) +{ + ULONG i; + UCHAR R, Result; + + R = 0; + + for (i = 0; i < 8; i++) + { + if (pAd->Mlme.ShiftReg & 0x00000001) + { + pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; + Result = 1; + } + else + { + pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; + Result = 0; + } + R = (R << 1) | Result; + } + + return R; +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AsicSwitchChannel( + IN PRTMP_ADAPTER pAd, + IN UCHAR Channel) +{ + ULONG R3; + UCHAR index; + int Value; + + // TODO: need to update E2PROM format to add 802.11a channel's TX power calibration values + if (Channel <= 14) + R3 = pAd->PortCfg.ChannelTxPower[Channel - 1]; + else + R3 = pAd->PortCfg.ChannelTxPower[0]; + + if (R3 > 31) R3 = 31; + + // E2PROM setting is calibrated for maximum TX power (i.e. 100%) + // We adjust TX power here according to the dBm specified from UI + // Krellan: Arbitrarily defining the recommended EEPROM value as 0 dBm, + // using signed number to get the dBm math right. + // Even if user has selected automatic TxPower level adjustment, + // driver starts the user's fixed settings as a base to adjust from. + Value = R3 + pAd->PortCfg.TxPowerUser; + Value = (Value > 31) ? 31 : Value; + Value = (Value < 0) ? 0 : Value; + R3 = Value; + + // Krellan: Save value for readout to user + pAd->PortCfg.TxPowerDriver = R3; + + R3 = R3 << 9; // shift TX power control to correct RF R3 bit position + + switch (pAd->PortCfg.RfType) + { + case RFIC_2522: + for (index = 0; index < NUM_OF_2522_CHNL; index++) + { + if (Channel == RF2522RegTable[index].Channel) + { + R3 = R3 | RF2522RegTable[index].R3; // set TX power + RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2522RegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF2522RegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF2522RegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF2522RegTable[index].R4; + break; + } + } + break; + + case RFIC_2523: + for (index = 0; index < NUM_OF_2523_CHNL; index++) + { + if (Channel == RF2523RegTable[index].Channel) + { + R3 = R3 | RF2523RegTable[index].R3; // set TX power + RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF2523RegTable[index].R4); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF2523RegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF2523RegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF2523RegTable[index].R4; + break; + } + } + break; + + case RFIC_2524: + for (index = 0; index < NUM_OF_2524_CHNL; index++) + { + if (Channel == RF2524RegTable[index].Channel) + { + R3 = R3 | RF2524RegTable[index].R3; // set TX power + RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF2524RegTable[index].R4); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF2524RegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF2524RegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF2524RegTable[index].R4; + break; + } + } + break; + + case RFIC_2525: + for (index = 0; index < NUM_OF_2525_CHNL; index++) + { + if (Channel == RF2525RegTable[index].Channel) + { + // Tx power should based on the real channel value + R3 = R3 | RF2525RegTable[index].R3; // set TX power + // Set the channel to half band higher - 8 channels + // The addition is based on Gary and Sheng's request + RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF2525HBOffsetRegTable[index].R4); + // Chnage to teh connect channel + RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF2525RegTable[index].R4); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF2525RegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF2525RegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF2525RegTable[index].R4; + break; + } + } + break; + + case RFIC_2525E: + for (index = 0; index < NUM_OF_2525E_CHNL; index++) + { + if (Channel == RF2525eRegTable[index].Channel) + { + R3 = R3 | RF2525eRegTable[index].R3; // set TX power + RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF2525eRegTable[index].R4); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF2525eRegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF2525eRegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF2525eRegTable[index].R4; + break; + } + } + break; + + case RFIC_5222: + for (index = 0; index < NUM_OF_5222_CHNL; index++) + { + if (Channel == RF5222RegTable[index].Channel) + { + R3 = R3 | RF5222RegTable[index].R3; // set TX power + RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R1); + RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R2); + RTMP_RF_IO_WRITE32(pAd, R3); + RTMP_RF_IO_WRITE32(pAd, RF5222RegTable[index].R4); + pAd->PortCfg.LatchRfRegs.Channel = Channel; + pAd->PortCfg.LatchRfRegs.R1 = RF5222RegTable[index].R1; + pAd->PortCfg.LatchRfRegs.R2 = RF5222RegTable[index].R2; + pAd->PortCfg.LatchRfRegs.R3 = R3; + pAd->PortCfg.LatchRfRegs.R4 = RF5222RegTable[index].R4; + break; + } + } + break; + + default: + break; + } + + DBGPRINT(RT_DEBUG_INFO, "AsicSwitchChannel(RF=%d) to #%d, TXPwr=%d, R1=0x%08x, R2=0x%08x, R3=0x%08x, R4=0x%08x\n", + pAd->PortCfg.RfType, + pAd->PortCfg.LatchRfRegs.Channel, + pAd->PortCfg.TxPower, + pAd->PortCfg.LatchRfRegs.R1, + pAd->PortCfg.LatchRfRegs.R2, + pAd->PortCfg.LatchRfRegs.R3, + pAd->PortCfg.LatchRfRegs.R4); +} + +/* + ========================================================================== + Description: + This function is required for 2421 only, and should not be used during + site survey. It's only required after NIC decided to stay at a channel + for a longer period. + When this function is called, it's always after AsicSwitchChannel(). + ========================================================================== + */ +VOID AsicLockChannel( + IN PRTMP_ADAPTER pAd, + IN UCHAR Channel) +{ + UCHAR r70; + ULONG FcsCnt; + + RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer); + RTMPSetTimer(pAd, &pAd->PortCfg.RfTuningTimer, 1000/HZ); // 1 msec timer to turn OFF RF auto tuning + + RTMP_BBP_IO_READ32_BY_REG_ID(pAd, 70, &r70); + if (Channel == 14) + r70 = 0x4E; //set r70 to 0x4E instead of r70 |= 0x08; for turn on Japan filter bit + else + r70 = 0x46; //set r70 to 0x46 instead of r70 &= 0xf7; for turn off Japan filter bit + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 70, r70); + + // Clear false CRC durning switch channel + RTMP_IO_READ32(pAd, CNT0, &FcsCnt); +} + +VOID AsicRfTuningExec( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + switch (pAd->PortCfg.RfType) + { + case RFIC_2522: + case RFIC_2524: + case RFIC_2525: + case RFIC_5222: + case RFIC_2525E: + pAd->PortCfg.LatchRfRegs.R1 &= 0xfffdffff; // RF R1.bit17 "tune_en1" OFF + pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF + RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R1); + RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3); + DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R1=0x%x,R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R1,pAd->PortCfg.LatchRfRegs.R3); + break; + + case RFIC_2523: + pAd->PortCfg.LatchRfRegs.R3 &= 0xfffffeff; // RF R3.bit8 "tune_en2" OFF + RTMP_RF_IO_WRITE32(pAd, pAd->PortCfg.LatchRfRegs.R3); + DBGPRINT(RT_DEBUG_INFO, "AsicRfTuningExec(R3=0x%x)\n",pAd->PortCfg.LatchRfRegs.R3); + break; + + default: + break; + } +} + +/* + ========================================================================== + Description: + Gives CCK TX rate 2 more dB TX power. + This routine works only in LINK UP in INFRASTRUCTURE mode. + + calculate desired Tx power in RF R3.Tx0~5, should consider - + 1. TxPowerPercentage + 2. auto calibration based on TSSI feedback + 3. extra 2 db for CCK + 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP + ========================================================================== + */ +VOID AsicAdjustTxPower( + IN PRTMP_ADAPTER pAd) +{ + ULONG R3, Channel, CurrTxPwr; + int Value; + + if ((pAd->PortCfg.Channel >= 1) && (pAd->PortCfg.Channel <= 14)) + Channel = pAd->PortCfg.Channel; + else + Channel = 1; // don't have calibration info for 11A, temporarily use Channel 1 + + // get TX Power base from E2PROM + R3 = pAd->PortCfg.ChannelTxPower[Channel - 1]; + if (R3 > 31) R3 = 31; + + // Krellan: Same as in AsicSwitchChannel() above + Value = R3 + pAd->PortCfg.TxPowerUser; + Value = (Value > 31) ? 31 : Value; + Value = (Value < 0) ? 0 : Value; + R3 = Value; + + // E2PROM setting is calibrated for maximum TX power (i.e. 100%) + // We lower TX power here according to the percentage specified from UI + if (pAd->PortCfg.TxPowerAuto == TRUE) // AUTO TX POWER control + { + // only INFRASTRUCTURE mode and 100% TX power need furthur calibration + if (pAd->MediaState == NdisMediaStateConnected) + { + // low TX power upon very-short distance to AP to solve some vendor's AP RX problem + // in this case, no TSSI compensation is required. + + if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) && + (pAd->PortCfg.AvgRssi > (pAd->PortCfg.RssiToDbm - RSSI_FOR_LOWEST_TX_POWER))) + R3 -= LOWEST_TX_POWER_DELTA; + else if ((pAd->DrsCounters.fNoisyEnvironment == FALSE) && + (pAd->PortCfg.AvgRssi > (pAd->PortCfg.RssiToDbm - RSSI_FOR_LOW_TX_POWER))) + R3 -= LOW_TX_POWER_DELTA; + + + // 2004-03-16 give OFDM rates lower than 48 mbps 2 more DB + else if ((pAd->PortCfg.TxRate <= RATE_36) && (pAd->PortCfg.TxRate > RATE_11)) + { + R3 +=2; + if (R3 > 31) R3 = 31; + } + + // 2 exclusive rules applied on CCK rates only - + // 1. always plus 2 db for CCK + // 2. adjust TX Power based on TSSI + else if (pAd->PortCfg.TxRate <= RATE_11) + { + // if "auto calibration based on TSSI" is not required, then + // always give CCK 2 more db + if (pAd->PortCfg.bAutoTxAgc == FALSE) + { + R3 += 2; // plus 2 db + if (R3 > 31) R3 = 31; + } + + // Auto calibrate Tx AGC if bAutoTxAgc is TRUE and TX rate is CCK, + // because E2PROM's TSSI reference is valid only in CCK range. + else + { + UCHAR R1,TxPowerRef, TssiRef; + + R3 = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f; + if (pAd->Mlme.PeriodicRound % 4 == 0) // every 4 second + { + TxPowerRef = pAd->PortCfg.ChannelTxPower[Channel - 1]; + TssiRef = pAd->PortCfg.ChannelTssiRef[Channel - 1]; + RTMP_BBP_IO_READ32_BY_REG_ID(pAd, BBP_Tx_Tssi, &R1); + if ((TssiRef >= (R1 + pAd->PortCfg.ChannelTssiDelta)) || + (TssiRef <= (R1 - pAd->PortCfg.ChannelTssiDelta))) + { + // Need R3 adjustment. However, we have to make sure there is only + // plus / minus 5 variation allowed + if (TssiRef > R1) + { + R3 = (R3 < (ULONG) (TxPowerRef + 5)) ? (R3 + 1) : R3; + if (R3 > 31) + R3 = 31; + DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, ++TxPwr=%d\n", R1, R3); + } + else + { + R3 = (R3 > (ULONG) (TxPowerRef - 5)) ? (R3 - 1) : R3; + DBGPRINT(RT_DEBUG_INFO,"TSSI(R1)=%d, --TxPwr=%d\n", R1, R3); + } + } + } + } + } + + } + } + else // fixed AUTO TX power + { + // 2004-03-16 give TX rates <= 36 mbps 2 more DB + if (pAd->PortCfg.TxRate <= RATE_36) + { + R3 +=2; + if (R3 > 31) R3 = 31; + } + } + + // Krellan: Save value for readout to user + pAd->PortCfg.TxPowerDriver = R3; + + // compare the desired R3.TxPwr value with current R3, if not equal + // set new R3.TxPwr + CurrTxPwr = (pAd->PortCfg.LatchRfRegs.R3 >> 9) & 0x0000001f; + if (CurrTxPwr != R3) + { + CurrTxPwr = R3; + R3 = (pAd->PortCfg.LatchRfRegs.R3 & 0xffffc1ff) | (R3 << 9); + RTMP_RF_IO_WRITE32(pAd, R3); + pAd->PortCfg.LatchRfRegs.R3 = R3; + } + DBGPRINT(RT_DEBUG_INFO, "AsicAdjustTxPower = %d, AvgRssi = %d\n", + CurrTxPwr, pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm); + +} + +/* + ========================================================================== + Description: + put PHY to sleep here, and set next wakeup timer + ========================================================================== + */ +VOID AsicSleepThenAutoWakeup( + IN PRTMP_ADAPTER pAd, + IN USHORT TbttNumToNextWakeUp) +{ + CSR20_STRUC Csr20; + PWRCSR1_STRUC Pwrcsr1; + + // we have decided to SLEEP, so at least do it for a BEACON period. + if (TbttNumToNextWakeUp==0) + TbttNumToNextWakeUp=1; + + // PWRCSR0 remains untouched + + // set CSR20 for next wakeup + Csr20.word = 0; + Csr20.field.NumBcnBeforeWakeup = TbttNumToNextWakeUp - 1; + Csr20.field.DelayAfterBcn = (pAd->PortCfg.BeaconPeriod - 20) << 4; // 20 TU ahead of desired TBTT + Csr20.field.AutoWake = 1; + RTMP_IO_WRITE32(pAd, CSR20, Csr20.word); + + // set PWRCSR1 to put PHY into SLEEP state + Pwrcsr1.word = 0; + Pwrcsr1.field.PutToSleep = 1; + Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP + Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP + RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word); + pAd->PortCfg.Pss = PWR_SAVE; +} + +/* + ========================================================================== + Description: + AsicForceWakeup() is used whenever manual wakeup is required + AsicForceSleep() should only be used when Massoc==FALSE. When + Massoc==TRUE, we should use AsicSleepThenAutoWakeup() instead. + ========================================================================== + */ +VOID AsicForceSleep( + IN PRTMP_ADAPTER pAd) +{ + PWRCSR1_STRUC Pwrcsr1; + + if (pAd->PortCfg.Pss == PWR_ACTIVE) + { + DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceSleep<<<\n"); + Pwrcsr1.word = 0; + Pwrcsr1.field.RfDesireState = 1; // 01:SLEEP state + Pwrcsr1.field.BbpDesireState = 1; // 01:SLEEP state + Pwrcsr1.field.SetState = 1; + RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word); + pAd->PortCfg.Pss = PWR_SAVE; + } +} + +VOID AsicForceWakeup( + IN PRTMP_ADAPTER pAd) +{ + CSR20_STRUC Csr20; + PWRCSR1_STRUC Pwrcsr1; + + if (pAd->PortCfg.Pss == PWR_SAVE) + { + DBGPRINT(RT_DEBUG_TRACE, ">>>AsicForceWakeup<<<\n"); + + // 2003-12-19 turn OFF auto wakeup first + Csr20.word = 0; + Csr20.field.AutoWake = 0; + RTMP_IO_WRITE32(pAd, CSR20, Csr20.word); + + Pwrcsr1.word = 0; + Pwrcsr1.field.RfDesireState = 3; // 11:AWAKE state + Pwrcsr1.field.BbpDesireState = 3; // 11:AWAKE state + Pwrcsr1.field.SetState = 1; + RTMP_IO_WRITE32(pAd, PWRCSR1, Pwrcsr1.word); + pAd->PortCfg.Pss = PWR_ACTIVE; + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AsicSetBssid( + IN PRTMP_ADAPTER pAd, + IN MACADDR *Bssid) +{ + ULONG Addr4; + + Addr4 = (ULONG)(Bssid->Octet[0]) | + (ULONG)(Bssid->Octet[1] << 8) | + (ULONG)(Bssid->Octet[2] << 16) | + (ULONG)(Bssid->Octet[3] << 24); + RTMP_IO_WRITE32(pAd, CSR5, Addr4); + + Addr4 = (ULONG)(Bssid->Octet[4]) | (ULONG)(Bssid->Octet[5] << 8); + RTMP_IO_WRITE32(pAd, CSR6, Addr4); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AsicDisableSync( + IN PRTMP_ADAPTER pAd) +{ + // TIMECSR_STRUC TimeCsr; + DBGPRINT(RT_DEBUG_TRACE, "--->Disable TSF synchronization\n"); +#if 1 + // 2003-12-20 disable TSF and Tbcn while NIC in power-saving have side effect + // that NIC will never wakes up because TSF stops and no more TBTT interrupts + RTMP_IO_WRITE32(pAd, CSR14, 0x00000009); +#else + RTMP_IO_WRITE32(pAd, CSR14, 0x00000000); +#endif + +#if 0 + RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word); + + // restore to 33 PCI-tick-per-Usec. for 2560a only where PCI-clock is used as TSF timing source + if (TimeCsr.field.UsCnt != 0x21) + { + TimeCsr.field.UsCnt = 0x21; + RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word); + } +#endif +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AsicEnableBssSync( + IN PRTMP_ADAPTER pAd) +{ + CSR12_STRUC Csr12; + CSR13_STRUC Csr13; + CSR14_STRUC Csr14; + BCNCSR1_STRUC Bcncsr1; + BOOLEAN IsApPc; + + DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableBssSync(INFRA mode)\n"); + + RTMP_IO_WRITE32(pAd, CSR14, 0x00000000); + + Csr12.word = 0; + Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU + Csr12.field.CfpMaxDuration = pAd->PortCfg.CfpMaxDuration << 4; // ASIC register in units of 1/16 TU + RTMP_IO_WRITE32(pAd, CSR12, Csr12.word); + + Csr13.word = 0; + Csr13.field.CfpPeriod = pAd->PortCfg.CfpDurRemain << 4; // ASIC register in units of 1/16 TU + RTMP_IO_WRITE32(pAd, CSR13, Csr13.word); + + Bcncsr1.word = 0; + Bcncsr1.field.Preload = TBTT_PRELOAD_TIME; // we guess TBTT is 2 TU ahead of BEACON-RxEnd time + Bcncsr1.field.BeaconCwMin = 5; + RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word); + + IsApPc = (CAP_IS_CF_POLLABLE_ON(pAd->PortCfg.CapabilityInfo) && + CAP_IS_CF_POLL_REQ_ON(pAd->PortCfg.CapabilityInfo)); + IsApPc = FALSE; // TODO: not support so far + + Csr14.word = 0; + Csr14.field.TsfCount = 1; + Csr14.field.TsfSync = 1; // sync TSF in INFRASTRUCTURE mode + if (IsApPc) + { + Csr14.field.CfpCntPreload = pAd->PortCfg.CfpCount; + Csr14.field.Tcfp = 1; + } + Csr14.field.BeaconGen = 0; +// Csr14.field.TbcnPreload = (pAd->PortCfg.BeaconPeriod - 30) << 4; // TODO: ???? 1 TU ??? + Csr14.field.Tbcn = 1; + RTMP_IO_WRITE32(pAd, CSR14, Csr14.word); + +} + +/* + ========================================================================== + Description: + Note: + BEACON frame in shared memory should be built ok before this routine + can be called. Otherwise, a garbage frame maybe transmitted out every + Beacon period. + ========================================================================== + */ +VOID AsicEnableIbssSync( + IN PRTMP_ADAPTER pAd) +{ + CSR12_STRUC Csr12; + CSR13_STRUC Csr13; + CSR14_STRUC Csr14; + // BCNCSR_STRUC Bcncsr; + BCNCSR1_STRUC Bcncsr1; + + DBGPRINT(RT_DEBUG_TRACE, "--->AsicEnableIbssSync(ADHOC mode)\n"); + + RTMP_IO_WRITE32(pAd, CSR14, 0x00000000); + + Csr12.word = 0; + Csr12.field.BeaconInterval = pAd->PortCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU + RTMP_IO_WRITE32(pAd, CSR12, Csr12.word); + + Csr13.word = 0; + Csr13.field.AtimwDuration = pAd->PortCfg.AtimWin << 4; // ASIC register in units of 1/16 TU + RTMP_IO_WRITE32(pAd, CSR13, Csr13.word); + + Bcncsr1.word = 0; + if ((pAd->PortCfg.PhyMode == PHY_11B) || (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)) + { + Bcncsr1.field.BeaconCwMin = 5; + Bcncsr1.field.Preload = 1024; // 192 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]); + } + else + { + Bcncsr1.field.BeaconCwMin = 6; + Bcncsr1.field.Preload = 700; // 24 + ((MAC_HDR_LEN << 4) / RateIdTo500Kbps[pAd->PortCfg.MlmeRate]); + } + RTMP_IO_WRITE32(pAd, BCNCSR1, Bcncsr1.word); + + Csr14.word = 0; + Csr14.field.TsfCount = 1; + Csr14.field.TsfSync = 2; // sync TSF in IBSS mode + Csr14.field.Tbcn = 1; + Csr14.field.BeaconGen = 1; + RTMP_IO_WRITE32(pAd, CSR14, Csr14.word); +} + +VOID AsicLedPeriodicExec( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + ULONG LedCsr = 0x0000461E; // 0x0000461E; + + pAd->PortCfg.LedCntl.fOdd = ! pAd->PortCfg.LedCntl.fOdd; + + if (INFRA_ON(pAd) || ADHOC_ON(pAd)) + LedCsr |= 0x00010000; // enable hardwired TX activity LED + if (pAd->PortCfg.LedCntl.fOdd && pAd->PortCfg.LedCntl.fRxActivity) + LedCsr |= 0x00020000; // turn on software-based RX activity LED + pAd->PortCfg.LedCntl.fRxActivity = FALSE; + + if (LedCsr != pAd->PortCfg.LedCntl.LastLedCsr) + { +// DBGPRINT(RT_DEBUG_TRACE, ("AsicLedPeriodicExec(%8x)\n",LedCsr)); + pAd->PortCfg.LedCntl.LastLedCsr = LedCsr; + RTMP_IO_WRITE32(pAd, LEDCSR, LedCsr); + } + + RTMPSetTimer(pAd, &pAd->PortCfg.LedCntl.BlinkTimer, 70); +} + +// pAd->PortCfg.CurrentRxAntenna +// 0xff: diversity, 0:antenna A, 1:antenna B +VOID AsicSetRxAnt( + IN PRTMP_ADAPTER pAd) +{ + UCHAR RxValue, TxValue; + ULONG Bbpcsr1; + + RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer); + pAd->PortCfg.RxAnt.AvgRssi[0] = (-95 + 120) << 3; // reset Ant-A's RSSI history + pAd->PortCfg.RxAnt.AvgRssi[1] = (-95 + 120) << 3; // reset Ant-B's RSSI history + + pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE; + + if (pAd->PortCfg.CurrentRxAntenna == 0xff) // Diversity + { + pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B + pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A + } + else if (pAd->PortCfg.CurrentRxAntenna == 0) // ant-A + { + pAd->PortCfg.RxAnt.PrimaryRxAnt = 0; // assume ant-A + pAd->PortCfg.RxAnt.SecondaryRxAnt = 1; // assume ant-B + } + else // ant-B + { + pAd->PortCfg.RxAnt.PrimaryRxAnt = 1; // assume ant-B + pAd->PortCfg.RxAnt.SecondaryRxAnt = 0; // assume ant-A + } + + DBGPRINT(RT_DEBUG_TRACE,"AntDiv - set RxAnt=%d, primary=%d, second=%d\n", + pAd->PortCfg.CurrentRxAntenna, pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.SecondaryRxAnt); + + // use primary antenna + RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1); + TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure]; + RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure]; + if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A + { + TxValue = (TxValue & 0xFC) | 0x00; + RxValue = 0x1c; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000; + } + else // ant-B + { + TxValue = (TxValue & 0xFC) | 0x02; + RxValue = 0x1e; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002; + } + RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1); + //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue); + +} + +// switch to secondary RxAnt for a while to collect it's average RSSI +// also set a timeout routine to DO the actual evaluation. If evaluation +// result shows a much better RSSI using secondary RxAnt, then a official +// RX antenna switch is performed. +VOID AsicEvaluateSecondaryRxAnt( + IN PRTMP_ADAPTER pAd) +{ + UCHAR RxValue, TxValue; + ULONG Bbpcsr1; + + if (pAd->PortCfg.CurrentRxAntenna != 0xff) + return; + + pAd->PortCfg.RxAnt.PrimaryInUsed = FALSE; + pAd->PortCfg.RxAnt.FirstPktArrivedWhenEvaluate = FALSE; + pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate = 0; + +// pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] = 0; + + DBGPRINT(RT_DEBUG_TRACE,"AntDiv - evaluate Ant #%d\n", pAd->PortCfg.RxAnt.SecondaryRxAnt); + + // temporarily switch to secondary antenna + RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure]; + TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure]; + RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1); + + if (pAd->PortCfg.RxAnt.SecondaryRxAnt == 0) // ant-A + { + TxValue = (TxValue & 0xFC) | 0x00; + RxValue = 0x1c; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000; + } + else // ant-B + { + TxValue = (TxValue & 0xFC) | 0x02; + RxValue = 0x1e; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002; + } + RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1); + //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue); + + // a one-shot timer to end the evalution + if (pAd->MediaState == NdisMediaStateConnected) + RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 150); + else + RTMPSetTimer(pAd, &pAd->PortCfg.RxAnt.RxAntDiversityTimer, 300); +} + +// this timeout routine collect AvgRssi[SecondaryRxAnt] and decide if +// SecondaryRxAnt is much better than PrimaryRxAnt +VOID AsicRxAntEvalTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + + DBGPRINT(RT_DEBUG_TRACE,"AntDiv - AsicRxAntEvalTimeout, \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)) + return; + + if (pAd->PortCfg.RxAnt.PrimaryInUsed == TRUE) + + return; + + // 1-db or more will we consider to switch antenna + if ((pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] >= + (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.PrimaryRxAnt]))) + + { + UCHAR temp; + // secondary antenna is much better than primary, switch RX antenna + temp = pAd->PortCfg.RxAnt.PrimaryRxAnt; + pAd->PortCfg.RxAnt.PrimaryRxAnt = pAd->PortCfg.RxAnt.SecondaryRxAnt; + pAd->PortCfg.RxAnt.SecondaryRxAnt = temp; + pAd->PortCfg.LastAvgRssi = (pAd->PortCfg.RxAnt.AvgRssi[pAd->PortCfg.RxAnt.SecondaryRxAnt] >> 3) - pAd->PortCfg.RssiToDbm; + + DBGPRINT(RT_DEBUG_TRACE,"AntDiv - Switch to Ant #%d, RSSI[0,1]=<%d, %d>\n", + pAd->PortCfg.RxAnt.PrimaryRxAnt, pAd->PortCfg.RxAnt.AvgRssi[0], pAd->PortCfg.RxAnt.AvgRssi[1]); + } + else + { + UCHAR RxValue, TxValue; + ULONG Bbpcsr1; + + // end of evaluation, swicth back to primary antenna + RxValue = pAd->PortCfg.BbpWriteLatch[BBP_Rx_Configure]; + TxValue = pAd->PortCfg.BbpWriteLatch[BBP_Tx_Configure]; + RTMP_IO_READ32(pAd, BBPCSR1, &Bbpcsr1); + if (pAd->PortCfg.RxAnt.PrimaryRxAnt == 0) // ant-A + { + TxValue = (TxValue & 0xFC) | 0x00; + RxValue = 0x1c; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00000000; + } + else // ant-B + { + TxValue = (TxValue & 0xFC) | 0x02; + RxValue = 0x1e; + Bbpcsr1 = (Bbpcsr1 & 0xFFFCFFFC) | 0x00020002; + } + RTMP_IO_WRITE32(pAd, BBPCSR1, Bbpcsr1); + //RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Tx_Configure, TxValue); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, BBP_Rx_Configure, RxValue); + DBGPRINT(RT_DEBUG_TRACE,"AntDiv - remain Ant #%d, RSSI[0,1]=<%d, %d>, RcvPktNumWhenEvaluate=%d\n", + pAd->PortCfg.RxAnt.PrimaryRxAnt, (pAd->PortCfg.RxAnt.AvgRssi[0] >> 3) - pAd->PortCfg.RssiToDbm, (pAd->PortCfg.RxAnt.AvgRssi[1] >> 3) - pAd->PortCfg.RssiToDbm, pAd->PortCfg.RxAnt.RcvPktNumWhenEvaluate); + + } + +// pAd->PortCfg.RxAnt.AvgRssi[0] = 0; // reset Ant-A's RSSI history +// pAd->PortCfg.RxAnt.AvgRssi[1] = 0; // reset Ant-B's RSSI history + pAd->PortCfg.RxAnt.PrimaryInUsed = TRUE; + pAd->PortCfg.RxAnt.FirstPktArrivedWhenEvaluate = TRUE; +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID AsicSetSlotTime( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN UseShortSlotTime) +{ + CSR11_STRUC Csr11; + CSR18_STRUC Csr18; + CSR19_STRUC Csr19; + UCHAR PhyMode; + + pAd->PortCfg.ShortSlotInUsed = UseShortSlotTime; + + PhyMode = pAd->PortCfg.PhyMode; + if (PhyMode == PHY_11ABG_MIXED) + { + if (pAd->PortCfg.Channel <=14) + PhyMode = PHY_11BG_MIXED; + else + PhyMode = PHY_11A; + } + + RTMP_IO_READ32(pAd, CSR11, &Csr11.word); + if (PhyMode == PHY_11A) + Csr11.field.SlotTime = 9; + else + Csr11.field.SlotTime = (UseShortSlotTime)? 9 : 20; + RTMP_IO_WRITE32(pAd, CSR11, Csr11.word); + + RTMP_IO_READ32(pAd, CSR18, &Csr18.word); + Csr18.field.PIFS = Csr18.field.SIFS + Csr11.field.SlotTime; + RTMP_IO_WRITE32(pAd, CSR18, Csr18.word); + + Csr19.word = 0; + Csr19.field.DIFS = Csr18.field.PIFS + Csr11.field.SlotTime; + if (PhyMode == PHY_11B) + Csr19.field.EIFS = 364; // SIFS + ACK @1Mbps + else + Csr19.field.EIFS = 60; // roughly = SIFS + ACK @6Mbps + RTMP_IO_WRITE32(pAd, CSR19, Csr19.word); + +#if 1 + // force using short SLOT time for FAE to demo performance only + if (pAd->PortCfg.EnableTxBurst == 1) + Csr11.field.SlotTime = 9; + RTMP_IO_WRITE32(pAd, CSR11, Csr11.word); +#endif + + DBGPRINT(RT_DEBUG_TRACE, "AsicSetSlotTime(=%d us, CSR18=0x%08x, CSR19=0x%08x)\n", + Csr11.field.SlotTime, Csr18.word, Csr19.word); +} + +/* + ========================================================================== + Description: + This routine is used for 2560a only where 2560a still use non-accurate + PCI-clock as TSF 1-usec source. we have to dynamically change tick-per-usec + to avoid ADHOC synchronization issue with SYMBOL 11b card + ========================================================================== + */ +VOID AsicAdjustUsec( + IN PRTMP_ADAPTER pAd) +{ + TIMECSR_STRUC TimeCsr; + UCHAR TickPerUsec = 20; + pAd->PortCfg.PciAdjustmentRound = (pAd->PortCfg.PciAdjustmentRound+1) & 0x03; + + RTMP_IO_READ32(pAd, TIMECSR, &TimeCsr.word); + if (pAd->PortCfg.PciAdjustmentRound == 0) + TickPerUsec = 0x21; + else if (pAd->PortCfg.PciAdjustmentRound == 1) + TickPerUsec = 0x21; + else if (pAd->PortCfg.PciAdjustmentRound == 2) + TickPerUsec = 0x20; + else + TickPerUsec = 0x21; + + if (TimeCsr.field.UsCnt!= TickPerUsec) + { + TimeCsr.field.UsCnt= TickPerUsec; + RTMP_IO_WRITE32(pAd, TIMECSR, TimeCsr.word); + DBGPRINT(RT_DEBUG_INFO, "AsicAdjustUsec - change TIMECSR=0x%08x)\n",TimeCsr.word); + } +} + +/* + ========================================================================== + Description: + danamic tune BBP R17 to find a balance between sensibility and + noise isolation + ========================================================================== + */ +VOID AsicBbpTuning( + IN PRTMP_ADAPTER pAd) +{ + ULONG Value; + UCHAR R17; + ULONG FalseCcaUpperThreshold = pAd->PortCfg.BbpTuning.FalseCcaUpperThreshold << 7; + int dbm = pAd->PortCfg.AvgRssi - pAd->PortCfg.RssiToDbm; + + if ((! pAd->PortCfg.BbpTuningEnable) || (pAd->PortCfg.BbpTuning.VgcDelta==0)) + return; + + R17 = pAd->PortCfg.BbpWriteLatch[17]; + + if ((pAd->PortCfg.Rt2560Version >= RT2560_VER_D) && + (pAd->MediaState == NdisMediaStateConnected)) + { + // Rule 0. + // when RSSI is too weak, many signals will become false CCA thus affect R17 tuning. + // so in this case, just stop R17 tuning (be sure R17 remains in range) + if ((dbm < -80) && (pAd->Mlme.PeriodicRound > 20)) + { + if (R17 >= BBP_R17_MID_SENSIBILITY) + { + R17 = pAd->PortCfg.LastR17Value; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + } + DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, stop R17 at 0x%x\n", dbm, R17); + return; + } + // Rule 1. "special big-R17 for short-distance" when not SCANNING + else if ((dbm >= RSSI_FOR_LOW_SENSIBILITY) && + (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) + { + if (R17 != BBP_R17_LOW_SENSIBILITY) + { + R17 = BBP_R17_LOW_SENSIBILITY; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + } + DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17); + return; + } + // Rule 2. "special mid-R17 for mid-distance" when not SCANNING + else if ((dbm >= RSSI_FOR_MID_SENSIBILITY) && + (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) + { + if (R17 != BBP_R17_MID_SENSIBILITY) + { + R17 = BBP_R17_MID_SENSIBILITY; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + } + DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, fixed R17 at 0x%x\n", dbm, R17); + return; + } + // Rule 3. leave "short or mid-distance" condition, restore R17 to the + // dynamic tuning range + else if (R17 >= BBP_R17_MID_SENSIBILITY) + { + R17 = pAd->PortCfg.LastR17Value; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + DBGPRINT(RT_DEBUG_INFO, "RSSI = %d dbm, restore R17 to 0x%x\n", dbm, R17); + return; + } + } + + // Rule 3. otherwise, R17 is currenly in dyanmic tuning range: . + // Keep dynamic tuning based on False CCA conter + + RTMP_IO_READ32(pAd, CNT3, &Value); + pAd->PrivateInfo.CCAErrCnt = (Value & 0x0000ffff); + DBGPRINT(RT_DEBUG_INFO, "CCA flase alarm = %d, Avg RSSI= %d dbm\n", + pAd->PrivateInfo.CCAErrCnt, dbm); + + if ((pAd->PrivateInfo.CCAErrCnt > FalseCcaUpperThreshold) && + (R17 < pAd->PortCfg.BbpTuning.VgcUpperBound)) + { + R17 += pAd->PortCfg.BbpTuning.VgcDelta; + pAd->PortCfg.LastR17Value = R17; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + DBGPRINT(RT_DEBUG_INFO, "++R17= 0x%x\n", R17); + } + else if ((pAd->PrivateInfo.CCAErrCnt < pAd->PortCfg.BbpTuning.FalseCcaLowerThreshold) && + (R17 > pAd->PortCfg.VgcLowerBound)) + { + R17 -= pAd->PortCfg.BbpTuning.VgcDelta; + pAd->PortCfg.LastR17Value = R17; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + DBGPRINT(RT_DEBUG_INFO, "--R17= 0x%x\n", R17); + } +} + +// stop and restore R17 value upon SITE-SURVEY and LINK-DOWN +VOID AsicRestoreBbpSensibility( + IN PRTMP_ADAPTER pAd) +{ + UCHAR R17; + + R17 = pAd->PortCfg.BbpWriteLatch[17]; + if (R17 >= BBP_R17_MID_SENSIBILITY) + { + R17 = pAd->PortCfg.LastR17Value; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAd, 17, R17); + DBGPRINT(RT_DEBUG_TRACE, "AsicRestoreBbpSensibility(set R17= 0x%x)\n", R17); + } +} + +/* + ======================================================================== + + Routine Description: + Mlme free the in-used nonpaged memory, + move it to the unused memory link list + + Arguments: + pAd Pointer to our adapter + AllocVa Pointer to the base virtual address for free + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID MlmeFreeMemory( + IN PRTMP_ADAPTER pAd, + IN PVOID AllocVa) +{ + PMLME_MEMORY_STRUCT pPrevious = NULL; + PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL; + UINT Index = 0; + BOOLEAN bIsFound = FALSE; + + DBGPRINT(RT_DEBUG_INFO, "==> MlmeFreeMemory\n"); + spin_lock(&pAd->MemLock); + if (pAd->Mlme.MemHandler.MemRunning) + { + //Mlme memory handler is busy. + //Move it to the Pending array for later free + pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingCount++] = (PULONG) AllocVa; + + DBGPRINT(RT_DEBUG_INFO, "Mlme memory Handler Busy!! move free memory to pending list [IN:%d][UN:%d][Pending:%d]\n", + pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount); + DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory\n"); + spin_unlock(&pAd->MemLock); + return; + } + else + { + pAd->Mlme.MemHandler.MemRunning = TRUE; + } + + //First check is there have to free memory in the pAd->Mlme.MemHandler.MemFreePending. + while (pAd->Mlme.MemHandler.PendingCount > 0) + { + pPrevious = NULL; + pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead; + while (pMlmeMemoryStruct) + { + if (pMlmeMemoryStruct->AllocVa == (PVOID) pAd->Mlme.MemHandler.MemFreePending[Index]) + { + //Found virtual address in the in-used link list + //Remove it from the memory in-used link list, and move it to the unused link list + if (pPrevious == NULL) + { + pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next; + // + // Update pInUseTail pointer, if this is an Empty list + // + if (pAd->Mlme.MemHandler.pInUseHead == NULL) + pAd->Mlme.MemHandler.pInUseTail = NULL; + } + else + { + pPrevious->Next = pMlmeMemoryStruct->Next; + // + // Update pInUseTail pointer, if move the pInUserTail to Unused link list. + // move the pInuseTail to his previous. + // + if (pMlmeMemoryStruct->Next == NULL) + { + // + // This pMlmeMemoryStruct is the one pInUseTail, since it's next pointer is NULL. + // Then we need to update pInUseTail. + // + pAd->Mlme.MemHandler.pInUseTail = pPrevious; + } + } + + if ((pAd->Mlme.MemHandler.pUnUseHead == NULL)) + { //No head, add it as head + pMlmeMemoryStruct->Next = NULL; + pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseHead; + } + else + { + //Append it to the tail in pAd->Mlme.MemHandler.pUnUseTail + pMlmeMemoryStruct->Next = NULL; + pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pUnUseTail = pAd->Mlme.MemHandler.pUnUseTail->Next; + } + pAd->Mlme.MemHandler.MemFreePending[Index++] = NULL; + pAd->Mlme.MemHandler.PendingCount--; + pAd->Mlme.MemHandler.UnUseCount++; + pAd->Mlme.MemHandler.InUseCount--; + bIsFound = TRUE; + break; + } + else + { + pPrevious = pMlmeMemoryStruct; + pMlmeMemoryStruct = pMlmeMemoryStruct->Next; + } + } + + if (!bIsFound) + { + //This shoult not be happened! Just in case! + DBGPRINT(RT_DEBUG_INFO, "Free memory faild!! memory corruption on [Va:0x%lu] not found in In-Used link list [IN:%d][UN:%d][Pending:%d]\n", + (unsigned long)pAd->Mlme.MemHandler.MemFreePending[pAd->Mlme.MemHandler.PendingCount], + pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount); + //lost a memory + pAd->Mlme.MemHandler.MemFreePending[Index++] = NULL; + pAd->Mlme.MemHandler.PendingCount--; + } + } + + pPrevious = NULL; + pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead; + while (pMlmeMemoryStruct) + { + if (pMlmeMemoryStruct->AllocVa == AllocVa) + { + //Found virtual address in the in-used link list + //Remove it from the memory in-used link list, and move it to the unused link list + if (pPrevious == NULL) + { + pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next; + // + // Update pInUseTail pointer, if this is an Empty list + // + if (pAd->Mlme.MemHandler.pInUseHead == NULL) + pAd->Mlme.MemHandler.pInUseTail = NULL; + } + else + { + pPrevious->Next = pMlmeMemoryStruct->Next; + // + // Update pInUseTail pointer, if move the pInUserTail to Unused link list. + // move the pInuseTail to his previous. + // + if (pMlmeMemoryStruct->Next == NULL) + { + // + // This pMlmeMemoryStruct is the one pInUseTail, since it's next pointer is NULL. + // Then we need to update pInUseTail. + // + pAd->Mlme.MemHandler.pInUseTail = pPrevious; + } + } + + if (pAd->Mlme.MemHandler.pUnUseHead == NULL) + { + pMlmeMemoryStruct->Next = NULL; + pAd->Mlme.MemHandler.pUnUseHead = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct; + } + else + { + pMlmeMemoryStruct->Next = NULL; + pAd->Mlme.MemHandler.pUnUseTail->Next = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pUnUseTail = pMlmeMemoryStruct; + } + + pAd->Mlme.MemHandler.InUseCount--; + pAd->Mlme.MemHandler.UnUseCount++; + DBGPRINT(RT_DEBUG_INFO, "MlmeFreeMemory Add it to the Unused memory link List[pMlmeMemoryStruct=0x%lu][VA=0x%lu]\n", (unsigned long)pMlmeMemoryStruct, (unsigned long)pMlmeMemoryStruct->AllocVa); + break; + } + pPrevious = pMlmeMemoryStruct; + pMlmeMemoryStruct = pMlmeMemoryStruct->Next; + } + + pAd->Mlme.MemHandler.MemRunning = FALSE; + spin_unlock(&pAd->MemLock); + + DBGPRINT(RT_DEBUG_INFO, "<== MlmeFreeMemory [IN:%d][UN:%d][Pending:%d]\n", + pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount); +} + +/* + ======================================================================== + + Routine Description: + Get an unused nonpaged system-space memory for use + + Arguments: + pAd Pointer to our adapter + AllocVa Pointer to the base virtual address for later use + + Return Value: + NDIS_STATUS_SUCCESS + NDIS_STATUS_FAILURE + NDIS_STATUS_RESOURCES + + Note: + + ======================================================================== +*/ +NDIS_STATUS MlmeAllocateMemory( + IN PRTMP_ADAPTER pAd, + OUT PVOID *AllocVa) +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL; + + DBGPRINT(RT_DEBUG_INFO, "==> MlmeAllocateMemory\n"); + spin_lock(&pAd->MemLock); + if (pAd->Mlme.MemHandler.MemRunning) + { + DBGPRINT(RT_DEBUG_INFO, "Mlme memory Handler Busy!!, MlmeAllocateMemory failed!!\n"); + Status = NDIS_STATUS_FAILURE; + DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n"); + spin_unlock(&pAd->MemLock); + return (Status); + } + else + { + pAd->Mlme.MemHandler.MemRunning = TRUE; + } + + if (pAd->Mlme.MemHandler.pUnUseHead == NULL) + { //There are no available memory for caller use + Status = NDIS_STATUS_RESOURCES; + pAd->Mlme.MemHandler.MemRunning = FALSE; + spin_unlock(&pAd->MemLock); + DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory, failed!! (There are no available memory in list)\n"); + DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory\n"); + return (Status); + } + + pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead; + *AllocVa = pMlmeMemoryStruct->AllocVa; //Saved porint to Pointer the base virtual address of the nonpaged memory for caller use. + //Unused memory point to next available + pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next; + pAd->Mlme.MemHandler.UnUseCount--; + + //Append the unused memory link list to the in-used link list tail + if (pAd->Mlme.MemHandler.pInUseHead == NULL) + {//no head, so current Item assign to In-use Head. + pAd->Mlme.MemHandler.pInUseHead = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pInUseHead->Next = NULL; + pAd->Mlme.MemHandler.pInUseTail = pAd->Mlme.MemHandler.pInUseHead; + } + else + { + pMlmeMemoryStruct->Next = NULL; + pAd->Mlme.MemHandler.pInUseTail->Next = pMlmeMemoryStruct; + pAd->Mlme.MemHandler.pInUseTail = pAd->Mlme.MemHandler.pInUseTail->Next; + } + pAd->Mlme.MemHandler.InUseCount++; + pAd->Mlme.MemHandler.MemRunning = FALSE; + spin_unlock(&pAd->MemLock); + DBGPRINT(RT_DEBUG_INFO, "MlmeAllocateMemory [pMlmeMemoryStruct=0x%lu][VA=0x%lu]\n", (unsigned long)pMlmeMemoryStruct, (unsigned long)pMlmeMemoryStruct->AllocVa); + DBGPRINT(RT_DEBUG_INFO, "<== MlmeAllocateMemory[IN:%d][UN:%d][Pending:%d]\n", + pAd->Mlme.MemHandler.InUseCount, pAd->Mlme.MemHandler.UnUseCount, pAd->Mlme.MemHandler.PendingCount); + + return (Status); +} + +/* + ======================================================================== + + Routine Description: + Allocates resident (nonpaged) system-space memory for MLME send frames + + Arguments: + pAd Pointer to our adapter + Number Total nonpaged memory for use + Size Each nonpaged memory size + + Return Value: + NDIS_STATUS_SUCCESS + NDIS_STATUS_RESOURCES + + Note: + + ======================================================================== +*/ +NDIS_STATUS MlmeInitMemoryHandler( + IN PRTMP_ADAPTER pAd, + IN UINT Number, + IN UINT Size) +{ + PMLME_MEMORY_STRUCT Current = NULL; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + UINT i; + + DBGPRINT(RT_DEBUG_INFO, "==> MlmeInitMemory\n"); + pAd->Mlme.MemHandler.MemoryCount = 0; + pAd->Mlme.MemHandler.pInUseHead = NULL; + pAd->Mlme.MemHandler.pInUseTail = NULL; + pAd->Mlme.MemHandler.pUnUseHead = NULL; + pAd->Mlme.MemHandler.pUnUseTail = NULL; + pAd->Mlme.MemHandler.MemRunning = FALSE; + + //initial the memory free-pending array all to NULL; + for (i = 0; i < MAX_MLME_HANDLER_MEMORY; i++) + pAd->Mlme.MemHandler.MemFreePending[i] = NULL; + + // + // Available nonpaged memory counts MAX_MLME_HANDLER_MEMORY + // + if (Number > MAX_MLME_HANDLER_MEMORY) + Number = MAX_MLME_HANDLER_MEMORY; + + for (i = 0; i < Number; i++) + { + //Allocate a nonpaged memory for link list use. + Current = kmalloc(sizeof(MLME_MEMORY_STRUCT), GFP_ATOMIC); + if (Current == NULL) + { + Status = NDIS_STATUS_RESOURCES; + break; + } + + //Allocate a nonpaged memory for mlme use, Current->AllocVa is VirtualAddress pointer + Current->AllocVa = kmalloc(Size, GFP_ATOMIC); + if (Current->AllocVa == NULL) + { + Status = NDIS_STATUS_RESOURCES; + //Free the nonpaged memory of the current link list + kfree((VOID *)Current); + break; + } + memset(Current->AllocVa, 0, Size); + + pAd->Mlme.MemHandler.MemoryCount++; + + //build up the link list + if (pAd->Mlme.MemHandler.pUnUseHead != NULL) + { + Current->Next = pAd->Mlme.MemHandler.pUnUseHead; + pAd->Mlme.MemHandler.pUnUseHead = Current; + } + else + { + Current->Next = NULL; + pAd->Mlme.MemHandler.pUnUseHead = Current; + } + + if (pAd->Mlme.MemHandler.pUnUseTail == NULL) + pAd->Mlme.MemHandler.pUnUseTail = Current; + + } + + if (pAd->Mlme.MemHandler.MemoryCount < Number) + { + Status = NDIS_STATUS_RESOURCES; + DBGPRINT(RT_DEBUG_TRACE, "MlmeInitMemory Initial failed [Require=%d, available=%d]\n", Number, pAd->Mlme.MemHandler.MemoryCount); + } + + pAd->Mlme.MemHandler.InUseCount = 0; + pAd->Mlme.MemHandler.UnUseCount = Number; + pAd->Mlme.MemHandler.PendingCount = 0; + DBGPRINT(RT_DEBUG_INFO, "<== MlmeInitMemory\n"); + return (Status); +} + +/* + ======================================================================== + + Routine Description: + Free Mlme memory handler (link list, nonpaged memory, spin lock) + + Arguments: + pAd Pointer to our adapter + + Return Value: + None + ======================================================================== +*/ +VOID MlmeFreeMemoryHandler( + IN PRTMP_ADAPTER pAd) +{ + PMLME_MEMORY_STRUCT pMlmeMemoryStruct = NULL; + + //Free nonpaged memory, free it in the *In-used* link list. + while (pAd->Mlme.MemHandler.pInUseHead != NULL) + { + pMlmeMemoryStruct = pAd->Mlme.MemHandler.pInUseHead; + pAd->Mlme.MemHandler.pInUseHead = pAd->Mlme.MemHandler.pInUseHead->Next; + //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER + kfree(pMlmeMemoryStruct->AllocVa); + //Free the link list item self + kfree(pMlmeMemoryStruct); + } + + //Free nonpaged memory, free it in the *Unused* link list. + while (pAd->Mlme.MemHandler.pUnUseHead != NULL) + { + pMlmeMemoryStruct = pAd->Mlme.MemHandler.pUnUseHead; + pAd->Mlme.MemHandler.pUnUseHead = pAd->Mlme.MemHandler.pUnUseHead->Next; + //Free the virtual address in AllocVa which size is MAX_LEN_OF_MLME_BUFFER + kfree(pMlmeMemoryStruct->AllocVa); + //Free the link list item self + kfree(pMlmeMemoryStruct); + } +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/mlme.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/mlme.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/mlme.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/mlme.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,504 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: mlme.h + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * John 28th Aug 03 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef __MLME_H__ +#define __MLME_H__ + +#include "oid.h" + +// maximum supported capability information - +// ESS, IBSS, Privacy, Short Preamble, Short Slot +#define SUPPORTED_CAPABILITY_INFO 0x0433 + +#define END_OF_ARGS -1 +#define LFSR_MASK 0x80000057 +#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps +#define MLME_TASK_EXEC_INTV 1000 // 1 sec + +#define BEACON_LOST_TIME (4*HZ) // 2048 msec = 2 sec + +//#define AUTH_KEY_TIMEOUT 500 // unit: msec +//#define AUTH_OPEN_TIMEOUT 200 // unit: msec +#define AUTH_TIMEOUT 300 // unit: msec +#define ASSOC_TIMEOUT 300 // unit: msec +#define JOIN_TIMEOUT 2000 // unit: msec +#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan +#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan +#define ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time +#define CW_MIN_IN_BITS 3 // actual CwMin = 2^CW_MIN_IN_BITS - 1 = 7 +#define CW_MAX_IN_BITS 8 // actual CwMax = 2^CW_MAX_IN_BITS - 1 = 255 + +#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm +#define RSSI_FOR_MID_TX_POWER 55 // -55 db is considered mid-distance +#define RSSI_FOR_LOW_TX_POWER 45 // -45 db is considered very short distance and + // eligible to use a lower TX power +#define RSSI_FOR_LOWEST_TX_POWER 30 +#define MID_TX_POWER_DELTA 0 // -3 db from full TX power upon mid-distance to AP +#define LOW_TX_POWER_DELTA 3 // -8 db from full TX power upon very short distance +#define LOWEST_TX_POWER_DELTA 6 // -12 db from full TX power upon shortest distance + +#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 +#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 +#define RSSI_THRESHOLD_FOR_ROAMING 25 +#define RSSI_DELTA 5 + +// Channel Quality Indication +//#define CQI_GOOD_THRESHOLD 70 // >= this threshold means channel quality GOOD +//#define CQI_FAIR_THRESHOLD 50 // >= this threshold means channel quality FAIR +//#define CQI_POOR_THRESHOLD 30 // >= this threshold means channel quality POOR + // < this threshold means channel quality really BAD, link down +#define CQI_IS_GOOD(cqi) ((cqi) >= 50) +#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) // (((cqi) >= 50) && ((cqi) < 70)) +#define CQI_IS_POOR(cqi) (((cqi) >= 5) && ((cqi) < 20)) // (((cqi) >= 25) && ((cqi) < 50)) +#define CQI_IS_BAD(cqi) ((cqi) < 5) // ((cqi) < 25) + +// weighting factor to calculate Channel quality, total should be 100% +#define RSSI_WEIGHTING 40 +#define TX_WEIGHTING 40 +#define RX_WEIGHTING 20 + +// prime number closest to 256 +//#define HASH_TABLE_SIZE 191 //191 is another prime +// Only allows 32 entries in the table +#define MAC_TABLE_MAX_CAPACITY 32 + +#define MAC_ENTRY_NOT_USED 0xff +#define CONTENT_NOT_AVAIL 0xaa + +// 10 minute of age out +#define MAC_TABLE_AGE_OUT_TIME 0xffffff + +#define MAC_ADDR_HASH_ERROR 0xfffffffe +#define MAC_TABLE_UNKNOWN_INDEX 0xff +#define MAC_TABLE_ADDR_NOT_IN 0xfffffffd + +#define PEER_KEY_NOT_USED 0 +#define PEER_KEY_64_BIT 64 +#define PEER_KEY_128_BIT 128 + +#define PEER_KEY_64BIT_LEN 8 +#define PEER_KEY_128BIT_LEN 16 + +#define MAX_LEN_OF_BSS_TABLE 64 +#define BSS_NOT_FOUND 0xFFFFFFFF + +#define MAX_LEN_OF_MLME_QUEUE 10 + +//! assoc state-machine states +#define ASSOC_IDLE 0 +#define ASSOC_WAIT_RSP 1 +#define REASSOC_WAIT_RSP 2 +#define DISASSOC_WAIT_RSP 3 +#define MAX_ASSOC_STATE 4 + +#define ASSOC_FUNC_SIZE 44 // 4-state * 12-event + +//authentication state machine +#define AUTH_REQ_IDLE 0 +#define AUTH_WAIT_SEQ2 1 +#define AUTH_WAIT_SEQ4 2 +#define MAX_AUTH_STATE 3 + +#define AUTH_FUNC_SIZE 15 // 3-state * 5-event + +#define AUTH_RSP_IDLE 0 +#define AUTH_RSP_WAIT_CHAL 1 +#define MAX_AUTH_RSP_STATE 2 + +#define AUTH_RSP_FUNC_SIZE 6 // 2-state * 3-event + +// SYNC state machine +#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state +#define JOIN_WAIT_BEACON 1 +#define SCAN_LISTEN 2 +#define MAX_SYNC_STATE 3 + +#define SYNC_FUNC_SIZE 30 // 3-state * 10-event + +#define SCAN_PASSIVE 18 +#define SCAN_ACTIVE 19 + +//WPA State machine +#define WPA_PSK_IDLE 0 +#define MAX_WPA_PSK_STATE 1 +#define WPA_PSK_FUNC_SIZE 5 + +// Control state machine +#define CNTL_IDLE 100 +#define CNTL_WAIT_DISASSOC 101 +#define CNTL_WAIT_JOIN 102 +#define CNTL_WAIT_REASSOC 103 +#define CNTL_WAIT_START 104 +#define CNTL_WAIT_AUTH 105 +#define CNTL_WAIT_ASSOC 106 +#define CNTL_WAIT_AUTH2 107 +#define CNTL_WAIT_OID_LIST_SCAN 108 +#define CNTL_WAIT_OID_DISASSOC 109 + +//#define BSS_TABLE_EMPTY(x) ((x).BssNr == 0) +#define CapabilityInfoGen(Ess,Ibss,Cfp,CfpReq,Priv) ((Ess) ? 0x0001 : 0x0000) | ((Ibss) ? 0x0002 : 0x0000) | ((Cfp) ? 0x0004 : 0x0000) | ((CfpReq) ? 0x0008 : 0x0000) | ((Priv) ? 0x0010: 0x0000) + +#define MAC_ADDR_IS_GROUP(Addr) ((((Addr).Octet[0]) & 0x01) != 0) +#define MAC_ADDR_HASH(Addr) ((Addr).Octet[0] ^ (Addr).Octet[1] ^ (Addr).Octet[2] ^ (Addr).Octet[3] ^ (Addr).Octet[4] ^ (Addr).Octet[5]) +#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) +#define MAC_ADDR_EQUAL(pAddr1,pAddr2) (memcmp((pAddr1), (pAddr2), ETH_ALEN) == 0) +#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), ETH_ALEN) +//#define MAKE_BROADCAST_ADDR(Addr) memset(&Addr, 0xff, ETH_ALEN) + +// LED Control +// assoiation ON. one LED ON. another blinking when TX, OFF when idle +#define ASIC_LED_ACT_ON(pAdapter) RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x0003461E) +// no association, both LED off +#define ASIC_LED_ACT_OFF(pAdapter) RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x0000461E) +//#define ASIC_LED_LINK_UP(pAdapter) RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x00011E46) +//#define ASIC_LED_LINK_DOWN(pAdapter) RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x00001E46) + +#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) +#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) +#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) +#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) +#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) + +// 802.11G capability features +#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) +#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) +#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) +#define CAP_IS_EXT_RATE_PBCC_ON(x) (((x) & 0x0100) != 0) +//#define CAP_IS_CCK_OFDM_ON(x) (((x) & 0x0200) != 0) +#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // defined in 802.11e d4.3 +#define CAP_IS_SHORT_SLOT_TIME(x) (((x) & 0x0400) != 0) +#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // defined in 802.11e d4.3 +#define CAP_IS_Q_ACK(x) (((x) & 0x1000) != 0) // defined in 802.11e d4.3 +#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) +#define CAP_IS_BLOCK_ACK(x) (((x) & 0x4000) != 0) // defined in 802.11e d4.3 + +#define CAP_GENERATE(ess,ibss,cfp,cfpreq,priv,prea) ((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((cfp) ? 0x0004 : 0x0000) | ((cfpreq) ? 0x0008 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((prea) ? 0x0020 : 0x0000) + +#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // define in 802.11g +#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // define in 802.11g +#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // define in 802.11g + +#define TX_FER_TOO_HIGH(TxFER) ((TxFER) > 15) // consider rate down if FER>15% +#define TX_FER_VERY_LOW(TxFER) ((TxFER) < 7) // consider rate up if FER<7% +#define FAIR_FER 10 // any value between TOO_HIGH and VERY_LOW +#define DRS_TX_QUALITY_WORST_BOUND 3 +#define DRS_PENALTY 8 + +// Ralink timer control block +typedef struct _RALINK_TIMER_STRUCT { + struct timer_list TimerObj; // Ndis Timer object + ULONG TimerValue; // Timer value in milliseconds + BOOLEAN State; // True if timer cancelled + BOOLEAN Repeat; // True if periodic timer +} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; + +// Mac Address data structure +typedef struct PACKED _MACADDR { + UCHAR Octet[ETH_ALEN]; +} MACADDR, *PMACADDR; + +// Mac Frame Header +typedef struct PACKED _MACHDR { + // 2-byte Frame Control. NOTE: bit field assigned from LSB first +#ifdef BIG_ENDIAN + USHORT Order:1; + USHORT Wep:1; + USHORT MoreData:1; + USHORT PwrMgmt:1; + USHORT Retry:1; + USHORT MoreFrag:1; + USHORT Frds:1; + USHORT Tods:1; + USHORT SubType:4; + USHORT Type:2; + USHORT Ver:2; +#else + USHORT Ver:2; + USHORT Type:2; + USHORT SubType:4; + USHORT Tods:1; + USHORT Frds:1; + USHORT MoreFrag:1; + USHORT Retry:1; + USHORT PwrMgmt:1; + USHORT MoreData:1; + USHORT Wep:1; + USHORT Order:1; +#endif + + USHORT Duration; + MACADDR Addr1; + MACADDR Addr2; + MACADDR Addr3; + +#ifdef BIG_ENDIAN + USHORT Seq:12; + USHORT Frag:4; +#else + USHORT Frag:4; + USHORT Seq:12; +#endif +} MACHDR, *PMACHDR; + +typedef struct PACKED _MACFRAME { + MACHDR Hdr; + CHAR Octet[1]; +} MACFRAME, *PMACFRAME; + +typedef struct PACKED _PSPOLL_FRAME { + USHORT Ver:2; + USHORT Type:2; + USHORT SubType:4; + USHORT Tods:1; + USHORT Frds:1; + USHORT MoreFrag:1; + USHORT Retry:1; + USHORT PwrMgmt:1; + USHORT MoreData:1; + USHORT Wep:1; + USHORT Order:1; + + USHORT Aid; + MACADDR Bssid; + MACADDR Ta; +} PSPOLL_FRAME; + +// +// Contention-free parameter (without ID and Length) +// +typedef struct PACKED _CF_PARM { + UCHAR CfpCount; + UCHAR CfpPeriod; + USHORT CfpMaxDuration; + USHORT CfpDurRemaining; +} CF_PARM, *PCF_PARM; + + +typedef struct PACKED _BSS_ENTRY{ + MACADDR Bssid; + UCHAR Channel; + UCHAR BssType; + USHORT AtimWin; + USHORT BeaconPeriod; + + UCHAR Rates[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR RatesLen; + BOOLEAN ExtendedRateIeExist; // records if this AP use EXTENDED_SUPPORTED_RATES IE + UCHAR Rssi; + UCHAR Noise; + UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. + UCHAR Hidden; + + USHORT DtimPeriod; + USHORT CapabilityInfo; + + USHORT CfpCount; + USHORT CfpPeriod; + USHORT CfpMaxDuration; + USHORT CfpDurRemaining; + UCHAR SsidLen; + CHAR Ssid[MAX_LEN_OF_SSID]; + + ULONG LastBeaconRxTime; // OS's timestamp + + // New for microsoft WPA support + NDIS_802_11_FIXED_IEs FixIEs; + NDIS_802_11_WEP_STATUS WepStatus; + UCHAR VarIELen; // Length of next VIE include EID & Length + UCHAR VarIEs[MAX_VIE_LEN]; +} BSS_ENTRY, *PBSS_ENTRY; + +typedef struct { + UCHAR BssNr; + BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; +} BSS_TABLE, *PBSS_TABLE; + +typedef struct PACKED _MLME_QUEUE_ELEM { + ULONG Machine; + ULONG MsgType; + ULONG MsgLen; + LARGE_INTEGER TimeStamp; + UCHAR Msg[MAX_LEN_OF_MLME_BUFFER]; + UCHAR Rssi; + UCHAR Noise; + UCHAR Channel; + BOOLEAN Occupied; +} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; + +typedef struct PACKED _MLME_QUEUE { + ULONG Num; + ULONG Head; + ULONG Tail; + spinlock_t Lock; + MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; +} MLME_QUEUE, *PMLME_QUEUE; + +typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); + +typedef struct PACKED _STATE_MACHINE { + ULONG Base; + ULONG NrState; + ULONG NrMsg; + ULONG CurrState; + STATE_MACHINE_FUNC *TransFunc; +} STATE_MACHINE, *PSTATE_MACHINE; + +// CNTL State Machine Aux data structure +typedef struct _CNTL_AUX { + UCHAR Ssid[MAX_LEN_OF_SSID]; + UCHAR SsidLen; + MACADDR Bssid; + BSS_TABLE SsidBssTab; // AP list for the same SSID + BSS_TABLE RoamTab; // AP list eligible for roaming + ULONG BssIdx; + ULONG RoamIdx; + BOOLEAN CurrReqIsFromNdis; // TRUE - then we should call NdisMSetInformationComplete() + // FALSE - req is from driver itself. + // no NdisMSetInformationComplete() is required +} CNTL_AUX, *PCNTL_AUX; + +// ASSOC State Machine Aux data structure +typedef struct _ASSOC_AUX { + MACADDR Addr; + USHORT CapabilityInfo; + USHORT ListenIntv; + CHAR Ssid[MAX_LEN_OF_SSID]; + UCHAR SsidLen; + RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; +} ASSOC_AUX, *PASSOC_AUX; + +// AUTH State Machine Aux data structure +typedef struct _AUTH_AUX { + MACADDR Addr; + USHORT Alg; + RALINK_TIMER_STRUCT AuthTimer; +} AUTH_AUX, *PAUTH_AUX; + +// AUTH-RSP State Machine Aux data structure +typedef struct PACKED _AUTH_RSP_AUX { + MACADDR Addr; + USHORT Alg; + CHAR Challenge[CIPHER_TEXT_LEN]; + RALINK_TIMER_STRUCT AuthRspTimer; +} AUTH_RSP_AUX, *PAUTH_RSP_AUX; + +// SYNC State Machine Aux data structure +typedef struct _SYNC_AUX { + MACADDR Addr; + MACADDR Bssid; + UCHAR BssType; + UCHAR SsidLen; + CHAR Ssid[MAX_LEN_OF_SSID]; + UCHAR ScanType; + UCHAR Channel; + RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; +} SYNC_AUX; + + // assoc struct is equal to reassoc +typedef struct PACKED _MLME_ASSOC_REQ_STRUCT{ + MACADDR Addr; + USHORT CapabilityInfo; + USHORT ListenIntv; + ULONG Timeout; +} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; + +typedef struct PACKED _MLME_DISASSOC_REQ_STRUCT{ + MACADDR Addr; + USHORT Reason; +} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; + +typedef struct PACKED _MLME_AUTH_REQ_STRUCT { + MACADDR Addr; + USHORT Alg; + ULONG Timeout; +} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; + +typedef struct PACKED _MLME_DEAUTH_REQ_STRUCT { + MACADDR Addr; + USHORT Reason; +} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; + +//typedef struct _MLME_AUTH_IND_STRUCT { +// MACADDR Addr; +// USHORT Alg; +//} MLME_AUTH_IND_STRUCT, *PMLME_AUTH_IND_STRUCT; + +//typedef struct _CLS2ERR_STRUCT { +// MACADDR Addr; +//} CLS2ERR_STRUCT, *PCLS2ERR_STRUCT; + +typedef struct PACKED _MLME_JOIN_REQ_STRUCT{ + ULONG BssIdx; +} MLME_JOIN_REQ_STRUCT; + +typedef struct PACKED _MLME_SCAN_REQ_STRUCT { + MACADDR Bssid; + UCHAR BssType; + UCHAR ScanType; + UCHAR SsidLen; + CHAR Ssid[MAX_LEN_OF_SSID]; +} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; + +typedef struct PACKED _MLME_START_REQ_STRUCT { + CHAR Ssid[MAX_LEN_OF_SSID]; + UCHAR SsidLen; +} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; + +typedef struct PACKED _ARC4_CONTEXT { + UCHAR x, y, State[256], Key[16]; // 128 bits key +} ARC4_CONTEXT, *PARC4_CONTEXT; + +typedef struct PACKED _BEACON_EID_STRUCT { + UCHAR Eid; + UCHAR Len; + CHAR Octet[1]; +} BEACON_EID_STRUCT,*PBEACON_EID_STRUCT; + +// New for WPA cipher suite +typedef struct PACKED _RSN_EID_STRUCT { + UCHAR Eid; + UCHAR Length; + UCHAR Oui[4]; + USHORT Version; + UCHAR Multicast[4]; + USHORT Count; + struct { + UCHAR Oui[4]; + } Unicast[1]; +} RSN_EID_STRUCT, *PRSN_EID_STRUCT; + +extern UCHAR RateIdToMbps[]; +extern USHORT RateIdTo500Kbps[]; + +#endif // MLME_H__ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/oid.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/oid.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/oid.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/oid.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,502 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: oid.h + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * RobinC 10th Dec 04 RFMON Support + ***************************************************************************/ + +#ifndef _OID_H_ +#define _OID_H_ + +#if WIRELESS_EXT <= 11 +#ifndef SIOCDEVPRIVATE +#define SIOCDEVPRIVATE 0x8BE0 +#endif +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif + +#define RT_PRIV_IOCTL SIOCIWFIRSTPRIV + 0x01 +#define RTPRIV_IOCTL_SET SIOCIWFIRSTPRIV + 0x02 + +// +// IEEE 802.11 OIDs +// + +// Ralink defined OIDs +#define RT_PRIV_IOCTL SIOCIWFIRSTPRIV + 0x01 +#define RTPRIV_IOCTL_SET SIOCIWFIRSTPRIV + 0x02 + +#define RTPRIV_IOCTL_BBP SIOCIWFIRSTPRIV + 0x03 +#define RTPRIV_IOCTL_MAC SIOCIWFIRSTPRIV + 0x05 +#define RTPRIV_IOCTL_E2P SIOCIWFIRSTPRIV + 0x07 +#define RTPRIV_IOCTL_RFMONTX SIOCIWFIRSTPRIV + 0x0D + +#define OID_GET_SET_TOGGLE 0x8000 + +#define OID_802_11_BSSID 0x0101 +#define OID_802_11_SSID 0x0102 +#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 +#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 +#define OID_802_11_TX_POWER_LEVEL 0x0105 +#define OID_802_11_RSSI 0x0106 +#define OID_802_11_RSSI_TRIGGER 0x0107 +#define OID_802_11_INFRASTRUCTURE_MODE 0x0108 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0109 +#define OID_802_11_RTS_THRESHOLD 0x010A +#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B +#define OID_802_11_RX_ANTENNA_SELECTED 0x010C +#define OID_802_11_TX_ANTENNA_SELECTED 0x010D +#define OID_802_11_SUPPORTED_RATES 0x010E +#define OID_802_11_DESIRED_RATES 0x010F +#define OID_802_11_CONFIGURATION 0x0110 +#define OID_802_11_STATISTICS 0x0111 +#define OID_802_11_ADD_WEP 0x0112 +#define OID_802_11_REMOVE_WEP 0x0113 +#define OID_802_11_DISASSOCIATE 0x0114 +#define OID_802_11_POWER_MODE 0x0115 +#define OID_802_11_BSSID_LIST 0x0116 +#define OID_802_11_AUTHENTICATION_MODE 0x0117 +#define OID_802_11_PRIVACY_FILTER 0x0118 +#define OID_802_11_BSSID_LIST_SCAN 0x0119 +#define OID_802_11_WEP_STATUS 0x011A +// Renamed to reflect better the extended set of encryption status +#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS +#define OID_802_11_RELOAD_DEFAULTS 0x011B +// Added to allow key mapping and default keys +#define OID_802_11_ADD_KEY 0x011C +#define OID_802_11_REMOVE_KEY 0x011D +#define OID_802_11_ASSOCIATION_INFORMATION 0x011E +#define OID_802_11_TEST 0x011F + +#define OID_802_3_CURRENT_ADDRESS 0x0120 +#define OID_GEN_RCV_OK 0x0121 +#define OID_GEN_RCV_NO_BUFFER 0x0122 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x0123 + +#define RT_OID_DEVICE_NAME 0x0200 +#define RT_OID_802_11_PREAMBLE 0x0201 +#define RT_OID_802_11_LINK_STATUS 0x0202 +#define RT_OID_802_11_RESET_COUNTERS 0x0203 +#define RT_OID_802_11_AC_CAM 0x0204 +#define RT_OID_802_11_HARDWARE_REGISTER 0x0205 +#define RT_OID_802_11_RACONFIG 0x0206 +#define RT_OID_802_11_COUNTRY_REGION 0x0207 +#define RT_OID_802_11_RADIO 0x0208 +#define RT_OID_802_11_RX_AGC_VGC_TUNING 0x0209 +#define RT_OID_802_11_EVENT_TABLE 0x0210 +#define RT_OID_802_11_MAC_TABLE 0x0211 +#define RT_OID_802_11_PHY_MODE 0x0212 +#define RT_OID_802_11_TX_PACKET_BURST 0x0213 +#define RT_OID_802_11_TURBO_MODE 0x0214 +#define RT_OID_802_11_AP_CONFIG 0x0215 +#define RT_OID_802_11_ACL 0x0216 +#define RT_OID_802_11_STA_CONFIG 0x0217 +#define RT_OID_VERSION_INFO 0x0218 + +#define RT_OID_802_11_WDS 0x0219 +#define RT_OID_802_11_RADIUS_DATA 0x0220 +#define RT_OID_802_11_WPA_REKEY 0x0221 + +#define RT_OID_802_11_ADD_WPA 0x0222 + +#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0223 + +// +// IEEE 802.11 Structures and definitions +// +// new types for Media Specific Indications + +#define NDIS_802_11_LENGTH_SSID 32 +#define NDIS_802_11_LENGTH_RATES 8 +#define NDIS_802_11_LENGTH_RATES_EX 16 + +typedef enum _NDIS_802_11_STATUS_TYPE +{ + Ndis802_11StatusType_Authentication, + Ndis802_11StatusTypeMax // not a real type, defined as an upper bound +} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; + +typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; + +typedef struct _NDIS_802_11_STATUS_INDICATION +{ + NDIS_802_11_STATUS_TYPE StatusType; +} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; + +// mask for authentication/integrity fields +#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f + +#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 +#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 +#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E + +typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST +{ + ULONG Length; // Length of structure + NDIS_802_11_MAC_ADDRESS Bssid; + ULONG Flags; +} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; + +// Added new types for OFDM 5G and 2.4G +typedef enum _NDIS_802_11_NETWORK_TYPE +{ + Ndis802_11FH, + Ndis802_11DS, + Ndis802_11OFDM5, + Ndis802_11OFDM24, + Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound +} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; + +typedef struct PACKED _NDIS_802_11_NETWORK_TYPE_LIST +{ + ULONG NumberOfItems; // in list below, at least 1 + NDIS_802_11_NETWORK_TYPE NetworkType [1]; +} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; + +typedef enum _NDIS_802_11_POWER_MODE +{ + Ndis802_11PowerModeCAM, + Ndis802_11PowerModeMAX_PSP, + Ndis802_11PowerModeFast_PSP, + Ndis802_11PowerModeMax // not a real mode, defined as an upper bound +} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; + +typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts + +// +// Received Signal Strength Indication +// +typedef LONG NDIS_802_11_RSSI; // in dBm + +typedef struct _NDIS_802_11_CONFIGURATION_FH +{ + ULONG Length; // Length of structure + ULONG HopPattern; // As defined by 802.11, MSB set + ULONG HopSet; // to one if non-802.11 + ULONG DwellTime; // units are Kusec +} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; + +typedef struct _NDIS_802_11_CONFIGURATION +{ + ULONG Length; // Length of structure + ULONG BeaconPeriod; // units are Kusec + ULONG ATIMWindow; // units are Kusec + ULONG DSConfig; // Frequency, units are kHz + NDIS_802_11_CONFIGURATION_FH FHConfig; +} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; + +typedef struct _NDIS_802_11_STATISTICS +{ + ULONG Length; // Length of structure + LARGE_INTEGER TransmittedFragmentCount; + LARGE_INTEGER MulticastTransmittedFrameCount; + LARGE_INTEGER FailedCount; + LARGE_INTEGER RetryCount; + LARGE_INTEGER MultipleRetryCount; + LARGE_INTEGER RTSSuccessCount; + LARGE_INTEGER RTSFailureCount; + LARGE_INTEGER ACKFailureCount; + LARGE_INTEGER FrameDuplicateCount; + LARGE_INTEGER ReceivedFragmentCount; + LARGE_INTEGER MulticastReceivedFrameCount; + LARGE_INTEGER FCSErrorCount; +} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; + +typedef ULONG NDIS_802_11_KEY_INDEX; +typedef ULONGLONG NDIS_802_11_KEY_RSC; + +// Key mapping keys require a BSSID +typedef struct _NDIS_802_11_KEY +{ + ULONG Length; // Length of this structure + ULONG KeyIndex; + ULONG KeyLength; // length of key in bytes + NDIS_802_11_MAC_ADDRESS BSSID; + NDIS_802_11_KEY_RSC KeyRSC; + UCHAR KeyMaterial[1]; // variable length depending on above field +} NDIS_802_11_KEY, *PNDIS_802_11_KEY; + +typedef struct _NDIS_802_11_REMOVE_KEY +{ + ULONG Length; // Length of this structure + ULONG KeyIndex; + NDIS_802_11_MAC_ADDRESS BSSID; +} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; + +typedef struct PACKED _NDIS_802_11_WEP +{ + ULONG Length; // Length of this structure + ULONG KeyIndex; // 0 is the per-client key, 1-N are the + // global keys + ULONG KeyLength; // length of key in bytes + UCHAR KeyMaterial[1];// variable length depending on above field +} NDIS_802_11_WEP, *PNDIS_802_11_WEP; + + +typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE +{ + Ndis802_11IBSS, + Ndis802_11Infrastructure, + Ndis802_11AutoUnknown, + Ndis802_11Monitor, + Ndis802_11InfrastructureMax // Not a real value, defined as upper bound +} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; + +// Add new authentication modes +typedef enum _NDIS_802_11_AUTHENTICATION_MODE +{ + Ndis802_11AuthModeOpen, + Ndis802_11AuthModeShared, + Ndis802_11AuthModeAutoSwitch, + Ndis802_11AuthModeWPA, + Ndis802_11AuthModeWPAPSK, + Ndis802_11AuthModeWPANone, + Ndis802_11AuthModeMax // Not a real mode, defined as upper bound +} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; + +typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates +typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates + +typedef struct PACKED _NDIS_802_11_SSID +{ + ULONG SsidLength; // length of SSID field below, in bytes; + // this can be zero. + UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field +} NDIS_802_11_SSID, *PNDIS_802_11_SSID; + + +typedef struct PACKED _NDIS_WLAN_BSSID +{ + ULONG Length; // Length of this structure + NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID + UCHAR Reserved[2]; + NDIS_802_11_SSID Ssid; // SSID + ULONG Privacy; // WEP encryption requirement + NDIS_802_11_RSSI Rssi; // receive signal + // strength in dBm + NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + NDIS_802_11_CONFIGURATION Configuration; + NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + NDIS_802_11_RATES SupportedRates; +} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; + +typedef struct PACKED _NDIS_802_11_BSSID_LIST +{ + ULONG NumberOfItems; // in list below, at least 1 + NDIS_WLAN_BSSID Bssid[1]; +} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; + +// Added Capabilities, IELength and IEs for each BSSID +typedef struct _NDIS_WLAN_BSSID_EX +{ + ULONG Length; // Length of this structure + NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID + UCHAR Reserved[2]; + NDIS_802_11_SSID Ssid; // SSID + ULONG Privacy; // WEP encryption requirement + NDIS_802_11_RSSI Rssi; // receive signal + // strength in dBm + NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + NDIS_802_11_CONFIGURATION Configuration; + NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + NDIS_802_11_RATES_EX SupportedRates; + ULONG IELength; + UCHAR IEs[1]; +} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; + +typedef struct _NDIS_802_11_BSSID_LIST_EX +{ + ULONG NumberOfItems; // in list below, at least 1 + NDIS_WLAN_BSSID_EX Bssid[1]; +} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; + +typedef struct _NDIS_802_11_FIXED_IEs +{ + UCHAR Timestamp[8]; + USHORT BeaconInterval; + USHORT Capabilities; +} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; + +typedef struct _NDIS_802_11_VARIABLE_IEs +{ + UCHAR ElementID; + UCHAR Length; // Number of bytes in data field + UCHAR data[1]; +} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; + +typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; + +typedef ULONG NDIS_802_11_RTS_THRESHOLD; + +typedef ULONG NDIS_802_11_ANTENNA; + +typedef enum _NDIS_802_11_PRIVACY_FILTER +{ + Ndis802_11PrivFilterAcceptAll, + Ndis802_11PrivFilter8021xWEP +} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; + +// Added new encryption types +// Also aliased typedef to new name +typedef enum _NDIS_802_11_WEP_STATUS +{ + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11Encryption2Enabled, + Ndis802_11Encryption2KeyAbsent, + Ndis802_11Encryption3Enabled, + Ndis802_11Encryption3KeyAbsent +} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, + NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; + +typedef enum _NDIS_802_11_RELOAD_DEFAULTS +{ + Ndis802_11ReloadWEPKeys +} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; + +#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 +#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 +#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 + +#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 +#define NDIS_802_11_AI_RESFI_STATUSCODE 2 +#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 + +typedef struct _NDIS_802_11_AI_REQFI +{ + USHORT Capabilities; + USHORT ListenInterval; + NDIS_802_11_MAC_ADDRESS CurrentAPAddress; +} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; + +typedef struct _NDIS_802_11_AI_RESFI +{ + USHORT Capabilities; + USHORT StatusCode; + USHORT AssociationId; +} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; + +typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION +{ + ULONG Length; + USHORT AvailableRequestFixedIEs; + NDIS_802_11_AI_REQFI RequestFixedIEs; + ULONG RequestIELength; + ULONG OffsetRequestIEs; + USHORT AvailableResponseFixedIEs; + NDIS_802_11_AI_RESFI ResponseFixedIEs; + ULONG ResponseIELength; + ULONG OffsetResponseIEs; +} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; + +typedef struct _NDIS_802_11_AUTHENTICATION_EVENT +{ + NDIS_802_11_STATUS_INDICATION Status; + NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; +} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; + +typedef struct _NDIS_802_11_TEST +{ + ULONG Length; + ULONG Type; + union + { + NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; + NDIS_802_11_RSSI RssiTrigger; + }tt; +} NDIS_802_11_TEST, *PNDIS_802_11_TEST; + +typedef enum _RT_802_11_PREAMBLE { + Rt802_11PreambleLong, + Rt802_11PreambleShort, + Rt802_11PreambleAuto +} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; + +typedef enum _RT_802_11_PHY_MODE { + PHY_11BG_MIXED, + PHY_11B, + PHY_11A, + PHY_11ABG_MIXED +} RT_802_11_PHY_MODE; + +// put all proprietery for-query objects here to reduce # of Query_OID +typedef struct _RT_802_11_LINK_STATUS { + ULONG CurrTxRate; // in units of 0.5Mbps + ULONG ChannelQuality; // 0..100 % + ULONG TxByteCount; // both ok and fail + ULONG RxByteCount; // both ok and fail +} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; + +// structure for query/set hardware register - MAC, BBP, RF register +typedef struct _RT_802_11_HARDWARE_REGISTER { + ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register + ULONG Offset; // Q/S register offset addr + ULONG Data; // R/W data buffer +} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; + +// structure to tune BBP R17 "RX AGC VGC init" +typedef struct _RT_802_11_RX_AGC_VGC_TUNING { + UCHAR FalseCcaLowerThreshold; // 0-255, def 10 + UCHAR FalseCcaUpperThreshold; // 0-255, def 100 + UCHAR VgcDelta; // R17 +-= VgcDelta whenever flase CCA over UpprThreshold + // or lower than LowerThresholdupper threshold + UCHAR VgcUpperBound; // max value of R17 +} RT_802_11_RX_AGC_VGC_TUNING, *PRT_802_11_RX_AGC_VGC_TUNING; + +// structure to query/set STA_CONFIG +typedef struct _RT_802_11_STA_CONFIG { + ULONG EnableTxBurst; // 0-disable, 1-enable + ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate + ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF + ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable + ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - allow OFDM rates + ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only + ULONG Rsv1; // must be 0 + ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY +} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; + +typedef struct PACKED _RT_VERSION_INFO{ + UCHAR DriverVersionW; + UCHAR DriverVersionX; + UCHAR DriverVersionY; + UCHAR DriverVersionZ; + UINT DriverBuildYear; + UINT DriverBuildMonth; + UINT DriverBuildDay; +} RT_VERSION_INFO, *PRT_VERSION_INFO; + +#endif diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rt2560.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/rt2560.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rt2560.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rt2560.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1520 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rt2560.h + * + * Abstract: RT2560 ASIC related definition & structures + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + ***************************************************************************/ + +#ifndef __RT2560_H__ +#define __RT2560_H__ + +// +// Control/Status Registers (CSR) +// +#define CSR0 0x0000 // ASIC revision number +#define CSR1 0x0004 // System control register +#define CSR2 0x0008 // System admin status register (invalid) +#define CSR3 0x000C // STA MAC address register 0 +#define CSR4 0x0010 // STA MAC address register 1 +#define CSR5 0x0014 // BSSID register 0 +#define CSR6 0x0018 // BSSID register 1 +#define CSR7 0x001C // Interrupt source register +#define CSR8 0x0020 // Interrupt mask register +#define CSR9 0x0024 // Maximum frame length register +#define CSR11 0x002C // Back-off control register +#define CSR12 0x0030 // Synchronization configuration register 0 +#define CSR13 0x0034 // Synchronization configuration register 1 +#define CSR14 0x0038 // Synchronization control register +#define CSR15 0x003C // Synchronization status register +#define CSR16 0x0040 // TSF timer register 0 +#define CSR17 0x0044 // TSF timer register 1 +#define CSR18 0x0048 // IFS timer register 0 +#define CSR19 0x004C // IFS timer register 1 +#define CSR20 0x0050 // WakeUp register +#define CSR21 0x0054 // EEPROM control register +#define CSR22 0x0058 // CFP Control Register + +// Security coprocessor registers +#define SECCSR0 0x0028 // WEP control register +#define SECCSR1 0x0158 // WEP control register +#define SECCSR3 0x00fc // AES control register + +// Transmit related CSRs +#define TXCSR0 0x0060 // TX cintrol register +#define TXCSR1 0x0064 // TX configuration register +#define TXCSR2 0x0068 // TX descriptor configuratioon register +#define TXCSR3 0x006C // TX Ring Base address register +#define TXCSR4 0x0070 // Atim Ring Base address register +#define TXCSR5 0x0074 // Prio Ring Base address register +#define TXCSR6 0x0078 // Beacon base address +#define TXCSR7 0x007C // AutoResponder Control Register +#define TXCSR8 0x0098 // CCK TX BBP registers +#define TXCSR9 0x0094 // OFDM TX BBP registers + +// Receive related CSRs +#define RXCSR0 0x0080 // RX control register +#define RXCSR1 0x0084 // RX descriptorconfiguration register +#define RXCSR2 0x0088 // RX Ring base address register +#define RXCSR3 0x0090 // BBP ID register 0 +//#define RXCSR4 0x0094 // BBP ID register 1 +//#define ARCSR0 0x0098 // Auto responder PLCP config register 1 +#define ARCSR1 0x009C // Auto responder PLCP config register 1 + +// PCI control CSRs +#define PCICSR 0x008C // PCI control register + +// +// Alias to all ring base registers. Easier to understand constant definition +// within codes. +// +#define RX_RING_BASE_REG (RXCSR2) +#define TX_RING_BASE_REG (TXCSR3) +#define ATIM_RING_BASE_REG (TXCSR4) +#define PRIO_RING_BASE_REG (TXCSR5) +#define BEACON_BASE_REG (TXCSR6) + +// Statistic Register +#define CNT0 0x00A0 // Dot11 FCS error count +#define CNT1 0x00AC // Dot11 PLCP error count +#define CNT2 0x00B0 // Dot11 long error count +#define CNT3 0x00B8 // Dot11 CCA false alarm count +#define CNT4 0x00BC // Dot11 Rx FIFO overflow count +#define CNT5 0x00C0 // Dot11 Tx FIFO underrun count + +// Baseband Control Register +#define PWRCSR0 0x00C4 +#define PSCSR0 0x00C8 +#define PSCSR1 0x00CC +#define PSCSR2 0x00D0 +#define PSCSR3 0x00D4 +#define PWRCSR1 0x00D8 +#define TIMECSR 0x00DC +#define MACCSR0 0x00E0 +#define MACCSR1 0x00E4 +#define RALINKCSR 0x00E8 // Ralink Auto-reset register +#define BCNCSR 0x00EC + +// BBP/RF/IF Control Register +#define BBPCSR 0x00F0 +#define RFCSR 0x00F4 +#define LEDCSR 0x00F8 + +// ASIC pointer information +#define RXPTR 0x0100 // Current RX ring address +#define TXPTR 0x0104 // Current Tx ring address +#define PRIPTR 0x0108 // Current Priority ring address +#define ATIMPTR 0x010c // Current ATIM ring address + +// some others +#define TXACKCSR0 0x0110 // TX ACK timeout +#define ACKCNT0 0x0114 // TX ACK timeout count +#define ACKCNT1 0x0118 // RX ACK timeout count + +// GPIO and others +#define GPIOCSR 0x0120 // GPIO direction & in/out +#define FIFOCSR0 0x0128 // TX FIFO pointer +#define FIFOCSR1 0x012C // RX FIFO pointer +#define BCNCSR1 0x0130 // Tx BEACON offset time, unit: 1 usec +#define MACCSR2 0x0134 // TX_PE to RX_PE delay time, unit: 1 PCI clock cycle +#define TESTCSR 0x0138 // TEST mode selection register + +#define PLCP1MCSR 0x013c // 1 Mbps ACK/CTS PLCP +#define PLCP2MCSR 0x0140 // 2 Mbps ACK/CTS PLCP +#define PLCP5MCSR 0x0144 // 5.5 Mbps ACK/CTS PLCP +#define PLCP11MCSR 0x0148 // 11 Mbps ACK/CTS PLCP + +#define ARTCSR0 0x014c // ACK/CTS payload consumed time for 1/2/5.5/11 mbps +#define ARTCSR1 0x0150 // OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps +#define ARTCSR2 0x0154 // OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps +#define SECCSR1 0x0158 // security control register +#define BBPCSR1 0x015c // BBP TX configuration + +#define DBANDCSR0 0x0160 // Dual band configuration register 0 +#define DBANDCSR1 0x0164 // Dual band configuration register 1 +#define BBPPCSR 0x0168 // BBP pin control register +#define DBGSEL0 0x016c // MAC special debug mode selection register 0 +#define DBGSEL1 0x0170 // MAC special debug mode selection register 1 +#define BISTCSR 0x0174 // BBP BIST register + +#define MCAST0 0x0178 // multicast filter register 0 +#define MCAST1 0x017c // multicast filter register 1 + +#define UARTCSR0 0x0180 // UART1 TX register +#define UARTCSR1 0x0184 // UART1 RX register +#define UARTCSR3 0x0188 // UART1 frame control register +#define UARTCSR4 0x018c // UART1 buffer control register +#define UART2CSR0 0x0190 // UART2 TX register +#define UART2CSR1 0x0194 // UART2 RX register +#define UART2CSR3 0x0198 // UART2 frame control register +#define UART2CSR4 0x019c // UART2 buffer control register + +#define TIMECSR2 0x00a8 +#define TIMECSR3 0x00b4 + +// +// Tx / Rx / Prio / Atim ring descriptor definition +// +#define DESC_OWN_HOST 0 +#define DESC_OWN_NIC 1 +#define DESC_VALID_TRUE 1 +#define DESC_VALID_FALSE 0 + +// +// BBP & RF definition +// +#define BUSY 1 +#define IDLE 0 + +#define BBP_Version 0x00 +#define BBP_Tx_Configure 2 // R2 +#define BBP_Tx_Tssi 1 // R1 +#define BBP_Rx_Configure 14 // R14 + +#define PHY_TR_SWITCH_TIME 5 // usec + +#define RT2560_VER_B 2 +#define RT2560_VER_C 3 +#define RT2560_VER_D 4 +#define BBP_R17_LOW_SENSIBILITY 0x50 +#define BBP_R17_MID_SENSIBILITY 0x41 +#define BBP_R17_DYNAMIC_UP_BOUND 0x40 +#define RSSI_FOR_LOW_SENSIBILITY -58 +#define RSSI_FOR_MID_SENSIBILITY -74 +//#define RSSI_HIGH_WATERMARK -53 +//#define RSSI_LOW_WATERMARK -58 + +//------------------------------------------------------------------------- +// EEPROM definition +//------------------------------------------------------------------------- +#define EEDO 0x10 +#define EEDI 0x08 +#define EECS 0x04 +#define EESK 0x02 +#define EERL 0x01 + +#define EEPROM_WRITE_OPCODE 0x05 +#define EEPROM_READ_OPCODE 0x06 +#define EEPROM_EWDS_OPCODE 0x10 +#define EEPROM_EWEN_OPCODE 0x13 + +#define NUM_EEPROM_BBP_PARMS 19 +#define NUM_EEPROM_TX_PARMS 7 +#define EEPROM_BBP_BASE_OFFSET 0x20 // 0x16 +#define EEPROM_TX_PWR_OFFSET 0x46 // 0x3c +#define EEPROM_TSSI_REF_OFFSET 0x54 +#define EEPROM_TSSI_DELTA_OFFSET 0x24 +#define EEPROM_CALIBRATE_OFFSET 0x7c +#define EEPROM_VERSION_OFFSET 0x7e +#define VALID_EEPROM_VERSION 1 + +// ================================================================================= +// TX / RX ring descriptor format +// ================================================================================= + +// +// TX descriptor format, Tx ring, Atim ring & Priority Ring +// +typedef struct _TXD_STRUC { + // Word 0 +#ifdef BIG_ENDIAN + ULONG CipherAlg:3; + ULONG Rsv1:1; //RTS:1; + ULONG DataByteCnt:12; + ULONG RetryMd:1; + ULONG IFS:2; + ULONG CipherOwn:1; + ULONG Ofdm:1; + ULONG Timestamp:1; + ULONG ACK:1; + ULONG MoreFrag:1; // More fragment following this tx ring + ULONG RetryCount:3; // Retry result + ULONG TxResult:3; // Filled by MAC ASIC + ULONG Valid:1; // Entry valid bit + ULONG Owner:1; // Descriptor owner bit +#else + ULONG Owner:1; // Descriptor owner bit + ULONG Valid:1; // Entry valid bit + ULONG TxResult:3; // Filled by MAC ASIC + ULONG RetryCount:3; // Retry result + ULONG MoreFrag:1; // More fragment following this tx ring + ULONG ACK:1; + ULONG Timestamp:1; + ULONG Ofdm:1; + ULONG CipherOwn:1; + ULONG IFS:2; + ULONG RetryMd:1; + ULONG DataByteCnt:12; + ULONG Rsv1:1; //RTS:1; + ULONG CipherAlg:3; +#endif + + // Word 1 + ULONG BufferAddressPa; + + // Word 2 +#ifdef BIG_ENDIAN + ULONG Rsv2:16; + ULONG CWmax:4; + ULONG CWmin:4; + ULONG Aifs:2; + ULONG IvOffset:6; +#else + ULONG IvOffset:6; + ULONG Aifs:2; + ULONG CWmin:4; + ULONG CWmax:4; + ULONG Rsv2:16; +#endif + + // Word 3 + ULONG PlcpSignal:8; + ULONG PlcpService:8; + ULONG PlcpLengthLow:8; + ULONG PlcpLengthHigh:8; + + // Word 4 + ULONG Iv; + + // Word 5 + ULONG Eiv; + + // Word 6-9 + UCHAR Key[16]; + + // Word 10 - 11 Reserved, not necessary to put into the structure. +#ifdef BIG_ENDIAN + ULONG Rsv3:24; + ULONG TxRate:7; // for software use to track per-rate TX result, RATE_1, ... + ULONG RTS:1; +#else + ULONG RTS:1; + ULONG TxRate:7; // software use only. keep record of the Tx rate, RATE_1,... + ULONG Rsv3:24; +#endif +} TXD_STRUC, *PTXD_STRUC; + +// +// Rx descriptor format, Rx Ring +// +typedef struct _RXD_STRUC { + // Word 0 +#ifdef BIG_ENDIAN + ULONG CipherAlg:3; + ULONG Rsv1:1; // Drop:1; // Drop this frame after NULL cipher operation + ULONG DataByteCnt:12; + ULONG IvOffset:6; + ULONG IcvError:1; + ULONG CipherOwner:1; + ULONG PhyErr:1; + ULONG Ofdm:1; + ULONG Crc:1; + ULONG MyBss:1; + ULONG Bcast:1; + ULONG Mcast:1; + ULONG U2M:1; + ULONG Owner:1; +#else + ULONG Owner:1; + ULONG U2M:1; + ULONG Mcast:1; + ULONG Bcast:1; + ULONG MyBss:1; + ULONG Crc:1; + ULONG Ofdm:1; + ULONG PhyErr:1; + ULONG CipherOwner:1; + ULONG IcvError:1; + ULONG IvOffset:6; + ULONG DataByteCnt:12; + ULONG Rsv1:1; // Drop:1; // Drop this frame after NULL cipher operation + ULONG CipherAlg:3; +#endif + + // Word 1 + ULONG BufferAddressPa; + + // Word 2 - 3 + UCHAR BBR0; + UCHAR BBR1; // suppose to read back RSSI + UCHAR TA[6]; + + // Word 4 + ULONG Iv; + + // Word 5 + ULONG Eiv; + + // Word 6-9 + UCHAR Key[16]; + + // Word 10 - 11 Reserved, not necessary to put into the structure. +#ifdef BIG_ENDIAN + ULONG Rsv2:31; + ULONG Drop:1; +#else + ULONG Drop:1; + ULONG Rsv2:31; +#endif +} RXD_STRUC, *PRXD_STRUC; + +// ================================================================================= +// CSR Registers +// ================================================================================= + +// +// CSR1: System control register +// +typedef union _CSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd1:29; + ULONG HostReady:1; // Host is ready after initialization, 1: ready + ULONG BbpReset:1; // Hardware reset BBP + ULONG SoftReset:1; // Software reset bit, 1: reset, 0: normal +#else + ULONG SoftReset:1; // Software reset bit, 1: reset, 0: normal + ULONG BbpReset:1; // Hardware reset BBP + ULONG HostReady:1; // Host is ready after initialization, 1: ready + ULONG Rsvd1:29; +#endif + } field; + ULONG word; +} CSR1_STRUC, *PCSR1_STRUC; + +// +// CSR3: STA MAC register 0 +// +typedef union _CSR3_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Byte3; // MAC address byte 3 + UCHAR Byte2; // MAC address byte 2 + UCHAR Byte1; // MAC address byte 1 + UCHAR Byte0; // MAC address byte 0 +#else + UCHAR Byte0; // MAC address byte 0 + UCHAR Byte1; // MAC address byte 1 + UCHAR Byte2; // MAC address byte 2 + UCHAR Byte3; // MAC address byte 3 +#endif + } field; + ULONG word; +} CSR3_STRUC, *PCSR3_STRUC; + +// +// CSR4: STA MAC register 1 +// +typedef union _CSR4_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Rsvd1; + UCHAR Rsvd0; + UCHAR Byte5; // MAC address byte 5 + UCHAR Byte4; // MAC address byte 4 +#else + UCHAR Byte4; // MAC address byte 4 + UCHAR Byte5; // MAC address byte 5 + UCHAR Rsvd0; + UCHAR Rsvd1; +#endif + } field; + ULONG word; +} CSR4_STRUC, *PCSR4_STRUC; + +// +// CSR5: BSSID register 0 +// +typedef union _CSR5_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Byte3; // BSSID byte 3 + UCHAR Byte2; // BSSID byte 2 + UCHAR Byte1; // BSSID byte 1 + UCHAR Byte0; // BSSID byte 0 +#else + UCHAR Byte0; // BSSID byte 0 + UCHAR Byte1; // BSSID byte 1 + UCHAR Byte2; // BSSID byte 2 + UCHAR Byte3; // BSSID byte 3 +#endif + } field; + ULONG word; +} CSR5_STRUC, *PCSR5_STRUC; + +// +// CSR6: BSSID register 1 +// +typedef union _CSR6_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Rsvd1; + UCHAR Rsvd0; + UCHAR Byte5; // BSSID byte 5 + UCHAR Byte4; // BSSID byte 4 +#else + UCHAR Byte4; // BSSID byte 4 + UCHAR Byte5; // BSSID byte 5 + UCHAR Rsvd0; + UCHAR Rsvd1; +#endif + } field; + ULONG word; +} CSR6_STRUC, *PCSR6_STRUC; + +// +// CSR7: Interrupt source register +// Write one to clear corresponding bit +// +typedef union _CSR7_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:12; + ULONG Timecsr3Expired:1; // TIMECSR3 hardware timer expired (for 802.1H quiet period) + ULONG Uart2RxBufferError:1; // UART2 RX buffer error + ULONG Uart2TxBufferError:1; // UART2 TX buffer error + ULONG Uart2IdleThreshold:1; // UART2 IDLE over threshold + ULONG Uart2RxThreshold:1; // UART2 RX reaches threshold + ULONG Uart2TxThreshold:1; // UART2 TX reaches threshold + ULONG UartRxBufferError:1; // UART1 RX buffer error + ULONG UartTxBufferError:1; // UART1 TX buffer error + ULONG UartIdleThreshold:1; // UART1 IDLE over threshold + ULONG UartRxThreshold:1; // UART1 RX reaches threshold + ULONG UartTxThreshold:1; // UART1 TX reaches threshold + ULONG EncryptionDone:1; // Encryption done interrupt + ULONG DecryptionDone:1; // Decryption done interrupt + ULONG RxDone:1; // Receive done interrupt + ULONG PrioRingTxDone:1; // Priority ring transmit done interrupt + ULONG AtimRingTxDone:1; // Atim ring transmit done interrupt + ULONG TxRingTxDone:1; // Tx ring transmit done interrupt + ULONG TatimwExpire:1; // Timer of atim window expired interrupt + ULONG TwakeExpire:1; // Wakeup timer expired interrupt + ULONG TbcnExpire:1; // Beacon timer expired interrupt +#else + ULONG TbcnExpire:1; // Beacon timer expired interrupt + ULONG TwakeExpire:1; // Wakeup timer expired interrupt + ULONG TatimwExpire:1; // Timer of atim window expired interrupt + ULONG TxRingTxDone:1; // Tx ring transmit done interrupt + ULONG AtimRingTxDone:1; // Atim ring transmit done interrupt + ULONG PrioRingTxDone:1; // Priority ring transmit done interrupt + ULONG RxDone:1; // Receive done interrupt + ULONG DecryptionDone:1; // Decryption done interrupt + ULONG EncryptionDone:1; // Encryption done interrupt + ULONG UartTxThreshold:1; // UART1 TX reaches threshold + ULONG UartRxThreshold:1; // UART1 RX reaches threshold + ULONG UartIdleThreshold:1; // UART1 IDLE over threshold + ULONG UartTxBufferError:1; // UART1 TX buffer error + ULONG UartRxBufferError:1; // UART1 RX buffer error + ULONG Uart2TxThreshold:1; // UART2 TX reaches threshold + ULONG Uart2RxThreshold:1; // UART2 RX reaches threshold + ULONG Uart2IdleThreshold:1; // UART2 IDLE over threshold + ULONG Uart2TxBufferError:1; // UART2 TX buffer error + ULONG Uart2RxBufferError:1; // UART2 RX buffer error + ULONG Timecsr3Expired:1; // TIMECSR3 hardware timer expired (for 802.1H quiet period) + ULONG Rsvd:12; +#endif + } field; + ULONG word; +} CSR7_STRUC, *PCSR7_STRUC, INTSRC_STRUC, *PINTSRC_STRUC; + +// +// CSR8: Interrupt Mask register +// Write one to mask off interrupt +// +typedef union _CSR8_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:12; + ULONG Timecsr3Expired:1; // TIMECSR3 hardware timer expired (for 802.1H quiet period) + ULONG Uart2RxBufferError:1; // UART2 RX buffer error + ULONG Uart2TxBufferError:1; // UART2 TX buffer error + ULONG Uart2IdleThreshold:1; // UART2 IDLE over threshold + ULONG Uart2RxThreshold:1; // UART2 RX reaches threshold + ULONG Uart2TxThreshold:1; // UART2 TX reaches threshold + ULONG UartRxBufferError:1; // UART1 RX buffer error + ULONG UartTxBufferError:1; // UART1 TX buffer error + ULONG UartIdleThreshold:1; // UART1 IDLE over threshold + ULONG UartRxThreshold:1; // UART1 RX reaches threshold + ULONG UartTxThreshold:1; // UART1 TX reaches threshold + ULONG EncryptionDone:1; // Encryption done interrupt + ULONG DecryptionDone:1; // Decryption done interrupt + ULONG RxDone:1; // Receive done interrupt mask + ULONG PrioRingTxDone:1; // Priority ring transmit done interrupt mask + ULONG AtimRingTxDone:1; // Atim ring transmit done interrupt mask + ULONG TxRingTxDone:1; // Tx ring transmit done interrupt mask + ULONG TatimwExpire:1; // Timer of atim window expired interrupt mask + ULONG TwakeExpire:1; // Wakeup timer expired interrupt mask + ULONG TbcnExpire:1; // Beacon timer expired interrupt mask +#else + ULONG TbcnExpire:1; // Beacon timer expired interrupt mask + ULONG TwakeExpire:1; // Wakeup timer expired interrupt mask + ULONG TatimwExpire:1; // Timer of atim window expired interrupt mask + ULONG TxRingTxDone:1; // Tx ring transmit done interrupt mask + ULONG AtimRingTxDone:1; // Atim ring transmit done interrupt mask + ULONG PrioRingTxDone:1; // Priority ring transmit done interrupt mask + ULONG RxDone:1; // Receive done interrupt mask + ULONG DecryptionDone:1; // Decryption done interrupt + ULONG EncryptionDone:1; // Encryption done interrupt + ULONG UartTxThreshold:1; // UART1 TX reaches threshold + ULONG UartRxThreshold:1; // UART1 RX reaches threshold + ULONG UartIdleThreshold:1; // UART1 IDLE over threshold + ULONG UartTxBufferError:1; // UART1 TX buffer error + ULONG UartRxBufferError:1; // UART1 RX buffer error + ULONG Uart2TxThreshold:1; // UART2 TX reaches threshold + ULONG Uart2RxThreshold:1; // UART2 RX reaches threshold + ULONG Uart2IdleThreshold:1; // UART2 IDLE over threshold + ULONG Uart2TxBufferError:1; // UART2 TX buffer error + ULONG Uart2RxBufferError:1; // UART2 RX buffer error + ULONG Timecsr3Expired:1; // TIMECSR3 hardware timer expired (for 802.1H quiet period) + ULONG Rsvd:12; +#endif + } field; + ULONG word; +} CSR8_STRUC, *PCSR8_STRUC, INTMSK_STRUC, *PINTMSK_STRUC; + +// +// CSR9: Maximum frame length register +// +typedef union _CSR9_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd1:20; + ULONG MaxFrameUnit:5; // Maximum frame legth in 128B unit, default is 12 = 0xC. + ULONG Rsvd0:7; +#else + ULONG Rsvd0:7; + ULONG MaxFrameUnit:5; // Maximum frame legth in 128B unit, default is 12 = 0xC. + ULONG Rsvd1:20; +#endif + } field; + ULONG word; +} CSR9_STRUC, *PCSR9_STRUC; + +// +// SECCSR0: WEP control register +// +typedef union _SECCSR0_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG DescAddress:30; // Descriptor physical address of frame in one-shot-mode. + ULONG OneShotMode:1; // 1: One shot only mode, 0: ring mode + ULONG KickDecypt:1; // Kick decryption engine, self-clear +#else + ULONG KickDecypt:1; // Kick decryption engine, self-clear + ULONG OneShotMode:1; // 1: One shot only mode, 0: ring mode + ULONG DescAddress:30; // Descriptor physical address of frame in one-shot-mode. +#endif + } field; + ULONG word; +} SECCSR0_STRUC, *PSECCSR0_STRUC; + +// +// SECCSR1: WEP control register +// +typedef union _SECCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG DescAddress:30; // Descriptor physical address of frame in one-shot-mode. + ULONG OneShotMode:1; // 1: One shot only mode, 0: ring mode + ULONG KickEncypt:1; // Kick encryption engine, self-clear +#else + ULONG KickEncypt:1; // Kick encryption engine, self-clear + ULONG OneShotMode:1; // 1: One shot only mode, 0: ring mode + ULONG DescAddress:30; // Descriptor physical address of frame in one-shot-mode. +#endif + } field; + ULONG word; +} SECCSR1_STRUC, *PSECCSR1_STRUC; + +// +// CSR11: Back-Off control register +// +typedef union _CSR11_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG ShortRetry:8; // Short retry count + ULONG LongRetry:8; // Long retry count + ULONG Rsvd:2; + ULONG CWSelect:1; // 1: CWmin/CWmax select from register, 0: select from TxD + ULONG SlotTime:5; // Slot time, default is 20us for 802.11B + ULONG CWMax:4; // Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + ULONG CWMin:4; // Bit for Cwmin. default Cwmin is 31 (2^5 - 1). +#else + ULONG CWMin:4; // Bit for Cwmin. default Cwmin is 31 (2^5 - 1). + ULONG CWMax:4; // Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + ULONG SlotTime:5; // Slot time, default is 20us for 802.11B + ULONG CWSelect:1; // 1: CWmin/Cwmax select from register, 0:select from TxD + ULONG Rsvd:2; + ULONG LongRetry:8; // Long retry count + ULONG ShortRetry:8; // Short retry count +#endif + } field; + ULONG word; +} CSR11_STRUC, *PCSR11_STRUC; + +// +// CSR12: Synchronization configuration register 0 +// All uint in 1/16 TU +// +typedef union _CSR12_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG CfpMaxDuration:16; // Beacon interval, default is 100 TU + ULONG BeaconInterval:16; // CFP maximum duration, default is 100 TU +#else + ULONG BeaconInterval:16; // CFP maximum duration, default is 100 TU + ULONG CfpMaxDuration:16; // Beacon interval, default is 100 TU +#endif + } field; + ULONG word; +} CSR12_STRUC, *PCSR12_STRUC; + +// +// CSR13: Synchronization configuration register 1 +// All uint in 1/16 TU +// +typedef union _CSR13_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:8; + ULONG CfpPeriod:8; // CFP period, default is 0 TU + ULONG AtimwDuration:16; // ATIM window duration, default is 10 TU +#else + ULONG AtimwDuration:16; // ATIM window duration, default is 10 TU + ULONG CfpPeriod:8; // CFP period, default is 0 TU + ULONG Rsvd:8; +#endif + } field; + ULONG word; +} CSR13_STRUC, *PCSR13_STRUC; + +// +// CSR14: Synchronization control register +// +typedef union _CSR14_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG TbcnPreload:16; // Tbcn preload value + ULONG CfpCntPreload:8; // Cfp count preload value + ULONG Rsvd:1; + ULONG BeaconGen:1; // Enable beacon generator + ULONG Tatimw:1; // Enable Tatimw & ATIM window switching + ULONG Tcfp:1; // Enable Tcfp & CFP / CP switching + ULONG Tbcn:1; // Enable Tbcn with reload value + ULONG TsfSync:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + ULONG TsfCount:1; // Enable TSF auto counting +#else + ULONG TsfCount:1; // Enable TSF auto counting + ULONG TsfSync:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + ULONG Tbcn:1; // Enable Tbcn with reload value + ULONG Tcfp:1; // Enable Tcfp & CFP / CP switching + ULONG Tatimw:1; // Enable Tatimw & ATIM window switching + ULONG BeaconGen:1; // Enable beacon generator + ULONG Rsvd:1; + ULONG CfpCntPreload:8; // Cfp count preload value + ULONG TbcnPreload:16; // Tbcn preload value +#endif + } field; + ULONG word; +} CSR14_STRUC, *PCSR14_STRUC; + +// +// CSR15: Synchronization status register +// +typedef union _CSR15_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:29; + ULONG BeaconSent:1; // Beacon sent + ULONG Atimw:1; // Atim window period + ULONG Cfp:1; // CFP period +#else + ULONG Cfp:1; // CFP period + ULONG Atimw:1; // Atim window period + ULONG BeaconSent:1; // Beacon sent + ULONG Rsvd:29; +#endif + } field; + ULONG word; +} CSR15_STRUC, *PCSR15_STRUC; + +// +// CSR18: IFS Timer register 0 +// +typedef union _CSR18_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd1:7; + ULONG PIFS:9; // PIFS, default is 30 TU + ULONG Rsvd0:7; + ULONG SIFS:9; // SIFS, default is 10 TU +#else + ULONG SIFS:9; // SIFS, default is 10 TU + ULONG Rsvd0:7; + ULONG PIFS:9; // PIFS, default is 30 TU + ULONG Rsvd1:7; +#endif + } field; + ULONG word; +} CSR18_STRUC, *PCSR18_STRUC; + +// +// CSR19: IFS Timer register 1 +// +typedef union _CSR19_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG EIFS:16; // EIFS, default is 364 TU + ULONG DIFS:16; // DIFS, default is 50 TU +#else + ULONG DIFS:16; // DIFS, default is 50 TU + ULONG EIFS:16; // EIFS, default is 364 TU +#endif + } field; + ULONG word; +} CSR19_STRUC, *PCSR19_STRUC; + +// +// CSR20: Wakeup timer register +// +typedef union _CSR20_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:7; + ULONG AutoWake:1; // Enable auto wakeup / sleep mechanism + ULONG NumBcnBeforeWakeup:8; // Number of beacon before wakeup + ULONG DelayAfterBcn:16; // Delay after Tbcn expired in units of 1/16 TU +#else + ULONG DelayAfterBcn:16; // Delay after Tbcn expired in units of 1/16 TU + ULONG NumBcnBeforeWakeup:8; // Number of beacon before wakeup + ULONG AutoWake:1; // Enable auto wakeup / sleep mechanism + ULONG Rsvd:7; +#endif + } field; + ULONG word; +} CSR20_STRUC, *PCSR20_STRUC; + +// +// CSR21: EEPROM control register +// +typedef union _CSR21_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:26; + ULONG Type:1; // 1: 93C46, 0:93C66 + ULONG EepromDO:1; + ULONG EepromDI:1; + ULONG EepromCS:1; + ULONG EepromSK:1; + ULONG Reload:1; // Reload EEPROM content, write one to reload, self-cleared. +#else + ULONG Reload:1; // Reload EEPROM content, write one to reload, self-cleared. + ULONG EepromSK:1; + ULONG EepromCS:1; + ULONG EepromDI:1; + ULONG EepromDO:1; + ULONG Type:1; // 1: 93C46, 0:93C66 + ULONG Rsvd:26; +#endif + } field; + ULONG word; +} CSR21_STRUC, *PCSR21_STRUC; + +// +// CSR22: CFP control register +// +typedef union _CSR22_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:15; + ULONG ReloadCfpDurRemain:1; // Reload CFP duration remain, write one to reload, self-cleared + ULONG CfpDurRemain:16; // CFP duration remain, in units of TU +#else + ULONG CfpDurRemain:16; // CFP duration remain, in units of TU + ULONG ReloadCfpDurRemain:1; // Reload CFP duration remain, write one to reload, self-cleared + ULONG Rsvd:15; +#endif + } field; + ULONG word; +} CSR22_STRUC, *PCSR22_STRUC; + +// ================================================================================= +// TX / RX Registers +// ================================================================================= + +// +// TXCSR0 <0x0060> : TX Control Register +// +typedef union _TXCSR0_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:28; + ULONG Abort:1; // Abort all transmit related ring operation + ULONG KickPrio:1; // Kick priority ring + ULONG KickAtim:1; // Kick ATIM ring + ULONG KickTx:1; // Kick Tx ring +#else + ULONG KickTx:1; // Kick Tx ring + ULONG KickAtim:1; // Kick ATIM ring + ULONG KickPrio:1; // Kick priority ring + ULONG Abort:1; // Abort all transmit related ring operation + ULONG Rsvd:28; +#endif + } field; + ULONG word; +} TXCSR0_STRUC, *PTXCSR0_STRUC; + +// +// TXCSR1 <0x0064> : TX Configuration Register +// +typedef union _TXCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Reserved:7; + ULONG AutoResponder:1; // enable auto responder which include ACK & CTS + ULONG TsFOffset:6; // Insert Tsf offset + ULONG AckConsumeTime:9; // ACK consume time, default = SIFS + ACKtime @ 1Mbps + ULONG AckTimeOut:9; // Ack timeout, default = SIFS + 2*SLOT_ACKtime @ 1Mbps +#else + ULONG AckTimeOut:9; // Ack timeout, default = SIFS + 2*SLOT_ACKtime @ 1Mbps + ULONG AckConsumeTime:9; // ACK consume time, default = SIFS + ACKtime @ 1Mbps + ULONG TsFOffset:6; // Insert Tsf offset + ULONG AutoResponder:1; // enable auto responder which include ACK & CTS + ULONG Reserved:7; +#endif + } field; + ULONG word; +} TXCSR1_STRUC, *PTXCSR1_STRUC; + +// +// TXCSR2: Tx descriptor configuration register +// +typedef union _TXCSR2_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG NumPrioD:8; // Number of PriorityD in ring + ULONG NumAtimD:8; // Number of AtimD in ring + ULONG NumTxD:8; // Number of TxD in ring + ULONG TxDSize:8; // Tx descriptor size, default is 48 +#else + ULONG TxDSize:8; // Tx descriptor size, default is 48 + ULONG NumTxD:8; // Number of TxD in ring + ULONG NumAtimD:8; // Number of AtimD in ring + ULONG NumPrioD:8; // Number of PriorityD in ring +#endif + } field; + ULONG word; +} TXCSR2_STRUC, *PTXCSR2_STRUC; + +// +// TXCSR7: Auto responder control register +// +typedef union _TXCSR7_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:31; + ULONG ARPowerManage:1; // Auto responder power management bit +#else + ULONG ARPowerManage:1; // Auto responder power management bit + ULONG Rsvd:31; +#endif + } field; + ULONG word; +} TXCSR7_STRUC, *PTXCSR7_STRUC; + +// +// TXCSR8: CCK Tx BBP register +// +typedef union _TXCSR8_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG CckLenHigh:8; // BBP length high byte address for CCK + ULONG CckLenLow:8; // BBP length low byte address for CCK + ULONG CckService:8; // BBP service field address for CCK + ULONG CckSignal:8; // BBP signal field address for CCK +#else + ULONG CckSignal:8; // BBP signal field address for CCK + ULONG CckService:8; // BBP service field address for CCK + ULONG CckLenLow:8; // BBP length low byte address for CCK + ULONG CckLenHigh:8; // BBP length high byte address for CCK +#endif + } field; + ULONG word; +} TXCSR8_STRUC, *PTXCSR8_STRUC; + +// +// TXCSR9: OFDM Tx BBP register +// +typedef union _TXCSR9_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG OfdmLenHigh:8; // BBP length high byte address for OFDM + ULONG OfdmLenLow:8; // BBP length low byte address for OFDM + ULONG OfdmService:8; // BBP service field address for OFDM + ULONG OfdmRate:8; // BBP rate field address for OFDM +#else + ULONG OfdmRate:8; // BBP rate field address for OFDM + ULONG OfdmService:8; // BBP service field address for OFDM + ULONG OfdmLenLow:8; // BBP length low byte address for OFDM + ULONG OfdmLenHigh:8; // BBP length high byte address for OFDM +#endif + } field; + ULONG word; +} TXCSR9_STRUC, *PTXCSR9_STRUC; + +// +// RXCSR0 <0x0080> : RX Control Register +// +typedef union _RXCSR0_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Reserved:20; + ULONG EnableQos:1; // 1: accept QOS data frame format and parse the QOS field + ULONG DropBcast:1; // Drop broadcast frames + ULONG DropMcast:1; // Drop multicast frames + ULONG PassPlcp:1; // Pass all receive packet with 4 bytes PLCP attached + ULONG PassCRC:1; // Pass all receive packet to host with CRC attached + ULONG DropVersionErr:1; // Drop version error frame + ULONG DropToDs:1; // Drop fram ToDs bit is true + ULONG DropNotToMe:1; // Drop not to me unicast frame + ULONG DropControl:1; // Drop control frame + ULONG DropPhysical:1; // Drop physical error + ULONG DropCRC:1; // Drop CRC error + ULONG DisableRx:1; // Disable Rx engine +#else + ULONG DisableRx:1; // Disable Rx engine + ULONG DropCRC:1; // Drop CRC error + ULONG DropPhysical:1; // Drop physical error + ULONG DropControl:1; // Drop control frame + ULONG DropNotToMe:1; // Drop not to me unicast frame + ULONG DropToDs:1; // Drop fram ToDs bit is true + ULONG DropVersionErr:1; // Drop version error frame + ULONG PassCRC:1; // Pass all receive packet to host with CRC attached + ULONG PassPlcp:1; // Pass all receive packet with 4 bytes PLCP attached + ULONG DropMcast:1; // Drop multicast frames + ULONG DropBcast:1; // Drop broadcast frames + ULONG EnableQos:1; // 1: accept QOS data frame format and parse the QOS field + ULONG Reserved:20; +#endif + } field; + ULONG word; +} RXCSR0_STRUC, *PRXCSR0_STRUC; + +// +// RXCSR1: RX descriptor configuration register +// +typedef union _RXCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:16; + ULONG NumRxD:8; // Number of RxD in ring. + ULONG RxDSize:8; // Rx descriptor size, default is 32B. +#else + ULONG RxDSize:8; // Rx descriptor size, default is 32B. + ULONG NumRxD:8; // Number of RxD in ring. + ULONG Rsvd:16; +#endif + } field; + ULONG word; +} RXCSR1_STRUC, *PRXCSR1_STRUC; + +// +// RXCSR3: BBP ID register for Rx operation +// +typedef union _RXCSR3_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG ValidBbp3:1; // BBP register 3 ID is valid or not + ULONG IdBbp3:7; // BBP register 3 ID + ULONG ValidBbp2:1; // BBP register 2 ID is valid or not + ULONG IdBbp2:7; // BBP register 2 ID + ULONG ValidBbp1:1; // BBP register 1 ID is valid or not + ULONG IdBbp1:7; // BBP register 1 ID + ULONG ValidBbp0:1; // BBP register 0 ID is valid or not + ULONG IdBbp0:7; // BBP register 0 ID +#else + ULONG IdBbp0:7; // BBP register 0 ID + ULONG ValidBbp0:1; // BBP register 0 ID is valid or not + ULONG IdBbp1:7; // BBP register 1 ID + ULONG ValidBbp1:1; // BBP register 1 ID is valid or not + ULONG IdBbp2:7; // BBP register 2 ID + ULONG ValidBbp2:1; // BBP register 2 ID is valid or not + ULONG IdBbp3:7; // BBP register 3 ID + ULONG ValidBbp3:1; // BBP register 3 ID is valid or not +#endif + } field; + ULONG word; +} RXCSR3_STRUC, *PRXCSR3_STRUC; +#if 0 +// +// RXCSR4: BBP ID register for Rx operation +// +typedef union _RXCSR4_STRUC { + struct { + ULONG IdBbp4:7; // BBP register 4 ID + ULONG ValidBbp4:1; // BBP register 4 ID is valid or not + ULONG IdBbp5:7; // BBP register 5 ID + ULONG ValidBbp5:1; // BBP register 5 ID is valid or not + ULONG Rsvd:16; + } field; + ULONG word; +} RXCSR4_STRUC, *PRXCSR4_STRUC; + +// +// ARCSR0: Auto Responder PLCP value register 0 +// +typedef union _ARCSR0_STRUC { + struct { + ULONG ArBbpData0:8; // Auto responder BBP register 0 data + ULONG ArBbpId0:8; // Auto responder BBP register 0 Id + ULONG ArBbpData1:8; // Auto responder BBP register 1 data + ULONG ArBbpId1:8; // Auto responder BBP register 1 Id + } field; + ULONG word; +} ARCSR0_STRUC, *PARCSR0_STRUC; + +// +// ARCSR0: Auto Responder PLCP value register 1 +// +typedef union _ARCSR1_STRUC { + struct { + ULONG ArBbpData2:8; // Auto responder BBP register 2 data + ULONG ArBbpId2:8; // Auto responder BBP register 2 Id + ULONG ArBbpData3:8; // Auto responder BBP register 3 data + ULONG ArBbpId3:8; // Auto responder BBP register 3 Id + } field; + ULONG word; +} ARCSR1_STRUC, *PARCSR1_STRUC; +#endif +// ================================================================================= +// Miscellaneous Registers +// ================================================================================= + +// +// PCISR: PCI control register +// +typedef union _PCICSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:22; + ULONG WriteInvalid:1; // Enable memory write & invalid + ULONG ReadMultiple:1; // Enable memory read multiple + ULONG EnableClk:1; // Enable CLK_RUN, PCI clock can't going down to non-operational + ULONG BurstLength:2; // PCI burst length + // 01: 8DW, 10: 16DW, 11:32DW, default 00: 4DW + ULONG TxThreshold:2; // Tx threshold in DW to start PCI access + // 01: 1DW, 10: 4DW, 11: store & forward, default 00: 0DW + ULONG RxThreshold:2; // Rx threshold in DW to start PCI access + // 01: 8DW, 10: 4DW, 11: 32DW, default 00: 16DW + ULONG BigEndian:1; // 1: big endian, 0: little endian +#else + ULONG BigEndian:1; // 1: big endian, 0: little endian + ULONG RxThreshold:2; // Rx threshold in DW to start PCI access + // 01: 8DW, 10: 4DW, 11: 32DW, default 00: 16DW + ULONG TxThreshold:2; // Tx threshold in DW to start PCI access + // 01: 1DW, 10: 4DW, 11: store & forward, default 00: 0DW + ULONG BurstLength:2; // PCI burst length + // 01: 8DW, 10: 16DW, 11:32DW, default 00: 4DW + ULONG EnableClk:1; // Enable CLK_RUN, PCI clock can't going down to non-operational + ULONG ReadMultiple:1; // Enable memory read multiple + ULONG WriteInvalid:1; // Enable memory write & invalid + ULONG Rsvd:22; +#endif + } field; + ULONG word; +} PCICSR_STRUC, *PPCICSR_STRUC; + +// +// PWRCSR0: Power mode configuration register +// Driver did not control it for now. + +// +// PSCSR0: Power saving delay time register 0 +// Driver did not control it for now. + +// +// PSCSR1: Power saving delay time register 1 +// Driver did not control it for now. + +// +// PSCSR2: Power saving delay time register 2 +// Driver did not control it for now. + +// +// PSCSR3: Power saving delay time register 3 +// Driver did not control it for now. + +// +// PWRCSR1: Manual power control / status register +// +typedef union _PWRCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:22; + ULONG PutToSleep:1; + ULONG RfCurrState:2; + ULONG BbpCurrState:2; + ULONG RfDesireState:2; + ULONG BbpDesireState:2; + ULONG SetState:1; +#else + ULONG SetState:1; + ULONG BbpDesireState:2; + ULONG RfDesireState:2; + ULONG BbpCurrState:2; + ULONG RfCurrState:2; + ULONG PutToSleep:1; + ULONG Rsvd:22; +#endif + } field; + ULONG word; +} PWRCSR1_STRUC, *PPWRCSR1_STRUC; + +// +// TIMECSR: Timer control register +// +typedef union _TIMECSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:13; + ULONG BeaconExpect:3; // Beacon expect window + ULONG Us64Cnt:8; // 64 us timer count in units of 1 us timer + ULONG UsCnt:8; // 1 us timer count in units of clock cycles +#else + ULONG UsCnt:8; // 1 us timer count in units of clock cycles + ULONG Us64Cnt:8; // 64 us timer count in units of 1 us timer + ULONG BeaconExpect:3; // Beacon expect window + ULONG Rsvd:13; +#endif + } field; + ULONG word; +} TIMECSR_STRUC, *PTIMECSR_STRUC; + +// +// MACCSR0: MAC configuration register 0 +// + +// +// MACCSR1: MAC configuration register 1 +// +typedef union _MACCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:24; + ULONG IntersilIF:1; // Intersil IF calibration pin + ULONG LoopBack:2; // Loopback mode. 00: normal, 01: internal, 10: external, 11:rsvd. + ULONG AutoRxBbp:1; // Auto Rx logic access BBP control register + ULONG AutoTxBbp:1; // Auto Tx logic access BBP control register + ULONG BbpRxResetMode:1; // Ralink BBP RX reset mode + ULONG OneShotRxMode:1; // Enable one-shot Rx mode for debugging + ULONG KickRx:1; // Kick one-shot Rx in one-shot Rx mode +#else + ULONG KickRx:1; // Kick one-shot Rx in one-shot Rx mode + ULONG OneShotRxMode:1; // Enable one-shot Rx mode for debugging + ULONG BbpRxResetMode:1; // Ralink BBP RX reset mode + ULONG AutoTxBbp:1; // Auto Tx logic access BBP control register + ULONG AutoRxBbp:1; // Auto Rx logic access BBP control register + ULONG LoopBack:2; // Loopback mode. 00: normal, 01: internal, 10: external, 11:rsvd. + ULONG IntersilIF:1; // Intersil IF calibration pin + ULONG Rsvd:24; +#endif + } field; + ULONG word; +} MACCSR1_STRUC, *PMACCSR1_STRUC; + +// +// RALINKCSR: Ralink Rx auto-reset BBCR +// +typedef union _RALINKCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG ArBbpValid1:1; // Auto reset BBP register 1 is valid + ULONG ArBbpId1:7; // Auto reset BBP register 1 Id + ULONG ArBbpData1:8; // Auto reset BBP register 1 data + ULONG ArBbpValid0:1; // Auto reset BBP register 0 is valid + ULONG ArBbpId0:7; // Auto reset BBP register 0 Id + ULONG ArBbpData0:8; // Auto reset BBP register 0 data +#else + ULONG ArBbpData0:8; // Auto reset BBP register 0 data + ULONG ArBbpId0:7; // Auto reset BBP register 0 Id + ULONG ArBbpValid0:1; // Auto reset BBP register 0 is valid + ULONG ArBbpData1:8; // Auto reset BBP register 1 data + ULONG ArBbpId1:7; // Auto reset BBP register 1 Id + ULONG ArBbpValid1:1; // Auto reset BBP register 1 is valid +#endif + } field; + ULONG word; +} RALINKCSR_STRUC, *PRALINKCSR_STRUC; + +// +// BCNCSR: Beacon interval control register +// +typedef union _BCNCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:16; + ULONG Plus:1; // plus or minus delta time value + ULONG Mode:2; // please refer to ASIC specs. + ULONG NumBcn:8; // Delta time value or number of beacon according to mode + ULONG DeltaTime:4; // The delta time value + ULONG Change:1; // Write one to change beacon interval +#else + ULONG Change:1; // Write one to change beacon interval + ULONG DeltaTime:4; // The delta time value + ULONG NumBcn:8; // Delta time value or number of beacon according to mode + ULONG Mode:2; // please refer to ASIC specs. + ULONG Plus:1; // plus or minus delta time value + ULONG Rsvd:16; +#endif + } field; + ULONG word; +} BCNCSR_STRUC, *PBCNCSR_STRUC; + +// +// BBPCSR: BBP serial control register +// +typedef union _BBPCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:15; + ULONG WriteControl:1; // 1: Write BBP, 0: Read BBP + ULONG Busy:1; // 1: ASIC is busy execute BBP programming. + ULONG RegNum:7; // Selected BBP register + ULONG Value:8; // Register value to program into BBP +#else + ULONG Value:8; // Register value to program into BBP + ULONG RegNum:7; // Selected BBP register + ULONG Busy:1; // 1: ASIC is busy execute BBP programming. + ULONG WriteControl:1; // 1: Write BBP, 0: Read BBP + ULONG Rsvd:15; +#endif + } field; + ULONG word; +} BBPCSR_STRUC, *PBBPCSR_STRUC; + +// +// RFCSR: RF serial control register +// +typedef union _RFCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Busy:1; // 1: ASIC is busy execute RF programming. + ULONG PLL_LD:1; // RF PLL_LD status + ULONG IFSelect:1; // 1: select IF to program, 0: select RF to program + ULONG NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) + ULONG RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. +#else + ULONG RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. + ULONG NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) + ULONG IFSelect:1; // 1: select IF to program, 0: select RF to program + ULONG PLL_LD:1; // RF PLL_LD status + ULONG Busy:1; // 1: ASIC is busy execute RF programming. +#endif + } field; + ULONG word; +} RFCSR_STRUC, *PRFCSR_STRUC; + +// +// LEDCSR: LED control register +// +typedef union _LEDCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:11; + ULONG LedADefault:1; // LED A default value for "enable" state. 0: LED ON, 1: LED OFF + ULONG LedBPolarity:1; // 0: active low, 1: active high + ULONG LedAPolarity:1; // 0: active low, 1: active high + ULONG LedB:1; // controlled by software, 1: ON, 0: OFF + ULONG LedA:1; // indicate TX activity, 1: enable, 0: disable + ULONG OffPeriod:8; // Off period, default 30ms + ULONG OnPeriod:8; // On period, default 70ms +#else + ULONG OnPeriod:8; // On period, default 70ms + ULONG OffPeriod:8; // Off period, default 30ms + ULONG LedA:1; // indicate TX activity, 1: enable, 0: disable + ULONG LedB:1; // controlled by software, 1: ON, 0: OFF + ULONG LedAPolarity:1; // 0: active low, 1: active high + ULONG LedBPolarity:1; // 0: active low, 1: active high + ULONG LedADefault:1; // LED A default value for "enable" state. 0: LED ON, 1: LED OFF + ULONG Rsvd:11; +#endif + } field; + ULONG word; +} LEDCSR_STRUC, *PLEDCSR_STRUC; + +// +// GPIOCSR: GPIO control register +// +typedef union _GPIOCSR_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:16; + ULONG Dir7:1; + ULONG Dir6:1; + ULONG Dir5:1; + ULONG Dir4:1; + ULONG Dir3:1; + ULONG Dir2:1; + ULONG Dir1:1; + ULONG Dir0:1; + ULONG Bit7:1; + ULONG Bit6:1; + ULONG Bit5:1; + ULONG Bit4:1; + ULONG Bit3:1; + ULONG Bit2:1; + ULONG Bit1:1; + ULONG Bit0:1; +#else + ULONG Bit0:1; + ULONG Bit1:1; + ULONG Bit2:1; + ULONG Bit3:1; + ULONG Bit4:1; + ULONG Bit5:1; + ULONG Bit6:1; + ULONG Bit7:1; + ULONG Dir0:1; + ULONG Dir1:1; + ULONG Dir2:1; + ULONG Dir3:1; + ULONG Dir4:1; + ULONG Dir5:1; + ULONG Dir6:1; + ULONG Dir7:1; + ULONG Rsvd:16; +#endif + } field; + ULONG word; +} GPIOCSR_STRUC, *PGPIOCSR_STRUC; + +// +// BCNCSR1: Tx BEACON offset time control register +// +typedef union _BCNCSR1_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:12; + ULONG BeaconCwMin:4; // 2^CwMin + ULONG Preload:16; // in units of usec +#else + ULONG Preload:16; // in units of usec + ULONG BeaconCwMin:4; // 2^CwMin + ULONG Rsvd:12; +#endif + } field; + ULONG word; +} BCNCSR1_STRUC, *PBCNCSR1_STRUC; + +// +// MACCSR2: TX_PE to RX_PE turn-around time control register +// +typedef union _MACCSR2_STRUC { + struct { +#ifdef BIG_ENDIAN + ULONG Rsvd:24; + ULONG Delay:8; // in units of PCI clock cycle +#else + ULONG Delay:8; // in units of PCI clock cycle + ULONG Rsvd:24; +#endif + } field; + ULONG word; +} MACCSR2_STRUC, *PMACCSR2_STRUC; + +// +// EEPROM antenna select format +// +typedef union _EEPROM_ANTENNA_STRUC { + struct { +#ifdef BIG_ENDIAN + USHORT RfType:5; // see E2PROM document for RF IC selection + USHORT HardwareRadioControl:1; // 1: Hardware controlled radio enabled, Read GPIO0 required. + USHORT DynamicTxAgcControl:1; + USHORT LedMode:3; // 0-default mode, 1:TX/RX activity mode, 2: Single LED (didn't care about link), 3: reserved + USHORT RxDefaultAntenna:2; // default of antenna, 0: diversity, 1:antenna-A, 2:antenna-B reserved (default = 0) + USHORT TxDefaultAntenna:2; // default of antenna, 0: diversity, 1:antenna-A, 2:antenna-B reserved (default = 0) + USHORT NumOfAntenna:2; // Number of antenna +#else + USHORT NumOfAntenna:2; // Number of antenna + USHORT TxDefaultAntenna:2; // default of antenna, 0: diversity, 1:antenna-A, 2:antenna-B reserved (default = 0) + USHORT RxDefaultAntenna:2; // default of antenna, 0: diversity, 1:antenna-A, 2:antenna-B reserved (default = 0) + USHORT LedMode:3; // 0-default mode, 1:TX/RX activity mode, 2: Single LED (didn't care about link), 3: reserved + USHORT DynamicTxAgcControl:1; + USHORT HardwareRadioControl:1; // 1: Hardware controlled radio enabled, Read GPIO0 required. + USHORT RfType:5; // see E2PROM document for RF IC selection +#endif + } field; + USHORT word; +} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; + +typedef union _EEPROM_NIC_CINFIG2_STRUC { + struct { +#ifdef BIG_ENDIAN + USHORT Rsv:12; // must be 0 + USHORT CckTxPower:2; // CCK TX power compensation + USHORT DynamicBbpTuning:1; // !!! NOTE: 0 - enable, 1 - disable + USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable +#else + USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable + USHORT DynamicBbpTuning:1; // !!! NOTE: 0 - enable, 1 - disable + USHORT CckTxPower:2; // CCK TX power compensation + USHORT Rsv:12; // must be 0 +#endif + } field; + USHORT word; +} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; + +typedef union _EEPROM_TX_PWR_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Byte1; // High Byte + UCHAR Byte0; // Low Byte +#else + UCHAR Byte0; // Low Byte + UCHAR Byte1; // High Byte +#endif + } field; + USHORT word; +} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; + +typedef union _EEPROM_VERSION_STRUC { + struct { +#ifdef BIG_ENDIAN + UCHAR Version; // High Byte + UCHAR FaeReleaseNumber; // Low Byte +#else + UCHAR FaeReleaseNumber; // Low Byte + UCHAR Version; // High Byte +#endif + } field; + USHORT word; +} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; + +#endif // __RT2560_H__ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rt_config.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/rt_config.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rt_config.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rt_config.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,164 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rt_config.h + * + * Abstract: Central header file for all includes + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * RoryC 21st Dec 02 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef __RT_CONFIG_H__ +#define __RT_CONFIG_H__ + +#define PROFILE_PATH "/etc/Wireless/RT2500STA/RT2500STA.dat" +#define NIC_DEVICE_NAME "RT2500STA" + +#define DRV_NAME "rt2500" +#define DRV_VERSION "1.1.0 BETA4" +#define DRV_RELDATE "2006/06/18" +#define DRV_VERSION_MAJOR 1 +#define DRV_VERSION_MINOR 1 +#define DRV_VERSION_SUB 0 +#define DRV_BUILD_YEAR 2006 +#define DRV_BUILD_MONTH 06 +#define DRV_BUILD_DAY 18 + +/* Operational parameters that are set at compile time. */ +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include //can delete +#include +#include +#include +#include +#include +#include //can delete +#include // can delete +#include +#include +#include +#include +#include +#include +#include //can delete +#include // can delete +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= 0x20407 +#include +#endif +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include +#include + +// The type definition has to be placed before including rt2460.h +#ifndef ULONG +#define CHAR char +#define INT int +#define SHORT int +#define UINT u32 +#define ULONG u32 +#define USHORT u16 +#define UCHAR u8 + +#define BOOLEAN u8 +//#define LARGE_INTEGER s64 +#define VOID void +#define LONG int +#define ULONGLONG u64 +typedef VOID *PVOID; +typedef CHAR *PCHAR; +typedef UCHAR *PUCHAR; +typedef LONG *PLONG; +typedef ULONG *PULONG; + +typedef union _LARGE_INTEGER { + struct { + ULONG LowPart; + LONG HighPart; + }vv; + struct { + ULONG LowPart; + LONG HighPart; + } u; + s64 QuadPart; +} LARGE_INTEGER; + +#endif + +#define IN +#define OUT + +#define TRUE 1 +#define FALSE 0 + +#define NDIS_STATUS INT +#define NDIS_STATUS_SUCCESS 0x00 +#define NDIS_STATUS_FAILURE 0x01 +#define NDIS_STATUS_RESOURCES 0x03 +#define NDIS_STATUS_MEDIA_DISCONNECT 0x04 +#define NDIS_STATUS_MEDIA_CONNECT 0x05 + +#ifdef __BIG_ENDIAN +#warning Compiling for big endian machine. +#define BIG_ENDIAN TRUE +#endif /* __BIG_ENDIAN */ + +#include "rtmp_type.h" +#include "rtmp_def.h" +#include "rt2560.h" +#include "rtmp.h" +#include "mlme.h" +#include "oid.h" +#include "wpa.h" +#include "md5.h" + +#define DEBUG_TASK_DELAY 2000 + +enum rt2560_chips { + RT2560A = 0, +}; + +#ifdef RTMP_EMBEDDED +#undef GFP_KERNEL +#define GFP_KERNEL (GFP_DMA | GFP_ATOMIC) +#endif + +#endif // __RT_CONFIG_H__ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,2622 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rt_config.h + * + * Abstract: Central header file for all includes + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * RoryC 21st Dec 02 Initial code + * MarkW 8th Dec 04 Baseline code + * MarkW (rt2400) 8th Dec 04 Promisc mode support + * Flavio (rt2400) 8th Dec 04 Elegant irqreturn_t handling + * RobinC 10th Dec 04 RFMON Support + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + * MarkW (rt2400) 15th Dec 04 Spinlock fix + * Ivo (rt2400) 15th Dec 04 Debug level switching + * GregorG 29th Mar 05 Big endian fixes + ***************************************************************************/ + +#ifndef __RTMP_H__ +#define __RTMP_H__ + +#include "mlme.h" +#include "oid.h" +#include "wpa.h" + +#ifndef IRQ_HANDLED +/* For 2.6.x compatability */ +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif + +#ifndef pci_name +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +#define pci_name(__pPci_Dev) (__pPci_Dev)->dev.bus_id +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) */ +#define pci_name(__pPci_Dev) (__pPci_Dev)->slot_name +#endif /*(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) */ +#endif /* pci_name */ + + +// Krellan: Limit range of user TxPower settings from -31 to +0 dBm. +// We could accept -31 to +31 dBm, relative to 0 dBm which is defined +// as the EEPROM's recommended power setting. +// Raw power settings out of 0-31 range are always clamped later. +// This would allow all possible raw power settings to be exercised, +// from 0-31, no matter what the scaled dBm range from EEPROM +// ends up becoming. +// This would be for testing only, under controlled conditions. +#define MIN_TXPOWER_DBM (-31) +#define MAX_TXPOWER_DBM (0) + + +// +// Defines the state of the LAN media +// +typedef enum _NDIS_MEDIA_STATE +{ + NdisMediaStateConnected, + NdisMediaStateDisconnected +} NDIS_MEDIA_STATE, *PNDIS_MEDIA_STATE; + +// +// MACRO for debugging information +// +extern int debug; +#ifdef RT2500_DBG +#define DBGPRINT(Level, fmt, args...) \ + if(debug){printk(Level DRV_NAME ": " fmt, ## args);} +#else +#define DBGPRINT(Level, fmt, args...) \ + while(0){} +#endif + +// +// spin_lock enhanced for Nested spin lock +// + +extern unsigned long IrqFlags; + +// Assert MACRO to make sure program running +// +#undef ASSERT +#define ASSERT(x) \ +{ \ + if (!(x)) \ + { \ + printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ + } \ +} + +// +// Macros for flag and ref count operations +// +#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) +#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) +#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) +#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) +#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) + +#define RTMP_INC_RCV_REF(_A) ((_A)->RcvRefCount++) +#define RTMP_DEC_RCV_REF(_A) ((_A)->RcvRefCount--) +#define RTMP_GET_RCV_REF(_A) ((_A)->RcvRefCount) + +#define RTMP_INC_SEND_REF(_A) ((_A)->SendRefCount++) +#define RTMP_DEC_SEND_REF(_A) ((_A)->SendRefCount--) +#define RTMP_GET_SEND_REF(_A) ((_A)->SendRefCount) + +#define NdisEqualMemory(Source1, Source2, Length) RTMPEqualMemory(Source1, Source2, Length) + +// +// MACRO for 32-bit PCI register read / write +// +// Usage : RTMP_IO_READ32( +// PRTMP_ADAPTER pAdapter, +// ULONG Register_Offset, +// PULONG pValue) +// +// RTMP_IO_WRITE32( +// PRTMP_ADAPTER pAdapter, +// ULONG Register_Offset, +// ULONG Value) +// +#ifdef RTMP_EMBEDDED +#define RTMP_IO_READ32(_A, _R, _pV) (*_pV = PCIMemRead32(__mem_pci(_A->CSRBaseAddress+_R))) +#define RTMP_IO_WRITE32(_A, _R, _V) (PCIMemWrite32(__mem_pci(_A->CSRBaseAddress+_R),_V)) +#else +#define RTMP_IO_READ32(_A, _R, _pV) (*_pV = readl( (void*) (_A->CSRBaseAddress + _R) ) ) +#define RTMP_IO_WRITE32(_A, _R, _V) (writel(_V, (void*) (_A->CSRBaseAddress + _R) ) ) +#endif + +// +// BBP & RF are using indirect access. Before write any value into it. +// We have to make sure there is no outstanding command pending via checking busy bit. +// +#define MAX_BUSY_COUNT 10 // Nunber of retry before failing access BBP & RF indirect register +// +#define RTMP_BBP_IO_WRITE32(_A, _V) \ +{ \ + BBPCSR_STRUC Value; \ + ULONG BusyCnt = 0; \ + do { \ + RTMP_IO_READ32(_A, BBPCSR, &Value.word); \ + if (Value.field.Busy == IDLE) \ + break; \ + BusyCnt++; \ + } while (BusyCnt < MAX_BUSY_COUNT); \ + if (BusyCnt < MAX_BUSY_COUNT) \ + { \ + RTMP_IO_WRITE32(_A, BBPCSR, _V); \ + } \ +} +// +#define RTMP_RF_IO_WRITE32(_A, _V) \ +{ \ + RFCSR_STRUC Value; \ + ULONG BusyCnt = 0; \ + do { \ + RTMP_IO_READ32(_A, RFCSR, &(Value.word)); \ + if (Value.field.Busy == IDLE) \ + break; \ + BusyCnt++; \ + } while (BusyCnt < MAX_BUSY_COUNT); \ + if (BusyCnt < MAX_BUSY_COUNT) \ + { \ + RTMP_IO_WRITE32(_A, RFCSR, _V); \ + } \ +} +// +#define RTMP_BBP_IO_READ32(_A, _pV) \ +{ \ + BBPCSR_STRUC Value; \ + ULONG BusyCnt = 0; \ + RTMP_BBP_IO_WRITE32(_A, *(_pV)); \ + do { \ + RTMP_IO_READ32(_A, BBPCSR, &Value.word);\ + if (Value.field.Busy == IDLE) \ + break; \ + BusyCnt++; \ + } while (BusyCnt < MAX_BUSY_COUNT); \ + if (BusyCnt == MAX_BUSY_COUNT) \ + *(_pV) = 0xff; \ + else \ + *(_pV) = Value.field.Value; \ +} +// Read BBP register by register's ID +#define RTMP_BBP_IO_READ32_BY_REG_ID(_A, _I, _pV) \ +{ \ + BBPCSR_STRUC BbpCsr; \ + BbpCsr.word = 0; \ + BbpCsr.field.WriteControl = 0; \ + BbpCsr.field.Busy = 1; \ + BbpCsr.field.RegNum = _I; \ + RTMP_BBP_IO_READ32(_A, &BbpCsr.word); \ + *(_pV) = (UCHAR) BbpCsr.field.Value; \ +} +// Write BBP register by register's ID & value +#define RTMP_BBP_IO_WRITE32_BY_REG_ID(_A, _I, _V) \ +{ \ + BBPCSR_STRUC BbpCsr; \ + BbpCsr.word = 0; \ + BbpCsr.field.WriteControl = 1; \ + BbpCsr.field.Busy = 1; \ + BbpCsr.field.Value = _V; \ + BbpCsr.field.RegNum = _I; \ + RTMP_BBP_IO_WRITE32(_A, BbpCsr.word); \ + (_A)->PortCfg.BbpWriteLatch[_I] = _V; \ +} + + +// +// Some utility macros +// +#ifndef min +#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +#ifndef max +#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + +#define INC_COUNTER(Val) (Val.QuadPart++) + +#define INFRA_ON(_p) (((_p)->PortCfg.Massoc) == TRUE) // Check Massoc +#define ADHOC_ON(_p) (((_p)->PortCfg.Mibss) == TRUE) // check Mibss +#define RTMP_SET_PACKET_FRAGMENTS(_p, number) ((_p)->cb[10] = number) +#define RTMP_GET_PACKET_FRAGMENTS(_p) ((_p)->cb[10]) +#define RTMP_SET_PACKET_RTS(_p, number) ((_p)->cb[11] = number) +#define RTMP_GET_PACKET_RTS(_p) ((_p)->cb[11]) + +#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ +{ \ + memcpy(_p, _pMac1, ETH_ALEN); \ + memcpy((_p + ETH_ALEN), _pMac2, ETH_ALEN); \ + memcpy((_p + ETH_ALEN * 2), _pType, LENGTH_802_3_TYPE); \ +} + +// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. +// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field in the result Ethernet frame +// else remove the LLC/SNAP field from the result Ethernet frame +// Note: +// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO +#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize) \ +{ \ + char LLC_Len[2]; \ + \ + if ((!RTMPEqualMemory(SNAP_802_1H, _pData, 6)) && \ + (!RTMPEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6))) \ + { \ + LLC_Len[0] = (UCHAR)(_DataSize / 256); \ + LLC_Len[1] = (UCHAR)(_DataSize % 256); \ + MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ + } \ + else \ + { \ + PUCHAR pProto = _pData + 6; \ + \ + if ((RTMPEqualMemory(IPX, pProto, 2) || RTMPEqualMemory(APPLE_TALK, pProto, 2)) && \ + RTMPEqualMemory(SNAP_802_1H, _pData, 6)) \ + { \ + LLC_Len[0] = (UCHAR)(_DataSize / 256); \ + LLC_Len[1] = (UCHAR)(_DataSize % 256); \ + MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ + } \ + else \ + { \ + MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ + _DataSize -= LENGTH_802_1_H; \ + _pData += LENGTH_802_1_H; \ + } \ + } \ +} + +// +// Register set pair for initialzation register set definition +// +typedef struct _RTMP_REG_PAIR +{ + ULONG Register; + ULONG Value; +} RTMP_REG_PAIR, *PRTMP_REG_PAIR; + +// +// Register set pair for initialzation register set definition +// +typedef struct _RTMP_RF_REGS +{ + UCHAR Channel; + ULONG R1; + ULONG R2; + ULONG R3; + ULONG R4; +} RTMP_RF_REGS, *PRTMP_RF_REGS; + +// +// Statistic counter structure +// +typedef struct _COUNTER_802_3 +{ + // General Stats + ULONG GoodTransmits; + ULONG GoodReceives; + ULONG TxErrors; + ULONG RxErrors; + ULONG RxNoBuffer; + + // Ethernet Stats + ULONG RcvAlignmentErrors; + ULONG OneCollision; + ULONG MoreCollisions; + +} COUNTER_802_3, *PCOUNTER_802_3; + +typedef struct _COUNTER_802_11 { + ULONG Length; + LARGE_INTEGER TransmittedFragmentCount; + LARGE_INTEGER MulticastTransmittedFrameCount; + LARGE_INTEGER FailedCount; + LARGE_INTEGER RetryCount; + LARGE_INTEGER MultipleRetryCount; + LARGE_INTEGER RTSSuccessCount; + LARGE_INTEGER RTSFailureCount; + LARGE_INTEGER ACKFailureCount; + LARGE_INTEGER FrameDuplicateCount; + LARGE_INTEGER ReceivedFragmentCount; + LARGE_INTEGER MulticastReceivedFrameCount; + LARGE_INTEGER FCSErrorCount; +} COUNTER_802_11, *PCOUNTER_802_11; + +typedef struct _COUNTER_RALINK { + ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput + ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput + ULONG BeenDisassociatedCount; + ULONG BadCQIAutoRecoveryCount; + ULONG PoorCQIRoamingCount; + ULONG MgmtRingFullCount; + ULONG RxCount; + ULONG DecryptCount; + ULONG RxRingErrCount; + ULONG EncryptCount; + ULONG KickTxCount; + ULONG TxRingErrCount; + LARGE_INTEGER RealFcsErrCount; +} COUNTER_RALINK, *PCOUNTER_RALINK; + +typedef struct _COUNTER_DRS { + // to record the each TX rate's quality. 0 is best, the bigger the worse. + USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR PER[MAX_LEN_OF_SUPPORTED_RATES]; + USHORT OneSecTxOkCount; + USHORT OneSecTxRetryOkCount; + USHORT OneSecTxFailCount; + UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition + ULONG CurrTxRateStableTime; // # of second in current TX rate + BOOLEAN fNoisyEnvironment; + UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down +} COUNTER_DRS, *PCOUNTER_DRS; + +// +// Arcfour Structure Added by PaulWu +// +typedef struct PACKED _ARCFOUR +{ + UINT X; + UINT Y; + UCHAR STATE[256]; +} ARCFOURCONTEXT, *PARCFOURCONTEXT; + +// Shared key data structure +typedef struct _WEP_KEY { + UCHAR KeyLen; // Key length for each key, 0: entry is invalid + UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max +} WEP_KEY, *PWEP_KEY; + +// Shared key data structure +typedef struct _WPA_KEY { + UCHAR KeyLen; // Key length for each key, 0: entry is invalid + UCHAR Key[16]; // right now we implement 4 keys, 128 bits max + UCHAR RxMic[8]; + UCHAR TxMic[8]; + NDIS_802_11_MAC_ADDRESS BssId; // For pairwise key only + UCHAR TxTsc[6]; // 48bit TSC value + UCHAR RxTsc[6]; // 48bit TSC value + UCHAR Type; // Indicate Pairwise / Group +} WPA_KEY, *PWPA_KEY; + +#if 0 +typedef struct _IV_CONTROL_ +{ + union + { + struct + { + UCHAR rc0; + UCHAR rc1; + UCHAR rc2; + + union + { + struct + { +#ifdef BIG_ENDIAN + UCHAR KeyID:2; + UCHAR ExtIV:1; + UCHAR Rsvd:5; +#else + UCHAR Rsvd:5; + UCHAR ExtIV:1; + UCHAR KeyID:2; +#endif + } field; + UCHAR Byte; + } CONTROL; + } field; + + ULONG word; + } IV16; + + ULONG IV32; +} TKIP_IV, *PTKIP_IV; +#endif + +typedef struct _IV_CONTROL_ +{ + union + { + struct + { +#ifdef BIG_ENDIAN + ULONG KeyID:2; + ULONG ExtIV:1; + ULONG Rsvd:5; + ULONG rc2:8; + ULONG rc1:8; + ULONG rc0:8; +#else + ULONG rc0:8; + ULONG rc1:8; + ULONG rc2:8; + ULONG Rsvd:5; + ULONG ExtIV:1; + ULONG KeyID:2; +#endif + }field; + ULONG word; + }IV16; + + ULONG IV32; +} TKIP_IV, *PTKIP_IV; + +// configuration to be used when this STA starts a new ADHOC network +typedef struct _IBSS_CONFIG { + USHORT BeaconPeriod; + USHORT AtimWin; + UCHAR Channel; + UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; // Supported rates + UCHAR SupportedRatesLen; +} IBSS_CONFIG, *PIBSS_CONFIG; + +typedef struct _LED_CONTROL { + BOOLEAN fOdd; + BOOLEAN fRxActivity; + RALINK_TIMER_STRUCT BlinkTimer; // 50 ms periodic timer + ULONG LastLedCsr; +} LED_CONTROL; + +typedef struct _BBP_TUNING_STRUCT { + BOOLEAN Enable; + UCHAR FalseCcaCountUpperBound; // 100 per sec + UCHAR FalseCcaCountLowerBound; // 10 per sec + UCHAR R17LowerBound; // specified in E2PROM + UCHAR R17UpperBound; // 0x68 according to David Tung + UCHAR CurrentR17Value; +} BBP_TUNING, *PBBP_TUNING; + +typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { + BOOLEAN PrimaryInUsed; + BOOLEAN FirstPktArrivedWhenEvaluate; + UCHAR PrimaryRxAnt; // 0:Ant-A, 1:Ant-B + UCHAR SecondaryRxAnt; // 0:Ant-A, 1:Ant-B + UCHAR CurrentRxAnt; // 0:Ant-A, 1:Ant-B + USHORT AvgRssi[2]; // AvgRssi[0]:Ant-A, AvgRssi[1]:Ant-B + ULONG RcvPktNumWhenEvaluate; + RALINK_TIMER_STRUCT RxAntDiversityTimer; +} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; + +typedef struct _STA_WITH_ETHER_BRIDGE_STRUCT { + BOOLEAN Enable; + MACADDR EtherMacAddr; +} STA_WITH_ETHER_BRIDGE, *PSTA_WITH_ETHER_BRIDGE; + +// PortConfig +typedef struct _PORT_CONFIG { + + // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) + USHORT CapabilityInfo; + USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) + USHORT BeaconPeriod; // in units of TU + + USHORT CfpMaxDuration; + USHORT CfpDurRemain; + USHORT CfpCount; + USHORT CfpPeriod; + + USHORT DisassocReason; + MACADDR DisassocSta; + USHORT DeauthReason; + MACADDR DeauthSta; + USHORT AuthFailReason; + MACADDR AuthFailSta; + + NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined + NDIS_802_11_WEP_STATUS WepStatus; + + // MIB:ieee802dot11.dot11smt(1).dot11WEPDefaultKeysTable(3) + WEP_KEY SharedKey[SHARE_KEY_NO]; // Keep for backward compatiable + WPA_KEY PairwiseKey[PAIRWISE_KEY_NO]; + WPA_KEY GroupKey[GROUP_KEY_NO]; + WPA_KEY PskKey; // WPA PSK mode PMK + UCHAR PTK[64]; + + // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED + UCHAR PortSecured; + + // For WPA countermeasures + ULONG LastMicErrorTime; // record last MIC error time + ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). + BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. + // For WPA-PSK supplicant state + WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x + UCHAR ReplayCounter[8]; + UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator + UCHAR SNonce[32]; // SNonce for WPA-PSK + + // MIB:ieee802dot11.dot11smt(1).dot11WEPKeyMappingsTable(4) + // not implemented yet + + // MIB:ieee802dot11.dot11smt(1).dot11PrivacyTable(5) + UCHAR DefaultKeyId; + NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X + + // MIB:ieee802dot11.dot11mac(2).dot11OperationTable(1) + USHORT RtsThreshold; // in units of BYTE + USHORT FragmentThreshold; + BOOLEAN bFragmentZeroDisable; // Microsoft use 0 as disable + + // MIB:ieee802dot11.dot11phy(4).dot11PhyAntennaTable(2) + UCHAR CurrentTxAntenna; + UCHAR CurrentRxAntenna; + UCHAR NumberOfAntenna; + + // MIB:ieee802dot11.dot11phy(4).dot11PhyTxPowerTable(3) + UCHAR CurrentTxPowerLevelIndex; //default&other value=MaxPower,1=MinPower,2=1*MaxPower/4,3=2*MaxPower/4,4=3*MaxPower/4, + UCHAR TxPower; + UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... + BOOLEAN EnableAutoRateSwitching; // 1 - enable auto rate switching; 0 - disable + // Krellan: Now using this instead of TxPowerPercentage + UCHAR TxPowerDriver; // Driver's last TxPower setting written to hardware, in raw units + int TxPowerUser; // User's desired fixed TxPower setting, in dBm + BOOLEAN TxPowerAuto; // 1 - enable auto TxPower; 0 - fixed + + // MIB:ieee802dot11.dot11phy(4).dot11PhyDSSSTable(5) + UCHAR Channel; // current (I)BSS channel used in the station + UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel + + // MIB:ieee802dot11.dot11phy(4).dot11AntennasListTable(8) + BOOLEAN AntennaSupportTx; + BOOLEAN AntennaSupportRx; + BOOLEAN AntennaSupportDiversityRx; + + // Use user changed MAC + BOOLEAN bLocalAdminMAC; + + // MIB:ieee802dot11.dot11phy(4).dot11SupportedDataRatesTxTable(9) + // MIB:ieee802dot11.dot11phy(4).dot11SupportedDataRatesRxTable(10) + UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; // Supported rates + UCHAR SupportedRatesLen; + UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; + // Copy supported rate from desired AP's beacon. We are trying to match + // AP's supported and extended rate settings. + UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR SupRateLen; + UCHAR ExtRateLen; + + // + // other parameters not defined in standard MIB + // + UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES + UCHAR MaxDesiredRate; + USHORT RecvDtim; + MACADDR Bssid; + MACADDR Broadcast; // FF:FF:FF:FF:FF:FF + USHORT Pss; // current power saving status (PWR_SAVE|PWR_ACTIVE) + UCHAR RssiTrigger; + UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD + UCHAR LastRssi; // last received BEACON's RSSI + SHORT LastAvgRssi; // last + USHORT AvgRssi; // last 8 BEACON's average RSSI + USHORT AtimWin; // in kusec; IBSS parameter set element + USHORT Aid; // association ID + UCHAR RtsRate; // RATE_xxx + UCHAR MlmeRate; // RATE_xxx, used to send MLME frames + UCHAR MaxTxRate; // RATE_xxx + USHORT DefaultListenCount; // default listen count; + UCHAR BssType; // BSS_INFRA or BSS_INDEP + + UCHAR SsidLen; // the actual ssid length in used + CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated + + BSS_TABLE BssTab; // BSS Table + + // global variables mXXXX used in MAC protocol state machines + BOOLEAN Mibss; + BOOLEAN Massoc; + BOOLEAN Mauth; + + // RFMON logic flags + BOOLEAN MallowRFMONTx; + + // PHY specification + UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED + USHORT Dsifs; // in units of usec + + ULONG WindowsPowerMode; // Power mode for AC power + ULONG WindowsBatteryPowerMode; // Power mode for battery if exists + BOOLEAN WindowsACCAMEnable; // Enable CAM power mode when AC on + ULONG PacketFilter; // Packet filter for receiving + BOOLEAN AutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID + + ULONG WindowsTxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto + + UCHAR ChannelTxPower[MAX_LEN_OF_CHANNELS]; // Store Tx power value for all channels. + UCHAR ChannelTssiRef[MAX_LEN_OF_CHANNELS]; // Store Tssi Reference value for all channels. + UCHAR ChannelTssiDelta; // Store Tx TSSI delta increment / decrement value + BOOLEAN bAutoTxAgc; + UCHAR ChannelList[MAX_LEN_OF_CHANNELS]; // list all supported channels for site survey + UCHAR ChannelListNum; // number of channel in ChannelList[] + BOOLEAN bShowHiddenSSID; + + // configuration to be used when this STA starts a new ADHOC network + IBSS_CONFIG IbssConfig; + + ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time + ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time + ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST + ULONG IgnoredScanNumber; // Ignored BSSID_SCAN_LIST requests + BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On + BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On + BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state + BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled + + LED_CONTROL LedCntl; + UCHAR RfType; + UCHAR LedMode; + RALINK_TIMER_STRUCT RfTuningTimer; + STA_WITH_ETHER_BRIDGE StaWithEtherBridge; + + // New for WPA, windows want us to to keep association information and + // Fixed IEs from last association response + NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; +// NDIS_802_11_FIXED_IEs FixIEs; + UCHAR ReqVarIELen; // Length of next VIE include EID & Length + UCHAR ReqVarIEs[MAX_VIE_LEN]; + UCHAR ResVarIELen; // Length of next VIE include EID & Length + UCHAR ResVarIEs[MAX_VIE_LEN]; + + // the following fields are user setting from UI + ULONG EnableTurboRate; // 0: disable, 1: enable 72/100 Mbps whenever applicable + ULONG EnableTxBurst; // 0: disable, 1: enable TX PACKET BURST + ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use + ULONG UseShortSlotTime; // 0: disable, 1: enable 9us short slot time if AP supports + ULONG AdhocMode; // 0:WIFI mode (11b rates only), 1:allow OFDM rates + + // this flag is the result calculated from UI settings and AP's ERP/Capability + ULONG BGProtectionInUsed; // 0: not in-used, 1: in-used + ULONG ShortSlotInUsed; // 0: not in-used, 1: in-used + USHORT TxPreambleInUsed; // Rt802_11PreambleLong, Rt802_11PreambleShort + + // PCI clock adjustment round + UCHAR PciAdjustmentRound; + + // latch th latest RF programming value here since RF IC doesn't support READ operation + RTMP_RF_REGS LatchRfRegs; + + BOOLEAN BbpTuningEnable; + UCHAR VgcLowerBound; + RT_802_11_RX_AGC_VGC_TUNING BbpTuning; + + UCHAR LastR17Value; + + // New for RSSI to dbm veriable + UCHAR RssiToDbm; // EEPROM 0x7c + + + ULONG SystemErrorBitmap; // b0: E2PROM version error + + // This soft Rx Antenna Diversity mechanism is used only when user set + // RX Antenna = DIVERSITY ON + SOFT_RX_ANT_DIVERSITY RxAnt; + + ULONG Rt2560Version; // MAC/BBP serial interface issue solved after ver.D + ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused + UCHAR BbpWriteLatch[100]; // record last BBP register value written via BBP_IO_WRITE +// ULONG CurrTxRateStableTime; // # of second in current TX rate + ULONG NumOfAvgRssiSample;// UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition +} PORT_CONFIG, *PPORT_CONFIG; + +typedef struct _MLME_MEMORY_STRUCT { + PVOID AllocVa; //Pointer to the base virtual address of the allocated memory + struct _MLME_MEMORY_STRUCT *Next; //Pointer to the next virtual address of the allocated memory +} MLME_MEMORY_STRUCT, *PMLME_MEMORY_STRUCT; + +typedef struct _MLME_MEMORY_HANDLER { + BOOLEAN MemRunning; //The flag of the Mlme memory handler's status + UINT MemoryCount; //Total nonpaged system-space memory not size + UINT InUseCount; //Nonpaged system-space memory in used counts + UINT UnUseCount; //Nonpaged system-space memory available counts + UINT PendingCount; //Nonpaged system-space memory for free counts + PMLME_MEMORY_STRUCT pInUseHead; //Pointer to the first nonpaed memory not used + PMLME_MEMORY_STRUCT pInUseTail; //Pointer to the last nonpaged memory not used + PMLME_MEMORY_STRUCT pUnUseHead; //Pointer to the first nonpaged memory in used + PMLME_MEMORY_STRUCT pUnUseTail; //Pointer to the last nonpaged memory in used + PULONG MemFreePending[MAX_MLME_HANDLER_MEMORY]; //an array to keep pending free-memory's pointer (32bits) +} MLME_MEMORY_HANDLER, *PMLME_MEMORY_HANDLER; + +typedef struct _MLME_STRUCT { + STATE_MACHINE CntlMachine, AssocMachine, AuthMachine, AuthRspMachine, SyncMachine, WpaPskMachine; + STATE_MACHINE_FUNC CntlFunc[CNTL_FUNC_SIZE], AssocFunc[ASSOC_FUNC_SIZE]; + STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE], AuthRspFunc[AUTH_RSP_FUNC_SIZE]; + STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE], WpaPskFunc[WPA_PSK_FUNC_SIZE]; + + ASSOC_AUX AssocAux; + AUTH_AUX AuthAux; + AUTH_RSP_AUX AuthRspAux; + SYNC_AUX SyncAux; + CNTL_AUX CntlAux; + + COUNTER_802_11 PrevWlanCounters; + ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming + + BOOLEAN Running; + spinlock_t TaskLock; + MLME_QUEUE Queue; + + UINT ShiftReg; + PSPOLL_FRAME PsFr; + MACHDR NullFr; + + RALINK_TIMER_STRUCT PeriodicTimer; + ULONG PeriodicRound; + ULONG PrevTxCnt; + + MLME_MEMORY_HANDLER MemHandler; //The handler of the nonpaged memory inside MLME +} MLME_STRUCT, *PMLME_STRUCT; + +// +// Management ring buffer format +// +typedef struct _MGMT_STRUC { + BOOLEAN Valid; + PUCHAR pBuffer; + ULONG Length; +} MGMT_STRUC, *PMGMT_STRUC; + +// +// P802.11 Frame control field, 16 bit +// +typedef struct PACKED _FRAME_CONTROL { +#ifdef BIG_ENDIAN + USHORT Order:1; + USHORT Wep:1; + USHORT MoreData:1; + USHORT PwrMgt:1; + USHORT Retry:1; + USHORT MoreFrag:1; + USHORT FrDs:1; + USHORT ToDs:1; + USHORT Subtype:4; + USHORT Type:2; + USHORT Ver:2; +#else + USHORT Ver:2; // Protocol version + USHORT Type:2; // MSDU type + USHORT Subtype:4; // MSDU subtype + USHORT ToDs:1; // To DS indication + USHORT FrDs:1; // From DS indication + USHORT MoreFrag:1; // More fragment bit + USHORT Retry:1; // Retry status bit + USHORT PwrMgt:1; // Power management bit + USHORT MoreData:1; // More data bit + USHORT Wep:1; // Wep data + USHORT Order:1; // Strict order expected +#endif +} FRAME_CONTROL, *PFRAME_CONTROL; + +// +// P802.11 intermediate header format +// +typedef struct PACKED _CONTROL_HEADER { + FRAME_CONTROL Frame; // Frame control structure + USHORT Duration; // Duration value + MACADDR Addr1; // Address 1 field + MACADDR Addr2; // Address 2 field +} CONTROL_HEADER, *PCONTROL_HEADER; + +// +// P802.11 header format +// +typedef struct PACKED _HEADER_802_11 { + CONTROL_HEADER Controlhead; + MACADDR Addr3; // Address 3 field +#ifdef BIG_ENDIAN + USHORT Sequence:12; // Sequence number + USHORT Frag:4; // Fragment number +#else + USHORT Frag:4; // Fragment number + USHORT Sequence:12; // Sequence number +#endif +} HEADER_802_11, *PHEADER_802_11; + +// +// Receive Tuple Cache Format +// +typedef struct PACKED _TUPLE_CACHE { + BOOLEAN Valid; + MACADDR MAC; + USHORT Sequence; + USHORT Frag; +} TUPLE_CACHE, *PTUPLE_CACHE; + +// +// Fragment Frame structure +// +typedef struct PACKED _FRAGMENT_FRAME { + UCHAR Header802_3[14]; + UCHAR Header_LLC[8]; + UCHAR Buffer[LENGTH_802_3 + MAX_FRAME_SIZE]; + ULONG RxSize; + USHORT Sequence; + USHORT LastFrag; + ULONG Flags; // Some extra frame information. bit 0: LLC presented +} FRAGMENT_FRAME, *PFRAGMENT_FRAME; + +// +// Tkip Key structure which RC4 key & MIC calculation +// +typedef struct PACKED _TKIP_KEY_INFO { + UINT nBytesInM; // # bytes in M for MICKEY + ULONG IV16; + ULONG IV32; + ULONG K0; // for MICKEY Low + ULONG K1; // for MICKEY Hig + ULONG L; // Current state for MICKEY + ULONG R; // Current state for MICKEY + ULONG M; // Message accumulator for MICKEY + UCHAR RC4KEY[16]; + UCHAR MIC[8]; +} TKIP_KEY_INFO, *PTKIP_KEY_INFO; + +// +// Private / Misc data, counters for driver internal use +// +typedef struct __PRIVATE_STRUC { + ULONG SystemResetCnt; // System reset counter + ULONG TxRingFullCnt; // Tx ring full occurrance number + ULONG ResetCountDown; // Count down before issue reset, patch for RT2430 + ULONG CCAErrCnt; // CCA error count, for debug purpose, might move to global counter + ULONG PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter + ULONG PhyTxErrCnt; // PHY Tx error count, for debug purpose, might move to global counter + // Variables for WEP encryption / decryption in rtmp_wep.c + ULONG FCSCRC32; + ULONG RxSetCnt; + ULONG DecryptCnt; + ARCFOURCONTEXT WEPCONTEXT; + // Tkip stuff + TKIP_KEY_INFO Tx; + TKIP_KEY_INFO Rx; +} PRIVATE_STRUC, *PPRIVATE_STRUC; + +// +// All DMA ring formats +// +struct ring_desc { + // Descriptor size & dma address + u32 size; + void *va_addr; + dma_addr_t pa_addr; + // Dma buffer size and address for real transfer + u32 data_size; + void *va_data_addr; + dma_addr_t pa_data_addr; + UCHAR FrameType; // Type of frame in ring buffer +}; + +#ifdef RALINK_ATE +typedef struct _ATE_INFO { + UCHAR Mode; + UCHAR TxPower; + UCHAR Addr1[6]; + UCHAR Addr2[6]; + UCHAR Addr3[6]; + UCHAR Channel; + ULONG TxLength; + ULONG TxCount; + ULONG TxDoneCount; + ULONG TxRate; +} ATE_INFO, *PATE_INFO; +#endif //#ifdef RALINK_ATE + +// +// The miniport adapter structure +// +typedef struct _RTMP_ADAPTER +{ + char nickn[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f + int chip_id; + + unsigned long CSRBaseAddress; // PCI MMIO Base Address, all access will use + // NdisReadRegisterXx or NdisWriteRegisterXx + + // configuration + UCHAR PermanentAddress[ETH_ALEN]; // Factory default MAC address + UCHAR CurrentAddress[ETH_ALEN]; // User changed MAC address + + UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 + USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; + + // resource for DMA operation + struct ring_desc TxRing[TX_RING_SIZE]; // Tx Ring + struct ring_desc AtimRing[ATIM_RING_SIZE]; // Atim Ring + struct ring_desc PrioRing[PRIO_RING_SIZE]; // Priority Ring + struct ring_desc RxRing[RX_RING_SIZE]; // Rx Ring + struct ring_desc BeaconRing; // Beacon Ring, only one + + MGMT_STRUC MgmtRing[MGMT_RING_SIZE]; // management ring size + + ULONG CurRxIndex; // Next RxD read pointer + ULONG CurDecryptIndex; // Next RxD decrypt read pointer + ULONG CurTxIndex; // Next TxD write pointer + ULONG CurEncryptIndex; // Next TxD encrypt write pointer + ULONG CurAtimIndex; // Next AtimD write pointer + ULONG CurPrioIndex; // Next PrioD write pointer + ULONG PushMgmtIndex; // Next SW management ring index + ULONG PopMgmtIndex; // Next SW management ring index + ULONG MgmtQueueSize; // Number of Mgmt request stored in MgmtRing + ULONG NextEncryptDoneIndex; + ULONG NextTxDoneIndex; + ULONG NextAtimDoneIndex; + ULONG NextPrioDoneIndex; + ULONG NextDecryptDoneIndex; + + // 802.3 multicast support + ULONG NumberOfMcAddresses; // Number of mcast entry exists + UCHAR McastTable[MAX_MCAST_LIST_SIZE][ETH_ALEN]; // Mcast list + //flags + ULONG Flags; // Represent current device status + + // Tx software priority queue list, 802.1q priority information mapped as. + // 0,1 -> queue0, 2,3 -> queue1, 4,5 -> queue2, 6,7 -> queue3 + struct sk_buff_head TxSwQueue0; // Tx software priority queue 0 mapped to 0.1 + struct sk_buff_head TxSwQueue1; // Tx software priority queue 1 mapped to 2.3 + struct sk_buff_head TxSwQueue2; // Tx software priority queue 2 mapped to 4.5 + struct sk_buff_head TxSwQueue3; + + USHORT Sequence; // Current sequence number + + TUPLE_CACHE TupleCache[MAX_CLIENT]; // Maximum number of tuple caches, only useful in Ad-Hoc + UCHAR TupleCacheLastUpdateIndex; // 0..MAX_CLIENT-1 + FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame + + // For MiniportTransferData + PUCHAR pRxData; // Pointer to current RxRing offset / fragment frame offset + + // Counters for 802.3 & generic. + // Add 802.11 specific counters later + COUNTER_802_3 Counters; // 802.3 counters + COUNTER_802_11 WlanCounters; // 802.11 MIB counters + COUNTER_RALINK RalinkCounters; // Ralink propriety counters + COUNTER_DRS DrsCounters; // counters for Dynamic Rate Switching + + NDIS_MEDIA_STATE MediaState; + + PRIVATE_STRUC PrivateInfo; // Private information & counters + + // SpinLocks + spinlock_t TxRingLock; // Tx Ring spinlock + spinlock_t PrioRingLock; // Prio Ring spinlock + spinlock_t AtimRingLock; // Atim Ring spinlock + spinlock_t RxRingLock; // Rx Ring spinlock + spinlock_t TxSwQueueLock; // SendTxWaitQueue spinlock + spinlock_t MemLock; // Memory handler spinlock + +// Boolean control for packet filter + BOOLEAN bAcceptDirect; + BOOLEAN bAcceptMulticast; + BOOLEAN bAcceptBroadcast; + BOOLEAN bAcceptAllMulticast; + BOOLEAN bAcceptPromiscuous; + + // Control to check Tx hang + BOOLEAN bTxBusy; + //PQUEUE_ENTRY FirstEntryInQueue; // The first packet in Tx queue + + // Control disconnect / connect event generation + ULONG LinkDownTime; + ULONG LastRxRate; + UCHAR LastSsidLen; // the actual ssid length in used + CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated + MACADDR LastBssid; + BOOLEAN bConfigChanged; + + PORT_CONFIG PortCfg; + MLME_STRUCT Mlme; + + struct pci_dev *pPci_Dev; + struct net_device *net_dev; + + RALINK_TIMER_STRUCT timer; // Periodic Media monitoring timer. + + BOOLEAN bNetDeviceStopQueue; + BOOLEAN NeedSwapToLittleEndian; + +#if WIRELESS_EXT >= 12 + struct iw_statistics iw_stats; +#endif + struct net_device_stats stats; + +#ifdef RALINK_ATE + ATE_INFO ate; +#endif //#ifdef RALINK_ATE + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + struct work_struct mlme_work; +#endif +} RTMP_ADAPTER, *PRTMP_ADAPTER; + +// +// SHA context +// +typedef struct _SHA_CTX +{ + ULONG H[5]; + ULONG W[80]; + INT lenW; + ULONG sizeHi, sizeLo; +} SHA_CTX; + +// +// Enable & Disable NIC interrupt via writing interrupt mask register +// Since it use ADAPTER structure, it have to be put after structure definition. +// +static inline VOID NICDisableInterrupt( + IN PRTMP_ADAPTER pAd) +{ + RTMP_IO_WRITE32(pAd, CSR8, 0xFFFF); + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); +} + +static inline VOID NICEnableInterrupt( + IN PRTMP_ADAPTER pAd) +{ + // 0xFF37 : Txdone & Rxdone, 0xFF07: Txdonw, Rxdone, PrioDone, AtimDone, + RTMP_IO_WRITE32(pAd, CSR8, 0xFE14); + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); +} + +BOOLEAN NICCheckForHang( + IN PRTMP_ADAPTER pAd); + + +INT RT2500_close( + IN struct net_device *net_dev); + +irqreturn_t RTMPIsr( + IN INT irq, + IN VOID *dev_instance, + IN struct pt_regs *rgs); + +VOID RT2500_timer( + IN unsigned long data); + +INT RT2500_open( + IN struct net_device *net_dev); + +INT RTMPSendPackets( + IN struct sk_buff *skb, + IN struct net_device *net_dev); + +INT RT2500_probe( + IN struct pci_dev *pPci_Dev, + IN const struct pci_device_id *ent); + +INT RT2500_ioctl( + IN struct net_device *net_dev, + IN OUT struct ifreq *rq, + IN INT cmd); + +VOID RTMPRingCleanUp( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR RingType); + +#if WIRELESS_EXT >= 12 +struct iw_statistics *RT2500_get_wireless_stats( + IN struct net_device *net_dev); +#endif + +struct net_device_stats *RT2500_get_ether_stats( + IN struct net_device *net_dev); + +VOID RT2500_set_rx_mode( + IN struct net_device *net_dev); + +NDIS_STATUS RTMPAllocDMAMemory( + IN PRTMP_ADAPTER pAd); + +VOID RTMPFreeDMAMemory( + IN PRTMP_ADAPTER pAd); + +VOID NICReadEEPROMParameters( + IN PRTMP_ADAPTER pAdapter); + +VOID NICInitAsicFromEEPROM( + IN PRTMP_ADAPTER pAdapter); + +VOID NICInitTransmit( + IN PRTMP_ADAPTER pAdapter); + +NDIS_STATUS NICReadAdapterInfo( + IN PRTMP_ADAPTER pAdapter); + +VOID NICInitializeAdapter( + IN PRTMP_ADAPTER pAdapter); + +VOID NICInitializeAsic( + IN PRTMP_ADAPTER pAdapter); + +VOID NICIssueReset( + IN PRTMP_ADAPTER pAdapter); + +VOID PortCfgInit( + IN PRTMP_ADAPTER pAdapter); + +VOID NICResetFromError( + IN PRTMP_ADAPTER pAdapter); + +PUCHAR RTMPFindSection( + IN PCHAR buffer, + IN PCHAR section); + +INT RTMPIsFindSection( + IN PUCHAR ptr, + IN PUCHAR buffer); + +INT RTMPGetKeyParameter( + IN PUCHAR section, + IN PCHAR key, + OUT PCHAR dest, + IN INT destsize, + IN PCHAR buffer); + +VOID RTMPReadParametersFromFile( + IN PRTMP_ADAPTER pAd); + +#define RTMPEqualMemory(p1,p2,n) (memcmp((p1),(p2),(n)) == 0) + +ULONG RTMPCompareMemory( + IN PVOID pSrc1, + IN PVOID pSrc2, + IN ULONG Length); + +void AtoH(char * src, UCHAR * dest, int destlen); +UCHAR BtoH(char ch); + +VOID RTMPInitTimer( + IN PRTMP_ADAPTER pAdapter, + IN PRALINK_TIMER_STRUCT pTimer, + IN PVOID pTimerFunc); + +VOID RTMPSetTimer( + IN PRTMP_ADAPTER pAdapter, + IN PRALINK_TIMER_STRUCT pTimer, + IN ULONG Value); + +VOID RTMPCancelTimer( + IN PRALINK_TIMER_STRUCT pTimer); + +// +// Private routines in rtmp_data.c +// +VOID RTMPHandleRxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleTxRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandlePrioRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleAtimRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleTbcnInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleTwakeupInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleDecryptionDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHandleEncryptionDoneInterrupt( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPHardTransmitDone( + IN PRTMP_ADAPTER pAdapter, + IN PTXD_STRUC pTxD, + IN UCHAR FrameType); + +NDIS_STATUS RTMPSendPacket( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb); + +//VOID RTMPDeQueuePacket( +// IN PRTMP_ADAPTER pAdapter, +// IN PQUEUE_HEADER pQueue); + +VOID RTMPDeQueuePacket( + IN PRTMP_ADAPTER pAdapter); + +NDIS_STATUS RTMPHardEncrypt( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb, + IN UCHAR NumberRequired, + IN ULONG EnableTxBurst, + IN UCHAR AccessCategory); + +NDIS_STATUS RTMPHardTransmit( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb, + IN UCHAR NumberRequired); + +NDIS_STATUS RTMPFreeDescriptorRequest( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR RingType, + IN UCHAR NumberRequired); + +VOID MlmeHardTransmit( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length); + +USHORT RTMPCalcDuration( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR Rate, + IN ULONG Size); + +VOID RTMPWriteTxDescriptor( + IN PTXD_STRUC pTxD, + IN BOOLEAN DoEncrypt, + IN UCHAR CipherAlg, + IN BOOLEAN Ack, + IN BOOLEAN Fragment, + IN BOOLEAN InsTimestamp, + IN UCHAR RetryMode, + IN UCHAR Ifs, + IN UINT Rate, + IN UCHAR Service, + IN ULONG Length, + IN USHORT TxPreamble, + IN UCHAR AccessCategory); + +BOOLEAN RTMPSearchTupleCache( + IN PRTMP_ADAPTER pAdapter, + IN PHEADER_802_11 pHeader); + +VOID RTMPUpdateTupleCache( + IN PRTMP_ADAPTER pAdapter, + IN PHEADER_802_11 pHeader); + +VOID RTMPSuspendMsduTransmission( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPResumeMsduTransmission( + IN PRTMP_ADAPTER pAdapter); + +NDIS_STATUS MiniportMMRequest( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length); + +VOID RTMPSendNullFrame( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length, + IN UCHAR TxRate); + +NDIS_STATUS RTMPApplyPacketFilter( + IN PRTMP_ADAPTER pAdapter, + IN PRXD_STRUC pRxD, + IN PHEADER_802_11 pHeader); + +struct sk_buff_head* RTMPCheckTxSwQueue( + IN PRTMP_ADAPTER pAdapter, + OUT UCHAR *AccessCategory); + +VOID RTMPReportMicError( + IN PRTMP_ADAPTER pAdapter, + IN PWPA_KEY pWpaKey); +// +// Private routines in rtmp_wep.c +// +VOID RTMPInitWepEngine( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pKey, + IN UCHAR KeyId, + IN UCHAR KeyLen, + IN PUCHAR pDest); + +VOID RTMPEncryptData( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN PUCHAR pDest, + IN UINT Len); + +BOOLEAN RTMPDecryptData( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN UINT Len); + +VOID RTMPSetICV( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pDest); + +VOID ARCFOUR_INIT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pKey, + IN UINT KeyLen); + +UCHAR ARCFOUR_BYTE( + IN PARCFOURCONTEXT Ctx); + +VOID ARCFOUR_DECRYPT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pDest, + IN PUCHAR pSrc, + IN UINT Len); + +VOID ARCFOUR_ENCRYPT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pDest, + IN PUCHAR pSrc, + IN UINT Len); + +ULONG RTMP_CALC_FCS32( + IN ULONG Fcs, + IN PUCHAR Cp, + IN INT Len); + +// +// MLME routines +// +//VOID Arc4Init(ARC4_CONTEXT *Ctx, UCHAR *Key, ULONG KeyLen); +//UCHAR Arc4Byte(ARC4_CONTEXT *Ctx); +//VOID Arc4Cipher(ARC4_CONTEXT *Ctx, UCHAR *Dest, UCHAR *Src, ULONG Len); + +// Asic/RF/BBP related functions + +VOID AsicAdjustTxPower( + IN PRTMP_ADAPTER pAd); + +VOID AsicSwitchChannel( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR Channel); + +VOID AsicLockChannel( + IN PRTMP_ADAPTER pAd, + IN UCHAR Channel) ; + +VOID AsicRfTuningExec( + IN unsigned long data); + +VOID AsicSleepThenAutoWakeup( + IN PRTMP_ADAPTER pAdapter, + IN USHORT TbttNumToNextWakeUp); + +VOID AsicForceSleep( + IN PRTMP_ADAPTER pAdapter); + +VOID AsicForceWakeup( + IN PRTMP_ADAPTER pAdapter); + +VOID AsicSetBssid( + IN PRTMP_ADAPTER pAdapter, + IN MACADDR *Bssid); + +VOID AsicDisableSync( + IN PRTMP_ADAPTER pAdapter); + +VOID AsicEnableBssSync( + IN PRTMP_ADAPTER pAdapter); + +VOID AsicEnableIbssSync( + IN PRTMP_ADAPTER pAdapter); + +VOID AsicLedPeriodicExec( + IN unsigned long data); + +VOID AsicSetRxAnt( + IN PRTMP_ADAPTER pAd); + +VOID AsicEvaluateSecondaryRxAnt( + IN PRTMP_ADAPTER pAd); + +VOID AsicRxAntEvalTimeout( + IN unsigned long data); + +VOID AsicSetSlotTime( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN UseShortSlotTime); + +VOID AsicAdjustUsec( + IN PRTMP_ADAPTER pAd); + +VOID AsicBbpTuning( + IN PRTMP_ADAPTER pAd); + +VOID AsicRestoreBbpSensibility( + IN PRTMP_ADAPTER pAd); + +VOID MacAddrRandomBssid( + IN PRTMP_ADAPTER pAdapter, + OUT PMACADDR Addr); + +VOID MgtMacHeaderInit( + IN PRTMP_ADAPTER pAdapter, + IN OUT PMACHDR Hdr, + IN UCHAR Subtype, + IN UCHAR ToDs, +// IN UCHAR AddrType, + IN PMACADDR Ds, + IN PMACADDR Bssid); + +VOID MlmeRadioOff( + IN PRTMP_ADAPTER pAd); + +VOID MlmeRadioOn( + IN PRTMP_ADAPTER pAd); + +VOID BssTableInit( + IN BSS_TABLE *Tab); + +ULONG BssTableSearch( + IN BSS_TABLE *Tab, + IN PMACADDR Bssid); + +VOID BssTableDeleteEntry( + IN OUT BSS_TABLE *Tab, + IN PMACADDR Bssid); + +VOID BssEntrySet( + IN PRTMP_ADAPTER pAdapter, + OUT BSS_ENTRY *Bss, + IN MACADDR *Bssid, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN USHORT BeaconPeriod, + IN BOOLEAN CfExist, + IN CF_PARM *CfParm, + IN USHORT AtimWin, + IN USHORT CapabilityInfo, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist, + IN UCHAR Channel, + IN UCHAR Rssi, + IN UCHAR Noise, + IN LARGE_INTEGER TimeStamp, + IN PNDIS_802_11_VARIABLE_IEs pVIE); + +ULONG BssTableSetEntry( + IN PRTMP_ADAPTER pAdapter, + OUT BSS_TABLE *Tab, + IN MACADDR *Bssid, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN USHORT BeaconPeriod, + IN BOOLEAN CfExist, + IN CF_PARM *CfParm, + IN USHORT AtimWin, + IN USHORT CapabilityInfo, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist, + IN UCHAR Channel, + IN UCHAR Rssi, + IN UCHAR Noise, + IN LARGE_INTEGER TimeStamp, + IN PNDIS_802_11_VARIABLE_IEs pVIE); + +VOID BssTableSsidSort( + IN PRTMP_ADAPTER pAd, + OUT BSS_TABLE *OutTab, + IN CHAR Ssid[], + IN UCHAR SsidLen); + +VOID BssTableSortByRssi( + IN OUT BSS_TABLE *OutTab); + +NDIS_802_11_WEP_STATUS BssCipherParse( + IN PUCHAR pCipher); + +NDIS_STATUS MlmeQueueInit( + IN MLME_QUEUE *Queue); + +VOID MlmeQueueDestroy( + IN MLME_QUEUE *Queue); + +BOOLEAN MlmeEnqueue( + OUT MLME_QUEUE *Queue, + IN ULONG Machine, + IN ULONG MsgType, + IN ULONG MsgLen, + IN VOID *Msg); + +BOOLEAN MlmeEnqueueForRecv( + IN PRTMP_ADAPTER pAdapter, + OUT MLME_QUEUE *Queue, + IN ULONG TimeStampHigh, + IN ULONG TimeStampLow, + IN UCHAR Rssi, + IN UCHAR Noise, + IN ULONG MsgLen, + IN PVOID Msg); + +BOOLEAN MlmeDequeue( + IN MLME_QUEUE *Queue, + OUT MLME_QUEUE_ELEM **Elem); + +VOID MlmeRestartStateMachine( + IN PRTMP_ADAPTER pAd); + +BOOLEAN MlmeQueueEmpty( + IN MLME_QUEUE *Queue); + +BOOLEAN MlmeQueueFull( + IN MLME_QUEUE *Queue); + +BOOLEAN MsgTypeSubst( + IN MACFRAME *Fr, + OUT INT *Machine, + OUT INT *MsgType); + +VOID StateMachineInit( + IN STATE_MACHINE *Sm, + IN STATE_MACHINE_FUNC Trans[], + IN ULONG StNr, + IN ULONG MsgNr, + IN STATE_MACHINE_FUNC DefFunc, + IN ULONG InitState, + IN ULONG Base); + +VOID StateMachineSetAction( + IN STATE_MACHINE *S, + IN ULONG St, + ULONG Msg, + IN STATE_MACHINE_FUNC F); + +VOID StateMachinePerformAction( + IN PRTMP_ADAPTER pAdapter, + IN STATE_MACHINE *S, + IN MLME_QUEUE_ELEM *Elem); + +VOID Drop( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID StateMachineDestroy( + IN STATE_MACHINE *Sm); + +VOID AssocStateMachineInit( + IN PRTMP_ADAPTER pAdapter, + IN STATE_MACHINE *Sm, + OUT STATE_MACHINE_FUNC Trans[]); + +VOID ReassocTimeout( + IN unsigned long data); + +VOID AssocTimeout( + IN unsigned long data); + +VOID DisassocTimeout( + IN unsigned long data); + +//---------------------------------------------- +VOID MlmeDisassocReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID MlmeAssocReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID MlmeReassocReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID MlmeDisassocReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAssocRspAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerReassocRspAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerDisassocAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID DisassocTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID AssocTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID ReassocTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID Cls3errAction( + IN PRTMP_ADAPTER pAdapter, + IN PMACADDR pAddr); + +VOID InvalidStateWhenAssoc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenReassoc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenDisassociate( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID ComposePsPoll( + IN PRTMP_ADAPTER pAdapter); + +VOID ComposeNullFrame( + IN PRTMP_ADAPTER pAdapter); + +VOID AssocPostProc( + IN PRTMP_ADAPTER pAdapter, + IN MACADDR *Addr2, + IN USHORT CapabilityInfo, + IN USHORT Aid, + IN UCHAR Rates[], + IN UCHAR RatesLen, + IN BOOLEAN ExtendedRateIeExist); + +VOID AuthStateMachineInit( + IN PRTMP_ADAPTER pAdapter, + IN PSTATE_MACHINE sm, + OUT STATE_MACHINE_FUNC Trans[]); + +VOID AuthTimeout( + IN unsigned long data); + +VOID MlmeAuthReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAuthRspAtSeq2Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAuthRspAtSeq4Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID AuthTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID Cls2errAction( + IN PRTMP_ADAPTER pAdapter, + IN PMACADDR pAddr); + +VOID MlmeDeauthReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenAuth( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +//VOID MlmeDeauthReqProc( +// IN PRTMP_ADAPTER pAdapter, +// IN MACADDR *Addr, +// IN USHORT Reason); + +//============================================= + +VOID AuthRspStateMachineInit( + IN PRTMP_ADAPTER pAdapter, + IN PSTATE_MACHINE Sm, + IN STATE_MACHINE_FUNC Trans[]); + + +VOID AuthRspChallengeTimeout( + IN unsigned long data); + +VOID AuthRspChallengeTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAuthAtAuthRspIdleAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAuthAtAuthRspWaitAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerDeauthAction( + IN PRTMP_ADAPTER pAdaptor, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerAuthSimpleRspGenAndSend( + IN PRTMP_ADAPTER pAdapter, + IN PMACHDR Hdr, + IN USHORT Alg, + IN USHORT Seq, + IN USHORT Reason, + IN USHORT Status); + +//======================================== + +VOID SyncStateMachineInit( + IN PRTMP_ADAPTER pAdapter, + IN STATE_MACHINE *Sm, + OUT STATE_MACHINE_FUNC Trans[]); + +VOID BeaconTimeout( + IN unsigned long data); + +VOID AtimTimeout( + IN unsigned long data); + +VOID ScanTimeout( + IN unsigned long data); + +VOID MlmeScanReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenScan( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenJoin( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID InvalidStateWhenStart( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerBeacon( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID EnqueueProbeRequest( + IN PRTMP_ADAPTER pAd); + +//========================================= + +VOID MlmeCntlInit( + IN PRTMP_ADAPTER pAdapter, + IN STATE_MACHINE *S, + OUT STATE_MACHINE_FUNC Trans[]); + +VOID MlmeCntlMachinePerformAction( + IN PRTMP_ADAPTER pAdapter, + IN STATE_MACHINE *S, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlIdleProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlOidScanProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlOidSsidProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM * Elem); + +VOID CntlOidRTBssidProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlMlmeRoamingProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitDisassocProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitJoinProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitReassocProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitStartProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitAuthProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitAuthProc2( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID CntlWaitAssocProc( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID LinkUp( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR BssType); + +VOID LinkDown( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeCntlConfirm( + IN PRTMP_ADAPTER pAdapter, + IN ULONG MsgType, + IN USHORT Msg); + +VOID IterateOnBssTab( + IN PRTMP_ADAPTER pAdapter); + +VOID IterateOnBssTab2( + IN PRTMP_ADAPTER pAdapter);; + +VOID JoinParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, + IN ULONG BssIdx); + +VOID AssocParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, + IN MACADDR *Addr, + IN USHORT CapabilityInfo, + IN ULONG Timeout, + IN USHORT ListenIntv); + +VOID ScanParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, + IN CHAR Ssid[], + IN UCHAR SsidLen, + IN UCHAR BssType, + IN UCHAR ScanType); + +VOID DisassocParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, + IN MACADDR *Addr, + IN USHORT Reason); + +VOID StartParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_START_REQ_STRUCT *StartReq, + IN CHAR Ssid[], + IN UCHAR SsidLen); + +VOID AuthParmFill( + IN PRTMP_ADAPTER pAdapter, + IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, + IN MACADDR *Addr, + IN USHORT Alg); + +VOID EnqueuePsPoll( + IN PRTMP_ADAPTER pAdapter); + +VOID EnqueueBeaconFrame( + IN PRTMP_ADAPTER pAdapter); + +VOID EnqueueNullFrame( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR TxRate); + +VOID MlmeJoinReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID MlmeScanReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID MlmeStartReqAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID ScanTimeoutAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID BeaconTimeoutAtJoinAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerBeaconAtScanAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerBeaconAtJoinAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerBeacon( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID PeerProbeReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem); + +VOID ScanNextChannel( + IN PRTMP_ADAPTER pAdapter); + +ULONG MakeIbssBeacon( + IN PRTMP_ADAPTER pAdapter); + +BOOLEAN MlmeScanReqSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT UCHAR *BssType, + OUT CHAR ssid[], + OUT UCHAR *SsidLen, + OUT UCHAR *ScanType); + +BOOLEAN PeerBeaconAndProbeRspSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT MACADDR *Bssid, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen, + OUT UCHAR *BssType, + OUT USHORT *BeaconPeriod, + OUT UCHAR *Channel, + OUT LARGE_INTEGER *Timestamp, + OUT BOOLEAN *CfExist, + OUT CF_PARM *Cf, + OUT USHORT *AtimWin, + OUT USHORT *CapabilityInfo, + OUT UCHAR Rate[], + OUT UCHAR *RateLen, + OUT BOOLEAN *ExtendedRateIeExist, + OUT UCHAR *Erp, + OUT UCHAR *DtimCount, + OUT UCHAR *DtimPeriod, + OUT UCHAR *BcastFlag, + OUT UCHAR *MessageToMe, + OUT UCHAR *Legacy, + OUT UCHAR SupRate[], + OUT UCHAR *SupRateLen, + OUT UCHAR ExtRate[], + OUT UCHAR *ExtRateLen, + OUT PNDIS_802_11_VARIABLE_IEs pVIE); + +//BOOLEAN JoinParmSanity( +// IN PRTMP_ADAPTER pAdapter, +// IN VOID *Msg, +// IN ULONG MsgLen, +// OUT ULONG *BssIdx, +// OUT UCHAR SupportedRates[], +// OUT UCHAR *SupportedRatesLen); + +BOOLEAN MlmeAssocReqSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *ApAddr, + OUT USHORT *CapabilityInfo, + OUT ULONG *Timeout, + OUT USHORT *ListenIntv); + +BOOLEAN MlmeAuthReqSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr, + OUT ULONG *Timeout, + OUT USHORT *Alg); + +BOOLEAN MlmeStartReqSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT CHAR Ssid[], + OUT UCHAR *Ssidlen); + +BOOLEAN PeerAuthSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr, + OUT USHORT *Alg, + OUT USHORT *Seq, + OUT USHORT *Status, + OUT CHAR ChlgText[]); + +BOOLEAN PeerAssocRspSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *CapabilityInfo, + OUT USHORT *Status, + OUT USHORT *Aid, + OUT UCHAR Rates[], + OUT UCHAR *RatesLen, + OUT BOOLEAN *ExtendedRateIeExist); + +BOOLEAN PeerDisassocSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *Reason); + +BOOLEAN PeerDeauthSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *Reason); + +BOOLEAN PeerProbeReqSanity( + IN PRTMP_ADAPTER pAdapter, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen); +// OUT UCHAR Rates[], +// OUT UCHAR *RatesLen); + +BOOLEAN GetTimBit( + IN CHAR *Ptr, + IN USHORT Aid, + OUT UCHAR *TimLen, + OUT UCHAR *BcastFlag, + OUT UCHAR *DtimCount, + OUT UCHAR *DtimPeriod, + OUT UCHAR *MessageToMe); + +BOOLEAN GetLegacy( + IN CHAR *Ptr, + OUT UCHAR *Legacy); + +ULONG MakeOutgoingFrame( + OUT CHAR *Buffer, + OUT ULONG *Length, ...); + +VOID LfsrInit( + IN PRTMP_ADAPTER pAdapter, + IN ULONG Seed); + +UCHAR RandomByte( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmePeriodicExec( + IN unsigned long data); + +VOID MlmeAutoScan( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeAutoRecoverNetwork( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeAutoReconnectLastSSID( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeCheckForRoaming( + IN PRTMP_ADAPTER pAdapter, + IN ULONG Now32); + +VOID MlmeCheckDynamicTxRateSwitching( + IN PRTMP_ADAPTER pAd); + +VOID MlmeCheckChannelQuality( + IN PRTMP_ADAPTER pAdapter, + IN ULONG Now); + +VOID MlmeCheckForPsmChange( + IN PRTMP_ADAPTER pAdapter, + IN ULONG Now32); + +VOID MlmeSetPsmBit( + IN PRTMP_ADAPTER pAdapter, + IN USHORT psm); + +VOID MlmeSetTxPreamble( + IN PRTMP_ADAPTER pAdapter, + IN USHORT TxPreamble); + +VOID MlmeUpdateTxRates( + IN PRTMP_ADAPTER pAdapter, + IN BOOLEAN bLinkUp); + +NDIS_STATUS MlmeInit( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeHandler( + IN PRTMP_ADAPTER pAdapter); + +VOID MlmeHalt( + IN PRTMP_ADAPTER pAdapter); + +NDIS_STATUS MlmeInitMemoryHandler( + IN PRTMP_ADAPTER pAd, + IN UINT Number, + IN UINT Size); + +NDIS_STATUS MlmeAllocateMemory( + IN PRTMP_ADAPTER pAd, + OUT PVOID *AllocVa); + +VOID MlmeFreeMemory( + IN PRTMP_ADAPTER pAd, + IN PVOID AllocVa); + +VOID MlmeFreeMemoryHandler( + IN PRTMP_ADAPTER pAd); + +VOID BuildChannelList( + IN PRTMP_ADAPTER pAdapter); + +UCHAR FirstChannel( + IN PRTMP_ADAPTER pAdapter); + +UCHAR NextChannel( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR channel); + +VOID RaiseClock( + IN PRTMP_ADAPTER pAd, + IN ULONG *x); + +VOID LowerClock( + IN PRTMP_ADAPTER pAd, + IN ULONG *x); + +USHORT ShiftInBits( + IN PRTMP_ADAPTER pAd); + +VOID ShiftOutBits( + IN PRTMP_ADAPTER pAd, + IN USHORT data, + IN USHORT count); + +VOID EEpromCleanup( + IN PRTMP_ADAPTER pAd); + +VOID EWDS( + IN PRTMP_ADAPTER pAd); + +VOID EWEN( + IN PRTMP_ADAPTER pAd); + +USHORT RTMP_EEPROM_READ16( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset); + +VOID RTMP_EEPROM_WRITE16( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Data); + +UCHAR ChannelSanity( + IN PRTMP_ADAPTER pAd, + IN UCHAR channel); + +// +// Prototypes of function definition in rtmp_tkip.c +// +VOID RTMPInitTkipEngine( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pTKey, + IN UCHAR KeyId, + IN PUCHAR pTA, + IN PUCHAR pMICKey, + IN PUCHAR pTSC, + OUT PULONG pIV16, + OUT PULONG pIV32); + +VOID RTMPInitMICEngine( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pKey, + IN PUCHAR pDA, + IN PUCHAR pSA, + IN PUCHAR pMICKey); + +BOOLEAN RTMPTkipCompareMICValue( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN PUCHAR pDA, + IN PUCHAR pSA, + IN PUCHAR pMICKey, + IN UINT Len); + +VOID RTMPCalculateMICValue( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb, + IN PUCHAR pEncap, + IN INT LenEncap, + IN PWPA_KEY pWpaKey); + +BOOLEAN RTMPTkipCompareMICValueWithLLC( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pLLC, + IN PUCHAR pSrc, + IN PUCHAR pDA, + IN PUCHAR pSA, + IN PUCHAR pMICKey, + IN UINT Len); + +VOID RTMPTkipAppend( + IN PTKIP_KEY_INFO pTkip, + IN PUCHAR pSrc, + IN UINT nBytes); + +VOID RTMPTkipGetMIC( + IN PTKIP_KEY_INFO pTkip); + +NDIS_STATUS RTMPWPAAddKeyProc( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf); + +NDIS_STATUS RTMPWPARemoveKeyProc( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf); + +VOID RTMPWPARemoveAllKeys( + IN PRTMP_ADAPTER pAdapter); + +VOID RTMPSetPhyMode( + IN PRTMP_ADAPTER pAdapter, + IN ULONG phymode); + +VOID RTMPSetDesiredRates( + IN PRTMP_ADAPTER pAdapter, + IN LONG Rates); + +INT RTMPSetInformation( + IN PRTMP_ADAPTER pAdapter, + IN OUT struct ifreq *rq, + IN INT cmd); + +INT RTMPQueryInformation( + IN PRTMP_ADAPTER pAdapter, + IN OUT struct ifreq *rq, + IN INT cmd); + +// +// Prototypes of function definition for *iwpriv* in rtmp_info.c +// +INT Set_CountryRegion_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_SSID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_WirelessMode_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_TxRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_AdhocModeRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_Channel_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR + arg); + +#ifdef RT2500_DBG +INT Set_Debug_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); +#endif + +INT Set_BGProtection_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_TxPreamble_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_StaWithEtherBridge_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_RTSThreshold_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_FragThreshold_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_TxBurst_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_TurboRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_NetworkType_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_AuthMode_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_EncrypType_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_DefaultKeyID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_Key1_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_Key2_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_Key3_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_Key4_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_WPAPSK_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_WPANONE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +VOID RTMPIoctlBBP( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq); + +VOID RTMPIoctlMAC( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq); + +#ifdef RALINK_ATE +VOID RTMPIoctlE2PROM( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq); +#endif + +int RTMPIoctlRFMONTX( + IN OUT PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq); + +// +// prototype in wpa.c +// +BOOLEAN WpaMsgTypeSubst( + IN UCHAR EAPType, + OUT ULONG *MsgType); + +VOID WpaPskStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + OUT STATE_MACHINE_FUNC Trans[]); + +VOID WpaEAPOLKeyAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID WpaPairMsg1Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID WpaPairMsg3Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID WpaGroupMsg1Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem); + +VOID WpaMacHeaderInit( + IN PRTMP_ADAPTER pAd, + IN OUT PHEADER_802_11 Hdr, + IN UCHAR wep, + IN PMACADDR pAddr1); + +VOID WpaHardEncrypt( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pPacket, + IN ULONG Len); + +VOID HMAC_SHA1( + IN UCHAR *text, + IN UINT text_len, + IN UCHAR *key, + IN UINT key_len, + IN UCHAR *digest); + +VOID PRF( + IN UCHAR *key, + IN INT key_len, + IN UCHAR *prefix, + IN INT prefix_len, + IN UCHAR *data, + IN INT data_len, + OUT UCHAR *output, + IN INT len); + +VOID WpaCountPTK( + IN UCHAR *PMK, + IN UCHAR *ANonce, + IN UCHAR *AA, + IN UCHAR *SNonce, + IN UCHAR *SA, + OUT UCHAR *output, + IN UINT len); + +VOID GenRandom( + IN PRTMP_ADAPTER pAd, + OUT UCHAR *random); + +VOID AES_GTK_KEY_UNWRAP( + IN UCHAR *key, + OUT UCHAR *plaintext, + IN UCHAR *ciphertext); + +ULONG RTMPTkipGetUInt32( + IN PUCHAR pMICKey); + +char * rtstrstr( + IN const char * s1, + IN const char * s2); + +#ifdef RALINK_ATE +INT Set_ATE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_DA_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_SA_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_BSSID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_CHANNEL_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_TX_POWER_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_TX_LENGTH_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_TX_COUNT_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +INT Set_ATE_TX_RATE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg); + +VOID RTMPStationStop( + IN PRTMP_ADAPTER pAd); + +VOID RTMPStationStart( + IN PRTMP_ADAPTER pAd); + +#endif //#ifdef RALINK_ATE + +int rt2500_set_mac_address(struct net_device *net_dev, void *addr); + +#ifdef BIG_ENDIAN +VOID RTMPFrameEndianChange( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pData, + IN ULONG Dir, + IN BOOLEAN FromRxDoneInt); + +VOID RTMPDescriptorEndianChange( + IN PUCHAR pData, + IN ULONG DescriptorType); +#endif + +#ifndef _PRISMHEADER +#define _PRISMHEADER + +enum { + DIDmsg_lnxind_wlansniffrm = 0x00000044, + DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, + DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, + DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, + DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, + DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, + DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, + DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, + DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, + DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, + DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 +}; +enum { + P80211ENUM_msgitem_status_no_value = 0x00 +}; +enum { + P80211ENUM_truth_false = 0x00, + P80211ENUM_truth_true = 0x01 +}; + +typedef struct { + u_int32_t did; + u_int16_t status; + u_int16_t len; + u_int32_t data; +} p80211item_uint32_t; + +typedef struct { + u_int32_t msgcode; + u_int32_t msglen; +#define WLAN_DEVNAMELEN_MAX 16 + u_int8_t devname[WLAN_DEVNAMELEN_MAX]; + p80211item_uint32_t hosttime; + p80211item_uint32_t mactime; + p80211item_uint32_t channel; + p80211item_uint32_t rssi; + p80211item_uint32_t sq; + p80211item_uint32_t signal; + p80211item_uint32_t noise; + p80211item_uint32_t rate; + p80211item_uint32_t istx; + p80211item_uint32_t frmlen; +} wlan_ng_prism2_header; + +#endif + +#endif // __RTMP_H__ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_data.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_data.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_data.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_data.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,4090 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_data.c + * + * Abstract: Data path subroutines + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * John 25th Feb 03 Modify for rt2560 + * MarkW 8th Dec 04 Baseline code + * MarkW (rt2400) 8th Dec 04 Promisc mode support + * RobinC 10th Dec 04 RFMON Support + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + * MarkW 17th Dec 04 Monitor mode through iwconfig + * MarkW 19th Feb 05 Fixes to incoming byte count + * GregorG 29th Mar 05 Big endian fixes + ***************************************************************************/ + +#include "rt_config.h" + +static UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; +static UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; +static UCHAR EAPOL[] = {0x88, 0x8e}; + +static UCHAR IPX[] = {0x81, 0x37}; +static UCHAR APPLE_TALK[] = {0x80, 0xf3}; +static UCHAR PlcpSignal[12] = { + 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec + 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 + 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 +static UINT _11G_RATES[12] = { 0, 0, 0, 0, 6, 9, 12, 18, 24, 36, 48, 54 }; + +#define COLLECT_RX_ANTENNA_AVERAGE_RSSI(_pAd, _RxAnt, _rssi) \ +{ \ + USHORT AvgRssi; \ + if (_RxAnt.PrimaryInUsed) \ + { \ + AvgRssi = _RxAnt.AvgRssi[_RxAnt.PrimaryRxAnt]; \ + if (AvgRssi > 0) \ + AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi; \ + else \ + AvgRssi = _rssi << 3; \ + _RxAnt.AvgRssi[_RxAnt.PrimaryRxAnt] = AvgRssi; \ + } \ + else \ + { \ + AvgRssi = _RxAnt.AvgRssi[_RxAnt.SecondaryRxAnt]; \ + _RxAnt.RcvPktNumWhenEvaluate++;\ + if ((AvgRssi > 0) && (_RxAnt.FirstPktArrivedWhenEvaluate)) \ + AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi; \ + else \ + { \ + _RxAnt.FirstPktArrivedWhenEvaluate = TRUE; \ + AvgRssi = _rssi << 3; \ + DBGPRINT(RT_DEBUG_TRACE,"Reset RSSI(%d) when first packet is rcved \n",_rssi-_pAd->PortCfg.RssiToDbm); \ + } \ + } \ +} \ + +/* + ======================================================================== + + Routine Description: + Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound + + Arguments: + pRxD Pointer to the Rx descriptor + + Return Value: + NDIS_STATUS_SUCCESS No err + NDIS_STATUS_FAILURE Error + + Note: + + ======================================================================== +*/ +inline NDIS_STATUS RTMPCheckRxDescriptor( + IN PRXD_STRUC pRxD) +{ + // Phy errors + if (pRxD->PhyErr) + return(NDIS_STATUS_FAILURE); + + // CRC errors + if (pRxD->Crc) + return(NDIS_STATUS_FAILURE); + + // Paul 04-03 for OFDM Rx length issue + if (pRxD->DataByteCnt > 1600) + return(NDIS_STATUS_FAILURE); + + return(NDIS_STATUS_SUCCESS); +} + +#ifdef BIG_ENDIAN +/* + ======================================================================== + + Routine Description: + Endian conversion of Tx/Rx descriptor . + + Arguments: + pAdapter Pointer to our adapter + pData Pointer to Tx/Rx descriptor + DescriptorType Direction of the frame + + Return Value: + None + + Note: + Call this function when read or update descriptor + ======================================================================== +*/ +inline VOID RTMPDescriptorEndianChange( + IN PUCHAR pData, + IN ULONG DescriptorType) +{ + *((ULONG *)(pData + 40)) = SWAP32(*((ULONG *)(pData + 40))); // Byte 10 + if(DescriptorType == TYPE_TXD) + *((ULONG *)(pData + 8)) = SWAP32(*((ULONG *)(pData + 8))); // Byte 2 + *(ULONG *)pData = SWAP32(*(ULONG *)pData); // Byte 0; this must be swapped last +} + +/* + ======================================================================== + + Routine Description: + Endian conversion of all kinds of 802.11 frames . + + Arguments: + pAdapter Pointer to our adapter + pData Pointer to the 802.11 frame structure + Dir Direction of the frame + FromRxDoneInt Caller is from RxDone interrupt + + Return Value: + None + + Note: + Call this function when read or update buffer data + ======================================================================== +*/ +VOID RTMPFrameEndianChange( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pData, + IN ULONG Dir, + IN BOOLEAN FromRxDoneInt) +{ + PMACHDR pFrame; + PUCHAR pMacHdr; + + // swab 16 bit fields - Frame Control field + if(Dir == DIR_READ) + { + *(USHORT *)pData = SWAP16(*(USHORT *)pData); + } + + pFrame = (PMACHDR) pData; + pMacHdr = (PUCHAR) pFrame; + + // swab 16 bit fields - Duration/ID field + *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); + + // swab 16 bit fields - Sequence Control field + *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); + + if(pFrame->Type == BTYPE_MGMT) + { + switch(pFrame->SubType) + { + case SUBTYPE_ASSOC_REQ: + case SUBTYPE_REASSOC_REQ: + // swab 16 bit fields - CapabilityInfo field + pMacHdr += MAC_HDR_LEN; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - Listen Interval field + pMacHdr += 2; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + break; + + case SUBTYPE_ASSOC_RSP: + case SUBTYPE_REASSOC_RSP: + // swab 16 bit fields - CapabilityInfo field + pMacHdr += MAC_HDR_LEN; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - Status Code field + pMacHdr += 2; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - AID field + pMacHdr += 2; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + break; + + case SUBTYPE_AUTH: + // If from RTMPHandleRxDoneInterrupt routine, it is still a encrypt format. + // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. + if(!FromRxDoneInt && pAdapter->NeedSwapToLittleEndian == TRUE) + { + // swab 16 bit fields - Auth Alg No. field + pMacHdr += MAC_HDR_LEN; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - Auth Seq No. field + pMacHdr += 2; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - Status Code field + pMacHdr += 2; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + } + break; + + case SUBTYPE_BEACON: + case SUBTYPE_PROBE_RSP: + // swab 16 bit fields - BeaconInterval field + pMacHdr += MAC_HDR_LEN + TIMESTAMP_LEN; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + + // swab 16 bit fields - CapabilityInfo field + pMacHdr += sizeof(USHORT); + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + break; + + case SUBTYPE_DEAUTH: + case SUBTYPE_DISASSOC: + // swab 16 bit fields - Reason code field + pMacHdr += MAC_HDR_LEN; + *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); + break; + } + } + else if( pFrame->Type == BTYPE_DATA ) + { + } + else if(pFrame->Type == BTYPE_CNTL) + { + } + else + { + DBGPRINT(RT_DEBUG_ERROR,"Invalid Frame Type!!!\n"); + } + + // swab 16 bit fields - Frame Control + if(Dir == DIR_WRITE) + { + *(USHORT *)pData = SWAP16(*(USHORT *)pData); + } +} +#endif + +/* + ======================================================================== + + Routine Description: + Process RxDone interrupt, running in DPC level + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + This routine has to maintain Rx ring read pointer. + ======================================================================== +*/ +VOID RTMPHandleRxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + PRXD_STRUC pRxD; +#ifdef BIG_ENDIAN + PRXD_STRUC pDestRxD; + RXD_STRUC RxD; +#endif + PHEADER_802_11 pHeader; + PUCHAR pData; + PUCHAR pDestMac, pSrcMac; + UCHAR Count; + UCHAR KeyIdx; + PWPA_KEY pWpaKey; + NDIS_STATUS Status; + BOOLEAN bDropFrame; + ULONG RegValue;//, Address; + ULONGLONG HwDecryptIndex; + unsigned long irqflag; + + // Make sure Rx ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->RxRingLock, irqflag); + + // Verify Hardware Decryption pointer with Software Decryption pointer + RTMP_IO_READ32(pAdapter, SECCSR0, &RegValue); + HwDecryptIndex = RegValue - pAdapter->RxRing[0].pa_addr; + do_div(HwDecryptIndex, RING_DESCRIPTOR_SIZE); + +#if 0 + Address = pAdapter->RxRing[pAdapter->CurDecryptIndex].pa_addr; + if (Address != RegValue) + { + DBGPRINT(RT_DEBUG_ERROR,"Decrypt pointer not matched SW = 0x%x, HW = 0x%x\n", Address, RegValue); + DBGPRINT(RT_DEBUG_ERROR,"Sw Decr Ptr = %d, Rx ptr = %d Hw ptr = %d\n", + pAdapter->CurDecryptIndex, pAdapter->CurRxIndex, HwDecryptIndex); + } +#endif + Count = 0; + do + { + // Point to Rx indexed rx ring descriptor +#ifndef BIG_ENDIAN + pRxD = (PRXD_STRUC) pAdapter->RxRing[pAdapter->CurRxIndex].va_addr; +#else + pDestRxD = (PRXD_STRUC) pAdapter->RxRing[pAdapter->CurRxIndex].va_addr; + RxD = *pDestRxD; + pRxD = &RxD; + RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); +#endif + // Initialize drop frame flag + bDropFrame = FALSE; + + // In case of false alarm or processed at last instance + if (pRxD->Owner != DESC_OWN_HOST) + { + break; + } + + // Decrypt engine stuck + if (pRxD->CipherOwner != DESC_OWN_HOST) + { + pAdapter->RalinkCounters.RxRingErrCount++; + break; + } + +#ifdef RALINK_ATE + if(pAdapter->ate.Mode == ATE_RXFRAME) + { + bDropFrame = TRUE; + } +#endif //#ifdef RALINK_ATE + + // Point to Rx ring buffer where stores the real data frame + pData = (PUCHAR) (pAdapter->RxRing[pAdapter->CurRxIndex].va_data_addr); + // Cast to 802.11 header for flags checking + pHeader = (PHEADER_802_11) pData; + +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pHeader, DIR_READ, TRUE); +#endif + + // Check for all RxD errors + Status = RTMPCheckRxDescriptor(pRxD); + + // Apply packet filtering rule based on microsoft requirements. + if (Status == NDIS_STATUS_SUCCESS) + Status = RTMPApplyPacketFilter(pAdapter, pRxD, pHeader); + + // Add receive counters + if (Status == NDIS_STATUS_SUCCESS) + { + // collect current antenna's average RSSI for software-based RX Antenna diversity + if (pRxD->U2M || pAdapter->bAcceptPromiscuous == TRUE || ((pHeader->Controlhead.Frame.Subtype == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAdapter->PortCfg.Bssid, &pHeader->Controlhead.Addr2)))) + { + //DBGPRINT(RT_DEBUG_TRACE, "COLLECT_RSSI:(%d)\n", pRxD->BBR1 - pAdapter->PortCfg.RssiToDbm); + pAdapter->PortCfg.NumOfAvgRssiSample ++; + COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAdapter, pAdapter->PortCfg.RxAnt, pRxD->BBR1); + + } + } + else + { + // Increase general counters + pAdapter->Counters.RxErrors++; + } + + // Check for retry bit, if this bit is on, search the cache with SA & sequence + // as index, if matched, discard this frame, otherwise, update cache + // This check only apply to unicast data & management frames + if ((Status == NDIS_STATUS_SUCCESS) && (pRxD->U2M) && (pHeader->Controlhead.Frame.Type != BTYPE_CNTL)) + { + if (pHeader->Controlhead.Frame.Retry) + { + if (RTMPSearchTupleCache(pAdapter, pHeader) == TRUE) + { + // Found retry frame in tuple cache, Discard this frame / fragment + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.FrameDuplicateCount); + Status = NDIS_STATUS_FAILURE; + } + else + RTMPUpdateTupleCache(pAdapter, pHeader); + } + else // Update Tuple Cache + RTMPUpdateTupleCache(pAdapter, pHeader); + } + + // + // Do RxD release operation for all failure frames + // + pRxD->CipherAlg = CIPHER_NONE; + if (Status == NDIS_STATUS_SUCCESS && pAdapter->PortCfg.BssType != BSS_MONITOR) + { + // pData : Pointer skip the first 24 bytes, 802.11 HEADER + pData += LENGTH_802_11; + + // + // Start of main loop to parse receiving frames. + // The sequence will be Type first, then subtype... + // + switch (pHeader->Controlhead.Frame.Type) + { + // Frame with data type + case BTYPE_DATA: + // Drop not my BSS frame + if (INFRA_ON(pAdapter)) + { + // Infrastructure mode, check address 2 for BSSID + if (!RTMPEqualMemory(&pHeader->Controlhead.Addr2, &pAdapter->PortCfg.Bssid, 6)) + { + // Receive frame not my BSSID + bDropFrame = TRUE; + break; + } + } + else // Ad-Hoc mode or Not associated + { + // Ad-Hoc mode, check address 3 for BSSID + if (!RTMPEqualMemory(&pHeader->Addr3, &pAdapter->PortCfg.Bssid, 6)) + { + // Receive frame not my BSSID + bDropFrame = TRUE; + break; + } + + // Drop frame from AP while we are in Ad-hoc mode or not associated + if (pHeader->Controlhead.Frame.FrDs) + { + bDropFrame = TRUE; + break; + } + } + + // Drop Null data frame, or CF with NULL data frame + if ((pHeader->Controlhead.Frame.Subtype == SUBTYPE_NULL_FUNC) || + (pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFACK) || + (pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFPOLL) || + (pHeader->Controlhead.Frame.Subtype == SUBTYPE_CFACK_CFPOLL)) + { + bDropFrame = TRUE; + break; + } + + // Good data frame appears, increase the counters + INC_COUNTER(pAdapter->WlanCounters.ReceivedFragmentCount); + pAdapter->RalinkCounters.ReceivedByteCount += pRxD->DataByteCnt; + + // Process Multicast data frame + if (pRxD->Mcast) + { + // Multicast 802.11 Counter + INC_COUNTER(pAdapter->WlanCounters.MulticastReceivedFrameCount); + DBGPRINT(RT_DEBUG_INFO,"Receiving multicast frame\n"); + } + + // Init WPA Key to NULL + pWpaKey = (PWPA_KEY) NULL; + + // Find the WPA key, either Group or Pairwise Key + if ((pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pHeader->Controlhead.Frame.Wep)) + { + INT idx; + + // First lookup the DA, if it's a group address, use GROUP key + if (pRxD->Bcast || pRxD->Mcast) + { + + idx = (*(pData + 3) & 0xc0) >> 6; + if ((pAdapter->PortCfg.GroupKey[idx].KeyLen != 0) && + ((INFRA_ON(pAdapter) && (NdisEqualMemory(&pHeader->Controlhead.Addr2, &pAdapter->PortCfg.Bssid, 6))) || + (ADHOC_ON(pAdapter) && (NdisEqualMemory(&pHeader->Addr3, &pAdapter->PortCfg.Bssid, 6))))) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[idx]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Rx Use Group Key %d\n", idx); + } + } + // Try to find the Pairwise Key + else + { + for (idx = 0; idx < PAIRWISE_KEY_NO; idx++) + { + if ((NdisEqualMemory(&pHeader->Controlhead.Addr2, pAdapter->PortCfg.PairwiseKey[idx].BssId, 6)) && + (pAdapter->PortCfg.PairwiseKey[idx].KeyLen != 0)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[idx]; + pWpaKey->Type = PAIRWISE_KEY; + DBGPRINT(RT_DEBUG_INFO, "Rx Use Pairwise Key\n"); + break; + } + } +#if 1 + // Use default Group Key if there is no Pairwise key present + if ((pWpaKey == NULL) && (pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Rx Use Group Key\n"); + } +#endif + } + } + + // Process Broadcast & Multicast data frame + if (pRxD->Bcast || pRxD->Mcast) + { + // Drop Mcast / Bcast frame with fragment bit on + if (pHeader->Controlhead.Frame.MoreFrag) + { + DBGPRINT(RT_DEBUG_ERROR,"Receiving multicast frame with fragment bit on\n"); + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + + // Filter out Bcast frame which AP relayed for us + if (pHeader->Controlhead.Frame.FrDs && RTMPEqualMemory(&pHeader->Addr3, pAdapter->CurrentAddress, 6)) + { + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + + // WEP encrypted frame + if (pHeader->Controlhead.Frame.Wep) + { + // Check our WEP setting, if no WEP turning on, just drop this frame + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) // WEP + { + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + memcpy(pRxD->Key, pAdapter->PortCfg.SharedKey[KeyIdx].Key, pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen); + if (pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen == 5) + pRxD->CipherAlg = CIPHER_WEP64; + else + pRxD->CipherAlg = CIPHER_WEP128; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) // TKIP + { + UCHAR Eiv_Tmp[4]; + + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + // Swap EIV byte order, due to ASIC's bug. + Eiv_Tmp[0] = *(pData + 7); + Eiv_Tmp[1] = *(pData + 6); + Eiv_Tmp[2] = *(pData + 5); + Eiv_Tmp[3] = *(pData + 4); + memcpy((PUCHAR) &pRxD->Eiv, Eiv_Tmp, 4); //Get WEP EIV + // Copy TA into RxD + memcpy(pRxD->TA, &pHeader->Controlhead.Addr2, 6); + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + memcpy(pRxD->Key, pWpaKey->Key, 16); + pRxD->CipherAlg = CIPHER_TKIP; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL)) // AES + { + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + memcpy((PUCHAR) &pRxD->Eiv, (pData + 4), 4); //Get WEP EIV + // Copy TA into RxD + memcpy(pRxD->TA, &pHeader->Controlhead.Addr2, 6); + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + memcpy(pRxD->Key, pWpaKey->Key, 16); + pRxD->CipherAlg = CIPHER_AES; + } + else + { + // Add error counter + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + } + else // Not encrypted frames + { + pRxD->CipherAlg = CIPHER_NONE; + } + } + + // Begin process unicast to me frame + else if (pRxD->U2M || pAdapter->bAcceptPromiscuous == TRUE) + { + // Send PS-Poll for AP to send next data frame + if ((pHeader->Controlhead.Frame.MoreData) && INFRA_ON(pAdapter) && (pAdapter->PortCfg.Psm == PWR_SAVE)) + { + EnqueuePsPoll(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "Sending PS-POLL\n"); + } + + // + // Begin frame processing + // + pDestMac = (PUCHAR) &(pHeader->Controlhead.Addr1); // DA is always address 1 + if (INFRA_ON(pAdapter)) // For infrastructure, SA is address 3 + pSrcMac = (PUCHAR) &(pHeader->Addr3); + else // For IBSS mode, SA is address 2 + pSrcMac = (PUCHAR) &(pHeader->Controlhead.Addr2); + + // WEP encrypted frame + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) // WEP + { + if (pHeader->Controlhead.Frame.Wep) + { + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + memcpy(pRxD->Key, pAdapter->PortCfg.SharedKey[KeyIdx].Key, pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen); + if (pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen == 5) + pRxD->CipherAlg = CIPHER_WEP64; + else + pRxD->CipherAlg = CIPHER_WEP128; + } + else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) && + (pHeader->Frag == 0)) + { + // Check 802.1x frame, if not drop it. + if (!RTMPEqualMemory(EAPOL, pData + 6, 2)) + { + // Not 802.1X frames + // Add error counter + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + } + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) // TKIP + { + if (pHeader->Controlhead.Frame.Wep) + { + UCHAR Eiv_Tmp[4]; + + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + // Swap EIV byte order, due to ASIC's bug. + Eiv_Tmp[0] = *(pData + 7); + Eiv_Tmp[1] = *(pData + 6); + Eiv_Tmp[2] = *(pData + 5); + Eiv_Tmp[3] = *(pData + 4); + memcpy((PUCHAR) &pRxD->Eiv, Eiv_Tmp, 4); //Get WEP EIV + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + // Copy TA into RxD + memcpy(pRxD->TA, &pHeader->Controlhead.Addr2, 6); + memcpy(pRxD->Key, pWpaKey->Key, 16); + pRxD->CipherAlg = CIPHER_TKIP; + } + else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) && + (pHeader->Frag == 0)) + { + // Check 802.1x frame, if not drop it. + if (!RTMPEqualMemory(EAPOL, pData + 6, 2)) + { + // Not 802.1X frames + // Add error counter + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + } + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL)) // AES + { + if (pHeader->Controlhead.Frame.Wep) + { + memcpy((PUCHAR) &pRxD->Iv, pData, 4); //Get WEP IV + memcpy((PUCHAR) &pRxD->Eiv, (pData + 4), 4); //Get WEP EIV + // Copy TA into RxD + memcpy(pRxD->TA, &pHeader->Controlhead.Addr2, 6); + KeyIdx = (*(pData + 3) & 0xc0) >> 6; + memcpy(pRxD->Key, pWpaKey->Key, 16); + pRxD->CipherAlg = CIPHER_AES; + } + else if ((pAdapter->PortCfg.PrivacyFilter == Ndis802_11PrivFilter8021xWEP) && + (pHeader->Frag == 0)) + { + // Check 802.1x frame, if not drop it. + if (!RTMPEqualMemory(EAPOL, pData + 6, 2)) + { + // Not 802.1X frames + // Add error counter + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + } + } + else if (pHeader->Controlhead.Frame.Wep) + { + // Drop WEP frame when PrivacyInvoked is FALSE + Status = NDIS_STATUS_FAILURE; + bDropFrame = TRUE; + break; + } + else // Not encryptrd frames + { + pRxD->CipherAlg = CIPHER_NONE; + } + } + break; + + case BTYPE_MGMT: + // Always None encrypted + pRxD->CipherAlg = CIPHER_NONE; + break; + + case BTYPE_CNTL: + // Ignore ??? + bDropFrame = TRUE; + break; + + default : + bDropFrame = TRUE; + break; + } + } + else + bDropFrame = TRUE; + + // Packet will still do NULL cipher operation and drop afterward + if (bDropFrame == TRUE) + { + pRxD->Drop = 1; + pRxD->CipherAlg = CIPHER_NONE; + } + else + { + pRxD->Drop = 0; + pRxD->IvOffset = LENGTH_802_11; + } + + pRxD->CipherOwner = DESC_OWN_NIC; + +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pHeader, DIR_WRITE, TRUE); + RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); + *pDestRxD = RxD; +#endif + + pAdapter->CurRxIndex++; + if (pAdapter->CurRxIndex >= RX_RING_SIZE) + { + pAdapter->CurRxIndex = 0; + } + Count++; + + pAdapter->RalinkCounters.RxCount ++; + + } while (Count < MAX_RX_PROCESS); + + // Kick Decrypt Control Register, based on ASIC's implementation + // We have to kick decrypt & encrypt every frame. + RTMP_IO_WRITE32(pAdapter, SECCSR0, 0x1); + + // Make sure to release Rx ring resource + spin_unlock_irqrestore(&pAdapter->RxRingLock, irqflag); +} + +/* + ======================================================================== + + Routine Description: + Process TxRing TxDone interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHandleTxRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + UCHAR Count; + unsigned long irqflag; + + // Make sure Tx ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxRingLock, irqflag); + + Count = 0; + do + { +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) (pAdapter->TxRing[pAdapter->NextTxDoneIndex].va_addr); +#else + pDestTxD = (PTXD_STRUC) (pAdapter->TxRing[pAdapter->NextTxDoneIndex].va_addr); + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if ((pTxD->Owner == DESC_OWN_NIC) || (pTxD->CipherOwn == DESC_OWN_NIC) || (pTxD->Valid == FALSE)) + { + break; + } + + RTMPHardTransmitDone( + pAdapter, + pTxD, + pAdapter->TxRing[pAdapter->NextTxDoneIndex].FrameType); + + // It might happend with no Ndis packet to indicate back to upper layer + // Clear for NdisSendComplete request + pTxD->Valid = FALSE; + + // Increase Total transmit byte counter after real data sent out + pAdapter->RalinkCounters.TransmittedByteCount += pTxD->DataByteCnt; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + pAdapter->NextTxDoneIndex++; + if (pAdapter->NextTxDoneIndex >= TX_RING_SIZE) + { + pAdapter->NextTxDoneIndex = 0; + } + } while (++Count < MAX_TX_PROCESS); + +#ifdef RALINK_ATE + if((pAdapter->ate.Mode == ATE_TXCONT) || (pAdapter->ate.Mode == ATE_TXCARR) || ((pAdapter->ate.Mode == ATE_TXFRAME))) + { + if (pAdapter->ate.TxDoneCount < pAdapter->ate.TxCount) + { + pAdapter->ate.TxDoneCount++; + DBGPRINT(RT_DEBUG_INFO, "pAdapter->ate.TxDoneCount = %d, Preamble=%d\n", pAdapter->ate.TxDoneCount, pAdapter->PortCfg.TxPreambleInUsed); + pTxD = (PTXD_STRUC)pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, + SHORT_RETRY, IFS_BACKOFF, pAdapter->ate.TxRate, 4, + pAdapter->ate.TxLength, Rt802_11PreambleLong, 0); + + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + } + else if (pAdapter->ate.Mode == ATE_TXFRAME) + { + DBGPRINT(RT_DEBUG_TRACE, "ATE TXFRAME completed!\n"); + } + } +#endif //#ifdef RALINK_ATE + + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + + if(pAdapter->bNetDeviceStopQueue) + { + DBGPRINT(RT_DEBUG_TRACE, "NetDevice start queue!!!\n\n"); + pAdapter->bNetDeviceStopQueue = FALSE; + netif_start_queue(pAdapter->net_dev); + } + + // Some Tx ring resource freed, check for pending send frame for hard transmit + if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && + (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) && + (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS))) + { + // RTMPDeQueuePacket(pAdapter, &pAdapter->TxSwQueue0); + // Call dequeue without selected queue, let the subroutine select the right priority + // Tx software queue + RTMPDeQueuePacket(pAdapter); + } +} + +/* + ======================================================================== + + Routine Description: + Process Priority ring TxDone interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHandlePrioRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + UCHAR Count; + PMGMT_STRUC pMgmt; + unsigned long irqflag; + + // Make sure Prio ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->PrioRingLock, irqflag); + + Count = 0; + do + { +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) (pAdapter->PrioRing[pAdapter->NextPrioDoneIndex].va_addr); +#else + pDestTxD = (PTXD_STRUC) (pAdapter->PrioRing[pAdapter->NextPrioDoneIndex].va_addr); + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + // Check for the descriptor ownership + if ((pTxD->Owner == DESC_OWN_NIC) || (pTxD->Valid == FALSE)) + { +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + break; + } + + // No need to put in reply for MLME + RTMPHardTransmitDone( + pAdapter, + pTxD, + pAdapter->PrioRing[pAdapter->NextPrioDoneIndex].FrameType); + + // It might happend with no Ndis packet to indicate back to upper layer + pTxD->Valid = FALSE; + + // Increase Total transmit byte counter after real data sent out + pAdapter->RalinkCounters.TransmittedByteCount += pTxD->DataByteCnt; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + pAdapter->NextPrioDoneIndex++; + if (pAdapter->NextPrioDoneIndex >= PRIO_RING_SIZE) + { + pAdapter->NextPrioDoneIndex = 0; + } + } while (++Count < MAX_TX_PROCESS); + + // Make sure to release Prio ring resource + spin_unlock_irqrestore(&pAdapter->PrioRingLock, irqflag); + + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) + return; + + + spin_lock_irqsave(&pAdapter->PrioRingLock, irqflag); + if (pAdapter->PushMgmtIndex != pAdapter->PopMgmtIndex) + { + if (RTMPFreeDescriptorRequest(pAdapter, PRIO_RING, 1) == NDIS_STATUS_SUCCESS) + { + pMgmt = (PMGMT_STRUC) &pAdapter->MgmtRing[pAdapter->PopMgmtIndex]; + if (pMgmt->Valid == TRUE) + { + MlmeHardTransmit(pAdapter, pMgmt->pBuffer, pMgmt->Length); + MlmeFreeMemory(pAdapter, pMgmt->pBuffer); + pMgmt->Valid = FALSE; + pAdapter->PopMgmtIndex++; + pAdapter->MgmtQueueSize--; + if (pAdapter->PopMgmtIndex >= MGMT_RING_SIZE) + { + pAdapter->PopMgmtIndex = 0; + } + } + } + } + spin_unlock_irqrestore(&pAdapter->PrioRingLock, irqflag); +} + +/* + ======================================================================== + + Routine Description: + Process Atim ring TxDone interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHandleAtimRingTxDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + // PTXD_STRUC pTxD; + // UCHAR Count; + + // Make sure Atim ring resource won't be used by other threads + //spin_lock_irqsave(&pAdapter->AtimRingLock); + + // Did not support ATIM, remove everything. + + // Make sure to release Atim ring resource + //spin_unlock_irqrestore(&pAdapter->AtimRingLock); +} + +/* + ======================================================================== + + Routine Description: + Process Rx ring DecryptionDone interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHandleDecryptionDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + PRXD_STRUC pRxD; +#ifdef BIG_ENDIAN + PRXD_STRUC pDestRxD; + RXD_STRUC RxD; +#endif + PHEADER_802_11 pHeader; + PUCHAR pData; + PVOID pManage; + PUCHAR pDestMac, pSrcMac; + UCHAR Header802_3[14]; + UCHAR LLC_Len[2]; + USHORT PacketSize; + ULONG High32TSF, Low32TSF; + UCHAR Count; + PWPA_KEY pWpaKey; + NDIS_STATUS Status; + ULONG RegValue; + ULONGLONG HwDecryptIndex; + ULONG i; + struct sk_buff *skb; + unsigned long irqflag; + + // Make sure Rx ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->RxRingLock, irqflag); + + RTMP_IO_READ32(pAdapter, SECCSR0, &RegValue); + HwDecryptIndex = RegValue - pAdapter->RxRing[0].pa_addr; + do_div(HwDecryptIndex, RING_DESCRIPTOR_SIZE); + + Count = 0; + //do + while (pAdapter->CurDecryptIndex != HwDecryptIndex) + { + // Point to Rx indexed rx ring descriptor +#ifndef BIG_ENDIAN + pRxD = (PRXD_STRUC) pAdapter->RxRing[pAdapter->CurDecryptIndex].va_addr; +#else + pDestRxD = (PRXD_STRUC) pAdapter->RxRing[pAdapter->CurDecryptIndex].va_addr; + RxD = *pDestRxD; + pRxD = &RxD; + RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); +#endif + + // In case of false alarm or processed at last instance + if ((pRxD->Owner != DESC_OWN_HOST) || (pRxD->CipherOwner != DESC_OWN_HOST)) + break; + + // Point to Rx ring buffer where stores the real data frame + pData = (PUCHAR) (pAdapter->RxRing[pAdapter->CurDecryptIndex].va_data_addr); + // Cast to 802.11 header for flags checking + pHeader = (PHEADER_802_11) pData; + +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pHeader, DIR_READ, FALSE); +#endif + // Driver will check the decrypt algorithm and decide whether this ICV is true or not + if ((pRxD->IcvError == 1) && (pRxD->CipherAlg == CIPHER_NONE)) + pRxD->IcvError = 0; + + // Since we already process header at RxDone interrupt, there is no need to proces + // header sanity again, the only thing we have to check is icv_err bit + if (pRxD->IcvError == 1) + { + DBGPRINT(RT_DEBUG_TRACE,"Rx DecryptDone - ICV error (len %d)\n", pRxD->DataByteCnt); + pRxD->Drop =1; // Drop frame with icv error + } + // Saved data pointer for management frame which will pass to MLME block + pManage = (PVOID) pData; + + if (pAdapter->PortCfg.BssType == BSS_MONITOR) + { + struct sk_buff *skb; + wlan_ng_prism2_header *ph; + + if ((skb = __dev_alloc_skb(2048, GFP_DMA|GFP_ATOMIC)) != NULL) + { + if (pAdapter->PortCfg.MallowRFMONTx == TRUE) + goto rfmontx_80211_receive; + + // setup the wlan-ng prismheader + + if (skb_headroom(skb) < sizeof(wlan_ng_prism2_header)) + pskb_expand_head(skb, sizeof(wlan_ng_prism2_header), 0, GFP_ATOMIC); + + ph = (wlan_ng_prism2_header *) + skb_push(skb, sizeof(wlan_ng_prism2_header)); + memset(ph, 0, sizeof(wlan_ng_prism2_header)); + + ph->msgcode = DIDmsg_lnxind_wlansniffrm; + ph->msglen = sizeof(wlan_ng_prism2_header); + strcpy(ph->devname, pAdapter->net_dev->name); + + ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + + ph->hosttime.len = 4; + ph->mactime.len = 4; + ph->channel.len = 4; + ph->rssi.len = 4; + ph->signal.len = 4; + ph->noise.len = 4; + ph->rate.len = 4; + ph->istx.len = 4; + ph->frmlen.len = 4; + + ph->hosttime.data = jiffies; + ph->signal.data = pRxD->BBR1; + ph->channel.data = pAdapter->PortCfg.IbssConfig.Channel; + ph->noise.data = pAdapter->PortCfg.LastR17Value; + ph->rssi.data = ph->signal.data - ph->noise.data; + ph->frmlen.data = pRxD->DataByteCnt; + + if (pRxD->Ofdm == 1) + { + for (i = 4; i < 12; i++) + if (pRxD->BBR0 == PlcpSignal[i]) + ph->rate.data = _11G_RATES[i] * 2; + } + else + ph->rate.data = pRxD->BBR0 / 5; + + // end prismheader setup + + rfmontx_80211_receive: + + skb->dev = pAdapter->net_dev; + memcpy(skb_put(skb, pRxD->DataByteCnt), pData, pRxD->DataByteCnt); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + } + pRxD->Drop = 1; + } + + // pData : Pointer skip the first 24 bytes, 802.11 HEADER + pData += LENGTH_802_11; + + // The total available payload should exclude 24-byte 802.11 Header + // If Security is enabled, IV, EIV, ICV size is excluded by ASIC + PacketSize = (USHORT) pRxD->DataByteCnt - LENGTH_802_11; + + // Find the WPA key, either Group or Pairwise Key + // Although the data has been decrypted by ASIC, + // driver has to calculate the RxMIC which required the key. + // The failed case should not happen. If it did, drop it. + // Init WPA Key + pWpaKey = (PWPA_KEY) NULL; + if ((pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pHeader->Controlhead.Frame.Wep)) + { + INT idx; + + // First lookup the DA, if it's a group address, use GROUP key + if (pRxD->Bcast || pRxD->Mcast) + { + // Get the IV index from RxD descriptor +#ifdef BIG_ENDIAN + idx = (pRxD->Iv & 0x000000c0) >> 6; +#else + idx = (pRxD->Iv & 0xc0000000) >> 30; +#endif + if ((pAdapter->PortCfg.GroupKey[idx].KeyLen != 0) && + ((INFRA_ON(pAdapter) && (NdisEqualMemory(&pHeader->Controlhead.Addr2, &pAdapter->PortCfg.Bssid, 6))) || + (ADHOC_ON(pAdapter) && (NdisEqualMemory(&pHeader->Addr3, &pAdapter->PortCfg.Bssid, 6))))) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[idx]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Decrypt Done: Rx Use Group Key %d\n", idx); + } + } + // Try to find the Pairwise Key + else + { + for (idx = 0; idx < PAIRWISE_KEY_NO; idx++) + { + if ((NdisEqualMemory(&pHeader->Controlhead.Addr2, pAdapter->PortCfg.PairwiseKey[idx].BssId, 6)) && + (pAdapter->PortCfg.PairwiseKey[idx].KeyLen != 0)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[idx]; + pWpaKey->Type = PAIRWISE_KEY; + DBGPRINT(RT_DEBUG_INFO, "Rx Use Pairwise Key\n"); + break; + } + } +#if 1 + // Use default Group Key if there is no Pairwise key present + if ((pWpaKey == NULL) && (pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Rx Use Group Key\n"); + } +#endif + } + + // If there is no WPA key matched, this frame should be dropped + if (pWpaKey == NULL) + pRxD->Drop = 1; + } + + // + // Start of main loop to parse receiving frames. + // The sequence will be Type first, then subtype... + // + if (pRxD->Drop == 0) + { + switch (pHeader->Controlhead.Frame.Type) + { + // Frame with data type + case BTYPE_DATA: + // DA is always address 1 + // For infrastructure, SA is address 3. For IBSS mode, SA is address 2 + pDestMac = (PUCHAR) &(pHeader->Controlhead.Addr1); + if (INFRA_ON(pAdapter)) + pSrcMac = (PUCHAR) &(pHeader->Addr3); + else + pSrcMac = (PUCHAR) &(pHeader->Controlhead.Addr2); + + // Process Broadcast & Multicast data frame + if (pRxD->Bcast || pRxD->Mcast) + { + // For TKIP frame, calculate the MIC value + if (pRxD->CipherAlg == CIPHER_TKIP) + { + INT i = 0; + + if (pWpaKey == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,"No matched TKIP in decryption done calculate MIC routine!!!\n"); + Status = NDIS_STATUS_FAILURE; + break; + } + + // Minus MIC length + PacketSize -= 8; + if (RTMPTkipCompareMICValue( + pAdapter, + pData, + pDestMac, + pSrcMac, + pWpaKey->RxMic, + PacketSize) == FALSE) + { + DBGPRINT(RT_DEBUG_ERROR,"Rx MIC Value error\n"); + RTMPReportMicError(pAdapter, pWpaKey); + Status = NDIS_STATUS_FAILURE; + break; + } + + // Second, increase RxTsc value for next transmission + while (++pWpaKey->RxTsc[i] == 0x0) + { + i++; + if (i == 6) + break; + } + // Rx TSC has done one full cycle, since re-key is done by transmitter + // We did not do anything for Rx path + } + + // build 802.3 header and decide if remove the 8-byte LLC/SNAP encapsulation + CONVERT_TO_802_3(Header802_3, pDestMac, pSrcMac, pData, PacketSize); + + pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; // for RX ACTIVITY LED + + // For miniportTransferData + pAdapter->pRxData = pData; + + // Acknolwdge upper layer the received frame +#ifdef RTMP_EMBEDDED + if ((skb = __dev_alloc_skb(PacketSize + LENGTH_802_3 + 2, GFP_DMA|GFP_ATOMIC)) != NULL) +#else + if ((skb = dev_alloc_skb(PacketSize + LENGTH_802_3 + 2)) != NULL) +#endif + { + skb->dev = pAdapter->net_dev; + skb_reserve(skb, 2); // 16 byte align the IP header + memcpy(skb_put(skb, LENGTH_802_3), Header802_3, LENGTH_802_3); + memcpy(skb_put(skb, PacketSize), pData, PacketSize); + skb->protocol = eth_type_trans(skb, pAdapter->net_dev); + netif_rx(skb); + pAdapter->net_dev->last_rx = jiffies; + pAdapter->stats.rx_packets++; + } + + DBGPRINT(RT_DEBUG_INFO, "!!! Broadcast Ethenet rx Indicated !!!\n"); + } + + // Begin process unicast to me frame + else if (pRxD->U2M || pAdapter->bAcceptPromiscuous == TRUE) + { + // Update Rx data rate first. + if (pRxD->Ofdm == 1) + { + for (i = 4; i < 12; i++) + { + if (pRxD->BBR0 == PlcpSignal[i]) + break; + } + if (i < 12) + pAdapter->LastRxRate = i; + } + else // receive CCK encoding + { + if (pRxD->BBR0 == 10) + pAdapter->LastRxRate = 0; + else if (pRxD->BBR0 == 20) + pAdapter->LastRxRate = 1; + else if (pRxD->BBR0 == 55) + pAdapter->LastRxRate = 2; + else if (pRxD->BBR0 == 110) + pAdapter->LastRxRate = 3; + } + + if (pHeader->Frag == 0) // First or Only fragment + { + // For TKIP frame, calculate the MIC value + if ((pHeader->Controlhead.Frame.MoreFrag == FALSE) && + (pRxD->CipherAlg == CIPHER_TKIP) && + (pHeader->Controlhead.Frame.Wep)) + { + if (pWpaKey == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,"No matched TKIP in decryption done calculate MIC routine!!!\n"); + Status = NDIS_STATUS_FAILURE; + break; + } + // Minus MIC length + PacketSize -= 8; + if (RTMPTkipCompareMICValue( + pAdapter, + pData, + pDestMac, + pSrcMac, + pWpaKey->RxMic, + PacketSize) == FALSE) + { + DBGPRINT(RT_DEBUG_ERROR,"Rx MIC Value error\n"); + RTMPReportMicError(pAdapter, pWpaKey); + Status = NDIS_STATUS_FAILURE; + break; + } + } + + pAdapter->FragFrame.Flags &= 0xFFFFFFFE; + + // Check for encapsulation other than RFC1042 & Bridge tunnel + if ((!RTMPEqualMemory(SNAP_802_1H, pData, 6)) && + (!RTMPEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6))) + { + LLC_Len[0] = PacketSize / 256; + LLC_Len[1] = PacketSize % 256; + MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len)); + } + else + { + char *pProto = pData + 6; + + // Remove 802.11 H header & reconstruct 802.3 header + // pData += (LENGTH_802_1_H - LENGTH_802_3_TYPE); + // Check for EAPOL frame when driver supplicant enabled + // TODO: It is not strickly correct. There is no fragment handling. It might damage driver + // TODO: But for WPAPSK, it's not likely fragment on EAPOL frame will happen + if (RTMPEqualMemory(EAPOL, pProto, 2) && ((pAdapter->PortCfg.WpaState != SS_NOTUSE))) + { + RTMP_IO_READ32(pAdapter, CSR17, &High32TSF); // TSF value + RTMP_IO_READ32(pAdapter, CSR16, &Low32TSF); // TSF vlaue + PacketSize += LENGTH_802_11; + // Enqueue this frame to MLME engine + MlmeEnqueueForRecv( + pAdapter, + &pAdapter->Mlme.Queue, + High32TSF, + Low32TSF, + (UCHAR)pRxD->BBR1, (UCHAR)pAdapter->PortCfg.LastR17Value, + PacketSize, + pManage); + break; + } + + if ((RTMPEqualMemory(IPX, pProto, 2) || RTMPEqualMemory(APPLE_TALK, pProto, 2)) && + RTMPEqualMemory(SNAP_802_1H, pData, 6)) + { + // preserved the LLC/SNAP filed + LLC_Len[0] = PacketSize / 256; + LLC_Len[1] = PacketSize % 256; + MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, ((PUCHAR) LLC_Len)); + } + else + { + // remove the LLC/SNAP field + MAKE_802_3_HEADER(Header802_3, pDestMac, pSrcMac, pProto); + memcpy(pAdapter->FragFrame.Header_LLC, pData, 8); + PacketSize -= LENGTH_802_1_H; + pData += LENGTH_802_1_H; + pAdapter->FragFrame.Flags |= 0x01; + } + } + + // One & The only fragment + if (pHeader->Controlhead.Frame.MoreFrag == FALSE) + { + // For miniportTransferData + pAdapter->pRxData = pData; + + pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; // for RX ACTIVITY LED + + // Acknowledge upper layer the received frame +#ifdef RTMP_EMBEDDED + if ((skb = __dev_alloc_skb(PacketSize + LENGTH_802_3 + 2, GFP_DMA|GFP_ATOMIC)) != NULL) +#else + if ((skb = dev_alloc_skb(PacketSize + LENGTH_802_3 + 2)) != NULL) +#endif + { + skb->dev = pAdapter->net_dev; + skb_reserve(skb, 2); // 16 byte align the IP header + memcpy(skb_put(skb, LENGTH_802_3), Header802_3, LENGTH_802_3); + memcpy(skb_put(skb, PacketSize), pData, PacketSize); + skb->protocol = eth_type_trans(skb, pAdapter->net_dev); + netif_rx(skb); + pAdapter->net_dev->last_rx = jiffies; + pAdapter->stats.rx_packets++; + } + + // ZdisZeroMemory(Header802_3, LENGTH_802_3); + DBGPRINT(RT_DEBUG_INFO, "!!! Frame without Fragment Indicated !!!\n"); + + // Increase general counters + pAdapter->Counters.GoodReceives++; + + } + // First fragment of fragmented frames + else + { + memcpy(&pAdapter->FragFrame.Buffer[LENGTH_802_3], pData, PacketSize); + memcpy(pAdapter->FragFrame.Header802_3, Header802_3, LENGTH_802_3); + //NdisZeroMemory(Header802_3, LENGTH_802_3); + pAdapter->FragFrame.RxSize = PacketSize; + pAdapter->FragFrame.Sequence = pHeader->Sequence; + pAdapter->FragFrame.LastFrag = pHeader->Frag; // Should be 0 + } + } + // Middle & End of fragment burst fragments + else + { + // No LLC-SNAP header in except the first fragment frame + + if ((pHeader->Sequence != pAdapter->FragFrame.Sequence) || + (pHeader->Frag != (pAdapter->FragFrame.LastFrag + 1))) + { + // Fragment is not the same sequence or out of fragment number order + // Clear Fragment frame contents + memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME)); + Status = NDIS_STATUS_FAILURE; + break; + } + else if ((pAdapter->FragFrame.RxSize + PacketSize) > MAX_FRAME_SIZE) + { + // Fragment frame is too large, it exeeds the maximum frame size. + // We have to drop it. + // Clear Fragment frame contents + memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME)); + Status = NDIS_STATUS_FAILURE; + break; + } + + // concatenate this fragment into the re-assembly buffer + memcpy(&pAdapter->FragFrame.Buffer[LENGTH_802_3 + pAdapter->FragFrame.RxSize], pData, PacketSize); + pAdapter->FragFrame.RxSize += PacketSize; + pAdapter->FragFrame.LastFrag = pHeader->Frag; // Update fragment number + + // Last fragment + if (pHeader->Controlhead.Frame.MoreFrag == FALSE) + { + // For TKIP frame, calculate the MIC value + if ((pRxD->CipherAlg == CIPHER_TKIP) && (pHeader->Controlhead.Frame.Wep)) + { + if (pWpaKey == NULL) + { + DBGPRINT(RT_DEBUG_ERROR,"No matched TKIP in decryption done calculate MIC routine!!!\n"); + Status = NDIS_STATUS_FAILURE; + break; + } + // Minus MIC length + pAdapter->FragFrame.RxSize -= 8; + + if (pAdapter->FragFrame.Flags & 0x00000001) + { + // originally there's an LLC/SNAP field in the first fragment + // but been removed in re-assembly buffer. here we have to include + // this LLC/SNAP field upon calculating TKIP MIC + // Copy LLC data to the position in front of real data for MIC calculation + memcpy(&pAdapter->FragFrame.Buffer[LENGTH_802_3 - LENGTH_802_1_H], + pAdapter->FragFrame.Header_LLC, + LENGTH_802_1_H); + pData = (PUCHAR) &pAdapter->FragFrame.Buffer[LENGTH_802_3 - LENGTH_802_1_H]; + PacketSize = (USHORT)pAdapter->FragFrame.RxSize + LENGTH_802_1_H; + //cketSize = (USHORT)pAdapter->FragFrame.RxSize + 8; + } + else + { + pData = (PUCHAR) &pAdapter->FragFrame.Buffer[LENGTH_802_3]; + PacketSize = (USHORT)pAdapter->FragFrame.RxSize; + } + + if (RTMPTkipCompareMICValue( + pAdapter, + pData, + pDestMac, + pSrcMac, + pWpaKey->RxMic, + PacketSize) == FALSE) + { + DBGPRINT(RT_DEBUG_ERROR,"Rx MIC Value error 2\n"); + RTMPReportMicError(pAdapter, pWpaKey); + Status = NDIS_STATUS_FAILURE; + break; + } + + // TODO: + // Getting RxTSC from Rx descriptor + } + + // for RX ACTIVITY LED + pAdapter->PortCfg.LedCntl.fRxActivity = TRUE; + + // For miniportTransferData + pAdapter->pRxData = &pAdapter->FragFrame.Buffer[LENGTH_802_3]; + + memcpy(pAdapter->FragFrame.Buffer, pAdapter->FragFrame.Header802_3, LENGTH_802_3); + // Acknowledge upper layer the received frame +#ifdef RTMP_EMBEDDED + if ((skb = __dev_alloc_skb(pAdapter->FragFrame.RxSize + LENGTH_802_3 + 2, GFP_DMA|GFP_ATOMIC)) != NULL) +#else + if ((skb = dev_alloc_skb(pAdapter->FragFrame.RxSize + LENGTH_802_3 + 2)) != NULL) +#endif + { + skb->dev = pAdapter->net_dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + memcpy(skb_put(skb, LENGTH_802_3), (PVOID) &pAdapter->FragFrame.Buffer[0], LENGTH_802_3); + memcpy(skb_put(skb, pAdapter->FragFrame.RxSize), (PVOID) &pAdapter->FragFrame.Buffer[LENGTH_802_3], pAdapter->FragFrame.RxSize); + skb->protocol = eth_type_trans(skb, pAdapter->net_dev); + netif_rx(skb); + pAdapter->net_dev->last_rx = jiffies; + pAdapter->stats.rx_packets++; + } + + // Increase general counters + pAdapter->Counters.GoodReceives++; + + // Clear Fragment frame contents + memset(&pAdapter->FragFrame, 0, sizeof(FRAGMENT_FRAME)); + DBGPRINT(RT_DEBUG_INFO, "!!! Frame with Fragment Indicated !!!\n"); + } + } + } + break; + + case BTYPE_MGMT: + // Read required regsiter for MLME engine + RTMP_IO_READ32(pAdapter, CSR17, &High32TSF); // TSF value + RTMP_IO_READ32(pAdapter, CSR16, &Low32TSF); // TSF vlaue + + // Enqueue this frame to MLME engine + MlmeEnqueueForRecv( + pAdapter, + &pAdapter->Mlme.Queue, + High32TSF, + Low32TSF, + (UCHAR)pRxD->BBR1, + (UCHAR)pAdapter->PortCfg.LastR17Value, + pRxD->DataByteCnt, + pManage); + break; + + case BTYPE_CNTL: + // Ignore ??? + break; + + default : + break; + } + } + + pAdapter->CurDecryptIndex++; + if (pAdapter->CurDecryptIndex >= RX_RING_SIZE) + { + pAdapter->CurDecryptIndex = 0; + } + Count++; + + pAdapter->RalinkCounters.DecryptCount ++; + + // Clear Cipherowner bit & Rx Owner bit for all drop & non-drop frames + pRxD->CipherOwner = DESC_OWN_HOST; + pRxD->Owner = DESC_OWN_NIC; +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); + *pDestRxD = RxD; +#endif + } + //} while (Count < RX_RING_SIZE); + //} while (pAdapter->CurDecryptIndex != HwDecryptIndex); + + // Make sure to release Rx ring resource + spin_unlock_irqrestore(&pAdapter->RxRingLock, irqflag); +} + +/* + ======================================================================== + + Routine Description: + Process Tx ring EncryptionDone interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHandleEncryptionDoneInterrupt( + IN PRTMP_ADAPTER pAdapter) +{ + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + UCHAR Count; + ULONG RegValue; + ULONGLONG HwEncryptIndex; + unsigned long irqflag; + + // Make sure Prio ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxRingLock, irqflag); + + RTMP_IO_READ32(pAdapter, SECCSR1, &RegValue); + HwEncryptIndex = RegValue - pAdapter->TxRing[0].pa_addr; + do_div(HwEncryptIndex, RING_DESCRIPTOR_SIZE); + + Count = 0; + //do + while (pAdapter->NextEncryptDoneIndex != HwEncryptIndex) + { +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) (pAdapter->TxRing[pAdapter->NextEncryptDoneIndex].va_addr); +#else + pDestTxD = (PTXD_STRUC) (pAdapter->TxRing[pAdapter->NextEncryptDoneIndex].va_addr); + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + // Check for the descriptor cipher ownership + if ((pTxD->CipherOwn == DESC_OWN_NIC) || (pTxD->Owner == DESC_OWN_NIC)) + { + pAdapter->RalinkCounters.TxRingErrCount++; +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + break; + } + + // Alter EIV due to ASIC's bug + if (pTxD->CipherAlg == CIPHER_TKIP) + { + UCHAR Eiv_Tmp[4]; + PUCHAR pTmp; + + memcpy(Eiv_Tmp, &pTxD->Eiv, 4); + pTmp = (PUCHAR) &pTxD->Eiv; + *pTmp = Eiv_Tmp[3]; + *(pTmp + 1) = Eiv_Tmp[2]; + *(pTmp + 2) = Eiv_Tmp[1]; + *(pTmp + 3) = Eiv_Tmp[0]; + } + // Sanity Check, CurTxIndex should equal to NextEncryptDoneIndex + // ASSERT(pAdapter->CurTxIndex == pAdapter->NextEncryptDoneIndex); + + pTxD->Valid = TRUE; + pTxD->Owner = DESC_OWN_NIC; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + pAdapter->NextEncryptDoneIndex++; + if (pAdapter->NextEncryptDoneIndex >= TX_RING_SIZE) + { + pAdapter->NextEncryptDoneIndex = 0; + } + pAdapter->CurTxIndex = pAdapter->NextEncryptDoneIndex; + pAdapter->RalinkCounters.KickTxCount++; + + if (pAdapter->CurTxIndex == pAdapter->CurEncryptIndex) + break; + } + //} while (++Count < MAX_TX_PROCESS); + //} while (pAdapter->NextEncryptDoneIndex != HwEncryptIndex); + + // Kick Tx Control Register at the end of all ring buffer preparation + RTMP_IO_WRITE32(pAdapter, TXCSR0, 0x1); + + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); +} + +/* + ======================================================================== + + Routine Description: + Arguments: + Adapter Pointer to our adapter + ======================================================================== +*/ +void RTMPHandleTbcnInterrupt(IN PRTMP_ADAPTER pAdapter) +{ + if (ADHOC_ON(pAdapter)) + { + MACHDR *pBcnHdr = (MACHDR *)pAdapter->BeaconRing.va_data_addr; + + // update BEACON frame's sequence number + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + pBcnHdr->Seq = pAdapter->Sequence; + +#ifdef BIG_ENDIAN + *(USHORT *)((UCHAR *)pBcnHdr + 22) = SWAP16(*(USHORT *)((UCHAR *)pBcnHdr + 22)); +#endif + } +} + +/* + ======================================================================== + + Routine Description: + Arguments: + Adapter Pointer to our adapter + ======================================================================== +*/ +void RTMPHandleTwakeupInterrupt(IN PRTMP_ADAPTER pAdapter) +{ + // DBGPRINT(RT_DEBUG_ERROR, ("Twakeup Expired... !!!\n")); + pAdapter->PortCfg.Pss = PWR_ACTIVE; +} + +/* + ======================================================================== + + Routine Description: + Process all transmit ring Tx Done interrupt, running in DPC level + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPHardTransmitDone( + IN PRTMP_ADAPTER pAdapter, + IN PTXD_STRUC pTxD, + IN UCHAR FrameType) +{ + + switch (pTxD->TxResult) + { + case SUCCESS_WITHOUT_RETRY: // Success without any retry + // Return send complete status + // DBGPRINT(RT_DEBUG_INFO, "TX Success without retry<<<\n"); + if (pTxD->RTS) + { + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.RTSSuccessCount); + pTxD->RTS = 0; + } + + // Increase general counters + pAdapter->Counters.GoodTransmits++; + INC_COUNTER(pAdapter->WlanCounters.TransmittedFragmentCount); + + // update DRS related counters + if (pTxD->ACK && (FrameType == BTYPE_DATA)) + { + pAdapter->DrsCounters.OneSecTxOkCount ++; + } + break; + + case SUCCESS_WITH_RETRY: // Success with some retry + // DBGPRINT(RT_DEBUG_INFO, "TX Success with retry(=%d)<<<\n",pTxD->RetryCount); + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.RetryCount); + INC_COUNTER(pAdapter->WlanCounters.ACKFailureCount); + INC_COUNTER(pAdapter->WlanCounters.TransmittedFragmentCount); + + // Increase general counters + pAdapter->Counters.GoodTransmits++; + + if (pTxD->RetryCount > 1) + { + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.MultipleRetryCount); + + // Increase general counters + pAdapter->Counters.MoreCollisions++; + } + else + { + // Increase general counters + pAdapter->Counters.OneCollision++; + } + + if (pTxD->RTS) + { + INC_COUNTER(pAdapter->WlanCounters.RTSSuccessCount); + pTxD->RTS = 0; + } + + // update DRS related counters + if (pTxD->ACK && (FrameType == BTYPE_DATA)) + { + if (pTxD->TxRate > pAdapter->PortCfg.TxRate) + { + // DRS - must be NULL frame retried @ UpRate; downgrade + // TxQuality[UpRate] so that not upgrade TX rate + pAdapter->DrsCounters.TxQuality[pTxD->TxRate] += 2; + if (pAdapter->DrsCounters.TxQuality[pTxD->TxRate] > DRS_TX_QUALITY_WORST_BOUND) + pAdapter->DrsCounters.TxQuality[pTxD->TxRate] = DRS_TX_QUALITY_WORST_BOUND; + } + else if (pTxD->TxRate == pAdapter->PortCfg.TxRate) + pAdapter->DrsCounters.OneSecTxRetryOkCount ++; + } + break; + + case FAIL_RETRY_LIMIT: // Fail on hitting retry count limit +// DBGPRINT(RT_DEBUG_WARN, ("TX Failed (RETRY LIMIT)<<<\n")); + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.FailedCount); + INC_COUNTER(pAdapter->WlanCounters.ACKFailureCount); + + // Increase general counters + pAdapter->Counters.TxErrors++; + + if (pTxD->RTS) + { + INC_COUNTER(pAdapter->WlanCounters.RTSFailureCount); + pTxD->RTS = 0; + } + + // update DRS related counters + if (pTxD->ACK && (FrameType == BTYPE_DATA)) + { + if (pTxD->TxRate > pAdapter->PortCfg.TxRate) + { + // DRS - must be NULL frame failed @ UpRate; downgrade + // TxQuality[UpRate] so that not upgrade TX rate + pAdapter->DrsCounters.TxQuality[pTxD->TxRate] = DRS_TX_QUALITY_WORST_BOUND; + } + else if (pTxD->TxRate == pAdapter->PortCfg.TxRate) + { + pAdapter->DrsCounters.OneSecTxFailCount ++; + } + } + break; + + case FAIL_INVALID: + // DBGPRINT(RT_DEBUG_WARN, ("TX Failed (INVALID)<<<\n")); + // Increase general counters + pAdapter->Counters.TxErrors++; + + if (pTxD->RTS) + { + INC_COUNTER(pAdapter->WlanCounters.RTSFailureCount); + pTxD->RTS = 0; + } + break; + + case FAIL_OTHER: + default: + // DBGPRINT(RT_DEBUG_ERROR, ("TX Failed (other=%d)<<<\n",pTxD->TxResult)); + // Increase 802.11 counters + INC_COUNTER(pAdapter->WlanCounters.FailedCount); + INC_COUNTER(pAdapter->WlanCounters.ACKFailureCount); + + // Increase general counters + pAdapter->Counters.TxErrors++; + + if (pTxD->RTS) + { + INC_COUNTER(pAdapter->WlanCounters.RTSFailureCount); + pTxD->RTS = 0; + } + break; + } +} + +/* + ======================================================================== + + Routine Description: + API for MLME to transmit management frame to AP (BSS Mode) + or station (IBSS Mode) + + Arguments: + pAdapter Pointer to our adapter + Buffer Pointer to memory of outgoing frame + Length Size of outgoing management frame + + Return Value: + NDIS_STATUS_FAILURE + NDIS_STATUS_PENDING + NDIS_STATUS_SUCCESS + + Note: + + ======================================================================== +*/ +NDIS_STATUS MiniportMMRequest( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length) +{ + PMGMT_STRUC pMgmt; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + unsigned long irqflag; + + DBGPRINT(RT_DEBUG_INFO, "---> MiniportMMRequest\n"); + // Check management ring free avaliability + pMgmt = (PMGMT_STRUC) &pAdapter->MgmtRing[pAdapter->PushMgmtIndex]; + + // This management cell has been occupied + if (pMgmt->Valid == TRUE) + { + // No Management ring buffer avaliable + MlmeFreeMemory(pAdapter, pBuffer); + Status = NDIS_STATUS_FAILURE; + DBGPRINT(RT_DEBUG_WARN, "<--- MiniportMMRequest (error:: MgmtRing full)\n"); + pAdapter->RalinkCounters.MgmtRingFullCount++; + return (Status); + } + + // Insert this request into software managemnet ring + if (pBuffer) + { + pMgmt->pBuffer = pBuffer; + pMgmt->Length = Length; + pMgmt->Valid = TRUE; + pAdapter->PushMgmtIndex++; + pAdapter->MgmtQueueSize++; + if (pAdapter->PushMgmtIndex >= MGMT_RING_SIZE) + { + pAdapter->PushMgmtIndex = 0; + } + } + else + { + // Null pBuffer, no need to free memory buffer. + // This should not happen + DBGPRINT(RT_DEBUG_WARN, "<--- MiniportMMRequest (error:: NULL msg)\n"); + Status = NDIS_STATUS_FAILURE; + return (Status); + } + + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) + return (Status); + + // Check Free priority queue + spin_lock_irqsave(&pAdapter->PrioRingLock, irqflag); + if (RTMPFreeDescriptorRequest(pAdapter, PRIO_RING, 1) == NDIS_STATUS_SUCCESS) + { + pMgmt = (PMGMT_STRUC) &pAdapter->MgmtRing[pAdapter->PopMgmtIndex]; + if (pMgmt->Valid == TRUE) + { + MlmeHardTransmit(pAdapter, pMgmt->pBuffer, pMgmt->Length); + MlmeFreeMemory(pAdapter, pMgmt->pBuffer); + pMgmt->Valid = FALSE; + pAdapter->PopMgmtIndex++; + pAdapter->MgmtQueueSize--; + if (pAdapter->PopMgmtIndex >= MGMT_RING_SIZE) + { + pAdapter->PopMgmtIndex = 0; + } + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "not enough space in PrioRing\n"); + } + spin_unlock_irqrestore(&pAdapter->PrioRingLock, irqflag); + + DBGPRINT(RT_DEBUG_INFO, "<--- MiniportMMRequest\n"); + return (Status); +} + +/* + ======================================================================== + + Routine Description: + Copy frame from waiting queue into relative ring buffer and set + appropriate ASIC register to kick hardware transmit function + + Arguments: + pAdapter Pointer to our adapter + pBuffer Pointer to memory of outgoing frame + Length Size of outgoing management frame + + Return Value: + NDIS_STATUS_FAILURE + NDIS_STATUS_PENDING + NDIS_STATUS_SUCCESS + + Note: + + ======================================================================== +*/ +VOID MlmeHardTransmit( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length) +{ + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + PUCHAR pDest; + PHEADER_802_11 pHeader_802_11; + BOOLEAN AckRequired, InsertTimestamp; + + DBGPRINT(RT_DEBUG_INFO, "MlmeHardTransmit\n"); + + // Make sure Prio ring resource won't be used by other threads + + pDest = (PUCHAR) pAdapter->PrioRing[pAdapter->CurPrioIndex].va_data_addr; +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->PrioRing[pAdapter->CurPrioIndex].va_addr; +#else + pDestTxD = (PTXD_STRUC) pAdapter->PrioRing[pAdapter->CurPrioIndex].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if (pTxD->Owner == DESC_OWN_NIC) + { + // Descriptor owned by NIC. No descriptor avaliable + // This should not happen since caller guaranteed. + return; + } + if (pTxD->Valid == TRUE) + { + // Ndis packet of last round did not cleared. + // This should not happen since caller guaranteed. + return; + } + if (pBuffer == NULL) + { + // The buffer shouldn't be NULL + return; + } + + // outgoing frame always wakeup PHY to prevent frame lost + AsicForceWakeup(pAdapter); + + pHeader_802_11 = (PHEADER_802_11) pBuffer; + pHeader_802_11->Controlhead.Frame.PwrMgt = 0; // (pAdapter->PortCfg.Psm == PWR_SAVE); + InsertTimestamp = FALSE; + if (pHeader_802_11->Controlhead.Frame.Type == BTYPE_CNTL) // must be PS-POLL + { + AckRequired = FALSE; + pAdapter->PrioRing[pAdapter->CurPrioIndex].FrameType = BTYPE_CNTL; + } + else // BTYPE_MGMT or BMGMT_DATA(must be NULL frame) + { + pAdapter->PrioRing[pAdapter->CurPrioIndex].FrameType = BTYPE_MGMT; + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + pHeader_802_11->Sequence = pAdapter->Sequence; + + if (pHeader_802_11->Controlhead.Addr1.Octet[0] & 0x01) // MULTICAST, BROADCAST + { + AckRequired = FALSE; + pHeader_802_11->Controlhead.Duration = 0; + } + else + { + AckRequired = TRUE; + pHeader_802_11->Controlhead.Duration = RTMPCalcDuration(pAdapter, pAdapter->PortCfg.MlmeRate, 14); + if (pHeader_802_11->Controlhead.Frame.Subtype == SUBTYPE_PROBE_RSP) + { + InsertTimestamp = TRUE; + } + } + } +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pBuffer, DIR_WRITE, FALSE); +#endif + memcpy(pDest, pBuffer, Length); + + // Initialize Priority Descriptor + // For inter-frame gap, the number is for this frame and next frame + // For MLME rate, we will fix as 2Mb to match other vendor's implement +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + RTMPWriteTxDescriptor(pTxD, FALSE, CIPHER_NONE, AckRequired, FALSE, InsertTimestamp, + SHORT_RETRY, IFS_BACKOFF, pAdapter->PortCfg.MlmeRate, 4, Length, pAdapter->PortCfg.TxPreambleInUsed, 0); + + // Increase & maintain Tx Ring Index + pAdapter->CurPrioIndex++; + if (pAdapter->CurPrioIndex >= PRIO_RING_SIZE) + { + pAdapter->CurPrioIndex = 0; + } + + // Kick priority ring transmit + RTMP_IO_WRITE32(pAdapter,TXCSR0,0x4); + + // Make sure to release Prio ring resource +} +/* + ======================================================================== + + Routine Description: + This routine is used to en-queue outgoing packets when + there is no enough shread memory + + Arguments: + pAdapter Pointer to our adapter + pPacket Pointer to send packet + + Return Value: + None + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPSendPacket( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb) +{ + PVOID pVirtualAddress; + UINT AllowFragSize; + UCHAR NumberOfFrag; + UCHAR RTSRequired; + NDIS_STATUS Status = NDIS_STATUS_FAILURE; + UCHAR PsMode; + + struct sk_buff_head *pTxQueue = NULL; + ULONG Priority; + UCHAR AccessCategory; + unsigned long irqflag; + + DBGPRINT(RT_DEBUG_INFO, "<==== RTMPSendPacket\n"); + + // Init priority value + Priority = 0; + AccessCategory = 0; + + if (skb) + { + Priority = skb->priority; + // 802.11e/d4.4 June, 2003 + if (Priority <=2) + AccessCategory = 0; + else if (Priority == 3) + AccessCategory = 1; + else if (Priority <= 5) + AccessCategory = 2; + else + AccessCategory = 3; + DBGPRINT(RT_DEBUG_INFO, "Priority = %d, AC = %d\n", Priority, AccessCategory); + } + + // For TKIP, MIC value is treated as payload, it might be fragmented through + // different MPDUs. + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) + { + skb->data_len += 8; + } + + pVirtualAddress = (PVOID)skb->data; + + // Check for virtual address allocation, it might fail !!! + if (pVirtualAddress == NULL) + { + // Resourece is low, system did not allocation virtual address + // return NDIS_STATUS_FAILURE directly to upper layer + return (Status); + } + + // Store Ethernet MAC address when APClinet mode on + if ((pAdapter->PortCfg.StaWithEtherBridge.Enable) + && ((*((PUCHAR) pVirtualAddress) & 0x01) == 0) + && !MAC_ADDR_EQUAL(&pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr, ((PUCHAR) pVirtualAddress) + 6) + /*&& !MAC_ADDR_EQUAL(&pAdapter->PermanentAddress, ((PUCHAR) pVirtualAddress) + 6)*/) + { + CSR3_STRUC StaMacReg0; + CSR4_STRUC StaMacReg1; + + COPY_MAC_ADDR(&pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr, ((PUCHAR) pVirtualAddress) + 6); + + StaMacReg0.field.Byte0 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[0]; + StaMacReg0.field.Byte1 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[1]; + StaMacReg0.field.Byte2 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[2]; + StaMacReg0.field.Byte3 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[3]; + + StaMacReg1.field.Byte4 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[4]; + StaMacReg1.field.Byte5 = pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[5]; + + pAdapter->CurrentAddress[0] = StaMacReg0.field.Byte0; + pAdapter->CurrentAddress[1] = StaMacReg0.field.Byte1; + pAdapter->CurrentAddress[2] = StaMacReg0.field.Byte2; + pAdapter->CurrentAddress[3] = StaMacReg0.field.Byte3; + pAdapter->CurrentAddress[4] = StaMacReg1.field.Byte4; + pAdapter->CurrentAddress[5] = StaMacReg1.field.Byte5; + + RTMP_IO_WRITE32(pAdapter, CSR3, StaMacReg0.word); + RTMP_IO_WRITE32(pAdapter, CSR4, StaMacReg1.word); + + DBGPRINT(RT_DEBUG_TRACE, "StaWithEtherBridge - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", + pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[0],pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[1],pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[2], + pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[3],pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[4],pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr.Octet[5]); + } + + // + // Check for multicast or broadcast (First byte of DA) + // + if ((*((PUCHAR) pVirtualAddress) & 0x01) != 0) + { + // For multicast & broadcast, there is no fragment allowed + NumberOfFrag = 1; + } + else + { + // Check for payload allowed for each fragment + AllowFragSize = (pAdapter->PortCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; + + // Calculate fragments required + NumberOfFrag = ((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; + // Minus 1 if the size just match to allowable fragment size + if (((skb->data_len - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) + { + NumberOfFrag--; + } + } + + // Check for requirement of RTS + if (NumberOfFrag > 1) + { + // If multiple fragment required, RTS is required only for the first fragment + // if the fragment size large than RTS threshold + RTSRequired = (pAdapter->PortCfg.FragmentThreshold > pAdapter->PortCfg.RtsThreshold) ? 1 : 0; + } + else + { + RTSRequired = (skb->data_len > pAdapter->PortCfg.RtsThreshold) ? 1 : 0; + } + DBGPRINT(RT_DEBUG_INFO, "Number of fragments include RTS :%d\n", NumberOfFrag + RTSRequired); + + // RTS/CTS may also be required in order to protect OFDM frame + if ((pAdapter->PortCfg.TxRate >= RATE_FIRST_OFDM_RATE) && pAdapter->PortCfg.BGProtectionInUsed) + RTSRequired = 1; + + // Save framnet number to Ndis packet reserved field + RTMP_SET_PACKET_FRAGMENTS(skb, NumberOfFrag); + + // Save RTS requirement to Ndis packet reserved field + RTMP_SET_PACKET_RTS(skb, RTSRequired); + + // Make sure SendTxWait queue resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxSwQueueLock, irqflag); + + // Select the right priority queue + // There should be no else statement since it should always fall within 0-3 + if (AccessCategory== 0) + pTxQueue = &pAdapter->TxSwQueue0; + else if (AccessCategory== 1) + pTxQueue = &pAdapter->TxSwQueue1; + else if (AccessCategory== 2) + pTxQueue = &pAdapter->TxSwQueue2; + else if (AccessCategory== 3) + pTxQueue = &pAdapter->TxSwQueue3; + + // + // For infrastructure mode, enqueue this frame immediately to sendwaitqueue + // For Ad-hoc mode, check the DA power state, then decide which queue to enqueue + // + if (INFRA_ON(pAdapter)) + { + // In infrastructure mode, simply enqueue the packet into Tx waiting queue. + DBGPRINT(RT_DEBUG_INFO, "Infrastructure -> Enqueue one frame\n"); + + // Enqueue Ndis packet to end of Tx wait queue + skb_queue_tail(pTxQueue, skb); + Status = NDIS_STATUS_SUCCESS; + } + else + { + // In IBSS mode, power state of destination should be considered. + PsMode = PWR_ACTIVE; // Faked + if (PsMode == PWR_ACTIVE) + { + DBGPRINT(RT_DEBUG_INFO,"Ad-Hoc -> Enqueue one frame\n"); + + // Enqueue Ndis packet to end of Tx wait queue + skb_queue_tail(pTxQueue, skb); + Status = NDIS_STATUS_SUCCESS; + } + } + + spin_unlock_irqrestore(&pAdapter->TxSwQueueLock, irqflag); + return (Status); +} + +/* + ======================================================================== + + Routine Description: + To do the enqueue operation and extract the first item of waiting + list. If a number of available shared memory segments could meet + the request of extracted item, the extracted item will be fragmented + into shared memory segments. + + Arguments: + pAdapter Pointer to our adapter + pQueue Pointer to Waiting Queue + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPDeQueuePacket( + IN PRTMP_ADAPTER pAdapter) +{ + UCHAR FragmentRequired; + NDIS_STATUS Status; + UCHAR Count = 0; + struct sk_buff_head *pQueue; + UCHAR AccessCategory; + struct sk_buff *skb; + unsigned long irqflag; + + // Make sure SendTxWait queue resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxSwQueueLock, irqflag); + + while (Count < MAX_TX_PROCESS) + // Check queue before dequeue + // while ((pQueue->Head != NULL) && (Count < MAX_TX_PROCESS)) + { + // Reset is in progress, stop immediately + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) + break; + + pQueue = RTMPCheckTxSwQueue(pAdapter, &AccessCategory); + if(!pQueue) + break; + + // Dequeue the first entry from head of queue list + skb = skb_dequeue(pQueue); + + if(!skb) + break; + + // RTS or CTS-to-self for B/G protection mode has been set already. + // There is no need to re-do it here. + // Total fragment required = number of fragment + RST if required + FragmentRequired = RTMP_GET_PACKET_FRAGMENTS(skb) + RTMP_GET_PACKET_RTS(skb); + + if (RTMPFreeDescriptorRequest(pAdapter, TX_RING, FragmentRequired) == NDIS_STATUS_SUCCESS) + { + // Avaliable ring descriptors are enough for this frame + // Call hard transmit + Status = RTMPHardEncrypt(pAdapter, skb, FragmentRequired, pAdapter->PortCfg.EnableTxBurst, AccessCategory); + + if (Status == NDIS_STATUS_FAILURE) + { + // Packet failed due to various Ndis Packet error + dev_kfree_skb_irq(skb); + break; + } + else if (Status == NDIS_STATUS_RESOURCES) + { + // Not enough free tx ring, it might happen due to free descriptor inquery might be not correct + // It also might change to NDIS_STATUS_FAILURE to simply drop the frame + // Put the frame back into head of queue + skb_queue_head(pQueue, skb); + break; + } + Count++; + } + else + { + skb_queue_head(pQueue, skb); + pAdapter->PrivateInfo.TxRingFullCnt++; + DBGPRINT(RT_DEBUG_INFO,"RTMPDequeuePacket --> Not enough free Tx Ring descriptor (CurEncryptIndex=%d,CurTxIndex=%d, NextTxDoneIndex=%d)!!!\n", + pAdapter->CurEncryptIndex, pAdapter->CurTxIndex, pAdapter->NextTxDoneIndex); + break; + } + } + + // Release TxSwQueue0 resources + spin_unlock_irqrestore(&pAdapter->TxSwQueueLock, irqflag); +} + +/* + ======================================================================== + + Routine Description: + This subroutine will scan through releative ring descriptor to find + out avaliable free ring descriptor and compare with request size. + + Arguments: + pAdapter Pointer to our adapter + RingType Selected Ring + + Return Value: + NDIS_STATUS_FAILURE Not enough free descriptor + NDIS_STATUS_SUCCESS Enough free descriptor + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPFreeDescriptorRequest( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR RingType, + IN UCHAR NumberRequired) +{ + UCHAR FreeNumber = 0; + UINT Index; + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + unsigned long irqflag; + NDIS_STATUS Status = NDIS_STATUS_FAILURE; + + switch (RingType) + { + case TX_RING: + spin_lock_irqsave(&pAdapter->TxRingLock, irqflag); + Index = pAdapter->CurEncryptIndex; + do + { +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->TxRing[Index].va_addr; +#else + pDestTxD = (PTXD_STRUC) pAdapter->TxRing[Index].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + // While Owner bit is NIC, obviously ASIC still need it. + // If valid bit is TRUE, indicate that TxDone has not process yet + // We should not use it until TxDone finish cleanup job + if ((pTxD->Owner == DESC_OWN_HOST) && (pTxD->CipherOwn == DESC_OWN_HOST) && (pTxD->Valid == FALSE)) + { + // This one is free + FreeNumber++; + } + else + { + DBGPRINT(RT_DEBUG_INFO,"RTMPFreeDescriptorRequest fail - Owner=%d,CipherOwn=%d,Valid=%d\n",pTxD->Owner, pTxD->CipherOwn, pTxD->Valid); + break; + } + + Index++; + if (Index >= TX_RING_SIZE) // Wrap around issue + { + Index = 0; + } + + } while (FreeNumber < NumberRequired); // Quit here ! Free number is enough ! + + if (FreeNumber >= NumberRequired) + { + Status = NDIS_STATUS_SUCCESS; + } + + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + break; + + case PRIO_RING: + Index = pAdapter->CurPrioIndex; + do + { +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->PrioRing[Index].va_addr; +#else + pDestTxD = (PTXD_STRUC) pAdapter->PrioRing[Index].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + // While Owner bit is NIC, obviously ASIC still need it. + // If valid bit is TRUE, indicate that TxDone has not process yet + // We should not use it until TxDone finish cleanup job + if ((pTxD->Owner == DESC_OWN_HOST) && (pTxD->Valid == FALSE)) + { + // This one is free + FreeNumber++; + } + else + { + break; + } + + Index++; + if (Index >= PRIO_RING_SIZE) // Wrap around issue + { + Index = 0; + } + + } while (FreeNumber < NumberRequired); // Quit here ! Free number is enough ! + + if (FreeNumber >= NumberRequired) + { + Status = NDIS_STATUS_SUCCESS; + } + + break; + + default: + break; + } + + return (Status); +} + +VOID RTMPSendNullFrame( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuffer, + IN ULONG Length, + IN UCHAR TxRate) +{ + PUCHAR pDest; + PTXD_STRUC pTxD; + UCHAR FrameGap; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; +#endif + unsigned long irqflag; + + if (pBuffer == NULL) + { + return; + } + + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) + { + MlmeFreeMemory(pAdapter, pBuffer); + return; + } + + // WPA 802.1x secured port control + if (((pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && + (pAdapter->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) + { + MlmeFreeMemory(pAdapter, pBuffer); + return; + } + + FrameGap = IFS_BACKOFF; // Default frame gap mode + + // outgoing frame always wakeup PHY to prevent frame lost and + // turn off PSM bit to improve performance + AsicForceWakeup(pAdapter); +#if 0 + if ((pAdapter->TxSwQueue0.Number != 0) || (pAdapter->TxSwQueue1.Number != 0) || + (pAdapter->TxSwQueue2.Number != 0) || (pAdapter->TxSwQueue3.Number != 0)) + { + DBGPRINT(RT_DEBUG_TRACE,("Drop Null frame due to Tx queue not empty!\n")); + } + else +#endif + { + // Make sure Tx ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxRingLock, irqflag); + + // Get the Tx Ring descriptor & Dma Buffer address + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; +#else + pDestTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if ((pTxD->Owner == DESC_OWN_HOST) && (pTxD->CipherOwn == DESC_OWN_HOST) && (pTxD->Valid == FALSE)) + { + HEADER_802_11 *pHeader_802_11; + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[TxRate]); +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pBuffer, DIR_WRITE, FALSE); +#endif + memcpy(pDest, pBuffer, Length); + pAdapter->TxRing[pAdapter->CurEncryptIndex].FrameType = BTYPE_DATA; + + pHeader_802_11 = (PHEADER_802_11) pDest; + pHeader_802_11->Controlhead.Frame.PwrMgt = (pAdapter->PortCfg.Psm == PWR_SAVE); + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, TRUE, FALSE, FALSE, LONG_RETRY, IFS_BACKOFF, + TxRate, 4, Length, pAdapter->PortCfg.TxPreambleInUsed, 0); + + // Increase & maintain Tx Ring Index + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + + pAdapter->RalinkCounters.EncryptCount++; + + // Kick Encrypt Control Register at the end of all ring buffer preparation + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + + } + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + } + MlmeFreeMemory(pAdapter, pBuffer); +} + +/* + ======================================================================== + + Routine Description: + Copy frame from waiting queue into relative ring buffer and set + appropriate ASIC register to kick hardware encryption before really + sent out to air. + + Arguments: + pAdapter Pointer to our adapter + PNDIS_PACKET Pointer to outgoing Ndis frame + NumberOfFrag Number of fragment required + + Return Value: + None + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPHardEncrypt( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb, + IN UCHAR NumberRequired, + IN ULONG EnableTxBurst, + IN UCHAR AccessCategory) +{ + PVOID pVirtualAddress; + UINT NdisBufferLength; + UINT BytesCopied; + UINT TxSize; + UINT FreeFragSize; + UINT RemainSize; + USHORT Protocol; + UCHAR FrameGap; + HEADER_802_11 Header_802_11; + PUCHAR pDest; + PUCHAR pSrc; + PUCHAR pEncap; + UCHAR CipherAlg; + PTXD_STRUC pTxD; + BOOLEAN StartOfFrame; + BOOLEAN EAPOLFrame; + BOOLEAN Encapped; + ULONG Iv16; + ULONG Iv32; + BOOLEAN MICFrag; + PWPA_KEY pWpaKey = NULL; + UCHAR RetryMode = SHORT_RETRY; + UCHAR AckRate = RATE_2; + USHORT AckDuration = 0; + USHORT EncryptionOverhead = 0; +#ifdef BIG_ENDIAN + PTXD_STRUC pDestTxD; + TXD_STRUC TxD; + PUCHAR pOriginDest; +#endif + unsigned long irqflag; + + // Make sure Tx ring resource won't be used by other threads + spin_lock_irqsave(&pAdapter->TxRingLock, irqflag); + + if(skb->data == NULL) + { + DBGPRINT(RT_DEBUG_ERROR, "Error, Null skb data buffer!!!\n"); + + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_FAILURE); + } + + if (pAdapter->PortCfg.BssType == BSS_MONITOR && pAdapter->PortCfg.MallowRFMONTx == TRUE) + { + pAdapter->TxRing[pAdapter->CurEncryptIndex].FrameType = BTYPE_DATA; + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + MlmeSetPsmBit(pAdapter, PWR_ACTIVE); + memcpy(pDest,skb->data,skb->len); + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, SHORT_RETRY, IFS_BACKOFF, pAdapter->PortCfg.TxRate, 4, skb->len, pAdapter->PortCfg.TxPreambleInUsed, AccessCategory); + + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + pAdapter->CurEncryptIndex = 0; + pAdapter->RalinkCounters.EncryptCount++; + + goto skip_packet_handling; + } + + if (EnableTxBurst == 1) + FrameGap = IFS_SIFS; + else + FrameGap = IFS_BACKOFF; // Default frame gap mode + + // outgoing frame always wakeup PHY to prevent frame lost and + // turn off PSM bit to improve performance + if (pAdapter->PortCfg.Psm == PWR_SAVE) + { + MlmeSetPsmBit(pAdapter, PWR_ACTIVE); + } + AsicForceWakeup(pAdapter); + + // Sequence Number is identical for all fragments belonged to the same frame + // Sequence is 0 - 4095 + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + + AckRate = pAdapter->PortCfg.ExpectedACKRate[pAdapter->PortCfg.TxRate]; + AckDuration = RTMPCalcDuration(pAdapter, AckRate, 14); + + pVirtualAddress = skb->data; + NdisBufferLength = skb->len; + + if ((*((PUCHAR) pVirtualAddress) & 0x01) != 0) // Multicast or Broadcast + { + INC_COUNTER(pAdapter->WlanCounters.MulticastTransmittedFrameCount); + } + + if (NdisBufferLength < 14) + { + DBGPRINT(RT_DEBUG_ERROR,"RTMPHardEncrypt --> Ndis Packet buffer error !!!\n"); + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_FAILURE); + } + + // + // Start making 802.11 frame header + // + memset(&Header_802_11, 0, sizeof(HEADER_802_11)); // Initialize 802.11 header for each fragment + if (INFRA_ON(pAdapter)) + { + // Address 1 - AP, Address 2 - this STA, Address 3 - DA + memcpy(&Header_802_11.Controlhead.Addr1, &pAdapter->PortCfg.Bssid, ETH_ALEN); + memcpy(&Header_802_11.Addr3, (PUCHAR) pVirtualAddress, ETH_ALEN); + Header_802_11.Controlhead.Frame.ToDs = 1; + } + else + { + // Address 1 - DA, Address 2 - this STA, Address 3 - BSSID + memcpy(&Header_802_11.Controlhead.Addr1, (PUCHAR) pVirtualAddress, ETH_ALEN); + memcpy(&Header_802_11.Addr3, &pAdapter->PortCfg.Bssid, ETH_ALEN); + } + memcpy(&Header_802_11.Controlhead.Addr2, pAdapter->CurrentAddress, ETH_ALEN); + + Header_802_11.Sequence = pAdapter->Sequence; // Sequence number + Header_802_11.Controlhead.Frame.Type = BTYPE_DATA; // Frame type + Header_802_11.Controlhead.Frame.PwrMgt = (pAdapter->PortCfg.Psm == PWR_SAVE); + + // Add 802.11x protocol check. + // For non-WPA network, 802.1x message should not encrypt even + // the privacy is on. + if (RTMPEqualMemory(EAPOL, ((PUCHAR) pVirtualAddress) + 12, 2)) + { + EAPOLFrame = TRUE; + if (pAdapter->PortCfg.MicErrCnt >= 2) + pAdapter->PortCfg.MicErrCnt++; + } + else + EAPOLFrame = FALSE; + + // WPA 802.1x secured port control + if (((pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && + ((pAdapter->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAdapter->PortCfg.MicErrCnt >= 2)) && + (EAPOLFrame == FALSE)) + { + DBGPRINT(RT_DEBUG_TRACE,"RTMPHardEncrypt --> Drop packet before port secured !!!\n"); + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_FAILURE); + } + + MICFrag = FALSE; // Flag to indicate MIC shall spread into two MPDUs + Encapped = FALSE; + pEncap = NULL; + + pSrc = (PUCHAR) pVirtualAddress; + Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); + if (Protocol > 1500) // CHeck for LLC encaped + { + pEncap = SNAP_802_1H; + Encapped = TRUE; + if (RTMPEqualMemory(IPX, pSrc + 12, 2) || + RTMPEqualMemory(APPLE_TALK, pSrc + 12, 2)) + { + pEncap = SNAP_BRIDGE_TUNNEL; + } + } + + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) && + (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)) + EncryptionOverhead = 8; // WEP: IV + ICV + else if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) + EncryptionOverhead = 12; // TKIP: IV + EIV + ICV, MIC already added to TotalPacketLength + else if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + EncryptionOverhead = 16; // AES: IV + EIV + Hardware MIC + else + EncryptionOverhead = 0; + + // + // Make RTS frame if required + // + if (RTMP_GET_PACKET_RTS(skb)) + { + PCONTROL_HEADER pControlHeader; + ULONG NextFragSize; + + // RTS-protected frame should use LONG_RETRY (=4), other frames use SHORT_RETRY (=7) + RetryMode = LONG_RETRY; + + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; +#else + pDestTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if ((pTxD->Owner == DESC_OWN_NIC) || (pTxD->CipherOwn == DESC_OWN_NIC)) + { + // Descriptor owned by NIC. No descriptor avaliable + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_RESOURCES); + } + if (pTxD->Valid == TRUE) + { + // This might happen when HardTransmit process faster than TxDone interrupt. + // However, Since we did call free descriptor number check before Tx HardTransmit. + // This case should not happened. We should return to higher caller and requeue this + // acket until next Tx hardtransmit. Hopefully this situation is corrected then. + // Ndis packet of last round did not cleared. + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + pTxD->Valid = FALSE; +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_RESOURCES); + } + + pAdapter->TxRing[pAdapter->CurEncryptIndex].FrameType = BTYPE_CNTL; + pControlHeader = (PCONTROL_HEADER) pDest; + memset(pControlHeader, 0, sizeof(CONTROL_HEADER)); + pControlHeader->Frame.Type = BTYPE_CNTL; + + // Calculate duration = 2 SIFS + CTS + Data Frame size + if (RTMP_GET_PACKET_FRAGMENTS(skb) > 1) + { + // If fragment required, size is maximum fragment size + NextFragSize = pAdapter->PortCfg.FragmentThreshold; + } + else + { + // Size should be frame with 802.11 header & CRC + NextFragSize = skb->data_len + LENGTH_802_11 + LENGTH_CRC - LENGTH_802_3; + + if (Encapped) + NextFragSize += LENGTH_802_1_H; + } + pControlHeader->Duration = 2 * (pAdapter->PortCfg.Dsifs) + + RTMPCalcDuration(pAdapter, pAdapter->PortCfg.TxRate, NextFragSize + EncryptionOverhead) + + AckDuration; + + // Write Tx descriptor + // Don't kick tx start until all frames are prepared + // RTS has to set more fragment bit for fragment burst + // RTS did not encrypt + if (pAdapter->PortCfg.BGProtectionInUsed == 1) + { + DBGPRINT(RT_DEBUG_TRACE,"Making CTS-to-self Frame\n"); + pControlHeader->Frame.Subtype = SUBTYPE_CTS; + memcpy(&pControlHeader->Addr1, pAdapter->CurrentAddress, ETH_ALEN); + +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pControlHeader, DIR_WRITE, FALSE); + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + + +#ifdef WIFI_TEST + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, SHORT_RETRY, + FrameGap, pAdapter->PortCfg.RtsRate, 4, 10, Rt802_11PreambleShort, + AccessCategory); +#else + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, SHORT_RETRY, + FrameGap, pAdapter->PortCfg.RtsRate, 4, 10, pAdapter->PortCfg.TxPreambleInUsed, + AccessCategory); +#endif + } + else + { + DBGPRINT(RT_DEBUG_TRACE,"Making RTS Frame\n"); + pControlHeader->Frame.Subtype = SUBTYPE_RTS; + if (INFRA_ON(pAdapter)) + memcpy(&pControlHeader->Addr1, &pAdapter->PortCfg.Bssid, ETH_ALEN); + else + memcpy(&pControlHeader->Addr1, (PUCHAR) pVirtualAddress, ETH_ALEN); + memcpy(&pControlHeader->Addr2, pAdapter->CurrentAddress, ETH_ALEN); +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, (PUCHAR)pControlHeader, DIR_WRITE, FALSE); + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, TRUE, TRUE, FALSE, SHORT_RETRY, + FrameGap, pAdapter->PortCfg.RtsRate, 4, sizeof(CONTROL_HEADER), + pAdapter->PortCfg.TxPreambleInUsed, AccessCategory); + pTxD->RTS = 1; + } + + FrameGap = IFS_SIFS; // Init frame gap for coming data after RTS + NumberRequired--; + + // Increase & maintain Tx Ring Index + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + pAdapter->RalinkCounters.EncryptCount++; + } + + // Find the WPA key, either Group or Pairwise Key + if (pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA) + { + INT idx; + + pWpaKey = (PWPA_KEY) NULL; + // First lookup the DA, if it's a group address, use GROUP key + if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01) + { + if (pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Tx Use Group Key\n"); + } + } + // Try to find the Pairwise Key + else + { + for (idx = 0; idx < PAIRWISE_KEY_NO; idx++) + { + if ((NdisEqualMemory(&Header_802_11.Controlhead.Addr1, pAdapter->PortCfg.PairwiseKey[idx].BssId, 6)) && + (pAdapter->PortCfg.PairwiseKey[idx].KeyLen != 0)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[idx]; + pWpaKey->Type = PAIRWISE_KEY; + DBGPRINT(RT_DEBUG_INFO, "Tx Use Pairwise Key\n"); + break; + } + } + // Use default Group Key if there is no Pairwise key present + if ((pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0) && (pWpaKey == NULL)) + { + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.GroupKey[pAdapter->PortCfg.DefaultKeyId]; + pWpaKey->Type = GROUP_KEY; + DBGPRINT(RT_DEBUG_INFO, "Tx Use Group Key\n"); + } + } + } + + // For the purpose to calculate duration for the second last fragment + RemainSize = skb->data_len - LENGTH_802_3 + LENGTH_CRC; + + StartOfFrame = TRUE; + // Start Copy Ndis Packet into Ring buffer. + // For frame required more than one ring buffer (fragment), all ring buffers + // have to be filled before kicking start tx bit. + do + { + // Get the Tx Ring descriptor & Dma Buffer address +#ifndef BIG_ENDIAN + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; +#else + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + pOriginDest = pDest; + pDestTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if ((pTxD->Owner == DESC_OWN_NIC) || (pTxD->CipherOwn == DESC_OWN_NIC)) + { + // Descriptor owned by NIC. No descriptor avaliable + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + pAdapter->RalinkCounters.TxRingErrCount++; + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_RESOURCES); + } + if (pTxD->Valid == TRUE) + { + // Ndis packet of last round did not cleared. + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + pTxD->Valid = FALSE; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + pAdapter->RalinkCounters.TxRingErrCount++; + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + return (NDIS_STATUS_RESOURCES); + } + pAdapter->TxRing[pAdapter->CurEncryptIndex].FrameType = BTYPE_DATA; + + // Make fragment number & more fragment bit of 802.11 header + if (StartOfFrame == TRUE) + Header_802_11.Frag = 0; // Start of fragment burst / Single Frame + else + Header_802_11.Frag++; // Rest of fragmented frames. + + // Maximum allowable payload with one ring buffer, bound by fragment size + FreeFragSize = pAdapter->PortCfg.FragmentThreshold - LENGTH_CRC; + + // + // calculate "duration" field of this fragment + // + if (NumberRequired > 1) + { + ULONG NextFragSize; + Header_802_11.Controlhead.Frame.MoreFrag = 1; + + if (NumberRequired == 2) + NextFragSize = RemainSize - pAdapter->PortCfg.FragmentThreshold + LENGTH_802_11 + LENGTH_802_11 + LENGTH_CRC; + else + NextFragSize = pAdapter->PortCfg.FragmentThreshold; + + Header_802_11.Controlhead.Duration = 3 * pAdapter->PortCfg.Dsifs + + 2 * AckDuration + + RTMPCalcDuration(pAdapter, pAdapter->PortCfg.TxRate, NextFragSize + EncryptionOverhead); + } + else // this is the last or only fragment + { + Header_802_11.Controlhead.Frame.MoreFrag = 0; + + if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01) // multicast/broadcast + Header_802_11.Controlhead.Duration = 0; + else + Header_802_11.Controlhead.Duration = pAdapter->PortCfg.Dsifs + AckDuration; + } + + // Check for WEP enable bit and prepare for software WEP + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) && (EAPOLFrame == FALSE) && + (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)) + Header_802_11.Controlhead.Frame.Wep = 1; + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) + Header_802_11.Controlhead.Frame.Wep = 1; + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL)) + Header_802_11.Controlhead.Frame.Wep = 1; + + // + // Copy 802.11 header to Tx ring buffer + // + memcpy(pDest, &Header_802_11, sizeof(Header_802_11)); + pDest += sizeof(Header_802_11); + FreeFragSize -= sizeof(Header_802_11); + + DBGPRINT(RT_DEBUG_TRACE,"pWpaKey = %s\n", pWpaKey == NULL ? "NULL" : "not NULL"); + + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) && (EAPOLFrame == FALSE) && + (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen != 0)) + { + DBGPRINT(RT_DEBUG_TRACE,"Ndis802_11Encryption1Enabled::DefaultKeyId = %d\n", pAdapter->PortCfg.DefaultKeyId); + // Prepare IV, IV offset, Key for Hardware encryption + RTMPInitWepEngine( + pAdapter, + pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].Key, + pAdapter->PortCfg.DefaultKeyId, + pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen, + (PUCHAR) &pTxD->Iv); + + if (pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen == 5) + CipherAlg = CIPHER_WEP64; + else + CipherAlg = CIPHER_WEP128; + + // Set Iv offset in TxD + pTxD->IvOffset = LENGTH_802_11; + // Copy Encrypt Key to TxD + memcpy( + pTxD->Key, + pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].Key, + pAdapter->PortCfg.SharedKey[pAdapter->PortCfg.DefaultKeyId].KeyLen); + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) + { + INT i = 0; + DBGPRINT(RT_DEBUG_TRACE,"Ndis802_11Encryption2Enabled::DefaultKeyId = %d\n", pAdapter->PortCfg.DefaultKeyId); + // Prepare 8 bytes TKIP encapsulation for MPDU + { + TKIP_IV tkipIv; + + tkipIv.IV32 = 0; // (ensure reserved fields clear) + tkipIv.IV16.field.rc0 = *(pWpaKey->TxTsc + 1); + tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; + tkipIv.IV16.field.rc2 = *pWpaKey->TxTsc; + tkipIv.IV16.field.ExtIV = 1;// 0: non-extended IV, 1: extended IV + tkipIv.IV16.field.KeyID = pAdapter->PortCfg.DefaultKeyId; + tkipIv.IV32 = *(PULONG)(pWpaKey->TxTsc + 2); +#if 0 //jett, 2004-1222 ------------------ +#if BIG_ENDIAN == TRUE + pTxD->Iv = (tkipIv.IV16.field.rc0 << 24) | (tkipIv.IV16.field.rc1 << 16) | (tkipIv.IV16.field.rc2 << 8) | (tkipIv.IV16.field.CONTROL.Byte); +#endif + +#ifdef RTMP_EMBEDDED + pTxD->Iv = (tkipIv.IV16.field.CONTROL.Byte << 24) | (tkipIv.IV16.field.rc2 << 16) | (tkipIv.IV16.field.rc1 << 8) | (tkipIv.IV16.field.rc0); +#else + pTxD->Iv = tkipIv.IV16.word; +#endif +#else //---------------------------------- +#ifdef BIG_ENDIAN + pTxD->Iv = SWAP32(tkipIv.IV16.word); +#else + pTxD->Iv = tkipIv.IV16.word; +#endif +#endif //---------------------------------- + + *((PUCHAR) &pTxD->Eiv) = *((PUCHAR) &tkipIv.IV32 + 3); + *((PUCHAR) &pTxD->Eiv + 1) = *((PUCHAR) &tkipIv.IV32 + 2); + *((PUCHAR) &pTxD->Eiv + 2) = *((PUCHAR) &tkipIv.IV32 + 1); + *((PUCHAR) &pTxD->Eiv + 3) = *((PUCHAR) &tkipIv.IV32); + } + + // Increase TxTsc value for next transmission + while (++pWpaKey->TxTsc[i] == 0x0) + { + i++; + if (i == 6) + break; + } + + // Set IV offset + pTxD->IvOffset = LENGTH_802_11; + + // Copy TKey + memcpy(pTxD->Key, pWpaKey->Key, 16); + + // Set Cipher suite + CipherAlg = CIPHER_TKIP; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL)) + { + INT i; + PUCHAR pTmp; + + i = 0; + pTmp = (PUCHAR) &Iv16; + *pTmp = pWpaKey->TxTsc[0]; + *(pTmp + 1) = pWpaKey->TxTsc[1]; + *(pTmp + 2) = 0; + *(pTmp + 3) = (pAdapter->PortCfg.DefaultKeyId << 6) | 0x20; + + Iv32 = *(PULONG)(&pWpaKey->TxTsc[2]); + + // Increase TxTsc value for next transmission + while (++pWpaKey->TxTsc[i] == 0x0) + { + i++; + if (i == 6) + break; + } + if (i == 6) + { + // TODO: TSC has done one full cycle, do re-keying stuff follow specs + // Should send a special event microsoft defined to request re-key + } + + memcpy(&pTxD->Iv, &Iv16, 4); // Copy IV + memcpy(&pTxD->Eiv, &Iv32, 4); // Copy EIV + pTxD->IvOffset = LENGTH_802_11; // Set IV offset + memcpy(pTxD->Key, pWpaKey->Key, 16); // Copy TKey + CipherAlg = CIPHER_AES; // Set Cipher suite + } + else + CipherAlg = CIPHER_NONE; + + // + // Only the first fragment required LLC-SNAP header !!! + // + if ((StartOfFrame == TRUE) && (Encapped == TRUE)) + { + // For WEP & no encryption required frame, just copy LLC header into buffer, + // Hardware will do the encryption job. + // For TKIP, we have to calculate MIC and store it first + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) + { + // Calculate MSDU MIC Value + RTMPCalculateMICValue(pAdapter, skb, pEncap, 6, pWpaKey); + } + + // Copy LLC header + memcpy(pDest, pEncap, 6); + pDest += 6; + + // Copy protocol type + pSrc = (PUCHAR) pVirtualAddress; + memcpy(pDest, pSrc + 12, 2); + pDest += 2; + + // Exclude 802.3 header size, we will recalculate the size at + // the end of fragment preparation. + NdisBufferLength -= LENGTH_802_3; + pSrc += LENGTH_802_3; + FreeFragSize -= LENGTH_802_1_H; + } + else if ((StartOfFrame == TRUE) && (Encapped == FALSE)) + { + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) + { + // Calculate MSDU MIC Value + RTMPCalculateMICValue(pAdapter, skb, pEncap, 0, pWpaKey); + } + + pSrc = (PUCHAR) pVirtualAddress + LENGTH_802_3; + NdisBufferLength -= LENGTH_802_3; + } + + // Start copying payload + BytesCopied = 0; + do + { + if (NdisBufferLength >= FreeFragSize) + { + // Copy only the free fragment size, and save the pointer + // of current buffer descriptor for next fragment buffer. + memcpy(pDest, pSrc, FreeFragSize); + BytesCopied += FreeFragSize; + pSrc += FreeFragSize; + pDest += FreeFragSize; + NdisBufferLength -= FreeFragSize; + break; + } + else + { + // Copy the rest of this buffer descriptor pointed data + // into ring buffer. + memcpy(pDest, pSrc, NdisBufferLength); + BytesCopied += NdisBufferLength; + pDest += NdisBufferLength; + FreeFragSize -= NdisBufferLength; + } + + // No more buffer descriptor + // Add MIC value if needed + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && + (MICFrag == FALSE) && + (pWpaKey != NULL)) + { + INT i; + + NdisBufferLength = 8; // Set length to MIC length + DBGPRINT(RT_DEBUG_INFO, "Calculated TX MIC value ="); + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PrivateInfo.Tx.MIC[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + + if (FreeFragSize >= NdisBufferLength) + { + memcpy(pDest, pAdapter->PrivateInfo.Tx.MIC, NdisBufferLength); + BytesCopied += NdisBufferLength; + pDest += NdisBufferLength; + FreeFragSize -= NdisBufferLength; + NdisBufferLength = 0; + RemainSize += 8; // Need to add MIC as payload + } + else + { + memcpy(pDest, pAdapter->PrivateInfo.Tx.MIC, FreeFragSize); + BytesCopied += FreeFragSize; + pSrc = pAdapter->PrivateInfo.Tx.MIC + FreeFragSize; + pDest += FreeFragSize; + NdisBufferLength -= FreeFragSize; + MICFrag = TRUE; + RemainSize += (8 - FreeFragSize); // Need to add MIC as payload + } + } + } while (FALSE); // End of copying payload + + // Real packet size, No 802.1H header for fragments except the first one. + if ((StartOfFrame == TRUE) && (Encapped == TRUE)) + { + TxSize = BytesCopied + LENGTH_802_11 + LENGTH_802_1_H; + } + else + { + TxSize = BytesCopied + LENGTH_802_11; + } + + RemainSize = RemainSize - BytesCopied; + + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) && (Header_802_11.Controlhead.Frame.Wep == 1)) + { + // IV + ICV which ASIC added after encryption done + TxSize += 8; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pWpaKey != NULL)) + { + // IV + EIV + ICV which ASIC added after encryption done + TxSize += 12; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pWpaKey != NULL)) + { + // IV + EIV + HW MIC + TxSize += 16; + } + + // Prepare Tx descriptors before kicking tx. + // The BBP register index in Tx descriptor has to be configured too. +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, pOriginDest, DIR_WRITE, FALSE); + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + if (Header_802_11.Controlhead.Addr1.Octet[0] & 0x01) + { + // Multicast, retry bit is off + RTMPWriteTxDescriptor(pTxD, TRUE, CipherAlg, FALSE, FALSE, FALSE, RetryMode, FrameGap, + pAdapter->PortCfg.TxRate, 4, TxSize, pAdapter->PortCfg.TxPreambleInUsed, AccessCategory); + } + else + { + RTMPWriteTxDescriptor(pTxD, TRUE, CipherAlg, TRUE, FALSE, FALSE, RetryMode, FrameGap, + pAdapter->PortCfg.TxRate, 4, TxSize, pAdapter->PortCfg.TxPreambleInUsed, AccessCategory); + } + + // Set frame gap for the rest of fragment burst. + // It won't matter if there is only one fragment (single fragment frame). + StartOfFrame = FALSE; + FrameGap = IFS_SIFS; + NumberRequired--; + + // Increase & maintain Tx Ring Index + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + + pAdapter->RalinkCounters.EncryptCount++; + + } while (NumberRequired > 0); + +skip_packet_handling: + + // Kick Encrypt Control Register at the end of all ring buffer preparation + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + + // Acknowledge protocol send complete of pending packet. + dev_kfree_skb_irq(skb); + + // Make sure to release Tx ring resource + spin_unlock_irqrestore(&pAdapter->TxRingLock, irqflag); + + return (NDIS_STATUS_SUCCESS); +} + +/* + ======================================================================== + + Routine Description: + Calculates the duration which is required to transmit out frames + with given size and specified rate. + + Arguments: + pAdapter Pointer to our adapter + Rate Transmit rate + Size Frame size in units of byte + + Return Value: + Duration number in units of usec + + Note: + + ======================================================================== +*/ +USHORT RTMPCalcDuration( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR Rate, + IN ULONG Size) +{ + ULONG Duration = 0; + + if (Rate < RATE_FIRST_OFDM_RATE) // CCK + { + if ((Rate > RATE_1) && (pAdapter->PortCfg.TxPreambleInUsed == Rt802_11PreambleShort)) + Duration = 96; // 72+24 preamble+plcp + else + Duration = 192; // 144+48 preamble+plcp + + Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); + if ((Size << 4) % RateIdTo500Kbps[Rate]) + Duration ++; + } + else // OFDM rates + { + Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension + Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); + if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) + Duration += 4; + } + + return (USHORT)Duration; + +} + +/* + ======================================================================== + + Routine Description: + Calculates the duration which is required to transmit out frames + with given size and specified rate. + + Arguments: + pTxD Pointer to transmit descriptor + Ack Setting for Ack requirement bit + Fragment Setting for Fragment bit + RetryMode Setting for retry mode + Ifs Setting for IFS gap + Rate Setting for transmit rate + Service Setting for service + Length Frame length + TxPreamble Short or Long preamble when using CCK rates + AccessCategory - 0-3, according to 802.11e/d4.4 June/2003 + + Return Value: + None + + ======================================================================== +*/ +VOID RTMPWriteTxDescriptor( + IN PTXD_STRUC pSourceTxD, + IN BOOLEAN DoEncrypt, + IN UCHAR CipherAlg, + IN BOOLEAN Ack, + IN BOOLEAN Fragment, + IN BOOLEAN InsTimestamp, + IN UCHAR RetryMode, + IN UCHAR Ifs, + IN UINT Rate, + IN UCHAR Service, + IN ULONG Length, + IN USHORT TxPreamble, + IN UCHAR AccessCategory) +{ + UINT Residual; + PTXD_STRUC pTxD; +#ifndef BIG_ENDIAN + pTxD = pSourceTxD; +#else + TXD_STRUC TxD; + + TxD = *pSourceTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + pTxD->MoreFrag = Fragment; + pTxD->ACK = Ack; + pTxD->Timestamp = InsTimestamp; + pTxD->RetryMd = RetryMode; + pTxD->IFS = Ifs; + pTxD->DataByteCnt = Length; + pTxD->TxRate = Rate; + switch (AccessCategory) // 802.11e/d4.4 June/2003 + { + case 3: // TC3, = <1, aCwMin/4, aCwMin/2> + pTxD->CWmin = CW_MIN_IN_BITS - 2; + pTxD->CWmax = CW_MIN_IN_BITS - 1; + pTxD->Aifs = 1; + break; + case 2: // TC2, = <1, aCwMin/2, aCwMin> + pTxD->CWmin = CW_MIN_IN_BITS - 1; + pTxD->CWmax = CW_MIN_IN_BITS; + pTxD->Aifs = 1; + break; + case 1: // TC1, = <1, aCwMin, aCwMax> + pTxD->CWmin = CW_MIN_IN_BITS; + pTxD->CWmax = CW_MAX_IN_BITS; + pTxD->Aifs = 1; + break; + case 0: // TC0, = <2, aCwMin, aCwMax> + default: + pTxD->CWmin = CW_MIN_IN_BITS; + pTxD->CWmax = CW_MAX_IN_BITS; + pTxD->Aifs = 2; + break; + } + + if (Rate < RATE_FIRST_OFDM_RATE) + pTxD->Ofdm = 0; + else + pTxD->Ofdm = 1; + + // fill up PLCP SIGNAL field + pTxD->PlcpSignal = PlcpSignal[Rate]; + if (((Rate == RATE_2) || (Rate == RATE_5_5) || (Rate == RATE_11)) && (TxPreamble == Rt802_11PreambleShort)) // no short preamble for RATE_1 + { + pTxD->PlcpSignal |= 0x0008; + } + + // fill up PLCP SERVICE field, not used for OFDM rates + pTxD->PlcpService = Service; + + // file up PLCP LENGTH_LOW and LENGTH_HIGH fields + Length += 4; + if (Rate < RATE_FIRST_OFDM_RATE) // 11b - RATE_1, RATE_2, RATE_5_5, RATE_11 + { + if ((Rate == RATE_1) || ( Rate == RATE_2)) + { + Length = Length * 8 / (Rate + 1); + } + else + { + Residual = ((Length * 16) % (11 * (1 + Rate - RATE_5_5))); + Length = Length * 16 / (11 * (1 + Rate - RATE_5_5)); + if (Residual != 0) + { + Length++; + } + if ((Residual <= (3 * (1 + Rate - RATE_5_5))) && (Residual != 0)) + { + if (Rate == RATE_11) // Only 11Mbps require length extension bit + pTxD->PlcpService |= 0x80; // 11b's PLCP Length extension bit + } + } + + pTxD->PlcpLengthHigh = Length / 256; + pTxD->PlcpLengthLow = Length % 256; + } + else // OFDM - RATE_6, RATE_9, RATE_12, RATE_18, RATE_24, RATE_36, RATE_48, RATE_54 + { + pTxD->PlcpLengthHigh = Length / 64; // high 6-bit of total byte count + pTxD->PlcpLengthLow = Length % 64; // low 6-bit of total byte count + } + + if (DoEncrypt == TRUE) // Do encryption only + { + pTxD->Owner = DESC_OWN_HOST; + pTxD->Valid = FALSE; + pTxD->CipherAlg = CipherAlg; + pTxD->CipherOwn = DESC_OWN_NIC; + } + else // Hard transmit + { + pTxD->Valid = TRUE; + pTxD->CipherAlg = CIPHER_NONE; + pTxD->CipherOwn = DESC_OWN_HOST; + pTxD->Owner = DESC_OWN_NIC; + } +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pSourceTxD = *pTxD; +#endif +} + +/* + ======================================================================== + + Routine Description: + Search tuple cache for receive duplicate frame from unicast frames. + + Arguments: + pAdapter Pointer to our adapter + pHeader 802.11 header of receiving frame + + Return Value: + TRUE found matched tuple cache + FALSE no matched found + + Note: + + ======================================================================== +*/ +BOOLEAN RTMPSearchTupleCache( + IN PRTMP_ADAPTER pAdapter, + IN PHEADER_802_11 pHeader) +{ + INT Index; + + for (Index = 0; Index < MAX_CLIENT; Index++) + { + if (pAdapter->TupleCache[Index].Valid == FALSE) + continue; + + if (RTMPEqualMemory(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6) && + (pAdapter->TupleCache[Index].Sequence == pHeader->Sequence) && + (pAdapter->TupleCache[Index].Frag == pHeader->Frag)) + { +// DBGPRINT(RT_DEBUG_TRACE,("DUPCHECK - duplicate frame hit entry %d\n", Index)); + return (TRUE); + } + } + return (FALSE); +} + +/* + ======================================================================== + + Routine Description: + Update tuple cache for new received unicast frames. + + Arguments: + pAdapter Pointer to our adapter + pHeader 802.11 header of receiving frame + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPUpdateTupleCache( + IN PRTMP_ADAPTER pAdapter, + IN PHEADER_802_11 pHeader) +{ + UCHAR Index; + + for (Index = 0; Index < MAX_CLIENT; Index++) + { + if (pAdapter->TupleCache[Index].Valid == FALSE) + { + // Add new entry + memcpy(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6); + pAdapter->TupleCache[Index].Sequence = pHeader->Sequence; + pAdapter->TupleCache[Index].Frag = pHeader->Frag; + pAdapter->TupleCache[Index].Valid = TRUE; + pAdapter->TupleCacheLastUpdateIndex = Index; + DBGPRINT(RT_DEBUG_INFO,"DUPCHECK - Add Entry %d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + Index, pAdapter->TupleCache[Index].MAC.Octet[0], pAdapter->TupleCache[Index].MAC.Octet[1], + pAdapter->TupleCache[Index].MAC.Octet[2], pAdapter->TupleCache[Index].MAC.Octet[3], + pAdapter->TupleCache[Index].MAC.Octet[4], pAdapter->TupleCache[Index].MAC.Octet[5]); + return; + } + else if (RTMPEqualMemory(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6)) + { + // Update old entry + pAdapter->TupleCache[Index].Sequence = pHeader->Sequence; + pAdapter->TupleCache[Index].Frag = pHeader->Frag; + return; + } + } + + // tuple cache full, replace the first inserted one (even though it may not be + // least referenced one) + if (Index == MAX_CLIENT) + { + pAdapter->TupleCacheLastUpdateIndex ++; + if (pAdapter->TupleCacheLastUpdateIndex >= MAX_CLIENT) + pAdapter->TupleCacheLastUpdateIndex = 0; + Index = pAdapter->TupleCacheLastUpdateIndex; + + // replace with new entry + memcpy(&pAdapter->TupleCache[Index].MAC, &pHeader->Controlhead.Addr2, 6); + pAdapter->TupleCache[Index].Sequence = pHeader->Sequence; + pAdapter->TupleCache[Index].Frag = pHeader->Frag; + pAdapter->TupleCache[Index].Valid = TRUE; + DBGPRINT(RT_DEBUG_INFO,"DUPCHECK - replace Entry %d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + Index, pAdapter->TupleCache[Index].MAC.Octet[0], pAdapter->TupleCache[Index].MAC.Octet[1], + pAdapter->TupleCache[Index].MAC.Octet[2], pAdapter->TupleCache[Index].MAC.Octet[3], + pAdapter->TupleCache[Index].MAC.Octet[4], pAdapter->TupleCache[Index].MAC.Octet[5]); + } +} + +/* + ======================================================================== + + Routine Description: + Suspend MSDU transmission + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPSuspendMsduTransmission( + IN PRTMP_ADAPTER pAdapter) +{ + DBGPRINT(RT_DEBUG_TRACE,"SCANNING, suspend MSDU transmission ...\n"); + RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); +} + +/* + ======================================================================== + + Routine Description: + Resume MSDU transmission + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPResumeMsduTransmission( + IN PRTMP_ADAPTER pAdapter) +{ + DBGPRINT(RT_DEBUG_INFO,"SCAN done, resume MSDU transmission ...\n"); + RTMP_CLEAR_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); + + // Dequeue Tx queue if Reset is not in progress + if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && + (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF))) + { + //RTMPDeQueuePacket(pAdapter, &pAdapter->TxSwQueue0); + // Call dequeue without selected queue, let the subroutine select the right priority + // Tx software queue + RTMPDeQueuePacket(pAdapter); + } +} + +/* + ======================================================================== + + Routine Description: + Apply packet filter policy, return NDIS_STATUS_FAILURE if this frame + should be dropped. + + Arguments: + pAdapter Pointer to our adapter + pRxD Pointer to the Rx descriptor + pHeader Pointer to the 802.11 frame header + + Return Value: + NDIS_STATUS_SUCCESS Accept frame + NDIS_STATUS_FAILURE Drop Frame + + Note: + Maganement frame should bypass this filtering rule. + + ======================================================================== +*/ +NDIS_STATUS RTMPApplyPacketFilter( + IN PRTMP_ADAPTER pAdapter, + IN PRXD_STRUC pRxD, + IN PHEADER_802_11 pHeader) +{ + UCHAR i; + + // 0. Management frame should bypass all these filtering rules. + if (pHeader->Controlhead.Frame.Type == BTYPE_MGMT) + { + return(NDIS_STATUS_SUCCESS); + } + + // 0.1 Drop all Rx frames if MIC countermeasures kicks in + if (pAdapter->PortCfg.MicErrCnt >= 2) + { + return(NDIS_STATUS_FAILURE); + } + + // 1. Drop unicast to me packet if NDIS_PACKET_TYPE_DIRECTED is FALSE + if (pRxD->U2M) + { + if (pAdapter->bAcceptDirect == FALSE) + { + return(NDIS_STATUS_FAILURE); + } + } + + // 2. Drop broadcast packet if NDIS_PACKET_TYPE_BROADCAST is FALSE + else if (pRxD->Bcast) + { + if (pAdapter->bAcceptBroadcast == FALSE) + { + return(NDIS_STATUS_FAILURE); + } + } + + // 3. Drop multicast packet if NDIS_PACKET_TYPE_ALL_MULTICAST is false + // and NDIS_PACKET_TYPE_MULTICAST is false. + // If NDIS_PACKET_TYPE_MULTICAST is true, but NDIS_PACKET_TYPE_ALL_MULTICAST is false. + // We have to deal with multicast table lookup & drop not matched packets. + else if (pRxD->Mcast) + { + if (pAdapter->bAcceptAllMulticast == FALSE) + { + if (pAdapter->bAcceptMulticast == FALSE) + { + return(NDIS_STATUS_FAILURE); + } + else + { + // Selected accept multicast packet based on multicast table + for (i = 0; i < pAdapter->NumberOfMcAddresses; i++) + { + if (RTMPEqualMemory(&pHeader->Controlhead.Addr1, pAdapter->McastTable[i], ETH_ALEN)) + { + break; // Matched + } + } + + // Not matched + if (i == pAdapter->NumberOfMcAddresses) + { + DBGPRINT(RT_DEBUG_INFO,"Drop multicast %02x:%02x:%02x:%02x:%02x:%02x\n", + pHeader->Controlhead.Addr1.Octet[0], pHeader->Controlhead.Addr1.Octet[1], + pHeader->Controlhead.Addr1.Octet[2], pHeader->Controlhead.Addr1.Octet[3], + pHeader->Controlhead.Addr1.Octet[4], pHeader->Controlhead.Addr1.Octet[5]); + return(NDIS_STATUS_FAILURE); + } + else + { + DBGPRINT(RT_DEBUG_INFO,"Accept multicast %02x:%02x:%02x:%02x:%02x:%02x\n", + pHeader->Controlhead.Addr1.Octet[0], pHeader->Controlhead.Addr1.Octet[1], + pHeader->Controlhead.Addr1.Octet[2], pHeader->Controlhead.Addr1.Octet[3], + pHeader->Controlhead.Addr1.Octet[4], pHeader->Controlhead.Addr1.Octet[5]); + } + } + } + } + + // 4. Not U2M, not Mcast, not Bcast, must be unicast to other DA. + // Since we did not implement promiscuous mode, just drop this kind of packet for now. + else if (pAdapter->bAcceptPromiscuous == FALSE) + { + return(NDIS_STATUS_FAILURE); + } + + return(NDIS_STATUS_SUCCESS); +} + +/* + ======================================================================== + + Routine Description: + Check and fine the packet waiting in SW queue with highest priority + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + pQueue Pointer to Waiting Queue + + Note: + + ======================================================================== +*/ +struct sk_buff_head* RTMPCheckTxSwQueue( + IN PRTMP_ADAPTER pAdapter, + OUT UCHAR *AccessCategory) +{ + if (!skb_queue_empty(&pAdapter->TxSwQueue3)) + { + *AccessCategory = 3; + return (&pAdapter->TxSwQueue3); + } + else if (!skb_queue_empty(&pAdapter->TxSwQueue2)) + { + *AccessCategory = 2; + return (&pAdapter->TxSwQueue2); + } + else if (!skb_queue_empty(&pAdapter->TxSwQueue1)) + { + *AccessCategory = 1; + return (&pAdapter->TxSwQueue1); + } + else if (!skb_queue_empty(&pAdapter->TxSwQueue0)) + { + *AccessCategory = 0; + return (&pAdapter->TxSwQueue0); + } + + // No packet pending in Tx Sw queue + *AccessCategory = 0; + return (NULL); +} + +/* + ======================================================================== + + Routine Description: + Process MIC error indication and record MIC error timer. + + Arguments: + pAdapter Pointer to our adapter + pWpaKey Pointer to the WPA key structure + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPReportMicError( + IN PRTMP_ADAPTER pAdapter, + IN PWPA_KEY pWpaKey) +{ + ULONG Now; + struct + { + NDIS_802_11_STATUS_INDICATION Status; + NDIS_802_11_AUTHENTICATION_REQUEST Request; + } Report; + + // 0. Set Status to indicate auth error + Report.Status.StatusType = Ndis802_11StatusType_Authentication; + + // 1. Check for Group or Pairwise MIC error + if (pWpaKey->Type == PAIRWISE_KEY) + Report.Request.Flags = NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR; + else + Report.Request.Flags = NDIS_802_11_AUTH_REQUEST_GROUP_ERROR; + + // 2. Copy AP MAC address + memcpy(Report.Request.Bssid, pWpaKey->BssId, 6); + + // 3. Calculate length + Report.Request.Length = sizeof(NDIS_802_11_AUTHENTICATION_REQUEST); + + // 4. Record Last MIC error time and count + Now = jiffies; + if (pAdapter->PortCfg.MicErrCnt == 0) + { + pAdapter->PortCfg.MicErrCnt++; + pAdapter->PortCfg.LastMicErrorTime = Now; + } + else if (pAdapter->PortCfg.MicErrCnt == 1) + { + if ((pAdapter->PortCfg.LastMicErrorTime + (60 * HZ)) < Now) + { + // Update Last MIC error time, this did not violate two MIC errors within 60 seconds + pAdapter->PortCfg.LastMicErrorTime = Now; + } + else + { + pAdapter->PortCfg.LastMicErrorTime = Now; + // Violate MIC error counts, MIC countermeasures kicks in + pAdapter->PortCfg.MicErrCnt++; + // We shall block all reception + // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame + RTMPRingCleanUp(pAdapter, TX_RING); + } + } + else + { + // MIC error count >= 2 + // This should not happen + ; + } +} diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_def.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_def.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_def.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,571 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_def.h + * + * Abstract: Miniport related definition header + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulL 1st Aug 02 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef __RTMP_DEF_H__ +#define __RTMP_DEF_H__ + +// +// Debug information verbosity: lower values indicate higher urgency +// +#define RT_DEBUG_ERROR KERN_ERR +#define RT_DEBUG_WARN KERN_WARNING +#define RT_DEBUG_TRACE KERN_NOTICE +#define RT_DEBUG_INFO KERN_INFO +#define RT_DEBUG_LOUD KERN_DEBUG + +// +// update the driver version number every time you release a new driver +// The high word is the major version. The low word is the minor version. +// +#define NIC_VENDOR_DRIVER_VERSION 0x00010001 + +// +// NDIS media type, current is ethernet, change if native wireless supported +// +#define NIC_PCI_HDR_LENGTH 0xe2 +#define NIC_MAX_PACKET_SIZE 2304 +#define NIC_HEADER_SIZE 14 + +// +// interface type, we use PCI +// + +// +// buffer size passed in NdisMQueryAdapterResources +// We should only need three adapter resources (IO, interrupt and memory), +// Some devices get extra resources, so have room for 10 resources +// + +// +// IO space length +// + +// +// Entry number for each DMA descriptor ring +// +#define TX_RING_SIZE 48 +#define ATIM_RING_SIZE 4 +#define PRIO_RING_SIZE 16 // 8 +#define RX_RING_SIZE 32 +#define BEACON_RING_SIZE 1 +#define DESCRIPTOR_REQUIRED ((TX_RING_SIZE) + (ATIM_RING_SIZE) + (PRIO_RING_SIZE) + (RX_RING_SIZE) + (BEACON_RING_SIZE)) +#define OTHER_DESC_REQUIRED ((ATIM_RING_SIZE) + (PRIO_RING_SIZE) + (RX_RING_SIZE) + (BEACON_RING_SIZE)) +#define MGMT_RING_SIZE 32 +#define RING_DESCRIPTOR_SIZE 48 +#define TX_BUFFER_SIZE 2048 +#define PRIO_BUFFER_SIZE 1024 // 2048 +#define RX_BUFFER_SIZE 2048 +#define ATIM_BUFFER_SIZE 512 +#define BEACON_BUFFER_SIZE 2048 +#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size +#define ALLOC_RX_PACKET_POOL (RX_RING_SIZE) +#define ALLOC_RX_BUFFER_POOL (ALLOC_RX_PACKET_POOL) +#define TX_RING 0xa +#define ATIM_RING 0xb +#define PRIO_RING 0xc +#define RX_RING 0xd +#define MAX_TX_PROCESS 4 +#define MAX_RX_PROCESS 4 +#define MAX_CLIENT 4 +#define MAX_MCAST_LIST_SIZE 32 + +// RTMP_ADAPTER flags +#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 +#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 +#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 +#define fRTMP_ADAPTER_MLME_INITIALIZED 0x00000008 +#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 +#define fRTMP_ADAPTER_RECEIVE_PACKET_ERROR 0x00000020 +#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 +#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 +#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000100 +#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 +#define fRTMP_ADAPTER_ATIM_RING_ALLOCATED 0x00000400 +#define fRTMP_ADAPTER_PRIO_RING_ALLOCATED 0x00000800 +#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 +#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 +#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 +#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x00008000 +#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 +#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 +#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x02000000 + +// Lock bit for accessing different ring buffers +#define fRTMP_ADAPTER_TX_RING_BUSY 0x80000000 +#define fRTMP_ADAPTER_PRIO_RING_BUSY 0x40000000 +#define fRTMP_ADAPTER_ATIM_RING_BUSY 0x20000000 +#define fRTMP_ADAPTER_RX_RING_BUSY 0x10000000 + +// Lock bit for accessing different queue +#define fRTMP_ADAPTER_TX_QUEUE_BUSY 0x08000000 +#define fRTMP_ADAPTER_PRIO_QUEUE_BUSY 0x04000000 + +// +// Error code section +// +// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND +#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L +#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L +#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L + +// NDIS_ERROR_CODE_ADAPTER_DISABLED +#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L + +// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION +#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L +#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L + +// NDIS_ERROR_CODE_OUT_OF_RESOURCES +#define ERRLOG_OUT_OF_MEMORY 0x00000401L +#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L +#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L +#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L +#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L +#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L +#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L +#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L + +// NDIS_ERROR_CODE_HARDWARE_FAILURE +#define ERRLOG_SELFTEST_FAILED 0x00000501L +#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L +#define ERRLOG_REMOVE_MINIPORT 0x00000503L + +// NDIS_ERROR_CODE_RESOURCE_CONFLICT +#define ERRLOG_MAP_IO_SPACE 0x00000601L +#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L +#define ERRLOG_NO_IO_RESOURCE 0x00000603L +#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L +#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L + + + +//============================================================ +// Length definitions +#define PEER_KEY_NO 2 +#define CRC_LEN 4 +#define TIMESTAMP_LEN 8 +#define MAX_LEN_OF_SUPPORTED_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 +#define MAX_NUM_OF_POWER_LEVEL 8 +#define MAX_NUM_OF_DOMAIN 8 +#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA +#define MAX_LEN_OF_CHANNELS 42 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 1 as NULL termination +#define MAX_LEN_OF_PEER_KEY 16 +#define MAC_HDR_LEN 24 +#define MAX_LEN_OF_MANUFACTURE_ID 32 +#define MAX_LEN_OF_PRODUCT_ID 32 +#define MAX_LEN_OF_MAC_TABLE 32 +#define MAX_LEN_OF_SSID 32 +#define CIPHER_TEXT_LEN 128 +#define HASH_TABLE_SIZE 256 +#define MAX_LEN_OF_MLME_BUFFER 1024 +#define MAX_FRAME_LEN 2338 +#define MAX_VIE_LEN 128 // New for WPA cipher suite variable IE sizes. +#define MAX_MLME_HANDLER_MEMORY 20 //each them cantains MAX_LEN_OF_MLME_BUFFER size +#define MAX_INI_BUFFER_SIZE 1024 + +#define MAX_TX_POWER_LEVEL 100 /* mW */ +#define MAX_RSSI_TRIGGER -10 /* dBm */ +#define MIN_RSSI_TRIGGER -200 /* dBm */ +#define MAX_FRAG_THRESHOLD 2346 /* byte count */ +#define MIN_FRAG_THRESHOLD 256 /* byte count */ +#define MAX_RTS_THRESHOLD 2347 /* byte count */ + +// key related definitions +#define SHARE_KEY_NO 4 +#define MAX_LEN_OF_SHARE_KEY 16 +#define PAIRWISE_KEY_NO 4 +#define GROUP_KEY_NO 4 + +// power status related definitions +#define PWR_ACTIVE 0 +#define PWR_SAVE 1 +#define PWR_UNKNOWN 2 + +// Auth and Assoc mode related definitions +#define AUTH_MODE 0x10 +#define ASSOC_MODE 0x20 + +#define AUTH_MODE_OPEN 0x00 +#define AUTH_MODE_SHARED 0x01 +#define AUTH_MODE_AUTO_SWITCH 0x03 +#define AUTH_MODE_DEAUTH 0x04 +#define AUTH_MODE_UPLAYER 0x05 // reserved for 802.11i use + +#define ASSOC_MODE_DISASSOC 0x04 +#define ASSOC_MODE_ASSOC 0x05 + +// BSS Type definitions +#define BSS_INDEP 0 // = Ndis802_11IBSS +#define BSS_INFRA 1 // = Ndis802_11Infrastructure +#define BSS_ANY 2 // = Ndis802_11AutoUnknown +#define BSS_MONITOR 3 // = Ndis802_11Monitor +// #define BSS_UNKNOWN 0xff + + +// WEP related definitions +// #define WEP_DISABLE 0 +// #define WEP_ENABLE 1 +// #define WEP_KEY_ABSENT 2 +// #define WEP_NOT_SUPPORTED 3 + +// value of FrameDesc.priority +// #define PRIO_CONTENTION 0 +// #define PRIO_CONTENTION_FREE 1 + +// value of auth_algorithm in Authentication frame body + +// Reason code definitions +#define REASON_RESERVED 0 +#define REASON_UNSPECIFY 1 +#define REASON_NO_LONGER_VALID 2 +#define REASON_DEAUTH_STA_LEAVING 3 +#define REASON_DISASSOC_INACTIVE 4 +#define REASON_DISASSPC_AP_UNABLE 5 +#define REASON_CLS2ERR 6 +#define REASON_CLS3ERR 7 +#define REASON_DISASSOC_STA_LEAVING 8 +#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 +#define REASON_INVALID_IE 13 +#define REASON_MIC_FAILURE 14 +#define REASON_4_WAY_HANDSHAKE_TIMEOUT 15 +#define REASON_GROUP_KEY_UPDATE_TIMEOUT 16 + +// Status code definitions +#define MLME_SUCCESS 0 +#define MLME_UNSPECIFY_FAIL 1 +#define MLME_CANNOT_SUPPORT_CAP 10 +#define MLME_REASSOC_DENY_ASSOC_EXIST 11 +#define MLME_ASSOC_DENY_OUT_SCOPE 12 +#define MLME_ALG_NOT_SUPPORT 13 +#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 +#define MLME_REJ_CHALLENGE_FAILURE 15 +#define MLME_REJ_TIMEOUT 16 +#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 +#define MLME_ASSOC_REJ_DATA_RATE 18 + +#define MLME_ASSOC_REJ_NO_EXT_RATE 22 +#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 +#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 + +#define MLME_INVALID_FORMAT 0x51 +#define MLME_FAIL_NO_RESOURCE 0x52 +#define MLME_STATE_MACHINE_REJECT 0x53 +#define MLME_MAC_TABLE_FAIL 0x54 + +//IE code +#define IE_SSID 0 +#define IE_SUPP_RATES 1 +#define IE_FH_PARM 2 +#define IE_DS_PARM 3 +#define IE_CF_PARM 4 +#define IE_TIM 5 +#define IE_IBSS_PARM 6 +#define IE_COUNTRY 7 // 802.11d +#define IE_802_11D_REQUEST 10 // 802.11d +#define IE_CHALLENGE_TEXT 16 +#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 +#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 +#define IE_TPC_REQUEST 34 // 802.11h d3.3 +#define IE_TPC_REPORT 35 // 802.11h d3.3 +#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 +#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 +#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 +#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 +#define IE_QUIET 40 // 802.11h d3.3 +#define IE_IBSS_DFS 41 // 802.11h d3.3 +#define IE_ERP 42 // 802.11g +#define IE_EXT_SUPP_RATES 50 // 802.11g +#define IE_WPA 221 // WPA +#define IE_RSN 48 // 802.11i d3.0 + +#define CNTL_FUNC_SIZE 1 + +// Message type for the MLME state machine +// Messages for Associate state machine +#define ASSOC_MACHINE_BASE 0 + +#define MT2_MLME_ASSOC_REQ 0 +#define MT2_MLME_REASSOC_REQ 1 +#define MT2_MLME_DISASSOC_REQ 2 +#define MT2_PEER_DISASSOC_REQ 3 +#define MT2_PEER_ASSOC_REQ 4 +#define MT2_PEER_ASSOC_RSP 5 +#define MT2_PEER_REASSOC_REQ 6 +#define MT2_PEER_REASSOC_RSP 7 +//#define MT2_CLS3ERR 8 +#define MT2_DISASSOC_TIMEOUT 8 +#define MT2_ASSOC_TIMEOUT 9 +#define MT2_REASSOC_TIMEOUT 10 + +#define MAX_ASSOC_MSG 11 + +// Messages for Authentication state machine +#define AUTH_MACHINE_BASE 11 + +#define MT2_MLME_AUTH_REQ 11 +//#define MT2_MLME_DEAUTH_REQ 12 +//#define MT2_CLS2ERR 13 +#define MT2_PEER_AUTH_EVEN 14 +#define MT2_AUTH_TIMEOUT 15 + +#define MAX_AUTH_MSG 5 + +// Messages for authentication response state machine +#define AUTH_RSP_MACHINE_BASE 16 + +#define MT2_AUTH_CHALLENGE_TIMEOUT 16 +#define MT2_PEER_AUTH_ODD 17 +#define MT2_PEER_DEAUTH 18 + +#define MAX_AUTH_RSP_MSG 3 + +// Messages for the sync state machine +#define SYNC_MACHINE_BASE 19 + +#define MT2_MLME_SCAN_REQ 19 +#define MT2_MLME_JOIN_REQ 20 +#define MT2_MLME_START_REQ 21 +#define MT2_PEER_BEACON 22 +#define MT2_PEER_PROBE_RSP 23 +#define MT2_PEER_ATIM 24 +#define MT2_SCAN_TIMEOUT 25 +#define MT2_BEACON_TIMEOUT 26 +#define MT2_ATIM_TIMEOUT 27 +#define MT2_PEER_PROBE_REQ 28 + +#define MAX_SYNC_MSG 10 + +// MIB access +#define MT2_GET_REQ 31 +#define MT2_SET_REQ 32 +#define MT2_RESET_REQ 33 + +// Confirm message +#define MT2_ASSOC_CONF 34 +#define MT2_AUTH_CONF 35 +#define MT2_DEAUTH_CONF 36 +#define MT2_DISASSOC_CONF 37 +#define MT2_REASSOC_CONF 38 +#define MT2_PWR_MGMT_CONF 39 +#define MT2_JOIN_CONF 40 +#define MT2_SCAN_CONF 41 +#define MT2_START_CONF 42 +#define MT2_GET_CONF 43 +#define MT2_SET_CONF 44 +#define MT2_RESET_CONF 45 + +// Indication message +#define MT2_DEAUTH_IND 46 +#define MT2_ASSOC_IND 47 +#define MT2_DISASSOC_IND 48 +#define MT2_REASSOC_IND 49 +#define MT2_AUTH_IND 50 + +#define MT2_SCAN_END_CONF 51 // For scan end +#define MT2_MLME_ROAMING_REQ 52 + +/* #define TXSTATUS_SUCCESS 0 */ +/* #define TXSTATUS_FAIL_RETRY_LIMIT 1 */ +/* #define TXSTATUS_EXCESSIVE_LENGTH 2 */ +/* #define TXSTATUS_NON_NULL_SOURCE_ROUTE 3 */ +/* #define TXSTATUS_UNSUPPORTED_PRIORITY 4 */ +/* #define TXSTATUS_UNSUPPORTED_SERVICE 5 */ +/* #define TXSTATUS_UNAVAILABLE_PRIORITY 6 // CF with no PC available; down-grade to contention */ +/* #define TXSTATUS_UNAVAILABLE_SERVICE 7 // strictly-ordered but STA isn't active */ +/* #define TXSTATUS_FAIL_LIFE_TIME 8 */ +/* #define TXSTATUS_FAIL_NOBSS 9 */ +/* #define TXSTATUS_FAIL_NULL_KEY 10 */ + +// value domain of MacHdr.tyte, which is b3..b2 of the 1st-byte of MAC header +#define BTYPE_MGMT 0 // 00 +#define BTYPE_CNTL 1 // 01 +#define BTYPE_DATA 2 // 10 + +// value domain of MacHdr.subtype, which is b7..4 of the 1st-byte of MAC header +// Management frame +#define SUBTYPE_ASSOC_REQ 0 +#define SUBTYPE_ASSOC_RSP 1 +#define SUBTYPE_REASSOC_REQ 2 +#define SUBTYPE_REASSOC_RSP 3 +#define SUBTYPE_PROBE_REQ 4 +#define SUBTYPE_PROBE_RSP 5 +#define SUBTYPE_BEACON 8 +#define SUBTYPE_ATIM 9 +#define SUBTYPE_DISASSOC 10 +#define SUBTYPE_AUTH 11 +#define SUBTYPE_DEAUTH 12 +#define SUBTYPE_ACTION 13 + +// Control Frame +#define SUBTYPE_BLOCK_ACK_REQ 8 +#define SUBTYPE_BLOCK_ACK 9 +#define SUBTYPE_PS_POLL 10 +#define SUBTYPE_RTS 11 // 1011 +#define SUBTYPE_CTS 12 // 1100 +#define SUBTYPE_ACK 13 // 1101 +#define SUBTYPE_CFEND 14 +#define SUBTYPE_CFEND_CFACK 15 + +// Data Frame +#define SUBTYPE_DATA 0 +#define SUBTYPE_DATA_CFACK 1 +#define SUBTYPE_DATA_CFPOLL 2 +#define SUBTYPE_DATA_CFACK_CFPOLL 3 +#define SUBTYPE_NULL_FUNC 4 +#define SUBTYPE_CFACK 5 // 0101 +#define SUBTYPE_CFPOLL 6 +#define SUBTYPE_CFACK_CFPOLL 7 +#define SUBTYPE_QDATA 8 +#define SUBTYPE_QDATA_CFACK 9 +#define SUBTYPE_QDATA_CFPOLL 10 +#define SUBTYPE_QDATA_CFACK_CFPOLL 11 +#define SUBTYPE_QOS_NULL 12 +#define SUBTYPE_QOS_CFACK 13 +#define SUBTYPE_QOS_CFPOLL 14 +#define SUBTYPE_QOS_CFACK_CFPOLL 15 + +#define ASSOC_STATE_MACHINE 1 +#define AUTH_STATE_MACHINE 2 +#define AUTH_RSP_STATE_MACHINE 3 +#define SYNC_STATE_MACHINE 4 +#define MLME_CNTL_STATE_MACHINE 5 +#define WPA_PSK_STATE_MACHINE 6 + +// +// rtmp_data.c use these definition +// +#define LENGTH_802_11 24 +#define LENGTH_802_11_AND_H 30 +#define LENGTH_802_11_CRC_H 34 +#define LENGTH_802_11_CRC 28 +#define LENGTH_802_3 14 +#define LENGTH_802_3_TYPE 2 +#define LENGTH_802_1_H 8 +#define LENGTH_EAPOL_H 4 +#define LENGTH_CRC 4 +#define MAX_SEQ_NUMBER 0x0fff + +#define SUCCESS_WITHOUT_RETRY 0 +#define SUCCESS_WITH_RETRY 1 +#define FAIL_RETRY_LIMIT 2 +#define FAIL_INVALID 3 +#define FAIL_OTHER 4 + +#define RATE_1 0 +#define RATE_2 1 +#define RATE_5_5 2 +#define RATE_11 3 +#define RATE_6 4 // OFDM +#define RATE_9 5 // OFDM +#define RATE_12 6 // OFDM +#define RATE_18 7 // OFDM +#define RATE_24 8 // OFDM +#define RATE_36 9 // OFDM +#define RATE_48 10 // OFDM +#define RATE_54 11 // OFDM +#define RATE_72 12 +#define RATE_100 13 +#define RATE_FIRST_OFDM_RATE RATE_6 +#define RATE_AUTO_SWITCH 255 // for PortCfg.FixedTxRate only + +#define IFS_BACKOFF 0 +#define IFS_SIFS 1 +#define IFS_NEW_BACKOFF 2 +#define IFS_NONE 3 + +#define LONG_RETRY 1 +#define SHORT_RETRY 0 + +// Country Region definition +#define REGION_MIN 0 +#define REGION_FCC 0 // 1-11 +#define REGION_IC 1 // 1-11 +#define REGION_ETSI 2 // 1-13 +#define REGION_SPAIN 3 // 10-11 +#define REGION_FRANCE 4 // 10-13 +#define REGION_MKK 5 // 14 +#define REGION_MKK1 6 // 1-14 +#define REGION_ISRAEL 7 // 3-9 +#define REGION_MAX REGION_ISRAEL + +#define CIPHER_NONE 0 +#define CIPHER_WEP64 1 +#define CIPHER_WEP128 2 +#define CIPHER_TKIP 3 +#define CIPHER_AES 4 + +// Stall execution time for ndisdpracquires[inlock in miniportReset function +#define WAIT_TIME_FOR_SPINLOCK 10 // usec + +// value domain for pAdapter->PortCfg.RfType +#define RFIC_2522 0 +#define RFIC_2523 1 +#define RFIC_2524 2 +#define RFIC_2525 3 +#define RFIC_2525E 4 +#define RFIC_5222 16 + +// value domain for pAdapter->PortCfg.LedMode and E2PROM +#define LED_MODE_DEFAULT 0 +#define LED_MODE_TXRX_ACTIVITY 1 +#define LED_MODE_SINGLE 2 // Single LED mode, driver lid the LED as soon as driver up & enable tx activity right away +#define LED_MODE_ASUS 3 // Two LED modes, bit 16 acts as LED_MODE_SINGLE, bit 17 acts as RADIO status. + +// RC4 init value, used fro WEP & TKIP +#define PPPINITFCS32 0xffffffff /* Initial FCS value */ + +// 802.1X controlled port definition +#define WPA_802_1X_PORT_SECURED 1 +#define WPA_802_1X_PORT_NOT_SECURED 2 + +#define PAIRWISE_KEY 1 +#define GROUP_KEY 2 + +#ifdef BIG_ENDIAN +#define DIR_READ 0 +#define DIR_WRITE 1 +#define TYPE_TXD 0 +#define TYPE_RXD 1 +#endif + +#ifdef RALINK_ATE +#define ATE_STASTOP 0 // Stop Station +#define ATE_STASTART 1 // Start Station +#define ATE_TXCONT 2 // Continuous Transmit +#define ATE_TXCARR 3 // Transmit Carrier +#define ATE_TXFRAME 4 // Transmit Frames +#define ATE_RXFRAME 5 // Receive Frames +#endif //#ifdef RALINK_ATE + +#endif // __RTMP_DEF_H__ diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_info.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_info.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_info.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_info.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,4776 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_info.c + * + * Abstract: IOCTL related subroutines + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * RoryC 3rd Jan 03 Initial code + * MarkW 8th Dec 04 Baseline code + * RobinC 10th Dec 04 RFMON Support + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + * MarkW 15th Dec 04 Removed debug iwpriv + * RobinC 16th Dec 04 Fix for range values + * RobinC 16th Dec 04 support ifpreup scripts + * RobinC 17th Dec 04 Link Quality reporting + * MarkW 17th Dec 04 iwconfig frequency fix + * MarkW 17th Dec 04 Monitor mode through iwconfig + * MarkW 22nd Dec 04 RSSI reporting for iwlist scanning + * MarkW 31st Jan 05 if pre-up fix for RaConfig + * LuisCorreia 23rd Feb 05 fix unknown IOCTL's + * MarkW 9th Mar 05 Quality reporting in scan for current + * MarkW 9th Jun 05 Fix channel change for ADHOC mode + ***************************************************************************/ + +#include "rt_config.h" +#include + +#ifndef IW_ESSID_MAX_SIZE +/* Maximum size of the ESSID and NICKN strings */ +#define IW_ESSID_MAX_SIZE 32 +#endif + +#define NR_WEP_KEYS 4 +#define WEP_SMALL_KEY_LEN (40/8) +#define WEP_LARGE_KEY_LEN (104/8) + +#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ + switch (ch) \ + { \ + case 1: khz = 2412000; break; \ + case 2: khz = 2417000; break; \ + case 3: khz = 2422000; break; \ + case 4: khz = 2427000; break; \ + case 5: khz = 2432000; break; \ + case 6: khz = 2437000; break; \ + case 7: khz = 2442000; break; \ + case 8: khz = 2447000; break; \ + case 9: khz = 2452000; break; \ + case 10: khz = 2457000; break; \ + case 11: khz = 2462000; break; \ + case 12: khz = 2467000; break; \ + case 13: khz = 2472000; break; \ + case 14: khz = 2484000; break; \ + case 36: /* UNII */ khz = 5180000; break; \ + case 40: /* UNII */ khz = 5200000; break; \ + case 44: /* UNII */ khz = 5220000; break; \ + case 48: /* UNII */ khz = 5240000; break; \ + case 52: /* UNII */ khz = 5260000; break; \ + case 56: /* UNII */ khz = 5280000; break; \ + case 60: /* UNII */ khz = 5300000; break; \ + case 64: /* UNII */ khz = 5320000; break; \ + case 149: /* UNII */ khz = 5745000; break; \ + case 153: /* UNII */ khz = 5765000; break; \ + case 157: /* UNII */ khz = 5785000; break; \ + case 161: /* UNII */ khz = 5805000; break; \ + case 100: /* HiperLAN2 */ khz = 5500000; break; \ + case 104: /* HiperLAN2 */ khz = 5520000; break; \ + case 108: /* HiperLAN2 */ khz = 5540000; break; \ + case 112: /* HiperLAN2 */ khz = 5560000; break; \ + case 116: /* HiperLAN2 */ khz = 5580000; break; \ + case 120: /* HiperLAN2 */ khz = 5600000; break; \ + case 124: /* HiperLAN2 */ khz = 5620000; break; \ + case 128: /* HiperLAN2 */ khz = 5640000; break; \ + case 132: /* HiperLAN2 */ khz = 5660000; break; \ + case 136: /* HiperLAN2 */ khz = 5680000; break; \ + case 140: /* HiperLAN2 */ khz = 5700000; break; \ + case 34: /* Japan MMAC */ khz = 5170000; break; \ + case 38: /* Japan MMAC */ khz = 5190000; break; \ + case 42: /* Japan MMAC */ khz = 5210000; break; \ + case 46: /* Japan MMAC */ khz = 5230000; break; \ + default: khz = 2412000; break; \ + } \ + } + +#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ + switch (khz) \ + { \ + case 2412000: ch = 1; break; \ + case 2417000: ch = 2; break; \ + case 2422000: ch = 3; break; \ + case 2427000: ch = 4; break; \ + case 2432000: ch = 5; break; \ + case 2437000: ch = 6; break; \ + case 2442000: ch = 7; break; \ + case 2447000: ch = 8; break; \ + case 2452000: ch = 9; break; \ + case 2457000: ch = 10; break; \ + case 2462000: ch = 11; break; \ + case 2467000: ch = 12; break; \ + case 2472000: ch = 13; break; \ + case 2484000: ch = 14; break; \ + case 5180000: ch = 36; /* UNII */ break; \ + case 5200000: ch = 40; /* UNII */ break; \ + case 5220000: ch = 44; /* UNII */ break; \ + case 5240000: ch = 48; /* UNII */ break; \ + case 5260000: ch = 52; /* UNII */ break; \ + case 5280000: ch = 56; /* UNII */ break; \ + case 5300000: ch = 60; /* UNII */ break; \ + case 5320000: ch = 64; /* UNII */ break; \ + case 5745000: ch = 149; /* UNII */ break; \ + case 5765000: ch = 153; /* UNII */ break; \ + case 5785000: ch = 157; /* UNII */ break; \ + case 5805000: ch = 161; /* UNII */ break; \ + case 5500000: ch = 100; /* HiperLAN2 */ break; \ + case 5520000: ch = 104; /* HiperLAN2 */ break; \ + case 5540000: ch = 108; /* HiperLAN2 */ break; \ + case 5560000: ch = 112; /* HiperLAN2 */ break; \ + case 5580000: ch = 116; /* HiperLAN2 */ break; \ + case 5600000: ch = 120; /* HiperLAN2 */ break; \ + case 5620000: ch = 124; /* HiperLAN2 */ break; \ + case 5640000: ch = 128; /* HiperLAN2 */ break; \ + case 5660000: ch = 132; /* HiperLAN2 */ break; \ + case 5680000: ch = 136; /* HiperLAN2 */ break; \ + case 5700000: ch = 140; /* HiperLAN2 */ break; \ + case 5170000: ch = 34; /* Japan MMAC */ break; \ + case 5190000: ch = 38; /* Japan MMAC */ break; \ + case 5210000: ch = 42; /* Japan MMAC */ break; \ + case 5230000: ch = 46; /* Japan MMAC */ break; \ + default: ch = 1; break; \ + } \ + } + +struct iw_priv_args privtab[] = { +{ RTPRIV_IOCTL_SET, + IW_PRIV_TYPE_CHAR | 1024, 0, + "set"}, +{ RTPRIV_IOCTL_BBP, + IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, + "bbp"}, +{ RTPRIV_IOCTL_MAC, + IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, + "mac"}, +{ RTPRIV_IOCTL_E2P, + IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, + "e2p"}, +{ RTPRIV_IOCTL_RFMONTX, + IW_PRIV_TYPE_INT | 2, IW_PRIV_TYPE_CHAR | sizeof (char), + "rfmontx"} +}; + +static struct { + char *name; + int (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); +} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { + {"CountryRegion", Set_CountryRegion_Proc }, + {"SSID", Set_SSID_Proc}, + {"WirelessMode", Set_WirelessMode_Proc}, + {"TxRate", Set_TxRate_Proc}, + {"AdhocOfdm", Set_AdhocModeRate_Proc}, + {"Channel", Set_Channel_Proc}, + {"BGProtection", Set_BGProtection_Proc}, + {"StaWithEtherBridge", Set_StaWithEtherBridge_Proc}, + {"TxPreamble", Set_TxPreamble_Proc}, + {"RTSThreshold", Set_RTSThreshold_Proc}, + {"FragThreshold", Set_FragThreshold_Proc}, + {"TxBurst", Set_TxBurst_Proc}, + {"TurboRate", Set_TurboRate_Proc}, + {"NetworkType", Set_NetworkType_Proc}, + {"AuthMode", Set_AuthMode_Proc}, + {"EncrypType", Set_EncrypType_Proc}, + {"DefaultKeyID", Set_DefaultKeyID_Proc}, + {"Key1", Set_Key1_Proc}, + {"Key2", Set_Key2_Proc}, + {"Key3", Set_Key3_Proc}, + {"Key4", Set_Key4_Proc}, + {"WPAPSK", Set_WPAPSK_Proc}, + {"WPANONE", Set_WPANONE_Proc}, + +#ifdef RALINK_ATE + {"ATE", Set_ATE_Proc }, // set ATE Mode to: STOP, TXCONT, TXCARR, TXFRAME, RXFRAME + {"ATEDA", Set_ATE_DA_Proc }, // set ATE TxFrames ADDR1, DA + {"ATESA", Set_ATE_SA_Proc }, // set ATE TxFrames ADDR2, SA + {"ATEBSSID", Set_ATE_BSSID_Proc }, // set ATE TxFrames ADDR3, BSSID + {"ATECHANNEL",Set_ATE_CHANNEL_Proc }, // set ATE Channel + {"ATETXPOW", Set_ATE_TX_POWER_Proc }, // set ATE TxPower + {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, // set ATE TxLength + {"ATETXCNT", Set_ATE_TX_COUNT_Proc }, // set ATE TxCount + {"ATETXRATE", Set_ATE_TX_RATE_Proc }, // set ATE TxRate +#endif //#ifdef RALINK_ATE + + {NULL,} +}; + +char * rtstrchr(const char * s, int c) +{ + for(; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; + } +/* +This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function +*/ +int rt_ioctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + struct iw_range *range = (struct iw_range *) extra; + u16 val; + int i,chan; + + DBGPRINT(RT_DEBUG_TRACE,"0. rtusb_ioctl_giwrange\n"); + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->txpower_capa = IW_TXPOW_DBM; + + if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) + { + range->min_pmp = 1 * 1024; + range->max_pmp = 65535 * 1024; + range->min_pmt = 1 * 1024; + range->max_pmt = 1000 * 1024; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | + IW_POWER_UNICAST_R | IW_POWER_ALL_R; + } + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 14; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; + + val = 0; + for (i = 0; i < 14; i++) { + chan = pAdapter->PortCfg.ChannelList[val]; + if (chan != 0) + { + range->freq[val].i = chan; + MAP_CHANNEL_ID_TO_KHZ(range->freq[val].i, range->freq[val].m); + range->freq[val].m*=100; + range->freq[val].e = 1; + val++; + } + } + + range->num_frequency = val; + range->num_channels = val; + + val = 0; + for (i = 0; i < pAdapter->PortCfg.SupportedRatesLen; i++) { + range->bitrate[i]=1000000*(pAdapter->PortCfg.SupportedRates[i] & 0x7f)/2; + val++; + if (val == IW_MAX_BITRATES) + break; + } + range->num_bitrates = val; + + range->max_qual.qual = 100; /* % sig quality*/ + + range->max_qual.level = 1; /* dB */ + range->max_qual.noise = 152; /* dB */ + range->max_qual.updated = 172; /* Updated all three */ + + /* What would be suitable values for "average/typical" qual? */ + range->avg_qual.qual = pAdapter->Mlme.ChannelQuality; + range->avg_qual.level = pAdapter->PortCfg.LastRssi; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + + range->sensitivity = -30; + + range->max_encoding_tokens = NR_WEP_KEYS; + range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + +#if 0 + over2 = 0; + len = prism2_get_datarates(dev, rates); + range->num_bitrates = 0; + for (i = 0; i < len; i++) { + if (range->num_bitrates < IW_MAX_BITRATES) { + range->bitrate[range->num_bitrates] = + rates[i] * 500000; + range->num_bitrates++; + } + if (rates[i] == 0x0b || rates[i] == 0x16) + over2 = 1; + } + /* estimated maximum TCP throughput values (bps) */ + range->throughput = over2 ? 5500000 : 1500000; +#endif + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + return 0; +} + +static int +rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, + void *w, char *extra) +{ + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + char *this_char; + char *value; + int Status; + + while ((this_char = strsep(&extra, ",")) != NULL) + { + if (!*this_char) + continue; + + if ((value = rtstrchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + continue; + + for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) + { + if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) + { + if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) + { //FALSE:Set private failed then return Invalid argument + Status = -EINVAL; + } + break; //Exit for loop. + } + } + + if(PRTMP_PRIVATE_SET_PROC->name == NULL) + { //Not found argument + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::(iwpriv) Not Support Set Command [%s=%s]\n", this_char, value); + break; + } + } + return 0; +} + +static const iw_handler rt_priv_handlers[] = { + (iw_handler) rt_ioctl_setparam, /* SIOCWFIRSTPRIV+0 */ +}; + +#ifdef SIOCGIWSCAN +int rt_ioctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + ULONG Now; + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + int Status = NDIS_STATUS_SUCCESS; + BOOLEAN StateMachineTouched = FALSE; + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) + return 0; + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_MLME_INITIALIZED)) + return 0; + do{ + Now = jiffies; + + if ((pAdapter->MediaState == NdisMediaStateConnected) && + ((pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && + (pAdapter->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) + ) + { + DBGPRINT(RT_DEBUG_TRACE, "!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n"); + Status = NDIS_STATUS_SUCCESS; + break; + } + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + // Reset Missed scan number + pAdapter->PortCfg.IgnoredScanNumber = 0; + pAdapter->PortCfg.LastScanTime = Now; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_BSSID_LIST_SCAN, + 0, + NULL); + + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + }while(0); + return 0; +} +int +rt_ioctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + int i=2, j; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + char *current_val; + struct iw_event iwe; + + for (i = 0; i < pAdapter->PortCfg.BssTab.BssNr; i++) + { + if (current_ev >= end_buf) + break; + + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &pAdapter->PortCfg.BssTab.BssEntry[i].Bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (pAdapter->PortCfg.BssTab.BssEntry[i].BssType == Ndis802_11IBSS) + { + iwe.u.mode = IW_MODE_ADHOC; + } + else if (pAdapter->PortCfg.BssTab.BssEntry[i].BssType == Ndis802_11Infrastructure) + { + iwe.u.mode = IW_MODE_INFRA; + } + else + { + iwe.u.mode = IW_MODE_AUTO; + } + + iwe.len = IW_EV_UINT_LEN; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = pAdapter->PortCfg.BssTab.BssEntry[i].SsidLen; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev,end_buf, &iwe, pAdapter->PortCfg.BssTab.BssEntry[i].Ssid); + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (CAP_IS_PRIVACY_ON (pAdapter->PortCfg.BssTab.BssEntry[i].CapabilityInfo )) + iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + current_ev = iwe_stream_add_point(current_ev, end_buf,&iwe, pAdapter->PortCfg.BssTab.BssEntry[i].Ssid); + + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + current_val = current_ev + IW_EV_LCP_LEN; + //for (j = 0; j < pAdapter->PortCfg.BssTab.BssEntry[i].RatesLen;j++) + for (j = 0; j < 1;j++) + { + iwe.u.bitrate.value = RateIdToMbps[pAdapter->PortCfg.BssTab.BssEntry[i].Rates[i]/2] * 1000000; + iwe.u.bitrate.disabled = 0; + current_val = iwe_stream_add_value(current_ev, + current_val, end_buf, &iwe, + IW_EV_PARAM_LEN); + } + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) + iwe.u.freq.m = pAdapter->PortCfg.BssTab.BssEntry[i].Channel; + else + iwe.u.freq.m = pAdapter->PortCfg.BssTab.BssEntry[i].Channel; + iwe.u.freq.e = 0; + iwe.u.freq.i = 0; + current_ev = iwe_stream_add_event(current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); + //================================ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + if (memcmp(&pAdapter->PortCfg.BssTab.BssEntry[i].Bssid, &pAdapter->PortCfg.Bssid, ETH_ALEN) == 0) + iwe.u.qual.qual = pAdapter->Mlme.ChannelQuality; + else + iwe.u.qual.qual = 0; + iwe.u.qual.level = pAdapter->PortCfg.BssTab.BssEntry[i].Rssi - RSSI_TO_DBM_OFFSET; // signal level (dBm) + iwe.u.qual.noise = pAdapter->PortCfg.BssTab.BssEntry[i].Noise; + //iwe.u.qual.noise = (pAdapter->PortCfg.LastR17Value > BBP_R17_DYNAMIC_UP_BOUND) ? BBP_R17_DYNAMIC_UP_BOUND : ((ULONG) pAdapter->PortCfg.LastR17Value); // // noise level (dBm) + + current_ev = iwe_stream_add_event(current_ev,end_buf, &iwe, IW_EV_QUAL_LEN); + + + //================================ + memset(&iwe, 0, sizeof(iwe)); + } + data->length = current_ev - extra; + DBGPRINT(RT_DEBUG_TRACE,"rtusb_ioctl_giwscan. %d BSS returned\n",pAdapter->PortCfg.BssTab.BssNr); + return 0; +} +#endif +static const iw_handler rt_handler[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) NULL, /* SIOCGIWNAME 1 */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) NULL, /* SIOCSIWFREQ */ + (iw_handler) NULL, /* SIOCGIWFREQ 5*/ + (iw_handler) NULL, /* SIOCSIWMODE */ + (iw_handler) NULL, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE 11 */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS f*/ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWAP */ + (iw_handler) NULL, /* SIOCGIWAP 0x15*/ + (iw_handler) NULL, /* -- hole -- 0x16 */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ +#ifdef SIOCGIWSCAN + (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN 0x18*/ + (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ +#else + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* SIOCGIWSCAN */ + (iw_handler) NULL, /* SIOCSIWESSID */ + (iw_handler) NULL, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN 1d*/ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE 20*/ + (iw_handler) NULL, /* SIOCGIWRATE */ + (iw_handler) NULL, /* SIOCSIWRTS */ + (iw_handler) NULL, /* SIOCGIWRTS */ + (iw_handler) NULL, /* SIOCSIWFRAG */ + (iw_handler) NULL, /* SIOCGIWFRAG 25*/ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY 29*/ + (iw_handler) NULL, /* SIOCSIWENCODE 2a*/ + (iw_handler) NULL, /* SIOCGIWENCODE 2b*/ + (iw_handler) NULL, /* SIOCSIWPOWER 2c*/ + (iw_handler) NULL, /* SIOCGIWPOWER 2d*/ +}; + +const struct iw_handler_def rt2500_iw_handler_def = +{ +#define N(a) (sizeof (a) / sizeof (a[0])) + .standard = (iw_handler *) rt_handler, + .num_standard = sizeof(rt_handler) / sizeof(iw_handler), + .private = (iw_handler *) rt_priv_handlers, + .num_private = N(rt_priv_handlers), + .private_args = (struct iw_priv_args *) privtab, + .num_private_args = N(privtab), +#if WIRELESS_EXT > 16 + .get_wireless_stats = RT2500_get_wireless_stats, +#endif +#if WIRELESS_EXT > 15 +// .spy_offset = offsetof(struct hostap_interface, spy_data), +#endif /* WIRELESS_EXT > 15 */ +}; +INT RTMPSetInformation( + IN PRTMP_ADAPTER pAdapter, + IN OUT struct ifreq *rq, + IN INT cmd) +{ + struct iwreq *wrq = (struct iwreq *) rq; + NDIS_802_11_SSID Ssid, *pSsid=NULL; + NDIS_802_11_MAC_ADDRESS Bssid; + RT_802_11_PHY_MODE PhyMode; + RT_802_11_STA_CONFIG StaConfig; + NDIS_802_11_RATES aryRates; + RT_802_11_PREAMBLE Preamble; + NDIS_802_11_WEP_STATUS WepStatus; + NDIS_802_11_AUTHENTICATION_MODE AuthMode; + NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; + NDIS_802_11_RTS_THRESHOLD RtsThresh; + NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; + NDIS_802_11_POWER_MODE PowerMode; + NDIS_802_11_TX_POWER_LEVEL TxPowerLevel; + PNDIS_802_11_KEY pKey = NULL; + PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; + NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; + ULONG Now; + ULONG KeyIdx; + INT Status = NDIS_STATUS_SUCCESS; + UCHAR CountryRegion; + BOOLEAN RadioState; + BOOLEAN StateMachineTouched = FALSE; + USHORT TxTotalCnt; + + switch(cmd & 0x7FFF) { + case RT_OID_802_11_COUNTRY_REGION: + if (wrq->u.data.length != sizeof(CountryRegion)) + Status = -EINVAL; + else + { + if(copy_from_user(&CountryRegion, wrq->u.data.pointer, wrq->u.data.length)) + Status = -EINVAL; + pAdapter->PortCfg.CountryRegion = CountryRegion; + BuildChannelList(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_COUNTRY_REGION (=%d) \n", pAdapter->PortCfg.CountryRegion); + } + break; + case OID_802_11_BSSID_LIST_SCAN: + Now = jiffies; + TxTotalCnt = pAdapter->DrsCounters.OneSecTxOkCount + + pAdapter->DrsCounters.OneSecTxRetryOkCount + + pAdapter->DrsCounters.OneSecTxFailCount; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", TxTotalCnt); + // For XP WZC, we will allow scan every 10 times, roughly 10 minutes. + // if ((Oid == OID_802_11_BSSID_LIST_SCAN) && + // (pAdapter->MediaState == NdisMediaStateConnected) && + // (pAdapter->PortCfg.IgnoredScanNumber < 10)) + if (TxTotalCnt > 100) + { + DBGPRINT(RT_DEBUG_TRACE, "!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n"); + Status = NDIS_STATUS_SUCCESS; + pAdapter->PortCfg.IgnoredScanNumber++; + break; + } + + if ((pAdapter->MediaState == NdisMediaStateConnected) && + ((pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPA) || + (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && + (pAdapter->PortCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) + ) + { + DBGPRINT(RT_DEBUG_TRACE, "!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n"); + Status = NDIS_STATUS_SUCCESS; + break; + } + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + // Reset Missed scan number + pAdapter->PortCfg.IgnoredScanNumber = 0; + pAdapter->PortCfg.LastScanTime = Now; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_BSSID_LIST_SCAN, + 0, + NULL); + + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + break; + case OID_802_11_SSID: + if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) + Status = -EINVAL; + else + { + if(copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + pSsid = &Ssid; + + if (pSsid->SsidLength > MAX_LEN_OF_SSID) + Status = -EINVAL; + else + { + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_SSID, + sizeof(NDIS_802_11_SSID), + (VOID *)pSsid + ); + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", pSsid->SsidLength, pSsid->Ssid); + } + } + break; + case OID_802_11_BSSID: + if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) + Status = -EINVAL; + else + { + if(copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_BSSID, + sizeof(NDIS_802_11_MAC_ADDRESS), + (VOID *)&Bssid); + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", + Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5]); + } + break; + case RT_OID_802_11_RADIO: + if (wrq->u.data.length != sizeof(BOOLEAN)) + Status = -EINVAL; + else + { + if(copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_RADIO (=%d)\n", RadioState); + if (pAdapter->PortCfg.bSwRadio != RadioState) + { + pAdapter->PortCfg.bSwRadio = RadioState; + if (pAdapter->PortCfg.bRadio != (pAdapter->PortCfg.bHwRadio && pAdapter->PortCfg.bSwRadio)) + { + pAdapter->PortCfg.bRadio = (pAdapter->PortCfg.bHwRadio && pAdapter->PortCfg.bSwRadio); + if (pAdapter->PortCfg.bRadio == TRUE) + MlmeRadioOn(pAdapter); + else + MlmeRadioOff(pAdapter); + } + } + } + break; + case RT_OID_802_11_PHY_MODE: + if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) + Status = -EINVAL; + else + { + if(copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + RTMPSetPhyMode(pAdapter, PhyMode); + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode); + } + break; + case RT_OID_802_11_STA_CONFIG: + if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) + Status = -EINVAL; + else + { + if(copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + pAdapter->PortCfg.EnableTxBurst = StaConfig.EnableTxBurst; + pAdapter->PortCfg.EnableTurboRate = StaConfig.EnableTurboRate; + pAdapter->PortCfg.UseBGProtection = StaConfig.UseBGProtection; +// pAdapter->PortCfg.UseShortSlotTime = StaConfig.UseShortSlotTime; + pAdapter->PortCfg.UseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable + if (pAdapter->PortCfg.AdhocMode != StaConfig.AdhocMode) + { + // allow dynamic change of "USE OFDM rate or not" in ADHOC mode + // if setting changed, need to reset current TX rate as well as BEACON frame format + pAdapter->PortCfg.AdhocMode = StaConfig.AdhocMode; + if (pAdapter->PortCfg.BssType == BSS_INDEP) + { + MlmeUpdateTxRates(pAdapter, FALSE); + MakeIbssBeacon(pAdapter); + } + } + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d,72/100=%d,Protection=%d,ShortSlot=%d,OFDM in 11g Adhoc=%d\n", + pAdapter->PortCfg.EnableTxBurst, + pAdapter->PortCfg.EnableTurboRate, + pAdapter->PortCfg.UseBGProtection, + pAdapter->PortCfg.UseShortSlotTime, + pAdapter->PortCfg.AdhocMode); + } + break; + case OID_802_11_DESIRED_RATES: + if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) + Status = -EINVAL; + else + { + if(copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + memset(pAdapter->PortCfg.DesiredRates, 0, MAX_LEN_OF_SUPPORTED_RATES); + memcpy(pAdapter->PortCfg.DesiredRates, &aryRates, sizeof(NDIS_802_11_RATES)); + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", + pAdapter->PortCfg.DesiredRates[0],pAdapter->PortCfg.DesiredRates[1], + pAdapter->PortCfg.DesiredRates[2],pAdapter->PortCfg.DesiredRates[3], + pAdapter->PortCfg.DesiredRates[4],pAdapter->PortCfg.DesiredRates[5], + pAdapter->PortCfg.DesiredRates[6],pAdapter->PortCfg.DesiredRates[7] ); + // Changing DesiredRate may affect the MAX TX rate we used to TX frames out + MlmeUpdateTxRates(pAdapter, FALSE); + } + break; + case RT_OID_802_11_PREAMBLE: + if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) + Status = -EINVAL; + else + { + if(copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (Preamble == Rt802_11PreambleShort) + { + pAdapter->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); + } + else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) + { + // if user wants AUTO, initialize to LONG here, then change according to AP's + // capability upon association. + pAdapter->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); + } + else + { + Status = EINVAL; + break; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_SET_PREAMBLE (=%d)\n", Preamble); + } + break; + case OID_802_11_WEP_STATUS: + if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) + Status = -EINVAL; + else + { + if(copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + // Since TKIP, AES, WEP are all supported. It should not have any invalid setting + if (WepStatus <= Ndis802_11Encryption3KeyAbsent) + { + if (pAdapter->PortCfg.WepStatus != WepStatus) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.WepStatus = WepStatus; + } + else + { + Status = -EINVAL; + break; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus); + } + break; + case OID_802_11_AUTHENTICATION_MODE: + if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) + Status = -EINVAL; + else + { + if(copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (AuthMode > Ndis802_11AuthModeMax) + { + Status = -EINVAL; + break; + } + else + { + if (pAdapter->PortCfg.AuthMode != AuthMode) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.AuthMode = AuthMode; + } + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->PortCfg.AuthMode); + } + break; + case OID_802_11_INFRASTRUCTURE_MODE: + if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) + Status = -EINVAL; + else + { + if(copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (BssType == Ndis802_11IBSS) + { + if (pAdapter->PortCfg.BssType != BSS_INDEP) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.BssType = BSS_INDEP; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_INFRASTRUCTURE_MODE (AD-HOC)\n"); + } + else if (BssType == Ndis802_11Infrastructure) + { + if (pAdapter->PortCfg.BssType != BSS_INFRA) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.BssType = BSS_INFRA; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_INFRASTRUCTURE_MODE (INFRA)\n"); + } + else + { + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n"); + } + } + // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key + pAdapter->PortCfg.WpaState = SS_NOTUSE; + break; + case RT_OID_802_11_RESET_COUNTERS: + memset(&pAdapter->WlanCounters, 0, sizeof(COUNTER_802_11)); + memset(&pAdapter->Counters, 0, sizeof(COUNTER_802_3)); + memset(&pAdapter->RalinkCounters, 0, sizeof(COUNTER_RALINK)); + memset(&pAdapter->Mlme.PrevWlanCounters, 0, sizeof(COUNTER_802_11)); + DBGPRINT(RT_DEBUG_INFO, "Set::RT_OID_802_11_RESET_COUNTERS \n"); + break; + case OID_802_11_RTS_THRESHOLD: + if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) + Status = -EINVAL; + else + { + if(copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (RtsThresh > MAX_RTS_THRESHOLD) + Status = -EINVAL; + else + pAdapter->PortCfg.RtsThreshold = (USHORT)RtsThresh; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_RTS_THRESHOLD (=%d)\n",RtsThresh); + break; + case OID_802_11_FRAGMENTATION_THRESHOLD: + if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) + Status = -EINVAL; + else + { + if(copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + pAdapter->PortCfg.bFragmentZeroDisable = FALSE; + if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) + { + if (FragThresh == 0) + { + pAdapter->PortCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; + pAdapter->PortCfg.bFragmentZeroDisable = TRUE; + } + else + Status = -EINVAL; + } + else + pAdapter->PortCfg.FragmentThreshold = (USHORT)FragThresh; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%d) \n",FragThresh); + break; + case OID_802_11_POWER_MODE: + if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) + Status = -EINVAL; + else + { + if(copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + // save user's policy here, but not change PortCfg.Psm immediately + if (PowerMode == Ndis802_11PowerModeCAM) + { + // clear PSM bit immediately + MlmeSetPsmBit(pAdapter, PWR_ACTIVE); + pAdapter->PortCfg.RecvDtim = TRUE; + if (pAdapter->PortCfg.WindowsACCAMEnable == FALSE) + pAdapter->PortCfg.WindowsPowerMode = PowerMode; + pAdapter->PortCfg.WindowsBatteryPowerMode = PowerMode; + } + else if (PowerMode == Ndis802_11PowerModeMAX_PSP) + { + // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() + // to exclude certain situations. + // MlmeSetPsmBit(pAdapter, PWR_SAVE); + if (pAdapter->PortCfg.WindowsACCAMEnable == FALSE) + pAdapter->PortCfg.WindowsPowerMode = PowerMode; + pAdapter->PortCfg.WindowsBatteryPowerMode = PowerMode; + pAdapter->PortCfg.RecvDtim = TRUE; // FALSE; + pAdapter->PortCfg.DefaultListenCount = 5; + } + else if (PowerMode == Ndis802_11PowerModeFast_PSP) + { + // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() + // to exclude certain situations. + // MlmeSetPsmBit(pAdapter, PWR_SAVE); + pAdapter->PortCfg.RecvDtim = TRUE; + if (pAdapter->PortCfg.WindowsACCAMEnable == FALSE) + pAdapter->PortCfg.WindowsPowerMode = PowerMode; + pAdapter->PortCfg.WindowsBatteryPowerMode = PowerMode; + pAdapter->PortCfg.DefaultListenCount = 3; + } + else + Status = -EINVAL; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode); + break; + case OID_802_11_TX_POWER_LEVEL: + if (wrq->u.data.length != sizeof(NDIS_802_11_TX_POWER_LEVEL)) + Status = -EINVAL; + else + { + if(copy_from_user(&TxPowerLevel, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (TxPowerLevel > MAX_TX_POWER_LEVEL) + Status = -EINVAL; + else + pAdapter->PortCfg.TxPower = (UCHAR)TxPowerLevel; + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_TX_POWER_LEVEL (=%d) \n",TxPowerLevel); + break; + // For WPA PSK PMK key + case RT_OID_802_11_ADD_WPA: + pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); + if(pKey == NULL) + { + Status = -ENOMEM; + break; + } + if(copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (pKey->Length != wrq->u.data.length) + { + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_ADD_WPA, Failed!!\n"); + } + else + { + if (pAdapter->PortCfg.AuthMode != Ndis802_11AuthModeWPAPSK) + { + Status = -EOPNOTSUPP; + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK]\n"); + } + else // Only for WPA PSK mode + { + pAdapter->PortCfg.PskKey.KeyLen = (UCHAR) pKey->KeyLength; + memcpy(pAdapter->PortCfg.PskKey.Key, &pKey->KeyMaterial, pKey->KeyLength); + // Use RaConfig as PSK agent. + // Start STA supplicant state machine + pAdapter->PortCfg.WpaState = SS_START; + + DBGPRINT(RT_DEBUG_TRACE, "Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength); + } + } + kfree(pKey); + break; + case OID_802_11_REMOVE_KEY: + pRemoveKey = kmalloc(wrq->u.data.length, GFP_KERNEL); + if(pRemoveKey == NULL) + { + Status = -ENOMEM; + break; + } + if(copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (pRemoveKey->Length != wrq->u.data.length) + { + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_REMOVE_KEY, Failed!!\n"); + } + else + { + if (pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA) + { + RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n"); + } + else + { + KeyIdx = pRemoveKey->KeyIndex; + + if (KeyIdx & 0x80000000) + { + // Should never set default bit when remove key + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n"); + } + else + { + KeyIdx = KeyIdx & 0x0fffffff; + if (KeyIdx > 3) + { + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx); + } + else + { + pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = 0; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length); + } + } + } + } + kfree(pRemoveKey); + break; + case OID_802_11_ADD_KEY: + pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); + if(pKey == NULL) + { + Status = -ENOMEM; + break; + } + if(copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + if (pKey->Length != wrq->u.data.length) + { + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_ADD_KEY, Failed!!\n"); + } + else + { + if (pAdapter->PortCfg.AuthMode >= Ndis802_11AuthModeWPA) + { + RTMPWPAAddKeyProc(pAdapter, pKey); + } + else // Old WEP stuff + { + KeyIdx = pKey->KeyIndex & 0x0fffffff; + + // it is a shared key + if (KeyIdx > 4) + Status = -EINVAL; + else + { + pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; + memcpy(pAdapter->PortCfg.SharedKey[KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); + if (pKey->KeyIndex & 0x80000000) + { + // Default key for tx (shared key) + pAdapter->PortCfg.DefaultKeyId = (UCHAR) KeyIdx; + } + } + } + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength); + } + kfree(pKey); + break; + case OID_802_11_CONFIGURATION: + if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) + Status = -EINVAL; + else + { + if(copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length)){ + Status = -EINVAL; + break; + } + pConfig = &Config; + pAdapter->PortCfg.IbssConfig.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; + pAdapter->PortCfg.IbssConfig.AtimWin = (USHORT) pConfig->ATIMWindow; + MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->PortCfg.IbssConfig.Channel); + DBGPRINT(RT_DEBUG_TRACE, "Set::OID_802_11_CONFIGURATION (BeacnPeriod=%d,AtimW=%d,Ch=%d)\n", + pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->PortCfg.IbssConfig.Channel); + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + break; + default: + DBGPRINT(RT_DEBUG_TRACE, "Set::unknown IOCTL's subcmd = 0x%08x\n", cmd); + Status = -EOPNOTSUPP; + break; + } + + return Status; +} + +INT RTMPQueryInformation( + IN PRTMP_ADAPTER pAdapter, + IN OUT struct ifreq *rq, + IN INT cmd) +{ + struct iwreq *wrq = (struct iwreq *) rq; + NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; + PNDIS_WLAN_BSSID_EX pBss; + NDIS_802_11_SSID Ssid; + NDIS_802_11_CONFIGURATION Configuration; + RT_802_11_LINK_STATUS LinkStatus; + RT_802_11_STA_CONFIG StaConfig; + NDIS_802_11_STATISTICS Statistics; + NDIS_802_11_RTS_THRESHOLD RtsThresh; + NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; + NDIS_802_11_POWER_MODE PowerMode; + NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; + RT_802_11_PREAMBLE PreamType; + NDIS_802_11_AUTHENTICATION_MODE AuthMode; + NDIS_802_11_WEP_STATUS WepStatus; + RT_VERSION_INFO DriverVersionInfo; + ULONG BssBufSize; + ULONG BssLen; + ULONG ulInfo = 0; + ULONG FcsValue; + PUCHAR pBuf = NULL; + PUCHAR pPtr; + INT Status = NDIS_STATUS_SUCCESS; + UCHAR Padding; + UINT i; + BOOLEAN RadioState; + + switch(cmd) { + case RT_OID_DEVICE_NAME: + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_DEVICE_NAME\n"); + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + { + // TODO: Any client apps that use this need to be reworked so they are okay when the module is loaded but the interface is down. Until then .... + // Interface is down, so pretend we don't exist. + Status = -EFAULT; + } + else + { + wrq->u.data.length = sizeof(NIC_DEVICE_NAME); + if(copy_to_user(wrq->u.data.pointer, NIC_DEVICE_NAME, wrq->u.data.length)) + Status = -EFAULT; + } + break; + case RT_OID_VERSION_INFO: + DBGPRINT(RT_DEBUG_INFO, "Query::RT_OID_VERSION_INFO \n"); + DriverVersionInfo.DriverVersionW = DRV_VERSION_MAJOR; + DriverVersionInfo.DriverVersionX = DRV_VERSION_MINOR; + DriverVersionInfo.DriverVersionY = DRV_VERSION_SUB; + DriverVersionInfo.DriverVersionZ = 0; + DriverVersionInfo.DriverBuildYear = DRV_BUILD_YEAR; + DriverVersionInfo.DriverBuildMonth = DRV_BUILD_MONTH; + DriverVersionInfo.DriverBuildDay = DRV_BUILD_DAY; + wrq->u.data.length = sizeof(RT_VERSION_INFO); + if(copy_to_user(wrq->u.data.pointer, &DriverVersionInfo, wrq->u.data.length)) + Status = -EFAULT; + break; + case OID_802_11_BSSID_LIST: + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->PortCfg.BssTab.BssNr); + // Claculate total buffer size required + BssBufSize = sizeof(ULONG); + + for (i = 0; i < pAdapter->PortCfg.BssTab.BssNr; i++) + { + // Align pointer to 4 bytes boundary. + Padding = 4 - (pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen & 0x0003); + if (Padding == 4) + Padding = 0; + BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 4 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen + Padding); + } + + // For safety issue, we add 256 bytes just in case + BssBufSize += 256; + // Allocate the same size as passed from higher layer + pBuf = kmalloc(BssBufSize, GFP_KERNEL); + if(pBuf == NULL) + { + Status = -ENOMEM; + break; + } + // Init 802_11_BSSID_LIST_EX structure + memset(pBuf, 0, BssBufSize); + pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; + pBssidList->NumberOfItems = pAdapter->PortCfg.BssTab.BssNr; + + // Calculate total buffer length + BssLen = 4; // Consist of NumberOfItems + // Point to start of NDIS_WLAN_BSSID_EX + // pPtr = pBuf + sizeof(ULONG); + pPtr = (PUCHAR) &pBssidList->Bssid[0]; + for (i = 0; i < pAdapter->PortCfg.BssTab.BssNr; i++) + { + pBss = (PNDIS_WLAN_BSSID_EX) pPtr; + memcpy(&pBss->MacAddress, &pAdapter->PortCfg.BssTab.BssEntry[i].Bssid, ETH_ALEN); + if ((pAdapter->PortCfg.BssTab.BssEntry[i].Hidden == 1) && (pAdapter->PortCfg.bShowHiddenSSID == FALSE)) + { + pBss->Ssid.SsidLength = 0; + } + else + { + pBss->Ssid.SsidLength = pAdapter->PortCfg.BssTab.BssEntry[i].SsidLen; + memcpy(pBss->Ssid.Ssid, pAdapter->PortCfg.BssTab.BssEntry[i].Ssid, pAdapter->PortCfg.BssTab.BssEntry[i].SsidLen); + } + pBss->Privacy = pAdapter->PortCfg.BssTab.BssEntry[i].Privacy; + pBss->Rssi = pAdapter->PortCfg.BssTab.BssEntry[i].Rssi - pAdapter->PortCfg.RssiToDbm; + pBss->NetworkTypeInUse = Ndis802_11DS; + pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); + pBss->Configuration.BeaconPeriod = pAdapter->PortCfg.BssTab.BssEntry[i].BeaconPeriod; + pBss->Configuration.ATIMWindow = pAdapter->PortCfg.BssTab.BssEntry[i].AtimWin; + + MAP_CHANNEL_ID_TO_KHZ(pAdapter->PortCfg.BssTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); + + if (pAdapter->PortCfg.BssTab.BssEntry[i].BssType == BSS_INFRA) + pBss->InfrastructureMode = Ndis802_11Infrastructure; + else + pBss->InfrastructureMode = Ndis802_11IBSS; + + memcpy(pBss->SupportedRates, pAdapter->PortCfg.BssTab.BssEntry[i].Rates, pAdapter->PortCfg.BssTab.BssEntry[i].RatesLen); + + DBGPRINT(RT_DEBUG_TRACE, "BSS#%d - %s, Ch %d = %d Khz\n", + i,pBss->Ssid.Ssid,pAdapter->PortCfg.BssTab.BssEntry[i].Channel,pBss->Configuration.DSConfig); + + if (pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen == 0) + { + pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); + memcpy(pBss->IEs, &pAdapter->PortCfg.BssTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); + pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 4 + sizeof(NDIS_802_11_FIXED_IEs); + } + else + { + pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen; + pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 4 + sizeof(NDIS_802_11_FIXED_IEs); + memcpy(pBss->IEs, &pAdapter->PortCfg.BssTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); + memcpy(pPtr, pAdapter->PortCfg.BssTab.BssEntry[i].VarIEs, pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen); + pPtr += pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen; + } + // Align pointer to 4 bytes boundary. + Padding = 4 - (pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen & 0x0003); + if (Padding == 4) + Padding = 0; + pPtr += Padding; + pBss->Length = sizeof(NDIS_WLAN_BSSID_EX) - 4 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->PortCfg.BssTab.BssEntry[i].VarIELen + Padding; + BssLen += pBss->Length; + } + wrq->u.data.length = BssLen; + if(copy_to_user(wrq->u.data.pointer, pBssidList, wrq->u.data.length)) + Status = -EFAULT; + kfree(pBssidList); + break; + case OID_802_3_CURRENT_ADDRESS: + wrq->u.data.length = ETH_ALEN; + if(copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length)){ + Status = -EFAULT; + break; + } + DBGPRINT(RT_DEBUG_INFO, "Query::OID_802_3_CURRENT_ADDRESS \n"); + break; + case OID_GEN_MEDIA_CONNECT_STATUS: + DBGPRINT(RT_DEBUG_INFO, "Query::OID_GEN_MEDIA_CONNECT_STATUS \n"); + wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); + if(copy_to_user(wrq->u.data.pointer, &pAdapter->MediaState, wrq->u.data.length)) + Status = -EFAULT; + break; + case OID_802_11_BSSID: + if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) + { + if(copy_to_user(wrq->u.data.pointer, &pAdapter->PortCfg.Bssid, sizeof(MACADDR))) + Status = -EFAULT; + + DBGPRINT(RT_DEBUG_INFO, "IOCTL::SIOCGIWAP(=%02x:%02x:%02x:%02x:%02x:%02x)\n", + pAdapter->PortCfg.Bssid.Octet[0],pAdapter->PortCfg.Bssid.Octet[1],pAdapter->PortCfg.Bssid.Octet[2], + pAdapter->PortCfg.Bssid.Octet[3],pAdapter->PortCfg.Bssid.Octet[4],pAdapter->PortCfg.Bssid.Octet[5]); + + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_BSSID(=EMPTY)\n"); + Status = -ENOTCONN; + } + break; + case OID_802_11_SSID: + Ssid.SsidLength = pAdapter->PortCfg.SsidLen; + memset(Ssid.Ssid, 0, MAX_LEN_OF_SSID); + memcpy(Ssid.Ssid, pAdapter->PortCfg.Ssid, Ssid.SsidLength); + wrq->u.data.length = sizeof(NDIS_802_11_SSID); + if(copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid); + break; + case RT_OID_802_11_LINK_STATUS: + LinkStatus.CurrTxRate = RateIdTo500Kbps[pAdapter->PortCfg.TxRate]; // unit : 500 kbps + LinkStatus.ChannelQuality = pAdapter->Mlme.ChannelQuality; + LinkStatus.RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; + LinkStatus.TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; + wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); + if(copy_to_user(wrq->u.data.pointer, &LinkStatus, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_LINK_STATUS\n"); + break; + case OID_802_11_CONFIGURATION: + Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); + Configuration.BeaconPeriod = pAdapter->PortCfg.BeaconPeriod; + Configuration.ATIMWindow = pAdapter->PortCfg.AtimWin; + MAP_CHANNEL_ID_TO_KHZ(pAdapter->PortCfg.Channel, Configuration.DSConfig); + wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); + if(copy_to_user(wrq->u.data.pointer, &Configuration, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_CONFIGURATION(BeaconPeriod=%d,AtimW=%d,Channel=%d) \n", + Configuration.BeaconPeriod, Configuration.ATIMWindow, pAdapter->PortCfg.Channel); + break; + case OID_802_11_RSSI: + ulInfo = pAdapter->PortCfg.LastRssi - pAdapter->PortCfg.RssiToDbm; + wrq->u.data.length = sizeof(ulInfo); + if(copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_RSSI(=%d)\n", ulInfo); + break; + case OID_802_11_STATISTICS: + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_STATISTICS \n"); + // Update FCS counters + RTMP_IO_READ32(pAdapter, CNT0, &FcsValue); + pAdapter->WlanCounters.FCSErrorCount.QuadPart += ((FcsValue & 0x0000ffff) >> 7); + // Add FCS error count to private counters + pAdapter->RalinkCounters.RealFcsErrCount.QuadPart += FcsValue; + + // Sanity check for calculation of sucessful count + if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) + pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; + + Statistics.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; + Statistics.MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; + Statistics.FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; + Statistics.RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; + Statistics.MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; + Statistics.RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; + Statistics.RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; + Statistics.ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; + Statistics.FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; + Statistics.ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; + Statistics.MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; +#ifdef RT2500_DBG + Statistics.FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; +#else + Statistics.FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; + Statistics.FrameDuplicateCount.vv.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.vv.LowPart / 100; +#endif + wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); + if(copy_to_user(wrq->u.data.pointer, &Statistics, wrq->u.data.length)) + Status = -EFAULT; + break; + case OID_GEN_RCV_OK: + DBGPRINT(RT_DEBUG_INFO, "Query::OID_GEN_RCV_OK \n"); + ulInfo = pAdapter->Counters.GoodReceives; + wrq->u.data.length = sizeof(ulInfo); + if(copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) + Status = -EFAULT; + break; + case OID_GEN_RCV_NO_BUFFER: + DBGPRINT(RT_DEBUG_INFO, "Query::OID_GEN_RCV_NO_BUFFER \n"); + ulInfo = pAdapter->Counters.RxNoBuffer; + wrq->u.data.length = sizeof(ulInfo); + if(copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) + Status = -EFAULT; + break; + case RT_OID_802_11_PHY_MODE: + ulInfo = (ULONG)pAdapter->PortCfg.PhyMode; + wrq->u.data.length = sizeof(ulInfo); + if(copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_PHY_MODE (=%d)\n", ulInfo); + break; + case RT_OID_802_11_STA_CONFIG: + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_QUERY_STA_CONFIG\n"); + StaConfig.EnableTxBurst = pAdapter->PortCfg.EnableTxBurst; + StaConfig.EnableTurboRate = pAdapter->PortCfg.EnableTurboRate; + StaConfig.UseBGProtection = pAdapter->PortCfg.UseBGProtection; + StaConfig.UseShortSlotTime = pAdapter->PortCfg.UseShortSlotTime; + StaConfig.AdhocMode = pAdapter->PortCfg.AdhocMode; + StaConfig.HwRadioStatus = (pAdapter->PortCfg.bHwRadio == TRUE) ? 1 : 0; + StaConfig.Rsv1 = 0; + StaConfig.SystemErrorBitmap = pAdapter->PortCfg.SystemErrorBitmap; + wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); + if(copy_to_user(wrq->u.data.pointer, &StaConfig, wrq->u.data.length)) + Status = -EFAULT; + break; + case OID_802_11_RTS_THRESHOLD: + RtsThresh = pAdapter->PortCfg.RtsThreshold; + wrq->u.data.length = sizeof(RtsThresh); + if(copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_RTS_THRESHOLD(=%d)\n", RtsThresh); + break; + case OID_802_11_FRAGMENTATION_THRESHOLD: + FragThresh = pAdapter->PortCfg.FragmentThreshold; + if (pAdapter->PortCfg.bFragmentZeroDisable == TRUE) + FragThresh = 0; + wrq->u.data.length = sizeof(FragThresh); + if(copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%d)\n", FragThresh); + break; + case OID_802_11_POWER_MODE: + PowerMode = pAdapter->PortCfg.WindowsPowerMode; + wrq->u.data.length = sizeof(PowerMode); + if(copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode); + break; + case RT_OID_802_11_RADIO: + RadioState = (BOOLEAN) pAdapter->PortCfg.bSwRadio; + wrq->u.data.length = sizeof(RadioState); + if(copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState); + break; + case OID_802_11_INFRASTRUCTURE_MODE: + if (ADHOC_ON(pAdapter)) + BssType = Ndis802_11IBSS; + else if (INFRA_ON(pAdapter)) + BssType = Ndis802_11Infrastructure; + else + BssType = Ndis802_11AutoUnknown; + + wrq->u.data.length = sizeof(BssType); + if(copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType); + break; + case RT_OID_802_11_PREAMBLE: + PreamType = pAdapter->PortCfg.WindowsTxPreamble; + wrq->u.data.length = sizeof(PreamType); + if(copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_QUERY_PREAMBLE(=%d)\n", PreamType); + break; + case OID_802_11_AUTHENTICATION_MODE: + AuthMode = pAdapter->PortCfg.AuthMode; + wrq->u.data.length = sizeof(AuthMode); + if(copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode); + break; + case OID_802_11_WEP_STATUS: + WepStatus = pAdapter->PortCfg.WepStatus; + wrq->u.data.length = sizeof(WepStatus); + if(copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus); + break; + + case RT_OID_802_11_QUERY_EEPROM_VERSION: + wrq->u.data.length = sizeof(ULONG); + if(copy_to_user(wrq->u.data.pointer, &pAdapter->PortCfg.EepromVersion, wrq->u.data.length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "Query::RT_OID_802_11_QUERY_EEPROM_VERSION (=%d)\n", pAdapter->PortCfg.EepromVersion); + break; + + default: + DBGPRINT(RT_DEBUG_TRACE, "Query::unknown IOCTL's subcmd = 0x%08x\n", cmd); + Status = -EOPNOTSUPP; + break; + } + + return Status; +} + +INT RT2500_ioctl( + IN struct net_device *net_dev, + IN OUT struct ifreq *rq, + IN INT cmd) +{ + PRTMP_ADAPTER pAdapter= net_dev->priv; + struct iwreq *wrq = (struct iwreq *) rq; + struct iw_point *erq = NULL; + struct iw_freq *frq = NULL; + NDIS_802_11_SSID Ssid, *pSsid=NULL; + NDIS_802_11_NETWORK_INFRASTRUCTURE BssType = Ndis802_11Infrastructure; + NDIS_802_11_RTS_THRESHOLD RtsThresh; + NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; + NDIS_802_11_MAC_ADDRESS Bssid; + INT Status = NDIS_STATUS_SUCCESS; + USHORT subcmd; + BOOLEAN StateMachineTouched = FALSE; + int i, chan = -1, index = 0, len = 0; + + + switch(cmd) { + case SIOCGIWNAME: + DBGPRINT(RT_DEBUG_TRACE, "IOCTL::SIOCGIWNAME\n"); + strcpy(wrq->u.name, "RT2500 Wireless"); //Less then 16 bytes. + break; + case SIOCSIWESSID: //Set ESSID + erq = &wrq->u.essid; + memset(&Ssid, 0x00, sizeof(NDIS_802_11_SSID)); + if (erq->flags) + { + if (erq->length > IW_ESSID_MAX_SIZE) + { + Status = -E2BIG; + break; + } + + if(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + { + if (copy_from_user(Ssid.Ssid, erq->pointer, (erq->length - 1))) + { + Status = -EFAULT; + break; + } + Ssid.SsidLength = erq->length - 1; //minus null character. + }else{ + // This SEEMS to be needed to actual work RobinC when iface + // is down + if (copy_from_user(pAdapter->PortCfg.Ssid, erq->pointer, (erq->length - 1))) + { + Status = -EFAULT; + break; + } + pAdapter->PortCfg.SsidLen = erq->length - 1; //minus null character. + + memcpy(pAdapter->Mlme.CntlAux.Ssid, pAdapter->PortCfg.Ssid, pAdapter->PortCfg.SsidLen); + pAdapter->Mlme.CntlAux.SsidLen = pAdapter->PortCfg.SsidLen; + } + } + else + Ssid.SsidLength = 0; // ANY ssid + + pSsid = &Ssid; + + // if network is down then me MUST not proceed into actualy + // running mlme stuff + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + break; + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_SSID, + sizeof(NDIS_802_11_SSID), + (VOID *)pSsid + ); + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWESSID[cmd=0x%x] (Len=%d,Ssid=%s)\n", SIOCSIWESSID, pSsid->SsidLength, pSsid->Ssid); + break; + case SIOCGIWESSID: //Get ESSID + erq = &wrq->u.essid; + + erq->flags=1; + erq->length = pAdapter->PortCfg.SsidLen; + if(copy_to_user(erq->pointer, pAdapter->PortCfg.Ssid, erq->length)) + Status = -EFAULT; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCGIWESSID (Len=%d, ssid=%s...)\n", erq->length, pAdapter->PortCfg.Ssid); + break; + case SIOCGIWNWID: // get network id + Status = -EOPNOTSUPP; + break; + case SIOCSIWNWID: // set network id (the cell) + Status = -EOPNOTSUPP; + break; + case SIOCSIWFREQ: // set channel/frequency (Hz) + frq = &wrq->u.freq; + if((frq->e == 0) && (frq->m <= 1000)) + chan = frq->m; // Setting by channel number + else + MAP_KHZ_TO_CHANNEL_ID( (frq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, + pAdapter->PortCfg.IbssConfig.Channel = chan; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->PortCfg.IbssConfig.Channel); + if(RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE) && (pAdapter->PortCfg.BssType == BSS_MONITOR || pAdapter->PortCfg.BssType == BSS_INDEP)) + { + pAdapter->PortCfg.Channel = chan; + AsicSwitchChannel(pAdapter, pAdapter->PortCfg.Channel); + AsicLockChannel(pAdapter, pAdapter->PortCfg.Channel); + } + break; + case SIOCGIWFREQ: // get channel/frequency (Hz) + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCGIWFREQ\n"); + if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)){ + MAP_CHANNEL_ID_TO_KHZ(pAdapter->PortCfg.Channel, wrq->u.freq.m); + }else{ + MAP_CHANNEL_ID_TO_KHZ(pAdapter->PortCfg.IbssConfig.Channel, wrq->u.freq.m); + } + // MW: Alter the multiplier so iwconfig reports GhZ + wrq->u.freq.e = 3; + wrq->u.freq.i = 0; + break; + case SIOCGIWNICKN: //get node name/nickname + erq = &wrq->u.data; + erq->length = strlen(pAdapter->nickn); + if(copy_to_user(erq->pointer, pAdapter->nickn, erq->length)) + Status = -EFAULT; + break; + case SIOCSIWNICKN: //set node name/nickname + erq = &wrq->u.data; + if (erq->flags) + { + if (erq->length <= IW_ESSID_MAX_SIZE){ + if(copy_from_user(pAdapter->nickn, erq->pointer, erq->length)){ + Status = -EINVAL; + break; + } + }else + Status = -E2BIG; + } + break; + case SIOCGIWRATE: //get default bit rate (bps) + wrq->u.bitrate.value = RateIdToMbps[pAdapter->PortCfg.TxRate] * 1000000; + wrq->u.bitrate.disabled = 0; + break; + case SIOCSIWRATE: //set default bit rate (bps) + RTMPSetDesiredRates(pAdapter, wrq->u.bitrate.value); + break; + case SIOCGIWRTS: // get RTS/CTS threshold (bytes) + wrq->u.rts.value = (INT) pAdapter->PortCfg.RtsThreshold; + wrq->u.rts.disabled = (wrq->u.rts.value == MAX_RTS_THRESHOLD); + wrq->u.rts.fixed = 1; + break; + case SIOCSIWRTS: //set RTS/CTS threshold (bytes) + RtsThresh = wrq->u.rts.value; + if (wrq->u.rts.disabled) + RtsThresh = MAX_RTS_THRESHOLD; + + if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) + pAdapter->PortCfg.RtsThreshold = (USHORT)RtsThresh; + else if (RtsThresh == 0) + pAdapter->PortCfg.RtsThreshold = MAX_RTS_THRESHOLD; + + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWRTS (=%d)\n", pAdapter->PortCfg.RtsThreshold); + break; + case SIOCGIWFRAG: //get fragmentation thr (bytes) + wrq->u.frag.value = (INT) pAdapter->PortCfg.FragmentThreshold; + wrq->u.frag.disabled = (wrq->u.frag.value >= MAX_FRAG_THRESHOLD); + wrq->u.frag.fixed = 1; + break; + case SIOCSIWFRAG: //set fragmentation thr (bytes) + FragThresh = wrq->u.frag.value; + if (wrq->u.rts.disabled) + FragThresh = MAX_FRAG_THRESHOLD; + + if ( (FragThresh >= MIN_FRAG_THRESHOLD) && (FragThresh <= MAX_FRAG_THRESHOLD)) + pAdapter->PortCfg.FragmentThreshold = (USHORT)FragThresh; + else if (FragThresh == 0) + pAdapter->PortCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; + + if (pAdapter->PortCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) + pAdapter->PortCfg.bFragmentZeroDisable = TRUE; + else + pAdapter->PortCfg.bFragmentZeroDisable = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWFRAG (=%d)\n", pAdapter->PortCfg.FragmentThreshold); + break; + case SIOCGIWENCODE: //get encoding token & mode + index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; + if ((index < 0) || (index >= NR_WEP_KEYS)) + index = pAdapter->PortCfg.DefaultKeyId; // Default key for tx (shared key) + + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeOpen) + wrq->u.encoding.flags = IW_ENCODE_OPEN; + else if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeShared) + wrq->u.encoding.flags = IW_ENCODE_RESTRICTED; + + if (pAdapter->PortCfg.WepStatus == Ndis802_11WEPDisabled) + wrq->u.encoding.flags |= IW_ENCODE_DISABLED; + else + { + if(wrq->u.encoding.pointer) + { + wrq->u.encoding.length = pAdapter->PortCfg.SharedKey[index].KeyLen; + if(copy_to_user(wrq->u.encoding.pointer, + pAdapter->PortCfg.SharedKey[index].Key, + pAdapter->PortCfg.SharedKey[index].KeyLen)) + Status = -EFAULT; + wrq->u.encoding.flags |= (index + 1); + } + } + break; + case SIOCSIWENCODE: //set encoding token & mode + index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; + /* take the old default key if index is invalid */ + if((index < 0) || (index >= NR_WEP_KEYS)) + index = pAdapter->PortCfg.DefaultKeyId; // Default key for tx (shared key) + + if(wrq->u.encoding.pointer) + { + len = wrq->u.encoding.length; + if(len > WEP_LARGE_KEY_LEN) + len = WEP_LARGE_KEY_LEN; + + memset(pAdapter->PortCfg.SharedKey[index].Key, 0x00, MAX_LEN_OF_KEY); + if(copy_from_user(pAdapter->PortCfg.SharedKey[index].Key, + wrq->u.encoding.pointer, len)){ + Status = -EINVAL; + break; + } + pAdapter->PortCfg.SharedKey[index].KeyLen = len <= WEP_SMALL_KEY_LEN ? WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; + } + pAdapter->PortCfg.DefaultKeyId = (UCHAR) index; + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) + pAdapter->PortCfg.WepStatus = Ndis802_11WEPDisabled; + else + pAdapter->PortCfg.WepStatus = Ndis802_11WEPEnabled; + + if (wrq->u.encoding.flags & IW_ENCODE_RESTRICTED) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeShared; + if (wrq->u.encoding.flags & IW_ENCODE_OPEN) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeOpen; + + if(pAdapter->PortCfg.WepStatus == Ndis802_11WEPDisabled) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeOpen; + +//#ifdef RT2500_DBG + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWENCODE Key[%x] => \n", index); + for (i = 0; i < len; i++) + { + DBGPRINT(RT_DEBUG_TRACE, "%02x:", pAdapter->PortCfg.SharedKey[index].Key[i]); + if (i%16 == 15) + DBGPRINT(RT_DEBUG_TRACE, "\n"); + } + DBGPRINT(RT_DEBUG_TRACE, "\n"); +//#endif + break; + case SIOCGIWAP: //get access point MAC addresses + if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) + { + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrq->u.ap_addr.sa_data, &pAdapter->PortCfg.Bssid, ETH_ALEN); + + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCGIWAP(=%02x:%02x:%02x:%02x:%02x:%02x)\n", + pAdapter->PortCfg.Bssid.Octet[0], pAdapter->PortCfg.Bssid.Octet[1], pAdapter->PortCfg.Bssid.Octet[2], + pAdapter->PortCfg.Bssid.Octet[3], pAdapter->PortCfg.Bssid.Octet[4], pAdapter->PortCfg.Bssid.Octet[5]); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCGIWAP(=EMPTY)\n"); + Status = -ENOTCONN; + } + break; + case SIOCSIWAP: //set access point MAC addresses + memcpy(&Bssid, &wrq->u.ap_addr.sa_data, sizeof(NDIS_802_11_MAC_ADDRESS)); + + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + break; + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_BSSID, + sizeof(NDIS_802_11_MAC_ADDRESS), + (VOID *)&Bssid); + Status = NDIS_STATUS_SUCCESS; + StateMachineTouched = TRUE; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", + Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5]); + break; + case SIOCGIWMODE: //get operation mode + if (pAdapter->PortCfg.BssType == BSS_INDEP) + { + BssType = Ndis802_11IBSS; + wrq->u.mode = IW_MODE_ADHOC; + } + else if (pAdapter->PortCfg.BssType == BSS_INFRA) + { + BssType = Ndis802_11Infrastructure; + wrq->u.mode = IW_MODE_INFRA; + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + else if (pAdapter->PortCfg.BssType == BSS_MONITOR) + { + BssType = Ndis802_11Monitor; + wrq->u.mode = IW_MODE_MONITOR; + } +#endif + else + { + BssType = Ndis802_11AutoUnknown; + wrq->u.mode = IW_MODE_AUTO; + } + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCGIWMODE(=%d)\n", BssType); + break; + case SIOCSIWMODE: //set operation mode + if(wrq->u.mode == IW_MODE_ADHOC) + { + if (pAdapter->PortCfg.BssType != BSS_INDEP) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.BssType = BSS_INDEP; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWMODE (AD-HOC)\n"); + } + else if (wrq->u.mode == IW_MODE_INFRA) + { + if (pAdapter->PortCfg.BssType != BSS_INFRA) + { + // Config has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.BssType = BSS_INFRA; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWMODE (INFRA)\n"); + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + else if (wrq->u.mode == IW_MODE_MONITOR) + { + if (pAdapter->PortCfg.BssType != BSS_MONITOR) + { + // COnfig has changed + pAdapter->bConfigChanged = TRUE; + } + pAdapter->PortCfg.BssType = BSS_MONITOR; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWMODE (MONITOR)\n"); + } +#endif + else + { + Status = -ENOSYS; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::SIOCSIWMODE (unknown)\n"); + } + + if (pAdapter->bConfigChanged == TRUE) + { + if (pAdapter->PortCfg.BssType == BSS_MONITOR) + { + if (pAdapter->PortCfg.MallowRFMONTx == TRUE) + pAdapter->net_dev->type = 801; // ARPHRD_IEEE80211 + else + pAdapter->net_dev->type = 802; // ARPHRD_IEEE80211_PRISM + + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x46); + } + else if (pAdapter->bAcceptPromiscuous == TRUE) + { + pAdapter->net_dev->type = 1; + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x6e); + } + else + { + pAdapter->net_dev->type = 1; + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x7e); + } + } + // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key + pAdapter->PortCfg.WpaState = SS_NOTUSE; + break; + case SIOCGIWSENS: //get sensitivity (dBm) + case SIOCSIWSENS: //set sensitivity (dBm) + case SIOCGIWPOWER: //get Power Management settings + case SIOCSIWPOWER: //set Power Management settings + Status = -EOPNOTSUPP; + break; + case SIOCGIWTXPOW: //get transmit power (dBm) +#if WIRELESS_EXT >= 17 + // Krellan: Get TxPower in dBm now, not percentage + { + ULONG R3; + UCHAR Channel = pAdapter->PortCfg.Channel; + + // Krellan: This code comes from AsicSwitchChannel(), + // as we must know the channel we are currently on, + // in order to get the correct EEPROM-recommended + // value to establish as 0 dBm. + if (Channel <= 14) + R3 = pAdapter->PortCfg.ChannelTxPower[Channel - 1]; + else + R3 = pAdapter->PortCfg.ChannelTxPower[0]; + + if (R3 > 31) R3 = 31; + + wrq->u.txpower.value = pAdapter->PortCfg.TxPowerDriver - R3; + wrq->u.txpower.flags = IW_TXPOW_DBM; + wrq->u.txpower.fixed = !(pAdapter->PortCfg.TxPowerAuto); + wrq->u.txpower.disabled = FALSE; + } + break; +#endif + case SIOCSIWTXPOW: //set transmit power (dBm) +#if WIRELESS_EXT >= 17 + // Krellan: Set TxPower in dBm now, not percentage + { + int Value; + + if (wrq->u.txpower.disabled) + { + // Krellan: I don't know how to turn off the radio entirely + Status = -EOPNOTSUPP; + printk(KERN_ERR DRV_NAME " SIOCSIWTXPOW: Setting txpower off is not supported\n"); + } + else + { + if (wrq->u.txpower.fixed) + { + if (wrq->u.txpower.flags != IW_TXPOW_DBM) + { + Status = -EINVAL; + printk(KERN_ERR DRV_NAME " SIOCSIWTXPOW: Value not in IW_TXPOW_DBM units\n"); + } + else + { + Value = wrq->u.txpower.value; + + if (Value < MIN_TXPOWER_DBM || Value > MAX_TXPOWER_DBM) + { + Status = -EINVAL; + printk(KERN_ERR DRV_NAME " SIOCSIWTXPOW: Value out of range [%d,%d]\n", + MIN_TXPOWER_DBM, MAX_TXPOWER_DBM); + } + else + { + pAdapter->PortCfg.TxPowerUser = Value; + pAdapter->PortCfg.TxPowerAuto = FALSE; + } + } + } + else + { + pAdapter->PortCfg.TxPowerAuto = TRUE; + } + } + } + break; +#endif + case SIOCGIWRETRY: //get retry limits and lifetime + case SIOCSIWRETRY: //set retry limits and lifetime + case 0x00008946: // ethtool specific IOCTL (FIXME!, minimal support should not be difficult) + case 0x00008947: // mrtg related IOCTL (ignored for now) + Status = -EOPNOTSUPP; + break; + case RT_PRIV_IOCTL: + subcmd = wrq->u.data.flags; + if( subcmd & OID_GET_SET_TOGGLE) + Status = RTMPSetInformation(pAdapter, rq, subcmd); + else + Status = RTMPQueryInformation(pAdapter, rq, subcmd); + break; + case SIOCGIWPRIV: + if (wrq->u.data.pointer) { + if ( !access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) ) + break; + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + Status = -EFAULT; + } + break; + + case RTPRIV_IOCTL_SET: + { + char *this_char; + char *value; + + if( !access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) ) + break; + + while ((this_char = strsep((char**)&wrq->u.data.pointer, ",")) != NULL) + { + if (!*this_char) + continue; + + if ((value = rtstrchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + continue; + + for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) + { + if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) + { + if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) + { //FALSE:Set private failed then return Invalid argument + Status = -EINVAL; + } + break; //Exit for loop. + } + } + + if(PRTMP_PRIVATE_SET_PROC->name == NULL) + { //Not found argument + Status = -EINVAL; + DBGPRINT(RT_DEBUG_TRACE, "ioctl::(iwpriv) Not Support Set Command [%s=%s]\n", this_char, value); + break; + } + } + } + break; + + case RTPRIV_IOCTL_BBP: + RTMPIoctlBBP(pAdapter, wrq); + break; + + case RTPRIV_IOCTL_MAC: + RTMPIoctlMAC(pAdapter, wrq); + break; + +#ifdef RALINK_ATE + case RTPRIV_IOCTL_E2P: + RTMPIoctlE2PROM(pAdapter, wrq); + break; +#endif + + case RTPRIV_IOCTL_RFMONTX: + Status = RTMPIoctlRFMONTX(pAdapter, wrq); + break; + + default: + DBGPRINT(RT_DEBUG_TRACE, "IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd); + Status = -EOPNOTSUPP; + break; + } + + if(StateMachineTouched) // Upper layer sent a MLME-related operations + MlmeHandler(pAdapter); + + return Status; +} + + +UCHAR BCAST[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +/* + ======================================================================== + + Routine Description: + Add WPA key process + + Arguments: + pAdapter Pointer to our adapter + pBuf Pointer to the where the key stored + + Return Value: + NDIS_SUCCESS Add key successfully + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPWPAAddKeyProc( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf) +{ + PNDIS_802_11_KEY pKey; + ULONG KeyIdx; + NDIS_STATUS Status; + PUCHAR pTxMic, pRxMic; + BOOLEAN bTxKey; // Set the key as transmit key + BOOLEAN bPairwise; // Indicate the key is pairwise key + BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. + // Otherwise, it will set by the NIC. + BOOLEAN bAuthenticator; // indicate key is set by authenticator. + INT i, PairwiseIdx; + + pKey = (PNDIS_802_11_KEY) pBuf; + KeyIdx = pKey->KeyIndex & 0xff; + // Bit 31 of Add-key, Tx Key + bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; + // Bit 30 of Add-key PairwiseKey + bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; + // Bit 29 of Add-key KeyRSC + bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; + // Bit 28 of Add-key Authenticator + bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; + + // 1. Check Group / Pairwise Key + if (bPairwise) // Pairwise Key + { + // 1. KeyIdx must be 0, otherwise, return NDIS_STATUS_INVALID_DATA + if (KeyIdx != 0) + return(NDIS_STATUS_FAILURE); + + // 2. Check bTx, it must be true, otherwise, return NDIS_STATUS_INVALID_DATA + if (bTxKey == FALSE) + return(NDIS_STATUS_FAILURE); + + // 3. If BSSID is not all 0xff, return NDIS_STATUS_INVALID_DATA + if (NdisEqualMemory(pKey->BSSID, BCAST, 6)) + return(NDIS_STATUS_FAILURE); + + // 4. Selct RxMic / TxMic based on Supp / Authenticator + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + // for WPA-None Tx, Rx MIC is the same + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pRxMic = pTxMic; + } + else if (bAuthenticator == TRUE) + { + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; + } + else + { + pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; + } + + // 5. Find the old entry to overwrite or find an empty entry. + PairwiseIdx = 0; + for (i = 0; i < PAIRWISE_KEY_NO; i++) + { + if (pAdapter->PortCfg.PairwiseKey[i].KeyLen == 0) + { + PairwiseIdx = i; + break; + } + else if (RTMPEqualMemory(pAdapter->PortCfg.PairwiseKey[i].BssId, pKey->BSSID, 6)) + { + // Found the old entry + PairwiseIdx = i; + break; + } + } + // If there is no match and no empty pairwise key, we have to replace an old one + // which will be index 0 in our case. + + // 6. Check RxTsc + if (bKeyRSC == TRUE) + { + memcpy(&pAdapter->PortCfg.PairwiseKey[PairwiseIdx].RxTsc, &pKey->KeyRSC, 6); + } + else + { + memset(pAdapter->PortCfg.PairwiseKey[PairwiseIdx].RxTsc, 0, 6); + } + + // 7. Copy information into Pairwise Key structure. + // pKey->KeyLength will include TxMic and RxMic, therefore, we use 16 bytes hardcoded. + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].KeyLen = 16; + memcpy(pAdapter->PortCfg.PairwiseKey[PairwiseIdx].Key, &pKey->KeyMaterial, 16); + memcpy(pAdapter->PortCfg.PairwiseKey[PairwiseIdx].RxMic, pRxMic, 8); + memcpy(pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxMic, pTxMic, 8); + memcpy(pAdapter->PortCfg.PairwiseKey[PairwiseIdx].BssId, pKey->BSSID, 6); + // Init TxTsc to one based on WiFi WPA specs + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[0] = 1; + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[1] = 0; + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[2] = 0; + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[3] = 0; + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[4] = 0; + pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxTsc[5] = 0; + Status = NDIS_STATUS_SUCCESS; + + DBGPRINT(RT_DEBUG_INFO, "TKIP Key = "); + for (i = 0; i < 16; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.PairwiseKey[PairwiseIdx].Key[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP Rx MIC Key = "); + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.PairwiseKey[PairwiseIdx].RxMic[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP Tx MIC Key = "); + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.PairwiseKey[PairwiseIdx].TxMic[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP RxTSC = "); + for (i = 0; i < 6; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.PairwiseKey[PairwiseIdx].RxTsc[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "BSSID:%02x:%02x:%02x:%02x:%02x:%02x \n", + pKey->BSSID[0],pKey->BSSID[1],pKey->BSSID[2],pKey->BSSID[3],pKey->BSSID[4],pKey->BSSID[5]); + + } + else // Group Key + { + // 1. Check BSSID, if not current BSSID or Bcast, return NDIS_STATUS_INVALID_DATA + if ((!NdisEqualMemory(&pKey->BSSID, &BCAST, 6)) && + (!NdisEqualMemory(&pKey->BSSID, &pAdapter->PortCfg.Bssid, 6))) + return(NDIS_STATUS_FAILURE); + + + // 2. Check Key index for supported Group Key + if (KeyIdx >= GROUP_KEY_NO) + return(NDIS_STATUS_FAILURE); + + // 3. Set as default Tx Key if bTxKey is TRUE + if (bTxKey == TRUE) + pAdapter->PortCfg.DefaultKeyId = (UCHAR) KeyIdx; + + // 4. Selct RxMic / TxMic based on Supp / Authenticator + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + // for WPA-None Tx, Rx MIC is the same + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pRxMic = pTxMic; + } + else if (bAuthenticator == TRUE) + { + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; + } + else + { + pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; + pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; + } + + // 5. Check RxTsc + if (bKeyRSC == TRUE) + { + memcpy(pAdapter->PortCfg.GroupKey[KeyIdx].RxTsc, &pKey->KeyRSC, 6); + } + else + { + memset(pAdapter->PortCfg.GroupKey[KeyIdx].RxTsc, 0, 6); + } + + // 6. Copy information into Group Key structure. + // pKey->KeyLength will include TxMic and RxMic, therefore, we use 16 bytes hardcoded. + pAdapter->PortCfg.GroupKey[KeyIdx].KeyLen = 16; + memcpy(pAdapter->PortCfg.GroupKey[KeyIdx].Key, &pKey->KeyMaterial, 16); + memcpy(pAdapter->PortCfg.GroupKey[KeyIdx].RxMic, pRxMic, 8); + memcpy(pAdapter->PortCfg.GroupKey[KeyIdx].TxMic, pTxMic, 8); + memcpy(pAdapter->PortCfg.GroupKey[KeyIdx].BssId, pKey->BSSID, 6); + // Init TxTsc to one based on WiFi WPA specs + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[0] = 1; + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[1] = 0; + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[2] = 0; + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[3] = 0; + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[4] = 0; + pAdapter->PortCfg.GroupKey[KeyIdx].TxTsc[5] = 0; + // 802.1x port control + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_SECURED; + Status = NDIS_STATUS_SUCCESS; + + // For WEP compatibility, in case it use OID_ADD_KEY, not OID_ADD_WEP + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; + memcpy(pAdapter->PortCfg.SharedKey[KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); + } + + DBGPRINT(RT_DEBUG_INFO, "TKIP Key = "); + for (i = 0; i < 16; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.GroupKey[KeyIdx].Key[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP Rx MIC Key = "); + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.GroupKey[KeyIdx].RxMic[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP Tx MIC Key = "); + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.GroupKey[KeyIdx].TxMic[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "TKIP RxTSC = "); + for (i = 0; i < 6; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PortCfg.GroupKey[KeyIdx].RxTsc[i]); + } + DBGPRINT(RT_DEBUG_INFO, "\n"); + DBGPRINT(RT_DEBUG_INFO, "BSSID:%02x:%02x:%02x:%02x:%02x:%02x \n", + pKey->BSSID[0],pKey->BSSID[1],pKey->BSSID[2],pKey->BSSID[3],pKey->BSSID[4],pKey->BSSID[5]); + + } + return (Status); +} + +/* + ======================================================================== + + Routine Description: + Remove WPA Key process + + Arguments: + pAdapter Pointer to our adapter + pBuf Pointer to the where the key stored + + Return Value: + NDIS_SUCCESS Add key successfully + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPWPARemoveKeyProc( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf) +{ + PNDIS_802_11_REMOVE_KEY pKey; + ULONG KeyIdx; + NDIS_STATUS Status = NDIS_STATUS_FAILURE; + BOOLEAN bTxKey; // Set the key as transmit key + BOOLEAN bPairwise; // Indicate the key is pairwise key + BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. + // Otherwise, it will set by the NIC. + BOOLEAN bAuthenticator; // indicate key is set by authenticator. + INT i; + + pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; + KeyIdx = pKey->KeyIndex & 0xff; + // Bit 31 of Add-key, Tx Key + bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; + // Bit 30 of Add-key PairwiseKey + bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; + // Bit 29 of Add-key KeyRSC + bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; + // Bit 28 of Add-key Authenticator + bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; + + // 1. If bTx is TRUE, return failure information + if (bTxKey == TRUE) + return(NDIS_STATUS_FAILURE); + + // 2. Check Pairwise Key + if (bPairwise) + { + // a. If BSSID is broadcast, remove all pairwise keys. + if (NdisEqualMemory(&pKey->BSSID, &BCAST, 6)) + { + for (i = 0; i < PAIRWISE_KEY_NO; i++) + { + pAdapter->PortCfg.PairwiseKey[i].KeyLen = 0; + } + Status = NDIS_STATUS_SUCCESS; + } + + // b. If not broadcast, remove the pairwise specified by BSSID + else + { + for (i = 0; i < PAIRWISE_KEY_NO; i++) + { + if (NdisEqualMemory(pAdapter->PortCfg.PairwiseKey[i].BssId, pKey->BSSID, 6)) + { + pAdapter->PortCfg.PairwiseKey[i].KeyLen = 0; + Status = NDIS_STATUS_SUCCESS; + break; + } + } + + } + // c. If no pairwise supported, delete Group Key 0. + // The will be false since we do support pairwise keys. + } + // 3. Group Key + else + { + // a. If BSSID is broadcast, remove all group keys indexed + if (NdisEqualMemory(&pKey->BSSID, &BCAST, 6)) + { + pAdapter->PortCfg.GroupKey[KeyIdx].KeyLen = 0; + Status = NDIS_STATUS_SUCCESS; + } + + // b. If BSSID matched, delte the group key indexed. + else if (NdisEqualMemory(pAdapter->PortCfg.GroupKey[KeyIdx].BssId, pKey->BSSID, 6)) + { + pAdapter->PortCfg.GroupKey[KeyIdx].KeyLen = 0; + Status = NDIS_STATUS_SUCCESS; + } + + // c. For WEP compatibility + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen = 0; + } + } + + return (Status); +} + + +/* + ======================================================================== + + Routine Description: + Remove All WPA Keys + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPWPARemoveAllKeys( + IN PRTMP_ADAPTER pAdapter) +{ + INT i; + + // For WPA-None, there is no need to remove it, since WinXP won't set it again after + // Link up. And it will be replaced if user changed it. + if (pAdapter->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + return; + + for (i = 0; i < PAIRWISE_KEY_NO; i++) + { + pAdapter->PortCfg.PairwiseKey[i].KeyLen = 0; + } + + for (i = 0; i < GROUP_KEY_NO; i++) + { + pAdapter->PortCfg.GroupKey[i].KeyLen = 0; + } +} + +/* + ======================================================================== + + Routine Description: + Change NIC PHY mode. Re-association may be necessary. + + Arguments: + pAdapter Pointer to our adapter + phmode + + ======================================================================== +*/ +VOID RTMPSetPhyMode( + IN PRTMP_ADAPTER pAdapter, + IN ULONG phymode) +{ + INT i; + + DBGPRINT(RT_DEBUG_TRACE,"RTMPSetPhyMode(=%d)\n", phymode); + + // the selected phymode must be supported by the RF IC encoded in E2PROM + if (pAdapter->PortCfg.RfType < RFIC_5222) + { + if (phymode == PHY_11A) + phymode = PHY_11BG_MIXED; + } + + // if no change, do nothing + if (pAdapter->PortCfg.PhyMode == phymode) + return; + + pAdapter->PortCfg.PhyMode = (UCHAR)phymode; + BuildChannelList(pAdapter); + + for (i = 0; i < pAdapter->PortCfg.ChannelListNum; i++) + { + if (pAdapter->PortCfg.IbssConfig.Channel == pAdapter->PortCfg.ChannelList[i]) + break; + } + if (i == pAdapter->PortCfg.ChannelListNum) + pAdapter->PortCfg.IbssConfig.Channel = FirstChannel(pAdapter); + pAdapter->PortCfg.Channel = pAdapter->PortCfg.IbssConfig.Channel; + + AsicSwitchChannel(pAdapter, pAdapter->PortCfg.Channel); + AsicLockChannel(pAdapter, pAdapter->PortCfg.Channel); + + switch (phymode) { + case PHY_11B: + pAdapter->PortCfg.IbssConfig.SupportedRates[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRatesLen = 4; + pAdapter->PortCfg.SupportedRates[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRatesLen = 4; + pAdapter->PortCfg.DesiredRates[0] = 2; // 1 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[1] = 4; // 2 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[2] = 11; // 5.5 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[3] = 22; // 11 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[4] = 0; + pAdapter->PortCfg.DesiredRates[5] = 0; + pAdapter->PortCfg.DesiredRates[6] = 0; + pAdapter->PortCfg.DesiredRates[7] = 0; + pAdapter->PortCfg.DesiredRates[8] = 0; + pAdapter->PortCfg.DesiredRates[9] = 0; + pAdapter->PortCfg.DesiredRates[10] = 0; + pAdapter->PortCfg.DesiredRates[11] = 0; + break; + + case PHY_11BG_MIXED: + case PHY_11ABG_MIXED: + pAdapter->PortCfg.IbssConfig.SupportedRates[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[4] = 0x12; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[5] = 0x24; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[6] = 0x48; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[8] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[9] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[10] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[11] = 0x60; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRatesLen = 12; + pAdapter->PortCfg.SupportedRates[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[4] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[5] = 0x12; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[6] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[7] = 0x24; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[8] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[9] = 0x48; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[10] = 0x60; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[11] = 0x6c; // 54 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRatesLen = 12; + pAdapter->PortCfg.DesiredRates[0] = 2; // 1 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[1] = 4; // 2 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[2] = 11; // 5.5 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[3] = 22; // 11 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[4] = 12; // 6 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[5] = 18; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[6] = 24; // 12 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[7] = 36; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[8] = 48; // 24 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[9] = 72; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[10] = 96; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[11] = 108; // 54 mbps, in units of 0.5 Mbps + break; + + case PHY_11A: + pAdapter->PortCfg.IbssConfig.SupportedRates[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[1] = 0x12; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[3] = 0x24; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.IbssConfig.SupportedRates[5] = 0x48; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[6] = 0x60; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.IbssConfig.SupportedRates[8] = 0; + pAdapter->PortCfg.IbssConfig.SupportedRates[9] = 0; + pAdapter->PortCfg.IbssConfig.SupportedRates[10] = 0; + pAdapter->PortCfg.IbssConfig.SupportedRates[11] = 0; + pAdapter->PortCfg.IbssConfig.SupportedRatesLen = 8; + pAdapter->PortCfg.SupportedRates[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[1] = 0x12; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[3] = 0x24; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate + pAdapter->PortCfg.SupportedRates[5] = 0x48; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[6] = 0x60; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.SupportedRates[8] = 0; + pAdapter->PortCfg.SupportedRates[9] = 0; + pAdapter->PortCfg.SupportedRates[10] = 0; + pAdapter->PortCfg.SupportedRates[11] = 0; + pAdapter->PortCfg.SupportedRatesLen = 8; + pAdapter->PortCfg.DesiredRates[0] = 12; // 6 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[1] = 18; // 9 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[2] = 24; // 12 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[3] = 36; // 18 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[4] = 48; // 24 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[5] = 72; // 36 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[6] = 96; // 48 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[7] = 108; // 54 mbps, in units of 0.5 Mbps + pAdapter->PortCfg.DesiredRates[8] = 0; + pAdapter->PortCfg.DesiredRates[9] = 0; + pAdapter->PortCfg.DesiredRates[10] = 0; + pAdapter->PortCfg.DesiredRates[11] = 0; + break; + + default: + break; + } + + MlmeUpdateTxRates(pAdapter, FALSE); + AsicSetSlotTime(pAdapter, FALSE); + MakeIbssBeacon(pAdapter); // supported rates may change +} + +VOID RTMPSetDesiredRates( + IN PRTMP_ADAPTER pAdapter, + IN LONG Rates) +{ + NDIS_802_11_RATES aryRates; + + memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); + switch (pAdapter->PortCfg.PhyMode) + { + case PHY_11A: // A only + switch (Rates) + { + case 6000000: //6M + aryRates[0] = 0x0c; // 6M + break; + case 9000000: //9M + aryRates[0] = 0x12; // 9M + break; + case 12000000: //12M + aryRates[0] = 0x18; // 12M + break; + case 18000000: //18M + aryRates[0] = 0x24; // 18M + break; + case 24000000: //24M + aryRates[0] = 0x30; // 24M + break; + case 36000000: //36M + aryRates[0] = 0x48; // 36M + break; + case 48000000: //48M + aryRates[0] = 0x60; // 48M + break; + case 54000000: //54M + aryRates[0] = 0x6c; // 54M + break; + case -1: //Auto + default: + aryRates[0] = 0x6c; // 54Mbps + aryRates[1] = 0x60; // 48Mbps + aryRates[2] = 0x48; // 36Mbps + aryRates[3] = 0x30; // 24Mbps + aryRates[4] = 0x24; // 18M + aryRates[5] = 0x18; // 12M + aryRates[6] = 0x12; // 9M + aryRates[7] = 0x0c; // 6M + break; + } + break; + case PHY_11BG_MIXED: // B/G Mixed + case PHY_11B: // B only + case PHY_11ABG_MIXED: // A/B/G Mixed + default: + switch (Rates) + { + case 1000000: //1M + aryRates[0] = 0x02; + break; + case 2000000: //2M + aryRates[0] = 0x04; + break; + case 5000000: //5.5M + aryRates[0] = 0x0b; // 5.5M + break; + case 11000000: //11M + aryRates[0] = 0x16; // 11M + break; + case 6000000: //6M + aryRates[0] = 0x0c; // 6M + break; + case 9000000: //9M + aryRates[0] = 0x12; // 9M + break; + case 12000000: //12M + aryRates[0] = 0x18; // 12M + break; + case 18000000: //18M + aryRates[0] = 0x24; // 18M + break; + case 24000000: //24M + aryRates[0] = 0x30; // 24M + break; + case 36000000: //36M + aryRates[0] = 0x48; // 36M + break; + case 48000000: //48M + aryRates[0] = 0x60; // 48M + break; + case 54000000: //54M + aryRates[0] = 0x6c; // 54M + break; + case -1: //Auto + default: + if (pAdapter->PortCfg.PhyMode == PHY_11B) + { //B Only + aryRates[0] = 0x16; // 11Mbps + aryRates[1] = 0x0b; // 5.5Mbps + aryRates[2] = 0x04; // 2Mbps + aryRates[3] = 0x02; // 1Mbps + } + else + { //(B/G) Mixed or (A/B/G) Mixed + aryRates[0] = 0x6c; // 54Mbps + aryRates[1] = 0x60; // 48Mbps + aryRates[2] = 0x48; // 36Mbps + aryRates[3] = 0x30; // 24Mbps + aryRates[4] = 0x16; // 11Mbps + aryRates[5] = 0x0b; // 5.5Mbps + aryRates[6] = 0x04; // 2Mbps + aryRates[7] = 0x02; // 1Mbps + } + break; + } + break; + } + + memset(pAdapter->PortCfg.DesiredRates, 0, MAX_LEN_OF_SUPPORTED_RATES); + memcpy(pAdapter->PortCfg.DesiredRates, &aryRates, sizeof(NDIS_802_11_RATES)); + DBGPRINT(RT_DEBUG_TRACE, " RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", + pAdapter->PortCfg.DesiredRates[0],pAdapter->PortCfg.DesiredRates[1], + pAdapter->PortCfg.DesiredRates[2],pAdapter->PortCfg.DesiredRates[3], + pAdapter->PortCfg.DesiredRates[4],pAdapter->PortCfg.DesiredRates[5], + pAdapter->PortCfg.DesiredRates[6],pAdapter->PortCfg.DesiredRates[7] ); + // Changing DesiredRate may affect the MAX TX rate we used to TX frames out + MlmeUpdateTxRates(pAdapter, FALSE); +} +/* + ========================================================================== + Description: + Set Country Region + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_CountryRegion_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG region; + int success = TRUE; + + region = simple_strtol(arg, 0, 10); + if( (region >= REGION_MIN) && (region <= REGION_MAX) ) + { + pAdapter->PortCfg.CountryRegion = (UCHAR) region; + DBGPRINT(RT_DEBUG_TRACE, "Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAdapter->PortCfg.CountryRegion); + BuildChannelList(pAdapter); + } + else + success = FALSE; + + return success; +} +/* + ========================================================================== + Description: + Set SSID + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_SSID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + NDIS_802_11_SSID Ssid, *pSsid=NULL; + BOOLEAN StateMachineTouched = FALSE; + int success = TRUE; + + + /* Protect against oops if net is down, this will not work with if-preup + use iwconfig properly */ + printk("'iwpriv set essid' is deprecated, please use 'iwconfg essid' instead\n"); + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + return FALSE; + + if( strlen(arg) <= MAX_LEN_OF_SSID) + { + memset(&Ssid, 0, MAX_LEN_OF_SSID); + memcpy(Ssid.Ssid, arg, strlen(arg)); + Ssid.SsidLength = strlen(arg); + pSsid = &Ssid; + + + + if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) + { + MlmeRestartStateMachine(pAdapter); + DBGPRINT(RT_DEBUG_TRACE, "!!! MLME busy, reset MLME state machine !!!\n"); + } + // tell CNTL state machine to call NdisMSetInformationComplete() after completing + // this request, because this request is initiated by NDIS. + pAdapter->Mlme.CntlAux.CurrReqIsFromNdis = FALSE; + + MlmeEnqueue(&pAdapter->Mlme.Queue, + MLME_CNTL_STATE_MACHINE, + OID_802_11_SSID, + sizeof(NDIS_802_11_SSID), + (VOID *)pSsid); + + StateMachineTouched = TRUE; + DBGPRINT(RT_DEBUG_TRACE, "Set_SSID_Proc::(Len=%d,Ssid=%s)\n", pAdapter->PortCfg.SsidLen, pAdapter->PortCfg.Ssid); + } + else + success = FALSE; + + if (StateMachineTouched) // Upper layer sent a MLME-related operations + MlmeHandler(pAdapter); + + return success; +} +/* + ========================================================================== + Description: + Set Wireless Mode + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_WirelessMode_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG WirelessMode; + int success = TRUE; + + WirelessMode = simple_strtol(arg, 0, 10); + + if ((WirelessMode == PHY_11BG_MIXED) || (WirelessMode == PHY_11B) || + (WirelessMode == PHY_11A) || (WirelessMode == PHY_11ABG_MIXED)) + { + RTMPSetPhyMode(pAdapter, WirelessMode); + DBGPRINT(RT_DEBUG_TRACE, "Set_WirelessMode_Proc::(=%d)\n", WirelessMode); + } + else + success = FALSE; + + return success; +} +/* + ========================================================================== + Description: + Set TxRate + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_TxRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG TxRate; + int success = TRUE; + ULONG rate_mapping[12] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; //according to README + + TxRate = simple_strtol(arg, 0, 10); + + if (TxRate == 0) + RTMPSetDesiredRates(pAdapter, -1); + else + RTMPSetDesiredRates(pAdapter, (LONG) (rate_mapping[TxRate-1] * 1000000)); + return success; +} +/* + ========================================================================== + Description: + Set AdhocMode support Rate can or can not exceed 11Mbps against WiFi spec. + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_AdhocModeRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG AdhocMode; + + AdhocMode = simple_strtol(arg, 0, 10); + + if (AdhocMode == 1) + pAdapter->PortCfg.AdhocMode = 1; + else if (AdhocMode == 0) + pAdapter->PortCfg.AdhocMode = 0; + else + return FALSE; //Invalid argument + + DBGPRINT(RT_DEBUG_TRACE, "Set_AdhocModeRate_Proc::(AdhocMode=%d)\n", pAdapter->PortCfg.AdhocMode); + + return TRUE; +} +/* + ========================================================================== + Description: + Set Channel + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_Channel_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + int success = TRUE; + UCHAR Channel; + + Channel = (UCHAR) simple_strtol(arg, 0, 10); + + if (ChannelSanity(pAdapter, Channel) == TRUE) + { + pAdapter->PortCfg.Channel = Channel; + pAdapter->PortCfg.IbssConfig.Channel = Channel; + DBGPRINT(RT_DEBUG_TRACE, "Set_Channel_Proc::(Channel=%d)\n", Channel); + } + else + success = FALSE; + + return success; +} +/* + ========================================================================== + Description: + Set 11B/11G Protection + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_BGProtection_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) + +{ + switch (simple_strtol(arg, 0, 10)) + { + case 0: //AUTO + pAdapter->PortCfg.UseBGProtection = 0; + break; + case 1: //Always On + pAdapter->PortCfg.UseBGProtection = 1; + break; + case 2: //Always OFF + pAdapter->PortCfg.UseBGProtection = 2; + break; + default: //Invalid argument + return FALSE; + } + DBGPRINT(RT_DEBUG_TRACE, "Set_BGProtection_Proc::(BGProtection=%d)\n", pAdapter->PortCfg.UseBGProtection); + + return TRUE; +} +/* + ========================================================================== + Description: + Set StaWithEtherBridge function on/off + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_StaWithEtherBridge_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) + +{ + switch (simple_strtol(arg, 0, 10)) + { + case 0: //Off + pAdapter->PortCfg.StaWithEtherBridge.Enable = FALSE; + break; + case 1: //On + pAdapter->PortCfg.StaWithEtherBridge.Enable = TRUE; + break; + default: //Invalid argument + return FALSE; + } + DBGPRINT(RT_DEBUG_TRACE, "Set_StaWithEtherBridge_Proc::(StaWithEtherBridge=%d)\n", pAdapter->PortCfg.StaWithEtherBridge.Enable); + + return TRUE; +} +/* + ========================================================================== + Description: + Set TxPreamble + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_TxPreamble_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + RT_802_11_PREAMBLE Preamble; + + Preamble = simple_strtol(arg, 0, 10); + switch (Preamble) + { + case Rt802_11PreambleShort: + pAdapter->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); + break; + case Rt802_11PreambleLong: + case Rt802_11PreambleAuto: + // if user wants AUTO, initialize to LONG here, then change according to AP's + // capability upon association. + pAdapter->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); + break; + default: //Invalid argument + return FALSE; + } + + DBGPRINT(RT_DEBUG_TRACE, "Set_TxPreamble_Proc::(TxPreamble=%d)\n", Preamble); + + return TRUE; +} +/* + ========================================================================== + Description: + Set RTS Threshold + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_RTSThreshold_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) + + +{ + NDIS_802_11_RTS_THRESHOLD RtsThresh; + + printk("'iwpriv set RTSThreshold' is deprecated, please use 'iwconfg rts' instead\n"); + + RtsThresh = simple_strtol(arg, 0, 10); + + if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) + pAdapter->PortCfg.RtsThreshold = (USHORT)RtsThresh; + else if (RtsThresh == 0) + pAdapter->PortCfg.RtsThreshold = MAX_RTS_THRESHOLD; + else + return FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAdapter->PortCfg.RtsThreshold); + return TRUE; +} +/* + ========================================================================== + Description: + Set Fragment Threshold + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_FragThreshold_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; + + printk("'iwpriv set FragThreshold' is deprecated, please use 'iwconfg frag' instead\n"); + + + FragThresh = simple_strtol(arg, 0, 10); + + if ( (FragThresh >= MIN_FRAG_THRESHOLD) && (FragThresh <= MAX_FRAG_THRESHOLD)) + pAdapter->PortCfg.FragmentThreshold = (USHORT)FragThresh; + else if (FragThresh == 0) + pAdapter->PortCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; + else + return FALSE; //Invalid argument + + if (pAdapter->PortCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) + pAdapter->PortCfg.bFragmentZeroDisable = TRUE; + else + pAdapter->PortCfg.bFragmentZeroDisable = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "Set_FragThreshold_Proc::(FragThreshold=%d)\n", FragThresh); + + return TRUE; +} +/* + ========================================================================== + Description: + Set TxBurst + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_TxBurst_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG TxBurst; + + TxBurst = simple_strtol(arg, 0, 10); + + if (TxBurst == 1) + pAdapter->PortCfg.EnableTxBurst = TRUE; + else if (TxBurst == 0) + pAdapter->PortCfg.EnableTxBurst = FALSE; + else + return FALSE; //Invalid argument + + DBGPRINT(RT_DEBUG_TRACE, "Set_TxBurst_Proc::(TxBurst=%d)\n", pAdapter->PortCfg.EnableTxBurst); + + return TRUE; +} +/* + ========================================================================== + Description: + Set TurboRate Enable or Disable + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_TurboRate_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG TurboRate; + + TurboRate = simple_strtol(arg, 0, 10); + + if (TurboRate == 1) + pAdapter->PortCfg.EnableTurboRate = TRUE; + else if (TurboRate == 0) + pAdapter->PortCfg.EnableTurboRate = FALSE; + else + return FALSE; //Invalid argument + + DBGPRINT(RT_DEBUG_TRACE, "Set_TurboRate_Proc::(TurboRate=%d)\n", pAdapter->PortCfg.EnableTurboRate); + + return TRUE; +} +/* + ========================================================================== + Description: + Set Short Slot Time Enable or Disable + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ShortSlot_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG ShortSlot; + + ShortSlot = simple_strtol(arg, 0, 10); + + if (ShortSlot == 1) + pAdapter->PortCfg.UseShortSlotTime = TRUE; + else if (ShortSlot == 0) + pAdapter->PortCfg.UseShortSlotTime = FALSE; + else + return FALSE; //Invalid argument + + DBGPRINT(RT_DEBUG_TRACE, "Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAdapter->PortCfg.UseShortSlotTime); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set Network Type(Infrastructure/Adhoc mode) + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_NetworkType_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + + printk("'iwpriv set NetworkType' is deprecated, please use 'iwconfg mode' instead\n"); + + if (strcmp(arg, "Adhoc") == 0) + pAdapter->PortCfg.BssType = BSS_INDEP; + else //Default Infrastructure mode + pAdapter->PortCfg.BssType = BSS_INFRA; + + // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key + pAdapter->PortCfg.WpaState = SS_NOTUSE; + + DBGPRINT(RT_DEBUG_TRACE, "Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->PortCfg.BssType); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set Authentication mode + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_AuthMode_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeOpen; + else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeShared; + else if ((strcmp(arg, "AUTO") == 0) || (strcmp(arg, "auto") == 0)) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; + else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeWPAPSK; + else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeWPANone; + else + return FALSE; + + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + + DBGPRINT(RT_DEBUG_TRACE, "Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->PortCfg.AuthMode); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set Encryption Type + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_EncrypType_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) + pAdapter->PortCfg.WepStatus = Ndis802_11WEPDisabled; + else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) + pAdapter->PortCfg.WepStatus = Ndis802_11WEPEnabled; + else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) + pAdapter->PortCfg.WepStatus = Ndis802_11Encryption2Enabled; + else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) + pAdapter->PortCfg.WepStatus = Ndis802_11Encryption3Enabled; + else + return FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->PortCfg.WepStatus); + + return TRUE; +} +/* + ========================================================================== + Description: + Set Default Key ID + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_DefaultKeyID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG KeyIdx; + + printk("'iwpriv set DefaultKeyID' is deprecated, please use 'iwconfg key' instead\n"); + + KeyIdx = simple_strtol(arg, 0, 10); + if((KeyIdx >= 1 ) && (KeyIdx <= 4)) + pAdapter->PortCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); + else + return FALSE; //Invalid argument + + DBGPRINT(RT_DEBUG_TRACE, "Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->PortCfg.DefaultKeyId); + + return TRUE; +} +/* + ========================================================================== + Description: + Set WEP KEY1 + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_Key1_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + int KeyLen; + int i; + + printk("'iwpriv set Key1' is deprecated, please use 'iwconfg key [1] ' instead\n"); + + KeyLen = strlen(arg); + + switch (KeyLen) + { + case 5: //wep 40 Ascii type + pAdapter->PortCfg.SharedKey[0].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[0].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii"); + break; + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[0].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[0].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex"); + break; + case 13: //wep 104 Ascii type + pAdapter->PortCfg.SharedKey[0].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[0].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[0].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[0].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex"); + break; + default: //Invalid argument + DBGPRINT(RT_DEBUG_TRACE, "Set_Key1_Proc::Invalid argument (=%s)\n", arg); + return FALSE; + } + + return TRUE; +} +/* + ========================================================================== + Description: + Set WEP KEY2 + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_Key2_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + int KeyLen; + int i; + + printk("'iwpriv set Key2' is deprecated, please use 'iwconfg key [2] ' instead\n"); + + + KeyLen = strlen(arg); + + switch (KeyLen) + { + case 5: //wep 40 Ascii type + pAdapter->PortCfg.SharedKey[1].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[1].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii"); + break; + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[1].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[1].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex"); + break; + case 13: //wep 104 Ascii type + pAdapter->PortCfg.SharedKey[1].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[1].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[1].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[1].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex"); + break; + default: //Invalid argument + DBGPRINT(RT_DEBUG_TRACE, "Set_Key2_Proc::Invalid argument (=%s)\n", arg); + return FALSE; + } + + return TRUE; +} +/* + ========================================================================== + Description: + Set WEP KEY3 + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_Key3_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + int KeyLen; + int i; + + printk("'iwpriv set Key3' is deprecated, please use 'iwconfg key [3] ' instead\n"); + + KeyLen = strlen(arg); + + switch (KeyLen) + { + case 5: //wep 40 Ascii type + pAdapter->PortCfg.SharedKey[2].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[2].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key3_Proc::(Key3=%s and type=%s)\n", arg, "Ascii"); + break; + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[2].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[2].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key3_Proc::(Key3=%s and type=%s)\n", arg, "Hex"); + break; + case 13: //wep 104 Ascii type + pAdapter->PortCfg.SharedKey[2].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[2].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key3_Proc::(Key3=%s and type=%s)\n", arg, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[2].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[2].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key3_Proc::(Key3=%s and type=%s)\n", arg, "Hex"); + break; + default: //Invalid argument + DBGPRINT(RT_DEBUG_TRACE, "Set_Key3_Proc::Invalid argument (=%s)\n", arg); + return FALSE; + } + + return TRUE; +} +/* + ========================================================================== + Description: + Set WEP KEY4 + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_Key4_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + int KeyLen; + int i; + + printk("'iwpriv set Key4' is deprecated, please use 'iwconfg key [4] ' instead\n"); + + KeyLen = strlen(arg); + + switch (KeyLen) + { + case 5: //wep 40 Ascii type + pAdapter->PortCfg.SharedKey[3].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[3].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii"); + break; + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[3].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[3].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex"); + break; + case 13: //wep 104 Ascii type + pAdapter->PortCfg.SharedKey[3].KeyLen = KeyLen; + memcpy(pAdapter->PortCfg.SharedKey[3].Key, arg, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(arg+i)) ) + return FALSE; //Not Hex value; + } + pAdapter->PortCfg.SharedKey[3].KeyLen = KeyLen / 2 ; + AtoH(arg, pAdapter->PortCfg.SharedKey[3].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex"); + break; + default: //Invalid argument + DBGPRINT(RT_DEBUG_TRACE, "Set_Key4_Proc::Invalid argument (=%s)\n", arg); + return FALSE; + } + + return TRUE; +} +/* + ========================================================================== + Description: + Set WPA PSK key + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_WPAPSK_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + UCHAR keyMaterial[40]; + + DBGPRINT(RT_DEBUG_TRACE, "Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg); + if ((strlen(arg) < 8) || (strlen(arg) > 64)) + { + DBGPRINT(RT_DEBUG_TRACE, "Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg); + return FALSE; + } + + if (strlen(arg) == 64) + { + AtoH(arg, pAdapter->PortCfg.PskKey.Key, 32); + } + else + { + PasswordHash((char *)arg, pAdapter->Mlme.CntlAux.Ssid, pAdapter->Mlme.CntlAux.SsidLen, keyMaterial); + + memcpy(&pAdapter->PortCfg.PskKey.Key, &keyMaterial, 32); + } + + // Use RaConfig as PSK agent. + // Start STA supplicant state machine + pAdapter->PortCfg.WpaState = SS_START; + + return TRUE; +} + + +/* + ========================================================================== + Description: + Set WPA NONE key + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ + +INT Set_WPANONE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + UCHAR keyMaterial[40]; + + DBGPRINT(RT_DEBUG_TRACE, "Set_WPANONE_Proc::(WPANONE=%s)\n", arg); + if ((strlen(arg) < 8) || (strlen(arg) > 64)) + { + DBGPRINT(RT_DEBUG_TRACE, "Set failed!!(WPANONE=%s), WPANONE key-string required 8 ~ 64 characters \n", arg); + return FALSE; + } + + if (strlen(arg) == 64) + { + AtoH(arg, pAdapter->PortCfg.PskKey.Key, 32); + } + else + { + PasswordHash((char *)arg, pAdapter->Mlme.CntlAux.Ssid, pAdapter->Mlme.CntlAux.SsidLen, keyMaterial); + + memcpy(pAdapter->PortCfg.PskKey.Key, keyMaterial, 32); + } + // Use RaConfig as PSK agent. + // Start STA supplicant state machine + pAdapter->PortCfg.WpaState = SS_START; + +//----------------------------------------------------------------------------- +// pasted from "RTMPWPAAddKeyProc(...)" +// major on Group Key only. + + // Group Key + { + // 3. Set as default Tx Key if bTxKey is TRUE + pAdapter->PortCfg.DefaultKeyId = 0; + + // 4. Selct RxMic / TxMic based on Supp / Authenticator + // for WPA-None Tx, Rx MIC is the same + //pTxMic = (PUCHAR) (keyMaterial) + 16; + //pRxMic = pTxMic; + + memset(pAdapter->PortCfg.GroupKey[0].RxTsc, 0x00, 6); + + // 6. Copy information into Group Key structure. + // pKey->KeyLength will include TxMic and RxMic, therefore, we use 16 bytes hardcoded. + pAdapter->PortCfg.GroupKey[0].KeyLen = 16; + memcpy(pAdapter->PortCfg.GroupKey[0].Key, (PUCHAR)(keyMaterial) + 0, 16); + memcpy(pAdapter->PortCfg.GroupKey[0].RxMic, (PUCHAR)(keyMaterial) + 16, 8); + memcpy(pAdapter->PortCfg.GroupKey[0].TxMic, (PUCHAR)(keyMaterial) + 16, 8); + memcpy(pAdapter->PortCfg.GroupKey[0].BssId, &pAdapter->PortCfg.Bssid, 6); + + // Init TxTsc to one based on WiFi WPA specs + pAdapter->PortCfg.GroupKey[0].TxTsc[0] = 1; + pAdapter->PortCfg.GroupKey[0].TxTsc[1] = 0; + pAdapter->PortCfg.GroupKey[0].TxTsc[2] = 0; + pAdapter->PortCfg.GroupKey[0].TxTsc[3] = 0; + pAdapter->PortCfg.GroupKey[0].TxTsc[4] = 0; + pAdapter->PortCfg.GroupKey[0].TxTsc[5] = 0; + + // 802.1x port control + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_SECURED; + } + + return TRUE; +} + +/* + ========================================================================== + Description: + Read / Write BBP +Arguments: + pAdapter Pointer to our adapter + wrq Pointer to the ioctl argument + + Return Value: + None + + Note: + Usage: + 1.) iwpriv ra0 bbp ==> read all BBP + 2.) iwpriv ra0 bbp 1,2,10,32 ==> raed BBP where ID=1,2,10,32 + 3.) iwpriv ra0 bbp 1=10,17=3E ==> write BBP R1=0x10, R17=0x3E + ========================================================================== +*/ +VOID RTMPIoctlBBP( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq) +{ + char *this_char; + char *value; + int i=0; + int count = 0; + UCHAR regBBP; + char *msg = NULL; + char *arg = NULL; + char *ptr; + ULONG bbpId; + ULONG bbpValue; + BOOLEAN bIsPrintAllBBP = FALSE; + + msg = kmalloc(1024, GFP_KERNEL); + arg = kmalloc(255, GFP_KERNEL); + + DBGPRINT(RT_DEBUG_TRACE, "==>RTMPIoctlBBP\n"); + memset(msg, 0x00, 1024); + memset(arg, 0x00, 255); + if (wrq->u.data.length > 1) //No parameters. + { + memcpy(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); + ptr = arg; + sprintf(msg, "\n"); + //Parsing Read or Write + while ((this_char = strsep(&ptr, ",")) != NULL) + { + i++; + DBGPRINT(RT_DEBUG_TRACE, "this_char=%s\n", this_char); + if (!*this_char) + continue; + + if ((value = rtstrchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + { //Read + DBGPRINT(RT_DEBUG_TRACE, "this_char=%s, value=%s\n", this_char, value); + bbpId = simple_strtol(this_char, 0, 10); + if ((bbpId >=0) && (bbpId <= 63)) + { + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, bbpId, ®BBP); + sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", (char*)msg); + } + else + {//Invalid parametes, so default print all bbp + bIsPrintAllBBP = TRUE; + break; + } + } + else + { //Write + DBGPRINT(RT_DEBUG_TRACE, "this_char=%s, value=%s\n", this_char, value); + bbpId = simple_strtol(this_char, 0, 10); + bbpValue = simple_strtol(value, 0, 10); + DBGPRINT(RT_DEBUG_TRACE, "bbpID=%02d, value=0x%x\n", bbpId, bbpValue); + if ((bbpId >=0) && (bbpId <= 63)) + { + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, (UCHAR) bbpId, (UCHAR) bbpValue); + //Read it back for showing + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, bbpId, ®BBP); + sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", (char*)msg); + } + else + {//Invalid parametes, so default print all bbp + bIsPrintAllBBP = TRUE; + break; + } + } + } + } + else + bIsPrintAllBBP = TRUE; + + if (bIsPrintAllBBP) + { + memset(msg, 0x00, 1024); + sprintf(msg, "\n"); + for (i = 0; i <= 63; i++) + { + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, i, ®BBP); + sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X ", i, i*2, regBBP); + if (i%5 == 4) + sprintf(msg+strlen(msg), "\n"); + } + // Copy the information into the user buffer + wrq->u.data.length = strlen(msg); + if(copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) + DBGPRINT(RT_DEBUG_ERROR, "RTMPIoctlBBP - copy to user failure\n"); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "copy to user [msg=%s]\n", (char*)msg); + // Copy the information into the user buffer + wrq->u.data.length = strlen(msg); + if(copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) + DBGPRINT(RT_DEBUG_ERROR, "RTMPIoctlBBP - copy to user failure\n"); + } + DBGPRINT(RT_DEBUG_TRACE, "<==RTMPIoctlBBP\n"); + + kfree(msg); + kfree(arg); +} + +int RTMPIoctlRFMONTX( + IN PRTMP_ADAPTER pAdapter, + IN OUT struct iwreq *wrq) +{ + char *pvalue; + char value; + + if (wrq->u.data.length) /* Argument : set the state. */ + { + pvalue = wrq->u.data.pointer; + value = *pvalue; + + if (value == 1) + { + pAdapter->PortCfg.MallowRFMONTx = TRUE; + pAdapter->net_dev->type = 801; // ARPHRD_IEEE80211 + } + else if (!value) + { + pAdapter->PortCfg.MallowRFMONTx = FALSE; + pAdapter->net_dev->type = 802; // ARPHRD_IEEE80211_PRISM + } + else return -EINVAL; + } + + /* Display the state. Use "value" to indicate it. */ + value = pAdapter->PortCfg.MallowRFMONTx == TRUE ? '1' + : '0'; + wrq->u.data.length = sizeof (char); + + if (copy_to_user (wrq->u.data.pointer, &value, wrq->u.data.length)) + DBGPRINT (RT_DEBUG_ERROR, "RTMPIoctlRFMONTX - copy to user failure.\n"); + + return 0; +} + +/* + ========================================================================== + Description: + Read / Write MAC +Arguments: + pAdapter Pointer to our adapter + wrq Pointer to the ioctl argument + + Return Value: + None + + Note: + Usage: + 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 + 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 + ========================================================================== +*/ +VOID RTMPIoctlMAC( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq) +{ + char *this_char; + char *value; + int j=0, k=0; + int count = 0; + char *msg; + char *arg; + char *ptr; + ULONG macAddr = 0; + UCHAR temp[16], temp2[16]; + ULONG macValue; + + msg = kmalloc(1024, GFP_KERNEL); + arg = kmalloc(255, GFP_KERNEL); + + DBGPRINT(RT_DEBUG_TRACE, "==>RTMPIoctlMAC\n"); + memset(msg, 0x00, 1024); + memset(arg, 0x00, 255); + + if (wrq->u.data.length > 1) //No parameters. + { + memcpy(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); + ptr = arg; + sprintf(msg, "\n"); + //Parsing Read or Write + while ((this_char = strsep(&ptr, ",")) != NULL) + { + DBGPRINT(RT_DEBUG_TRACE, "this_char=%s\n", this_char); + if (!*this_char) + continue; + + if ((value = rtstrchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + { //Read + // Sanity check + if(strlen(this_char) > 4) + break; + + j = strlen(this_char); + while(j-- > 0) + { + if(this_char[j] > 'f' || this_char[j] < '0') + return; + } + + // Mac Addr + k = j = strlen(this_char); + while(j-- > 0) + { + this_char[4-k+j] = this_char[j]; + } + + while(k < 4) + this_char[3-k++]='0'; + this_char[4]='\0'; + + if(strlen(this_char) == 4) + { + AtoH(this_char, temp, 4); + macAddr = *temp*256 + temp[1]; + if (macAddr < 0xFFFF) + { + RTMP_IO_READ32(pAdapter, macAddr, &macValue); + DBGPRINT(RT_DEBUG_TRACE, "macAddr=%x, regMAC=%x\n", macAddr, macValue); + sprintf(msg+strlen(msg), "[0x%08X]:%08X ", macAddr , macValue); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", (char*)msg); + } + else + {//Invalid parametes, so default print all bbp + break; + } + } + } + else + { //Write + memcpy(&temp2, value, strlen(value)); + temp2[strlen(value)] = '\0'; + + // Sanity check + if((strlen(this_char) > 4) || strlen(temp2) > 8) + break; + + j = strlen(this_char); + while(j-- > 0) + { + if(this_char[j] > 'f' || this_char[j] < '0') + return; + } + + j = strlen(temp2); + while(j-- > 0) + { + if(temp2[j] > 'f' || temp2[j] < '0') + return; + } + + //MAC Addr + k = j = strlen(this_char); + while(j-- > 0) + { + this_char[4-k+j] = this_char[j]; + } + + while(k < 4) + this_char[3-k++]='0'; + this_char[4]='\0'; + + //MAC value + k = j = strlen(temp2); + while(j-- > 0) + { + temp2[8-k+j] = temp2[j]; + } + + while(k < 8) + temp2[7-k++]='0'; + temp2[8]='\0'; + + { + AtoH(this_char, temp, 4); + macAddr = *temp*256 + temp[1]; + + AtoH(temp2, temp, 8); + macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; + + DBGPRINT(RT_DEBUG_TRACE, "macAddr=%02x, macValue=0x%x\n", macAddr, macValue); + + RTMP_IO_WRITE32(pAdapter, macAddr, macValue); + sprintf(msg+strlen(msg), "[0x%02X]:%02X ", macAddr, macValue); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", (char*)msg); + } + } + } + } + + if(strlen(msg) == 1) + sprintf(msg+strlen(msg), "===>Error command format!"); + DBGPRINT(RT_DEBUG_TRACE, "copy to user [msg=%s]\n", (char*)msg); + // Copy the information into the user buffer + wrq->u.data.length = strlen(msg); + if(copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) + DBGPRINT(RT_DEBUG_ERROR, "RTMPIoctlMAC - copy to user failure.\n"); + + DBGPRINT(RT_DEBUG_TRACE, "<==RTMPIoctlMAC\n"); + + kfree(msg); + kfree(arg); +} + +#ifdef RALINK_ATE + +/* + ========================================================================== + Description: + Read / Write E2PROM +Arguments: + pAdapter Pointer to our adapter + wrq Pointer to the ioctl argument + + Return Value: + None + + Note: + Usage: + 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 + 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 + ========================================================================== +*/ +VOID RTMPIoctlE2PROM( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq) +{ + char *this_char; + char *value; + int j=0, k=0; + int count = 0; + char *msg; + char *arg; + char *ptr; + USHORT eepAddr = 0; + UCHAR temp[16], temp2[16]; + USHORT eepValue; + + msg = kmalloc(1024, GFP_KERNEL); + arg = kmalloc(255, GFP_KERNEL); + + DBGPRINT(RT_DEBUG_TRACE, "==>RTMPIoctlE2PROM\n"); + memset(msg, 0x00, 1024); + memset(arg, 0x00, 255); + + memset(msg, 0x00, 1024); + if (wrq->u.data.length > 1) //No parameters. + { + memcpy(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); + ptr = arg; + sprintf(msg, "\n"); + //Parsing Read or Write + while ((this_char = strsep(&ptr, ",")) != NULL) + { + DBGPRINT(RT_DEBUG_TRACE, "this_char=%s\n", this_char); + if (!*this_char) + continue; + + if ((value = strchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + { //Read + DBGPRINT(RT_DEBUG_TRACE, "Read: this_char=%s, strlen=%d\n", this_char, strlen(this_char)); + + // Sanity check + if(strlen(this_char) > 4) + break; + + j = strlen(this_char); + while(j-- > 0) + { + if(this_char[j] > 'f' || this_char[j] < '0') + return; + } + + // E2PROM addr + k = j = strlen(this_char); + while(j-- > 0) + { + this_char[4-k+j] = this_char[j]; + } + + while(k < 4) + this_char[3-k++]='0'; + this_char[4]='\0'; + + if(strlen(this_char) == 4) + { + AtoH(this_char, temp, 4); + eepAddr = *temp*256 + temp[1]; + if (eepAddr < 0xFFFF) + { + eepValue = RTMP_EEPROM_READ16(pAdapter, eepAddr); + DBGPRINT(RT_DEBUG_TRACE, "eepAddr=%x, eepValue=%x\n", eepAddr, eepValue); + sprintf(msg+strlen(msg), "[0x%04X]:%04X ", eepAddr , eepValue); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", *msg); + } + else + {//Invalid parametes, so default printk all bbp + break; + } + } + } + else + { //Write + DBGPRINT(RT_DEBUG_TRACE, "Write: this_char=%s, strlen(value)=%d, value=%s\n", this_char, strlen(value), value); + memcpy(&temp2, value, strlen(value)); + temp2[strlen(value)] = '\0'; + + // Sanity check + if((strlen(this_char) > 4) || strlen(temp2) > 8) + break; + + j = strlen(this_char); + while(j-- > 0) + { + if(this_char[j] > 'f' || this_char[j] < '0') + return; + } + j = strlen(temp2); + while(j-- > 0) + { + if(temp2[j] > 'f' || temp2[j] < '0') + return; + } + + //MAC Addr + k = j = strlen(this_char); + while(j-- > 0) + { + this_char[4-k+j] = this_char[j]; + } + + while(k < 4) + this_char[3-k++]='0'; + this_char[4]='\0'; + + //MAC value + k = j = strlen(temp2); + while(j-- > 0) + { + temp2[4-k+j] = temp2[j]; + } + + while(k < 4) + temp2[3-k++]='0'; + temp2[4]='\0'; + + AtoH(this_char, temp, 4); + eepAddr = *temp*256 + temp[1]; + + AtoH(temp2, temp, 4); + eepValue = *temp*256 + temp[1]; + + DBGPRINT(RT_DEBUG_TRACE, "eepAddr=%02x, eepValue=0x%x\n", eepAddr, eepValue); + + RTMP_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); + sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); + count++; + if (count%5 == 4) + sprintf(msg+strlen(msg), "\n"); + DBGPRINT(RT_DEBUG_TRACE, "msg=%s\n", *msg); + } + } + } + + if(strlen(msg) == 1) + sprintf(msg+strlen(msg), "===>Error command format!"); + + // Copy the information into the user buffer + DBGPRINT(RT_DEBUG_TRACE, "copy to user [msg=%s]\n", *msg); + wrq->u.data.length = strlen(msg); + copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); + + DBGPRINT(RT_DEBUG_TRACE, "<==RTMPIoctlE2PROM\n"); + + kfree(msg); + kfree(arg); +} + +UCHAR TempletFrame[24] = {0x08,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes + +/* + ========================================================================== + Description: + Set ATE operation mode to + 0. APSTOP = Stop STA Mode + 1. APSTART = Start STA Mode + 2. TXCONT = Continuous Transmit + 3. TXCARR = Transmit Carrier + 4. TXFRAME = Transmit Frames + 5. RXFRAME = Receive Frames + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + USHORT BbpData; + ULONG MacData; + PTXD_STRUC pTxD; + PUCHAR pDest; + UINT i, j; + + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_Proc (arg = %s)\n", arg); + + mdelay(5); + + AsicSwitchChannel(pAdapter, pAdapter->ate.Channel); + AsicLockChannel(pAdapter, pAdapter->ate.Channel); + + mdelay(5); + + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, 63, &BbpData); + RTMP_IO_READ32(pAdapter, MACCSR1, &MacData); + + BbpData = 0; + MacData &= 0xFBFFFFFF; + + if (!strcmp(arg, "STASTOP")) + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: STASTOP\n"); + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + pAdapter->ate.Mode = ATE_STASTOP; + + LinkDown(pAdapter); + AsicEnableBssSync(pAdapter); + netif_stop_queue(pAdapter->net_dev); + RTMPStationStop(pAdapter); + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0xffffffff); // Stop Rx + } + else if (!strcmp(arg, "STASTART")) + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: STASTART\n"); + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + pAdapter->ate.Mode = ATE_STASTART; + + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x56); // Start Rx + netif_start_queue(pAdapter->net_dev); + RTMPStationStart(pAdapter); + } + else if (!strcmp(arg, "TXCONT")) // Continuous Tx + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: TXCONT\n"); + + pAdapter->ate.Mode = ATE_TXCONT; + + BbpData |= 0x80; + MacData |= 0x04000000; + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + for (i = 0; (i < TX_RING_SIZE) && (i < pAdapter->ate.TxCount); i++) + { + pTxD = (PTXD_STRUC)pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + + // Prepare frame payload + memcpy(pDest, &TempletFrame, LENGTH_802_11); + for(j = LENGTH_802_11; j < pAdapter->ate.TxLength; j++) + pDest[j] = 0xAA; + memcpy(&pDest[4], &pAdapter->ate.Addr1, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[10], &pAdapter->ate.Addr2, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[16], &pAdapter->ate.Addr3, ETH_LENGTH_OF_ADDRESS); + + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, + SHORT_RETRY, IFS_BACKOFF, pAdapter->ate.TxRate, 4, + pAdapter->ate.TxLength, pAdapter->PortCfg.TxPreambleInUsed, 0); + + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + } + + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0xffffffff); + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + } + else if (!strcmp(arg, "TXCARR")) // Tx Carrier ------------------------------------- + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: TXCARR\n"); + pAdapter->ate.Mode = ATE_TXCARR; + + BbpData |= 0x40; + MacData |= 0x04000000; + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + for (i = 0; (i < TX_RING_SIZE) && (i < pAdapter->ate.TxCount); i++) + { + pTxD = (PTXD_STRUC)pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + + // Prepare frame payload + memcpy(pDest, &TempletFrame, LENGTH_802_11); + for(j = LENGTH_802_11; j < pAdapter->ate.TxLength; j++) + pDest[j] = 0xAA; + memcpy(&pDest[4], &pAdapter->ate.Addr1, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[10], &pAdapter->ate.Addr2, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[16], &pAdapter->ate.Addr3, ETH_LENGTH_OF_ADDRESS); + + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, + SHORT_RETRY, IFS_BACKOFF, pAdapter->ate.TxRate, 4, + pAdapter->ate.TxLength, pAdapter->PortCfg.TxPreambleInUsed, 0); + + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + } + + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0xffffffff); + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + } + else if (!strcmp(arg, "TXFRAME")) // Tx Frames -------------------------------------- + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: TXFRAME(Count=%d)\n", pAdapter->ate.TxCount); + pAdapter->ate.Mode = ATE_TXFRAME; + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + pAdapter->ate.TxDoneCount = 0; + + for (i = 0; (i < TX_RING_SIZE) && (i < pAdapter->ate.TxCount); i++) + { + pTxD = (PTXD_STRUC)pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; + + // Prepare frame payload + memcpy(pDest, &TempletFrame, LENGTH_802_11); + for(j = LENGTH_802_11; j < pAdapter->ate.TxLength; j++) + pDest[j] = 0xAA; + memcpy(&pDest[4], &pAdapter->ate.Addr1, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[10], &pAdapter->ate.Addr2, ETH_LENGTH_OF_ADDRESS); + memcpy(&pDest[16], &pAdapter->ate.Addr3, ETH_LENGTH_OF_ADDRESS); + + RTMPWriteTxDescriptor(pTxD, TRUE, CIPHER_NONE, FALSE, FALSE, FALSE, + SHORT_RETRY, IFS_BACKOFF, pAdapter->ate.TxRate, 4, + pAdapter->ate.TxLength, Rt802_11PreambleLong, 0); + + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + } + pAdapter->ate.TxDoneCount += i; + DBGPRINT(RT_DEBUG_TRACE, "TXFRAME txcount=%d\n", pAdapter->ate.TxCount); + DBGPRINT(RT_DEBUG_TRACE, "pAdapter->ate.TxDoneCount = %d\n", pAdapter->ate.TxDoneCount); + + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0xffffffff); + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + } + else if (!strcmp(arg, "RXFRAME")) // Rx Frames -------------------------------------- + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: RXFRAME\n"); + + RTMP_IO_WRITE32(pAdapter, MACCSR1, MacData); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 63, BbpData); + + pAdapter->ate.Mode = ATE_RXFRAME; + pAdapter->ate.TxDoneCount = pAdapter->ate.TxCount; + + RTMP_IO_WRITE32(pAdapter, TXCSR0, 0x08); // Abort Tx + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x56); // Start Rx + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "ATE: Invalid arg!\n"); + return FALSE; + } + + mdelay(5); + + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_Proc\n"); + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE ADDR1=DA for TxFrames Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_DA_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + char *value; + int i; + + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_DA_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 + return FALSE; + + for (i=0, value = strtok(arg,":"); value; value = strtok(NULL,":")) + { + if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) + return FALSE; //Invalid + + AtoH(value, &pAdapter->ate.Addr1[i++], 2); + } + + if(i != 6) + return FALSE; //Invalid + + DBGPRINT(RT_DEBUG_TRACE, "DA=%2X:%2X:%2X:%2X:%2X:%2X\n", pAdapter->ate.Addr1[0], pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5]); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_DA_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE ADDR2=SA for TxFrames Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_SA_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + char *value; + int i; + + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_SA_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 + return FALSE; + + for (i=0, value = strtok(arg,":"); value; value = strtok(NULL,":")) + { + if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) + return FALSE; //Invalid + + AtoH(value, &pAdapter->ate.Addr2[i++], 2); + } + + if(i != 6) + return FALSE; //Invalid + + DBGPRINT(RT_DEBUG_TRACE, "DA=%2X:%2X:%2X:%2X:%2X:%2X\n", pAdapter->ate.Addr2[0], pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5]); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_SA_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE ADDR3=BSSID for TxFrames Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_BSSID_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + char *value; + int i; + + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_BSSID_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 + return FALSE; + + for (i=0, value = strtok(arg,":"); value; value = strtok(NULL,":")) + { + if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) + return FALSE; //Invalid + + AtoH(value, &pAdapter->ate.Addr3[i++], 2); + } + + if(i != 6) + return FALSE; //Invalid + + DBGPRINT(RT_DEBUG_TRACE, "DA=%2X:%2X:%2X:%2X:%2X:%2X\n", pAdapter->ate.Addr3[0], pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5]); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_BSSID_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE Channel Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_CHANNEL_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_CHANNEL_Proc (arg = %s)\n", arg); + + pAdapter->ate.Channel = simple_strtol(arg, 0, 10); + if((pAdapter->ate.Channel < 1) || (pAdapter->ate.Channel > 14)) + { + pAdapter->ate.Channel = 1; + return FALSE; + } + + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAdapter->ate.Channel); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE Tx Power Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_TX_POWER_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + ULONG R3; + + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_TX_POWER_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + pAdapter->ate.TxPower = simple_strtol(arg, 0, 10); + + if(pAdapter->ate.TxPower >= 32) + { + pAdapter->ate.TxPower = pAdapter->PortCfg.ChannelTxPower[pAdapter->PortCfg.Channel - 1];; + return FALSE; + } + + R3 = pAdapter->ate.TxPower; + R3 = R3 << 9; // shift TX power control to correct RF register bit position + + R3 |= (pAdapter->PortCfg.LatchRfRegs.R3 & 0xffffc1ff); + RTMP_RF_IO_WRITE32(pAdapter, R3); + + DBGPRINT(RT_DEBUG_TRACE, "TxPower = %d\n", pAdapter->ate.TxPower); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_TX_POWER_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE Tx Length Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_TX_LENGTH_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_TX_LENGTH_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + pAdapter->ate.TxLength = simple_strtol(arg, 0, 10); + + if((pAdapter->ate.TxLength < 24) || (pAdapter->ate.TxLength > 1500)) + { + pAdapter->ate.TxLength = 1500; + return FALSE; + } + + DBGPRINT(RT_DEBUG_TRACE, "TxLength = %d\n", pAdapter->ate.TxLength); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_TX_LENGTH_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE Tx Count Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_TX_COUNT_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_TX_COUNT_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + pAdapter->ate.TxCount = simple_strtol(arg, 0, 10); + + DBGPRINT(RT_DEBUG_TRACE, "TxCount = %d\n", pAdapter->ate.TxCount); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_TX_COUNT_Proc\n"); + + return TRUE; +} + +/* + ========================================================================== + Description: + Set ATE Tx Rate + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== +*/ +INT Set_ATE_TX_RATE_Proc( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR arg) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> Set_ATE_TX_RATE_Proc\n"); + DBGPRINT(RT_DEBUG_TRACE, "arg=%s\n", arg); + + pAdapter->ate.TxRate = simple_strtol(arg, 0, 10); + + if(pAdapter->ate.TxRate > RATE_54) + { + pAdapter->ate.TxRate = RATE_11; + return FALSE; + } + + DBGPRINT(RT_DEBUG_TRACE, "TxRate = %d\n", pAdapter->ate.TxRate); + DBGPRINT(RT_DEBUG_TRACE, "<== Set_ATE_TX_RATE_Proc\n"); + + return TRUE; +} + +VOID RTMPStationStop( + IN PRTMP_ADAPTER pAd) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> RTMPStationStop\n"); + RTMPCancelTimer(&pAd->timer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.AssocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.ReassocTimer); + RTMPCancelTimer(&pAd->Mlme.AssocAux.DisassocTimer); + RTMPCancelTimer(&pAd->Mlme.AuthAux.AuthTimer); + RTMPCancelTimer(&pAd->Mlme.AuthRspAux.AuthRspTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + RTMPCancelTimer(&pAd->Mlme.PeriodicTimer); + RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer); + if (pAd->PortCfg.LedMode == LED_MODE_TXRX_ACTIVITY) + RTMPCancelTimer(&pAd->PortCfg.LedCntl.BlinkTimer); + RTMPCancelTimer(&pAd->PortCfg.RxAnt.RxAntDiversityTimer); + DBGPRINT(RT_DEBUG_TRACE, "<== RTMPStationStop\n"); +} + +VOID RTMPStationStart( + IN PRTMP_ADAPTER pAd) +{ + DBGPRINT(RT_DEBUG_TRACE, "==> RTMPStationStart\n"); + RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); + //RTMPSetTimer(pAd, &pAd->timer, DEBUG_TASK_DELAY); //not used. + DBGPRINT(RT_DEBUG_TRACE, "<== RTMPStationStart\n"); +} + +#endif //#ifdef RALINK_ATE + + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_init.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_init.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_init.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,2461 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_init.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulL 1st Aug 02 Initial code + * MarkW 8th Dec 04 Baseline code + * MarkW (rt2400) 8th Dec 04 Promisc mode support + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 + * LuisCorreia 15th Feb 05 Added Yann's patch for radio hw + * MarkW 12th Jul 05 Disabled all but CAM Power modes + ***************************************************************************/ + +#include "rt_config.h" + +// +// BBP register initialization set +// +ULONG BBPRegTable[] = { + 0x00018302, // R03 + 0x00018419, // R04 + 0x00018E1C, // R14 + 0x00018F30, // R15 + 0x000190ac, // R16 + 0x00019148, // R17 + 0x00019218, // R18 + 0x000193ff, // R19 + 0x0001941E, // R20 + 0x00019508, // R21 + 0x00019608, // R22 + 0x00019708, // R23 + 0x00019870, // R24 + 0x00019940, // R25 + 0x00019A08, // R26 + 0x00019B23, // R27 + 0x00019E10, // R30 + 0x00019F2B, // R31 + 0x0001A0B9, // R32 + 0x0001A212, // R34 + 0x0001A350, // R35 + 0x0001A7c4, // R39 + 0x0001A802, // R40 + 0x0001A960, // R41 + 0x0001B510, // R53 + 0x0001B618, // R54 + 0x0001B808, // R56 + 0x0001B910, // R57 + 0x0001BA08, // R58 + 0x0001BD6d, // R61 + 0x0001BE10, // R62 +}; + +// +// MAC register initialization sets +// +RTMP_REG_PAIR MACRegTable[] = { + {PSCSR0, 0x00020002}, // 0xc8 + {PSCSR1, 0x00000002}, // 0xcc +// {PSCSR2, 0x00023f20}, // 0xd0 + {PSCSR2, 0x00020002}, // 0xd0 + {PSCSR3, 0x00000002}, // 0xd4 + {TIMECSR, 0x00003f21}, // 0xDC, to slower down our 1-us tick + {CSR9, 0x00000780}, // 0x24 + {CSR11, 0x07041483}, // 0x2C, lrc=7, src=4, slot=20us, CWmax=2^8, CWmax=2^3 + {CSR18, 0x00140000}, // SIFS=10us - TR switch time, PIFS=SIFS+20us + {CSR19, 0x016C0028}, // DIFS=SIFS+2*20us, EIFS=364us + {CNT3, 0x00000000}, // Backoff_CCA_Th, RX_&_TX_CCA_Th + + {TXCSR1, 0x07614562}, // 0x64, ACK as 1Mb time + {TXCSR8, 0x8c8d8b8a}, // 0x98, CCK TX BBP register ID + //{TXCSR9, 0x86870885}, // 0x94, OFDM TX BBP register ID + + {ARCSR1, 0x0000000f}, // 0x9c, Basic rate set bitmap + {PLCP1MCSR, 0x00700400}, // 0x13c, ACK/CTS PLCP at 1 Mbps + {PLCP2MCSR, 0x00380401}, // 0x140, ACK/CTS PLCP at 2 Mbps + {PLCP5MCSR, 0x00150402}, // 0x144, ACK/CTS PLCP at 5.5 Mbps + {PLCP11MCSR,0x000b8403}, // 0x148, ACK/CTS PLCP at 11 Mbps + + {ARTCSR0, 0x7038140a}, // 0x14c, ACK/CTS payload consumed time for 1/2/5.5/11 mbps + {ARTCSR1, 0x1d21252d}, // 0x150, alexsu : OFDM ACK/CTS payload consumed time for 18/12/9/6 mbps + {ARTCSR2, 0x1919191d}, // 0x154, alexsu : OFDM ACK/CTS payload consumed time for 54/48/36/24 mbps + + {RXCSR0, 0xffffffff}, // 0x80 + {RXCSR3, 0xb3aab3af}, // 0x90. RT2530 BBP 51:RSSI, R42:OFDM rate, R47:CCK SIGNAL + {PCICSR, 0x000003b8}, // 0x8c, alexsu : PCI control register + {PWRCSR0, 0x3f3b3100}, // 0xC4 + {GPIOCSR, 0x0000ff00}, // 0x120, GPIO default value + {TESTCSR, 0x000000f0}, // 0x138, Test CSR, make sure it's running at normal mode + {PWRCSR1, 0x000001ff}, // 0xd8 + {MACCSR0, 0x00213223}, // 0xE0, Enable Tx dribble mode - 2003/10/22:Gary + {MACCSR1, 0x00235518}, // 0xE4, Disable Rx Reset, tx dribble count, 2x30x16 = 960n, + {MACCSR2, 0x00000040}, // 0x0134, 64*33ns = 2us + {RALINKCSR, 0x9a009a11}, // 0xE8 + {CSR7, 0xffffffff}, // 0x1C, Clear all pending interrupt source + {LEDCSR, 0x00001E46}, // default both LEDs off + {BBPCSR1, 0x82188200}, // for 2560+2522 + {TXACKCSR0, 0x00000020}, // 0x110, TX ACK timeout in usec + {SECCSR3, 0x0000e78f}, // AES, mask off more data bit for MIC calculation +}; + +#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(ULONG)) +#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) + +/* + ======================================================================== + + Routine Description: + Allocate all DMA releated resources + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +NDIS_STATUS RTMPAllocDMAMemory( + IN PRTMP_ADAPTER pAd) +{ + INT index; + VOID *ring; // VA of ring descriptor + VOID *ring_data; // VA of DMA data buffer + dma_addr_t ring_dma; // PA of ring descriptor + dma_addr_t ring_data_dma; // PA of DMA data buffer + PTXD_STRUC pTxD; // Tx type ring descriptor + PRXD_STRUC pRxD; // Rx type ring descriptor + + DBGPRINT(RT_DEBUG_INFO, "--> RTMPAllocDMAMemory\n"); + + // 1. Allocate Tx Ring DMA descriptor and buffer memory + // Allocate Ring descriptors DMA block + ring = pci_alloc_consistent(pAd->pPci_Dev, (TX_RING_SIZE * RING_DESCRIPTOR_SIZE), &ring_dma); + if (!ring) { + printk(KERN_ERR DRV_NAME "Could not allocate DMA ring descriptor memory.\n"); + goto err_out_allocate_txring; + } + + // Zero init ring descriptors + memset(ring, 0, (TX_RING_SIZE * RING_DESCRIPTOR_SIZE)); + + // Allocate Ring data DMA blocks + ring_data = pci_alloc_consistent(pAd->pPci_Dev, (TX_RING_SIZE * TX_BUFFER_SIZE), &ring_data_dma); + + // If failed, release ring descriptors DMA block & exit + if (!ring_data) { + pci_free_consistent(pAd->pPci_Dev, (TX_RING_SIZE * RING_DESCRIPTOR_SIZE), ring, ring_dma); + printk(KERN_ERR DRV_NAME "Could not allocate DMA ring buffer memory.\n"); + goto err_out_allocate_txring; + } + + // Start with Tx ring & DMA buffer + for (index = 0; index < TX_RING_SIZE; index++) + { + // Init Tx Ring Size, Va, Pa variables + pAd->TxRing[index].size = RING_DESCRIPTOR_SIZE; + pAd->TxRing[index].va_addr = ring; + pAd->TxRing[index].pa_addr = ring_dma; + ring += RING_DESCRIPTOR_SIZE; + ring_dma += RING_DESCRIPTOR_SIZE; + + // Init Tx DMA buffer + pAd->TxRing[index].data_size = TX_BUFFER_SIZE; + pAd->TxRing[index].va_data_addr = ring_data; + pAd->TxRing[index].pa_data_addr = ring_data_dma; + ring_data += TX_BUFFER_SIZE; + ring_data_dma += TX_BUFFER_SIZE; + + // Write TxD buffer address & allocated buffer length + pTxD = (PTXD_STRUC) pAd->TxRing[index].va_addr; +#ifndef BIG_ENDIAN + pTxD->BufferAddressPa = pAd->TxRing[index].pa_data_addr; +#else + pTxD->BufferAddressPa = SWAP32(pAd->TxRing[index].pa_data_addr); +#endif + + DBGPRINT(RT_DEBUG_INFO, "TxRing[%d] va = 0x%lu, pa = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->TxRing[index].va_addr, (UINT)pAd->TxRing[index].pa_addr, pAd->TxRing[index].size); + DBGPRINT(RT_DEBUG_INFO, "TxRing[%d] va_data = 0x%lu, pa_data = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->TxRing[index].va_data_addr, (UINT)pAd->TxRing[index].pa_data_addr, pAd->TxRing[index].data_size); + } + + // 2. Allocate Prio Ring DMA descriptor and buffer memory + // Allocate Ring descriptors DMA block + ring = pci_alloc_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * RING_DESCRIPTOR_SIZE), &ring_dma); + if (!ring) { + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring descriptor memory.\n"); + goto err_out_allocate_prioring; + } + + // Zero init ring descriptors + memset(ring, 0, (PRIO_RING_SIZE * RING_DESCRIPTOR_SIZE)); + + // Allocate Ring data DMA blocks + ring_data = pci_alloc_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * PRIO_BUFFER_SIZE), &ring_data_dma); + + // If failed, release ring descriptors DMA block & exit + if (!ring_data) { + pci_free_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * RING_DESCRIPTOR_SIZE), ring, ring_dma); + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring buffer memory.\n"); + goto err_out_allocate_prioring; + } + + // Second with Prio ring & DMA buffer + for (index = 0; index < PRIO_RING_SIZE; index++) + { + // Init Prio Ring Size, Va, Pa variables + pAd->PrioRing[index].size = RING_DESCRIPTOR_SIZE; + pAd->PrioRing[index].va_addr = ring; + pAd->PrioRing[index].pa_addr = ring_dma; + ring += RING_DESCRIPTOR_SIZE; + ring_dma += RING_DESCRIPTOR_SIZE; + + // Init Prio DMA buffer + pAd->PrioRing[index].data_size = PRIO_BUFFER_SIZE; + pAd->PrioRing[index].va_data_addr = ring_data; + pAd->PrioRing[index].pa_data_addr = ring_data_dma; + ring_data += PRIO_BUFFER_SIZE; + ring_data_dma += PRIO_BUFFER_SIZE; + + // Write TxD buffer address & allocated buffer length for priority ring + pTxD = (PTXD_STRUC) pAd->PrioRing[index].va_addr; +#ifndef BIG_ENDIAN + pTxD->BufferAddressPa = pAd->PrioRing[index].pa_data_addr; +#else + pTxD->BufferAddressPa = SWAP32(pAd->PrioRing[index].pa_data_addr); +#endif + + DBGPRINT(RT_DEBUG_INFO, "PrioRing[%d] va = 0x%lu, pa = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->PrioRing[index].va_addr, (UINT)pAd->PrioRing[index].pa_addr, pAd->PrioRing[index].size); + DBGPRINT(RT_DEBUG_INFO, "PrioRing[%d] va_data = 0x%lu, pa_data = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->PrioRing[index].va_data_addr, (UINT)pAd->PrioRing[index].pa_data_addr, pAd->PrioRing[index].data_size); + } + + // 3. Allocate Atim Ring DMA descriptor and buffer memory + // Allocate Ring descriptors DMA block + ring = pci_alloc_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * RING_DESCRIPTOR_SIZE), &ring_dma); + if (!ring) { + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring descriptor memory.\n"); + goto err_out_allocate_atimring; + } + + // Zero init ring descriptors + memset(ring, 0, (ATIM_RING_SIZE * RING_DESCRIPTOR_SIZE)); + + // Allocate Ring data DMA blocks + ring_data = pci_alloc_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * ATIM_BUFFER_SIZE), &ring_data_dma); + + // If failed, release ring descriptors DMA block & exit + if (!ring_data) { + pci_free_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * RING_DESCRIPTOR_SIZE), ring, ring_dma); + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring buffer memory.\n"); + goto err_out_allocate_atimring; + } + + // Atim ring & DMA buffer + for (index = 0; index < ATIM_RING_SIZE; index++) + { + // Init Atim Ring Size, Va, Pa variables + pAd->AtimRing[index].size = RING_DESCRIPTOR_SIZE; + pAd->AtimRing[index].va_addr = ring; + pAd->AtimRing[index].pa_addr = ring_dma; + ring += RING_DESCRIPTOR_SIZE; + ring_dma += RING_DESCRIPTOR_SIZE; + + // Init Atim DMA buffer + pAd->AtimRing[index].data_size = ATIM_BUFFER_SIZE; + pAd->AtimRing[index].va_data_addr = ring_data; + pAd->AtimRing[index].pa_data_addr = ring_data_dma; + ring_data += ATIM_BUFFER_SIZE; + ring_data_dma += ATIM_BUFFER_SIZE; + + // Write TxD buffer address & allocated buffer length + pTxD = (PTXD_STRUC) pAd->AtimRing[index].va_addr; +#ifndef BIG_ENDIAN + pTxD->BufferAddressPa = pAd->AtimRing[index].pa_data_addr; +#else + pTxD->BufferAddressPa = SWAP32(pAd->AtimRing[index].pa_data_addr); +#endif + + DBGPRINT(RT_DEBUG_INFO, "AtimRing[%d] va = 0x%lu, pa = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->AtimRing[index].va_addr, (UINT)pAd->AtimRing[index].pa_addr, pAd->AtimRing[index].size); + DBGPRINT(RT_DEBUG_INFO, "AtimRing[%d] va_data = 0x%lu, pa_data = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->AtimRing[index].va_data_addr, (UINT)pAd->AtimRing[index].pa_data_addr, pAd->AtimRing[index].data_size); + } + + // 4. Allocate Rx Ring DMA descriptor and buffer memory + // Allocate Ring descriptors DMA block + ring = pci_alloc_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RING_DESCRIPTOR_SIZE), &ring_dma); + if (!ring) { + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring descriptor memory.\n"); + goto err_out_allocate_rxring; + } + + // Zero init ring descriptors + memset(ring, 0, (RX_RING_SIZE * RING_DESCRIPTOR_SIZE)); + + // Allocate Ring data DMA blocks + ring_data = pci_alloc_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RX_BUFFER_SIZE), &ring_data_dma); + + // If failed, release ring descriptors DMA block & exit + if (!ring_data) { + pci_free_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RING_DESCRIPTOR_SIZE), ring, ring_dma); + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring buffer memory.\n"); + goto err_out_allocate_rxring; + } + + // Rx ring & DMA buffer + for (index = 0; index < RX_RING_SIZE; index++) + { + // Init Rx Ring Size, Va, Pa variables + pAd->RxRing[index].size = RING_DESCRIPTOR_SIZE; + pAd->RxRing[index].va_addr = ring; + pAd->RxRing[index].pa_addr = ring_dma; + ring += RING_DESCRIPTOR_SIZE; + ring_dma += RING_DESCRIPTOR_SIZE; + + // Init Rx DMA buffer + pAd->RxRing[index].data_size = RX_BUFFER_SIZE; + pAd->RxRing[index].va_data_addr = ring_data; + pAd->RxRing[index].pa_data_addr = ring_data_dma; + ring_data += RX_BUFFER_SIZE; + ring_data_dma += RX_BUFFER_SIZE; + + // Write RxD buffer address & allocated buffer length + pRxD = (PRXD_STRUC) pAd->RxRing[index].va_addr; +#ifndef BIG_ENDIAN + pRxD->BufferAddressPa = pAd->RxRing[index].pa_data_addr; +#else + pRxD->BufferAddressPa = SWAP32(pAd->RxRing[index].pa_data_addr); +#endif + // Rx owner bit assign to NIC immediately + pRxD->Owner = DESC_OWN_NIC; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); +#endif + + DBGPRINT(RT_DEBUG_INFO, "RxRing[%d] va = 0x%lu, pa = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->RxRing[index].va_addr, (UINT)pAd->RxRing[index].pa_addr, pAd->RxRing[index].size); + DBGPRINT(RT_DEBUG_INFO, "RxRing[%d] va_data = 0x%lu, pa_data = 0x%x, size = 0x%x\n", + index, (unsigned long)pAd->RxRing[index].va_data_addr, (UINT)pAd->RxRing[index].pa_data_addr, pAd->RxRing[index].data_size); + } + + // 5. Allocate Beacon Ring DMA descriptor and buffer memory + // Init Beacon Ring Size, Va, Pa variables + ring = pci_alloc_consistent(pAd->pPci_Dev, RING_DESCRIPTOR_SIZE, &ring_dma); + if (!ring) { + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring descriptor memory.\n"); + goto err_out_allocate_beaconring; + } + + // Zero init ring descriptors + memset(ring, 0, (RING_DESCRIPTOR_SIZE)); + + // Allocate Ring data DMA blocks + ring_data = pci_alloc_consistent(pAd->pPci_Dev, BEACON_BUFFER_SIZE, &ring_data_dma); + + // If failed, release ring descriptors DMA block & exit + if (!ring_data) { + pci_free_consistent(pAd->pPci_Dev, RING_DESCRIPTOR_SIZE, ring, ring_dma); + DBGPRINT(RT_DEBUG_ERROR, "Could not allocate DMA ring buffer memory.\n"); + goto err_out_allocate_beaconring; + } + + pAd->BeaconRing.size = RING_DESCRIPTOR_SIZE; + pAd->BeaconRing.va_addr = ring; + pAd->BeaconRing.pa_addr = ring_dma; + + // Init Beacon DMA buffer + pAd->BeaconRing.data_size = BEACON_BUFFER_SIZE; + pAd->BeaconRing.va_data_addr = ring_data; + pAd->BeaconRing.pa_data_addr = ring_data_dma; + + // Write RxD buffer address & allocated buffer length + pTxD = (PTXD_STRUC) pAd->BeaconRing.va_addr; +#ifndef BIG_ENDIAN + pTxD->BufferAddressPa = pAd->BeaconRing.pa_data_addr; +#else + pTxD->BufferAddressPa = SWAP32(pAd->BeaconRing.pa_data_addr); +#endif + + DBGPRINT(RT_DEBUG_INFO, "BeaconRing va = 0x%lu, pa = 0x%x, size = 0x%x\n", + (unsigned long)pAd->BeaconRing.va_addr, (UINT)pAd->BeaconRing.pa_addr, pAd->BeaconRing.size); + DBGPRINT(RT_DEBUG_INFO, "BeaconRing va_data = 0x%lu, pa_data = 0x%x, size = 0x%x\n", + (unsigned long)pAd->BeaconRing.va_data_addr, (UINT)pAd->BeaconRing.pa_data_addr, pAd->BeaconRing.data_size); + + DBGPRINT(RT_DEBUG_INFO, "<-- RTMPAllocDMAMemory\n"); + return NDIS_STATUS_SUCCESS; + + +err_out_allocate_beaconring: + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RX_BUFFER_SIZE), + pAd->RxRing[0].va_data_addr, pAd->RxRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->RxRing[0].va_addr, pAd->RxRing[0].pa_addr); +err_out_allocate_rxring: + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * ATIM_BUFFER_SIZE), + pAd->AtimRing[0].va_data_addr, pAd->AtimRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->AtimRing[0].va_addr, pAd->AtimRing[0].pa_addr); +err_out_allocate_atimring: + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * PRIO_BUFFER_SIZE), + pAd->PrioRing[0].va_data_addr, pAd->PrioRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->PrioRing[0].va_addr, pAd->PrioRing[0].pa_addr); +err_out_allocate_prioring: + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (TX_RING_SIZE * TX_BUFFER_SIZE), + pAd->TxRing[0].va_data_addr, pAd->TxRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (TX_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->TxRing[0].va_addr, pAd->TxRing[0].pa_addr); +err_out_allocate_txring: + DBGPRINT(RT_DEBUG_ERROR, "<-- RTMPAllocDMAMemory (memory not allocate successfully!)\n"); + + return -ENOMEM; +} + +/* + ======================================================================== + + Routine Description: + Free all DMA memory. + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPFreeDMAMemory( + IN PRTMP_ADAPTER pAd) +{ + DBGPRINT(RT_DEBUG_INFO, "--> RTMPFreeDMAMemory\n"); + + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (TX_RING_SIZE * TX_BUFFER_SIZE), + pAd->TxRing[0].va_data_addr, pAd->TxRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (TX_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->TxRing[0].va_addr, pAd->TxRing[0].pa_addr); + + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * PRIO_BUFFER_SIZE), + pAd->PrioRing[0].va_data_addr, pAd->PrioRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (PRIO_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->PrioRing[0].va_addr, pAd->PrioRing[0].pa_addr); + + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * ATIM_BUFFER_SIZE), + pAd->AtimRing[0].va_data_addr, pAd->AtimRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (ATIM_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->AtimRing[0].va_addr, pAd->AtimRing[0].pa_addr); + + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RX_BUFFER_SIZE), + pAd->RxRing[0].va_data_addr, pAd->RxRing[0].pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (RX_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->RxRing[0].va_addr, pAd->RxRing[0].pa_addr); + + // Free data DMA blocks first, the start address is the same as TxRing first DMA data block + pci_free_consistent(pAd->pPci_Dev, (BEACON_RING_SIZE * BEACON_BUFFER_SIZE), + pAd->BeaconRing.va_data_addr, pAd->BeaconRing.pa_data_addr); + // Free ring descriptor second, the start address is the same as TxRing first elment + pci_free_consistent(pAd->pPci_Dev, (BEACON_RING_SIZE * RING_DESCRIPTOR_SIZE), + pAd->BeaconRing.va_addr, pAd->BeaconRing.pa_addr); + +} + +/* + ======================================================================== + + Routine Description: + Initialize transmit data structures + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + Initialize all transmit releated private buffer, include those define + in RTMP_ADAPTER structure and all private data structures. + + ======================================================================== +*/ +VOID NICInitTransmit( + IN PRTMP_ADAPTER pAdapter) +{ + DBGPRINT(RT_DEBUG_TRACE, "--> NICInitTransmit\n"); + + // Initialize all Transmit releated queues + skb_queue_head_init(&pAdapter->TxSwQueue0); + skb_queue_head_init(&pAdapter->TxSwQueue1); + skb_queue_head_init(&pAdapter->TxSwQueue2); + skb_queue_head_init(&pAdapter->TxSwQueue3); + + // Init Ring index pointer + pAdapter->CurRxIndex = 0; + pAdapter->CurDecryptIndex = 0; + pAdapter->CurTxIndex = 0; + pAdapter->CurEncryptIndex = 0; + pAdapter->CurAtimIndex = 0; + pAdapter->CurPrioIndex = 0; + pAdapter->NextEncryptDoneIndex = 0; + pAdapter->NextTxDoneIndex = 0; + pAdapter->NextAtimDoneIndex = 0; + pAdapter->NextPrioDoneIndex = 0; + pAdapter->NextDecryptDoneIndex = 0; + pAdapter->PushMgmtIndex = 0; + pAdapter->PopMgmtIndex = 0; + pAdapter->MgmtQueueSize = 0; + + pAdapter->PrivateInfo.TxRingFullCnt = 0; + + DBGPRINT(RT_DEBUG_TRACE, "<-- NICInitTransmit\n"); +} + +/* + ======================================================================== + + Routine Description: + Read additional information from EEPROM, such as MAC address + + Arguments: + Adapter Pointer to our adapter + + Return Value: + NDIS_STATUS_SUCCESS + NDIS_STATUS_FAILURE + + Note: + + ======================================================================== +*/ +NDIS_STATUS NICReadAdapterInfo( + IN PRTMP_ADAPTER pAd) +{ + CSR3_STRUC StaMacReg0; + CSR4_STRUC StaMacReg1; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + // + // Read MAC address from CSR3 & CSR4, these CSRs reflects real value + // stored with EEPROM. + // + RTMP_IO_READ32(pAd, CSR3, &StaMacReg0.word); + RTMP_IO_READ32(pAd, CSR4, &StaMacReg1.word); + // Set Current address + pAd->CurrentAddress[0] = StaMacReg0.field.Byte0; + pAd->CurrentAddress[1] = StaMacReg0.field.Byte1; + pAd->CurrentAddress[2] = StaMacReg0.field.Byte2; + pAd->CurrentAddress[3] = StaMacReg0.field.Byte3; + pAd->CurrentAddress[4] = StaMacReg1.field.Byte4; + pAd->CurrentAddress[5] = StaMacReg1.field.Byte5; + pAd->PermanentAddress[0] = StaMacReg0.field.Byte0; + pAd->PermanentAddress[1] = StaMacReg0.field.Byte1; + pAd->PermanentAddress[2] = StaMacReg0.field.Byte2; + pAd->PermanentAddress[3] = StaMacReg0.field.Byte3; + pAd->PermanentAddress[4] = StaMacReg1.field.Byte4; + pAd->PermanentAddress[5] = StaMacReg1.field.Byte5; + + return Status; +} + +/* + ======================================================================== + + Routine Description: + Read initial parameters from EEPROM + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID NICReadEEPROMParameters( + IN PRTMP_ADAPTER pAdapter) +{ + ULONG data; + USHORT i, value; + UCHAR TmpPhy; + EEPROM_TX_PWR_STRUC Power; + EEPROM_VERSION_STRUC Version; + EEPROM_ANTENNA_STRUC Antenna; + + DBGPRINT(RT_DEBUG_TRACE, "--> NICReadEEPROMParameters\n"); + + // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 + RTMP_IO_READ32(pAdapter, CSR21, &data); + + if(data & 0x20) + pAdapter->EEPROMAddressNum = 6; + else + pAdapter->EEPROMAddressNum = 8; + + // if E2PROM version mismatch with driver's expectation, then skip + // all subsequent E2RPOM retieval and set a system error bit to notify GUI + Version.word = RTMP_EEPROM_READ16(pAdapter, EEPROM_VERSION_OFFSET); + if (Version.field.Version != VALID_EEPROM_VERSION) + { + DBGPRINT(RT_DEBUG_ERROR, "WRONG E2PROM VERSION %d, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION); + pAdapter->PortCfg.SystemErrorBitmap |= 0x00000001; + return; + } + + // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAdapter + for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) + { + value = RTMP_EEPROM_READ16(pAdapter, EEPROM_BBP_BASE_OFFSET + i*2); + + pAdapter->EEPROMDefaultValue[i] = value; + } + +#if 1 + // We have to parse NIC configuration 0 at here. + // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false + // Therefore, we have to read TxAutoAgc control beforehand. + // Read Tx AGC control bit + Antenna.word = pAdapter->EEPROMDefaultValue[0]; + if (Antenna.field.DynamicTxAgcControl == 1) + pAdapter->PortCfg.bAutoTxAgc = TRUE; + else + pAdapter->PortCfg.bAutoTxAgc = FALSE; + + // Read Tx power value for all 14 channels + // Value from 0 - 31. Default value is 24. + // Krellan: Log values read from EEPROM, to aid troubleshooting + printk(KERN_DEBUG DRV_NAME " EEPROM:"); + for (i = 0; i < NUM_EEPROM_TX_PARMS; i++) + { + printk("%3d%3d", (i * 2) + 1, (i * 2) + 2); + } + printk(" Channel\n"); + printk(KERN_DEBUG DRV_NAME " EEPROM:"); + for (i = 0; i < NUM_EEPROM_TX_PARMS; i++) + { + UCHAR by0; + UCHAR by1; + Power.word = RTMP_EEPROM_READ16(pAdapter, EEPROM_TX_PWR_OFFSET + i*2); + by0 = Power.field.Byte0; + by1 = Power.field.Byte1; + pAdapter->PortCfg.ChannelTxPower[i * 2] = ((by0 > 32) ? 24 : by0); + pAdapter->PortCfg.ChannelTxPower[i * 2 + 1] = ((by1 > 32) ? 24 : by1); + // Krellan: This is the theoretical max dBm value possible (raw + // power 31), which will most likely be a small positive number + // of dBm, since we scale a user setting of 0 dBm to correspond + // to exactly the recommended value from the EEPROM, a raw + // power value usually just a little bit under the max of 31. + printk("%3d%3d", 31 - ((int)by0), 31 - ((int)by1)); + } + printk(" dBm Maximum\n"); + + // Read Tx TSSI reference value, OK to reuse Power data structure + for (i = 0; i < NUM_EEPROM_TX_PARMS; i++) + { + Power.word = RTMP_EEPROM_READ16(pAdapter, EEPROM_TSSI_REF_OFFSET + i * 2); + pAdapter->PortCfg.ChannelTssiRef[i * 2] = Power.field.Byte0; + pAdapter->PortCfg.ChannelTssiRef[i * 2 + 1] = Power.field.Byte1; + // Disable TxAgc if the value is not right + if ((pAdapter->PortCfg.ChannelTssiRef[i * 2] == 0xff) || + (pAdapter->PortCfg.ChannelTssiRef[i * 2 + 1] == 0xff)) + pAdapter->PortCfg.bAutoTxAgc = FALSE; + } + + // Tx Tssi delta offset 0x24 + Power.word = RTMP_EEPROM_READ16(pAdapter, EEPROM_TSSI_DELTA_OFFSET); + pAdapter->PortCfg.ChannelTssiDelta = Power.field.Byte0; + +#endif + + //CountryRegion byte offset = 0x35 + value = pAdapter->EEPROMDefaultValue[2] >> 8; + if ((value <= 7)) + { + pAdapter->PortCfg.CountryRegion = (UCHAR) value; + TmpPhy = pAdapter->PortCfg.PhyMode; + pAdapter->PortCfg.PhyMode = 0xff; + RTMPSetPhyMode(pAdapter, TmpPhy); + } + + // Read new Calibrated CV value, reuse the power variable + Power.word = RTMP_EEPROM_READ16(pAdapter, EEPROM_CALIBRATE_OFFSET); + if (Power.field.Byte0 == 0xff) + { + //pAdapter->PortCfg.R17Dec = 0; + pAdapter->PortCfg.RssiToDbm = 0x79; + } + else + { + //pAdapter->PortCfg.R17Dec = 0x79 - Power.field.Byte0; + pAdapter->PortCfg.RssiToDbm = Power.field.Byte0; + } + + + DBGPRINT(RT_DEBUG_TRACE, "<-- NICReadEEPROMParameters\n"); +} + +/* + ======================================================================== + + Routine Description: + Set default value from EEPROM + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID NICInitAsicFromEEPROM( + IN PRTMP_ADAPTER pAdapter) +{ + ULONG data, BbpCsr1; + USHORT i, value; + UCHAR TxValue,RxValue; + EEPROM_ANTENNA_STRUC Antenna; + EEPROM_NIC_CONFIG2_STRUC NicConfig2; + + DBGPRINT(RT_DEBUG_TRACE, "--> NICInitAsicFromEEPROM\n"); + + for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) + { + value = pAdapter->EEPROMDefaultValue[i]; + + if((value != 0xFFFF) && (value != 0)) + { + data = value | 0x18000; + RTMP_BBP_IO_WRITE32(pAdapter, data); + } + } + + Antenna.word = pAdapter->EEPROMDefaultValue[0]; + DBGPRINT(RT_DEBUG_TRACE, "--> Antenna.word = 0x%x\n",pAdapter->EEPROMDefaultValue[0]); + + if ((Antenna.word == 0xFFFF) || (Antenna.field.TxDefaultAntenna > 2) || (Antenna.field.RxDefaultAntenna > 2)) + { + DBGPRINT(RT_DEBUG_TRACE, "E2PROM error(=0x%04x), hard code as 0x0002\n", Antenna.word); + Antenna.word = 0x0002; + } + + pAdapter->PortCfg.NumberOfAntenna = 2; // (UCHAR)Antenna.field.NumOfAntenna; + pAdapter->PortCfg.CurrentTxAntenna = (UCHAR)Antenna.field.TxDefaultAntenna; + pAdapter->PortCfg.CurrentRxAntenna = (UCHAR)Antenna.field.RxDefaultAntenna; + pAdapter->PortCfg.RfType = (UCHAR) Antenna.field.RfType; + + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, BBP_Tx_Configure, &TxValue); + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, BBP_Rx_Configure, &RxValue); + RTMP_IO_READ32(pAdapter, BBPCSR1, &BbpCsr1); + + // Tx antenna select + if(Antenna.field.TxDefaultAntenna == 1) // Antenna A + { + TxValue = (TxValue & 0xFC) | 0x00; + BbpCsr1 = (BbpCsr1 & 0xFFFCFFFC) | 0x00000000; + } + else if(Antenna.field.TxDefaultAntenna == 2) // Antenna B + { + TxValue = (TxValue & 0xFC) | 0x02; + BbpCsr1 = (BbpCsr1 & 0xFFFCFFFC) | 0x00020002; + } + else // diverity - start from Antenna B + { + TxValue = (TxValue & 0xFC) | 0x02; + BbpCsr1 = (BbpCsr1 & 0xFFFCFFFC) | 0x00020002; + } + + // Rx antenna select + if(Antenna.field.RxDefaultAntenna == 1) // Antenna A + RxValue = (RxValue & 0xFC) | 0x00; + else if(Antenna.field.RxDefaultAntenna == 2) // Antenna B + RxValue = (RxValue & 0xFC) | 0x02; + else // Antenna Diversity + RxValue = (RxValue & 0xFC) | 0x02; + + // RT5222 needs special treatment to swap TX I/Q + if (pAdapter->PortCfg.RfType == RFIC_5222) + { + BbpCsr1 |= 0x00040004; + TxValue |= 0x04; // TX I/Q flip + } + // RT2525E need to flip TX I/Q but not RX I/Q + else if (pAdapter->PortCfg.RfType == RFIC_2525E) + { + BbpCsr1 |= 0x00040004; + TxValue |= 0x04; // TX I/Q flip + RxValue &= 0xfb; // RX I/Q no flip + } + + // Change to match microsoft definition, 0xff: diversity, 0: A, 1: B + pAdapter->PortCfg.CurrentTxAntenna--; + pAdapter->PortCfg.CurrentRxAntenna--; + + RTMP_IO_WRITE32(pAdapter, BBPCSR1, BbpCsr1); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, BBP_Tx_Configure, TxValue); + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, BBP_Rx_Configure, RxValue); + + // 2003-12-16 software-based RX antenna diversity + // pAdapter->PortCfg.CurrentRxAntenna = 0xff; // Diversity ON + AsicSetRxAnt(pAdapter); + + if (Antenna.field.LedMode == LED_MODE_TXRX_ACTIVITY) + pAdapter->PortCfg.LedMode = LED_MODE_TXRX_ACTIVITY; + else if (Antenna.field.LedMode == LED_MODE_SINGLE) + { + pAdapter->PortCfg.LedMode = LED_MODE_SINGLE; + ASIC_LED_ACT_ON(pAdapter); + } + else if (Antenna.field.LedMode == LED_MODE_ASUS) + { + pAdapter->PortCfg.LedMode = LED_MODE_ASUS; + RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x0002461E); + } + else + pAdapter->PortCfg.LedMode = LED_MODE_DEFAULT; + + // Read Hardware controlled Radio state enable bit + if (0 && Antenna.field.HardwareRadioControl == 1) + { + pAdapter->PortCfg.bHardwareRadio = TRUE; + + // Read GPIO pin0 as Hardware controlled radio state + RTMP_IO_READ32(pAdapter, GPIOCSR, &data); + if ((data & 0x01) == 0) + { + pAdapter->PortCfg.bHwRadio = FALSE; + pAdapter->PortCfg.bRadio = FALSE; + RTMP_IO_WRITE32(pAdapter, PWRCSR0, 0x00000000); + RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF); + if (pAdapter->PortCfg.LedMode == LED_MODE_ASUS) + { + // Turn bit 17 for Radio OFF + RTMP_IO_WRITE32(pAdapter, LEDCSR, 0x0000461E); + } + } + } + else + pAdapter->PortCfg.bHardwareRadio = FALSE; + + NicConfig2.word = pAdapter->EEPROMDefaultValue[1]; + if (NicConfig2.word == 0xffff) + NicConfig2.word = 0; // empty E2PROM, use default + + // for dynamic BBP R17:RX sensibility tuning + { + UCHAR r17; + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, 17, &r17); + pAdapter->PortCfg.BbpTuningEnable = (NicConfig2.field.DynamicBbpTuning==0)? 1:0; + pAdapter->PortCfg.VgcLowerBound = r17; + + // 2004-3-4 per David's request, R7 starts at upper bound + pAdapter->PortCfg.BbpTuning.VgcUpperBound = BBP_R17_DYNAMIC_UP_BOUND; + r17 = pAdapter->PortCfg.BbpTuning.VgcUpperBound; + pAdapter->PortCfg.LastR17Value = r17; + RTMP_BBP_IO_WRITE32_BY_REG_ID(pAdapter, 17, r17); + + // 2004-2-2 per David's request, lower R17 low-bound for very good quality NIC + pAdapter->PortCfg.VgcLowerBound -= 6; + DBGPRINT(RT_DEBUG_TRACE,"R17 tuning enable=%d, R17=0x%02x, range=<0x%02x, 0x%02x>\n", + pAdapter->PortCfg.BbpTuningEnable, r17, pAdapter->PortCfg.VgcLowerBound, pAdapter->PortCfg.BbpTuning.VgcUpperBound); + } + + DBGPRINT(RT_DEBUG_TRACE, "RF IC=%d, LED mode=%d\n", pAdapter->PortCfg.RfType, pAdapter->PortCfg.LedMode); + + DBGPRINT(RT_DEBUG_TRACE, "<-- NICInitAsicFromEEPROM\n"); +} + +extern VOID MlmeWork(void *vpAd); + +void NICInitializeAdapter(IN PRTMP_ADAPTER pAdapter) +{ + TXCSR2_STRUC TxCSR2; + RXCSR1_STRUC RxCSR1; + ULONG Value; + + DBGPRINT(RT_DEBUG_TRACE, "--> NICInitializeAdapter\n"); + + // Init spin locks + spin_lock_init(&pAdapter->TxRingLock); + spin_lock_init(&pAdapter->PrioRingLock); + spin_lock_init(&pAdapter->AtimRingLock); + spin_lock_init(&pAdapter->RxRingLock); + spin_lock_init(&pAdapter->TxSwQueueLock); + spin_lock_init(&pAdapter->MemLock); + + // Write TXCSR2 register + TxCSR2.field.TxDSize = RING_DESCRIPTOR_SIZE; + TxCSR2.field.NumTxD = TX_RING_SIZE; + TxCSR2.field.NumAtimD = ATIM_RING_SIZE; + TxCSR2.field.NumPrioD = PRIO_RING_SIZE; + RTMP_IO_WRITE32(pAdapter, TXCSR2, TxCSR2.word); + + // Write TXCSR3 register + Value = pAdapter->TxRing[0].pa_addr; + RTMP_IO_WRITE32(pAdapter, TX_RING_BASE_REG, Value); + + // Write TXCSR4 register + Value = pAdapter->PrioRing[0].pa_addr; + RTMP_IO_WRITE32(pAdapter, PRIO_RING_BASE_REG, Value); + + // Write TXCSR5 register + Value = pAdapter->AtimRing[0].pa_addr; + RTMP_IO_WRITE32(pAdapter, ATIM_RING_BASE_REG, Value); + + // Write TXCSR6 register + Value = pAdapter->BeaconRing.pa_addr; + RTMP_IO_WRITE32(pAdapter, BEACON_BASE_REG, Value); + + // Write RXCSR1 register + RxCSR1.field.RxDSize = RING_DESCRIPTOR_SIZE; + RxCSR1.field.NumRxD = RX_RING_SIZE; + RTMP_IO_WRITE32(pAdapter, RXCSR1, RxCSR1.word); + + // Write RXCSR2 register + Value = pAdapter->RxRing[0].pa_addr; + RTMP_IO_WRITE32(pAdapter, RX_RING_BASE_REG, Value); + + // Write CSR1 for host ready + // Move Host reay to end of ASIC initialization + // to ensure no Rx will perform before ASIC init + // RTMP_IO_WRITE32(pAdapter, CSR1, 0x4); + + // Initialze ASIC for TX & Rx operation + NICInitializeAsic(pAdapter); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + INIT_WORK(&pAdapter->mlme_work, MlmeWork, (void*)pAdapter); +#endif + DBGPRINT(RT_DEBUG_TRACE, "<-- NICInitializeAdapter\n"); +} + +void NICInitializeAsic(IN PRTMP_ADAPTER pAdapter) +{ + ULONG Index; + UCHAR Value = 0xff; + + DBGPRINT(RT_DEBUG_TRACE, "--> NICInitializeAsic\n"); + + // Initialize MAC register to default value + for (Index = 0; Index < NUM_MAC_REG_PARMS; Index++) + { + RTMP_IO_WRITE32(pAdapter, MACRegTable[Index].Register, MACRegTable[Index].Value); + } + + // Set Host ready before kicking Rx + RTMP_IO_WRITE32(pAdapter, CSR1, 0x1); // reset MAC state machine, requested by Kevin 2003-2-11 + RTMP_IO_WRITE32(pAdapter, CSR1, 0x4); + + // Read BBP register, make sure BBP is up and running before write new data + Index = 0; + while (((Value == 0xff) || (Value == 0x00)) && Index < 10) + { + RTMP_BBP_IO_READ32_BY_REG_ID(pAdapter, BBP_Version, &Value); + mdelay(1); + Index++; + } + if(Index >= 10){ + DBGPRINT(RT_DEBUG_TRACE, "BBP register was never ready!\n"); + return; + } + + // Initialize BBP register to default value + for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) + { + RTMP_BBP_IO_WRITE32(pAdapter, BBPRegTable[Index]); + } + + // Initialize RF register to default value + AsicSwitchChannel(pAdapter, pAdapter->PortCfg.Channel); + AsicLockChannel(pAdapter, pAdapter->PortCfg.Channel); + + // Add radio off control + if (pAdapter->PortCfg.bRadio == FALSE) + { + RTMP_IO_WRITE32(pAdapter, PWRCSR0, 0x00000000); + RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF); + } + + // Kick Rx + if (pAdapter->PortCfg.BssType == BSS_MONITOR) + { + // Register bits to receive everything + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x46); + } + else if (pAdapter->bAcceptPromiscuous == TRUE) + { + // Register bits with "drop unicast not to me disabled" + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x6e); + } + else + { + // Standard default register bits. + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x7e); + } + + // Clear old FCS jitter before init ASIC + RTMP_IO_READ32(pAdapter, CNT0, &Index); + // Clear old Rx FIFO error jitter before init ASIC + RTMP_IO_READ32(pAdapter, CNT4, &Index); + + pAdapter->MediaState=NdisMediaStateDisconnected; + + DBGPRINT(RT_DEBUG_TRACE, "<-- NICInitializeAsic\n"); +} + +/* + ======================================================================== + + Routine Description: + Reset NIC Asics + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + Reset NIC to initial state AS IS system boot up time. + + ======================================================================== +*/ +VOID NICIssueReset( + IN PRTMP_ADAPTER pAdapter) +{ + CSR3_STRUC StaMacReg0; + CSR4_STRUC StaMacReg1; + + DBGPRINT(RT_DEBUG_TRACE, "--> NICIssueReset\n"); + + // Abort Tx, prevent ASIC from writing to Host memory + RTMP_IO_WRITE32(pAdapter, TXCSR0, 0x08); + + // Disable Rx, register value supposed will remain after reset + RTMP_IO_WRITE32(pAdapter, RXCSR0, 0x01); + + if (pAdapter->PortCfg.bLocalAdminMAC) + { + // Write Back Permanent MAC address to CSR3 & CSR4 + StaMacReg0.field.Byte0 = pAdapter->PermanentAddress[0]; + StaMacReg0.field.Byte1 = pAdapter->PermanentAddress[1]; + StaMacReg0.field.Byte2 = pAdapter->PermanentAddress[2]; + StaMacReg0.field.Byte3 = pAdapter->PermanentAddress[3]; + StaMacReg1.field.Byte4 = pAdapter->PermanentAddress[4]; + StaMacReg1.field.Byte5 = pAdapter->PermanentAddress[5]; + RTMP_IO_WRITE32(pAdapter, CSR3, StaMacReg0.word); + RTMP_IO_WRITE32(pAdapter, CSR4, StaMacReg1.word); + } + + // Issue reset and clear from reset state + RTMP_IO_WRITE32(pAdapter, CSR1, 0x01); + RTMP_IO_WRITE32(pAdapter, CSR1, 0x00); + + DBGPRINT(RT_DEBUG_TRACE, "<-- NICIssueReset\n"); +} + +/* + ======================================================================== + + Routine Description: + Check ASIC registers and find any reason the system might hang + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + + ======================================================================== +*/ +BOOLEAN NICCheckForHang( + IN PRTMP_ADAPTER pAd) +{ + // garbage collection +// if ((pAd->RalinkCounters.EncryptCount - pAd->RalinkCounters.TxDoneCount) == TX_RING_SIZE) +// { +// DBGPRINT(RT_DEBUG_WARNING,"\nNICCheckForHang --- Garbage Collection!!!\n\n"); +// } + + { + RTMPHandleTxRingTxDoneInterrupt(pAd); + RTMPHandleEncryptionDoneInterrupt(pAd); + } + + return (FALSE); +} + +/* + ======================================================================== + + Routine Description: + Reset NIC from error + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + Reset NIC from error state + + ======================================================================== +*/ +VOID NICResetFromError( + IN PRTMP_ADAPTER pAdapter) +{ + // Reset BBP (according to alex, reset ASIC will force reset BBP + // Therefore, skip the reset BBP + // RTMP_IO_WRITE32(pAdapter, CSR1, 0x2); + // Release BBP reset + // RTMP_IO_WRITE32(pAdapter, CSR1, 0x0); + + RTMP_IO_WRITE32(pAdapter, CSR1, 0x1); + // Remove ASIC from reset state + RTMP_IO_WRITE32(pAdapter, CSR1, 0x0); + + // Init send data structures and related parameters + NICInitTransmit(pAdapter); + + NICInitializeAdapter(pAdapter); + NICInitAsicFromEEPROM(pAdapter); + + // Switch to current channel, since during reset process, the connection should remains on. + AsicSwitchChannel(pAdapter, pAdapter->PortCfg.Channel); + AsicLockChannel(pAdapter, pAdapter->PortCfg.Channel); +} +/* + ======================================================================== + + Routine Description: + Verify section is valid for Get key parameter. + + Arguments: + buffer Pointer to the buffer to start find the key section + ptr pointer to section + + Return Value: + TRUE Success + FALSE Fail + ======================================================================== +*/ +INT RTMPIsFindSection( + IN PUCHAR ptr, + IN PUCHAR buffer) +{ + if(ptr == buffer) + return TRUE; + else if (ptr > buffer) + { + while (ptr > buffer) + { + ptr--; + if( *ptr == 0x0a) + return TRUE; + else if( (*ptr == ' ') || (*ptr == '\t')) + continue; + else + return FALSE; + } + return TRUE; + } + + return FALSE; +} +/* + ======================================================================== + + Routine Description: + Find key section for Get key parameter. + + Arguments: + buffer Pointer to the buffer to start find the key section + section the key of the secion to be find + + Return Value: + NULL Fail + Others Success + ======================================================================== +*/ +PUCHAR RTMPFindSection( + IN PCHAR buffer, + IN PCHAR section) +{ + CHAR temp_buf[255]; + PUCHAR ptr; + + strcpy(temp_buf, "["); /* and the opening bracket [ */ + strcat(temp_buf, section); + strcat(temp_buf, "]"); + + if((ptr = rtstrstr(buffer, temp_buf)) != NULL) + { + if(RTMPIsFindSection(ptr, buffer)) + return (ptr+strlen("\n")); + else + return NULL; + } + else + return NULL; +} + /** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ +char * rtstrstr(const char * s1,const char * s2) +{ + int l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *) s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1,s2,l2)) + return (char *) s1; + s1++; + } + return NULL; +} +/* + ======================================================================== + + Routine Description: + Get key parameter. + + Arguments: + section the key of the secion + key Pointer to key string + dest Pointer to destination + destsize The datasize of the destination + buffer Pointer to the buffer to start find the key + + Return Value: + TRUE Success + FALSE Fail + + Note: + This routine get the value with the matched key (case case-sensitive) + ======================================================================== +*/ +INT RTMPGetKeyParameter( + IN PUCHAR section, + IN PCHAR key, + OUT PCHAR dest, + IN INT destsize, + IN PCHAR buffer) +{ + char *temp_buf1; + char *temp_buf2; + char *start_ptr; + char *end_ptr; + char *ptr; + char *too_far_ptr; + char *offset; + int len; + + temp_buf1 = kmalloc(600, GFP_KERNEL); + temp_buf2 = kmalloc(600, GFP_KERNEL); + + //find section + if((offset = RTMPFindSection(buffer, section)) == NULL) + return (FALSE); + + strcpy(temp_buf1, "\n"); + strcat(temp_buf1, key); + strcat(temp_buf1, "="); + + //search key + if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) + goto fail; + + start_ptr+=strlen("\n"); + if((too_far_ptr=rtstrstr(offset+1, "["))==NULL) + too_far_ptr=offset+strlen(offset); + + if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) + end_ptr=start_ptr+strlen(start_ptr); + + if (too_far_ptr Error %ld opening %s\n", -PTR_ERR(srcf),src); + } + else + { + /* The object must have a read method */ + if (srcf->f_op && srcf->f_op->read) + { + memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); + retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); + if (retval < 0) + { + DBGPRINT(RT_DEBUG_TRACE, "--> Read %s error %d\n", src, -retval); + } + else + { + // set file parameter to portcfg + //CountryRegion + if (RTMPGetKeyParameter("Default", "CountryRegion", tmpbuf, 255, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + if ((ulInfo >= REGION_MIN) && (ulInfo <= REGION_MAX) ) + { + pAd->PortCfg.CountryRegion = (UCHAR) ulInfo; + DBGPRINT(RT_DEBUG_TRACE, "%s::(CountryRegion=%d)\n", __FUNCTION__, pAd->PortCfg.CountryRegion); + } + } + //SSID + memset(tmpbuf, 0x00, 255); + if (RTMPGetKeyParameter("Default", "SSID", tmpbuf, 32, buffer)) + { + pAd->PortCfg.SsidLen = (UCHAR) strlen(tmpbuf); + memcpy(pAd->PortCfg.Ssid, tmpbuf, pAd->PortCfg.SsidLen); + + pAd->Mlme.CntlAux.SsidLen = pAd->PortCfg.SsidLen; + memcpy(pAd->Mlme.CntlAux.Ssid, tmpbuf, pAd->Mlme.CntlAux.SsidLen); + + DBGPRINT(RT_DEBUG_TRACE, "%s::(SSID=%s Len=%d)\n", __FUNCTION__, tmpbuf, pAd->PortCfg.SsidLen); + } + //NetworkType + if (RTMPGetKeyParameter("Default", "NetworkType", tmpbuf, 255, buffer)) + { + pAd->bConfigChanged = TRUE; + if (strcmp(tmpbuf, "Adhoc") == 0) + pAd->PortCfg.BssType = BSS_INDEP; + else //Default Infrastructure mode + pAd->PortCfg.BssType = BSS_INFRA; + // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key + pAd->PortCfg.WpaState = SS_NOTUSE; + DBGPRINT(RT_DEBUG_TRACE, "%s::(NetworkType=%d)\n", __FUNCTION__, pAd->PortCfg.BssType); + } + //WirelessMode + if (RTMPGetKeyParameter("Default", "WirelessMode", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + if ((ulInfo == PHY_11BG_MIXED) || (ulInfo == PHY_11B) || + (ulInfo == PHY_11A) || (ulInfo == PHY_11ABG_MIXED)) + { + RTMPSetPhyMode(pAd, ulInfo); + DBGPRINT(RT_DEBUG_TRACE, "%s::(WirelessMode=%d)\n", __FUNCTION__, ulInfo); + } + } + //TxRate + if (RTMPGetKeyParameter("Default", "TxRate", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + { + if (ulInfo == 0) + RTMPSetDesiredRates(pAd, -1); + else + RTMPSetDesiredRates(pAd, (LONG) (rate_mapping[ulInfo-1] * 1000000)); + + DBGPRINT(RT_DEBUG_TRACE, "%s::(TxRate=%d)\n", __FUNCTION__, ulInfo); + } + } + //Channel + if (RTMPGetKeyParameter("Default", "Channel", tmpbuf, 10, buffer)) + { + Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); + if (ChannelSanity(pAd, Channel) == TRUE) + { + pAd->PortCfg.Channel = Channel; + // If default profile in Registry is an ADHOC network, driver should use the specified channel + // number when starting IBSS the first time, because RaConfig is passive and will not set this + // via OID_802_11_CONFIGURATION upon driver bootup. + pAd->PortCfg.IbssConfig.Channel = pAd->PortCfg.Channel; + DBGPRINT(RT_DEBUG_TRACE, "%s::(Channel=%d)\n", __FUNCTION__, Channel); + } + } + //BGProtection + if (RTMPGetKeyParameter("Default", "BGProtection", tmpbuf, 10, buffer)) + { + switch (simple_strtol(tmpbuf, 0, 10)) + { + case 1: //Always On + pAd->PortCfg.UseBGProtection = 1; + break; + case 2: //Always OFF + pAd->PortCfg.UseBGProtection = 2; + break; + case 0: //AUTO + default: + pAd->PortCfg.UseBGProtection = 0; + break; + } + DBGPRINT(RT_DEBUG_TRACE, "%s::(BGProtection=%d)\n", __FUNCTION__, pAd->PortCfg.UseBGProtection); + } + //StaWithEtherBridge + if (RTMPGetKeyParameter("Default", "StaWithEtherBridge", tmpbuf, 10, buffer)) + { + switch (simple_strtol(tmpbuf, 0, 10)) + { + case 0: //Off + pAd->PortCfg.StaWithEtherBridge.Enable = FALSE; + break; + case 1: //On + pAd->PortCfg.StaWithEtherBridge.Enable = TRUE; + break; + default: + pAd->PortCfg.StaWithEtherBridge.Enable = FALSE; + break; + } + DBGPRINT(RT_DEBUG_TRACE, "%s::(StaWithEtherBridge=%d)\n", __FUNCTION__, pAd->PortCfg.StaWithEtherBridge.Enable); + } + //TxPreamble + if (RTMPGetKeyParameter("Default", "TxPreamble", tmpbuf, 10, buffer)) + { + Preamble = simple_strtol(tmpbuf, 0, 10); + switch (Preamble) + { + case Rt802_11PreambleShort: + pAd->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); + break; + case Rt802_11PreambleLong: + case Rt802_11PreambleAuto: + default: + // if user wants AUTO, initialize to LONG here, then change according to AP's + // capability upon association. + pAd->PortCfg.WindowsTxPreamble = Preamble; + MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); + } + DBGPRINT(RT_DEBUG_TRACE, "%s::(TxPreamble=%d)\n", __FUNCTION__, Preamble); + } + //RTSThreshold + if (RTMPGetKeyParameter("Default", "RTSThreshold", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if((ulInfo > 0) && (ulInfo <= MAX_RTS_THRESHOLD)) + pAd->PortCfg.RtsThreshold = (USHORT)ulInfo; + else + pAd->PortCfg.RtsThreshold = MAX_RTS_THRESHOLD; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(RTSThreshold=%d)\n", __FUNCTION__, pAd->PortCfg.RtsThreshold); + } + //FragThreshold + if (RTMPGetKeyParameter("Default", "FragThreshold", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if ( (ulInfo >= MIN_FRAG_THRESHOLD) && (ulInfo <= MAX_FRAG_THRESHOLD)) + pAd->PortCfg.FragmentThreshold = (USHORT)ulInfo; + else + pAd->PortCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; + + if (pAd->PortCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) + pAd->PortCfg.bFragmentZeroDisable = TRUE; + else + pAd->PortCfg.bFragmentZeroDisable = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(FragThreshold=%d)\n", __FUNCTION__, ulInfo); + } + //AdhocOfdm + if (RTMPGetKeyParameter("Default", "AdhocOfdm", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if (ulInfo == 1) + pAd->PortCfg.AdhocMode = 1; + else + pAd->PortCfg.AdhocMode = 0; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(AdhocOfdm=%d)\n", __FUNCTION__, pAd->PortCfg.AdhocMode); + } + //TxBurst + if (RTMPGetKeyParameter("Default", "TxBurst", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if (ulInfo == 1) + pAd->PortCfg.EnableTxBurst = TRUE; + else + pAd->PortCfg.EnableTxBurst = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(TxBurst=%d)\n", __FUNCTION__, pAd->PortCfg.EnableTxBurst); + } + //TurboRate + if (RTMPGetKeyParameter("Default", "TurboRate", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if (ulInfo == 1) + pAd->PortCfg.EnableTurboRate = TRUE; + else + pAd->PortCfg.EnableTurboRate = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(TurboRate=%d)\n", __FUNCTION__, pAd->PortCfg.EnableTurboRate); + } + //ShortSlot + if (RTMPGetKeyParameter("Default", "ShortSlot", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + + if (ulInfo == 1) + pAd->PortCfg.UseShortSlotTime = TRUE; + else + pAd->PortCfg.UseShortSlotTime = FALSE; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(ShortSlot=%d)\n", __FUNCTION__, pAd->PortCfg.UseShortSlotTime); + } + //POWER_MODE + if (RTMPGetKeyParameter("Default", "PSMode", tmpbuf, 10, buffer)) + { + if (pAd->PortCfg.BssType == BSS_INFRA) + { + if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) + { + DBGPRINT(RT_DEBUG_INFO, "MAX_PSP power mode not available - defaulting to CAM\n"); + } + else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) + || (strcmp(tmpbuf, "FAST_PSP") == 0)) + { + DBGPRINT(RT_DEBUG_INFO, "FAST_PSP power mode not available - defaulting to CAM\n"); + } + + //Default Ndis802_11PowerModeCAM + // clear PSM bit immediately + MlmeSetPsmBit(pAd, PWR_ACTIVE); + pAd->PortCfg.RecvDtim = TRUE; + if (pAd->PortCfg.WindowsACCAMEnable == FALSE) + pAd->PortCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; + pAd->PortCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; + DBGPRINT(RT_DEBUG_TRACE, "%s::(PSMode=%d)\n", __FUNCTION__, pAd->PortCfg.WindowsPowerMode); + } + } + //AuthMode + if (RTMPGetKeyParameter("Default", "AuthMode", tmpbuf, 10, buffer)) + { + if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) + pAd->PortCfg.AuthMode = Ndis802_11AuthModeShared; + else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) + pAd->PortCfg.AuthMode = Ndis802_11AuthModeWPAPSK; + else if ((strcmp(tmpbuf, "AUTO") == 0) || (strcmp(tmpbuf, "auto") == 0)) + pAd->PortCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; + else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) + pAd->PortCfg.AuthMode = Ndis802_11AuthModeWPANone; + else + pAd->PortCfg.AuthMode = Ndis802_11AuthModeOpen; + + pAd->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + DBGPRINT(RT_DEBUG_TRACE, "%s::(AuthMode=%d)\n", __FUNCTION__, pAd->PortCfg.AuthMode); + } + //EncrypType + if (RTMPGetKeyParameter("Default", "EncrypType", tmpbuf, 10, buffer)) + { + if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) + pAd->PortCfg.WepStatus = Ndis802_11WEPEnabled; + else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) + pAd->PortCfg.WepStatus = Ndis802_11Encryption2Enabled; + else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) + pAd->PortCfg.WepStatus = Ndis802_11Encryption3Enabled; + else + pAd->PortCfg.WepStatus = Ndis802_11WEPDisabled; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(EncrypType=%d)\n", __FUNCTION__, pAd->PortCfg.WepStatus); + } + //WPANONE_KEY + if (RTMPGetKeyParameter("Default", "WPANONE", tmpbuf, 255, buffer)) + { + Set_WPANONE_Proc(pAd, tmpbuf); + } + //WPAPSK_KEY + if (RTMPGetKeyParameter("Default", "WPAPSK", tmpbuf, 255, buffer)) + { + if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) + { + PasswordHash((char *)tmpbuf, pAd->PortCfg.Ssid, pAd->PortCfg.SsidLen, keyMaterial); + memcpy(pAd->PortCfg.PskKey.Key, keyMaterial, 32); + // Use RaConfig as PSK agent. + // Start STA supplicant state machine + pAd->PortCfg.WpaState = SS_START; +#if 0 + DBGPRINT(RT_DEBUG_TRACE, "%s WPAPSK Key => \n", __FUNCTION__); + for (i = 0; i < 32; i++) + { + DBGPRINT(RT_DEBUG_TRACE, "%02x:", pAd->PortCfg.PskKey.Key[i]); + if (i%16 == 15) + DBGPRINT(RT_DEBUG_TRACE, "\n"); + } + DBGPRINT(RT_DEBUG_TRACE, "\n"); +#endif + } + else if (strlen(tmpbuf) == 64) + { + AtoH(tmpbuf, pAd->PortCfg.PskKey.Key, 32); + pAd->PortCfg.WpaState = SS_START; + } + } + //DefaultKeyID + if (RTMPGetKeyParameter("Default", "DefaultKeyID", tmpbuf, 10, buffer)) + { + ulInfo = simple_strtol(tmpbuf, 0, 10); + if((ulInfo >= 1 ) && (ulInfo <= 4)) + pAd->PortCfg.DefaultKeyId = (UCHAR) (ulInfo - 1 ); + else + pAd->PortCfg.DefaultKeyId = 0; + + DBGPRINT(RT_DEBUG_TRACE, "%s::(DefaultKeyID=%d)\n", __FUNCTION__, pAd->PortCfg.DefaultKeyId); + } + //Key1Str + if (RTMPGetKeyParameter("Default", "Key1", tmpbuf, 26, buffer) || + RTMPGetKeyParameter("Default", "Key1Str", tmpbuf, 26, buffer)) + { + KeyLen = strlen(tmpbuf); + switch (KeyLen) + { + case 0: + pAd->PortCfg.SharedKey[0].KeyLen = 0; + break; + case 5: //wep 40 Ascii type + pAd->PortCfg.SharedKey[0].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[0].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key1=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[0].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[0].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key1=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + case 13: //wep 104 Ascii type + pAd->PortCfg.SharedKey[0].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[0].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key1=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[0].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[0].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key1=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + default: + pAd->PortCfg.SharedKey[0].KeyLen = 0; + DBGPRINT(RT_DEBUG_TRACE, "%s::Invalid Key (=%s)\n", __FUNCTION__, tmpbuf); + } + } + //Key2Str + if (RTMPGetKeyParameter("Default", "Key2", tmpbuf, 26, buffer) || + RTMPGetKeyParameter("Default", "Key2Str", tmpbuf, 26, buffer)) + { + KeyLen = strlen(tmpbuf); + switch (KeyLen) + { + case 0: + pAd->PortCfg.SharedKey[1].KeyLen = 0; + break; + case 5: //wep 40 Ascii type + pAd->PortCfg.SharedKey[1].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[1].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key2=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[1].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[1].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key2=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + case 13: //wep 104 Ascii type + pAd->PortCfg.SharedKey[1].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[1].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key2=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[1].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[1].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key2=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + default: + pAd->PortCfg.SharedKey[1].KeyLen = 0; + DBGPRINT(RT_DEBUG_TRACE, "%s::Invalid argument (=%s)\n", __FUNCTION__, tmpbuf); + } + } + //Key3Str + if (RTMPGetKeyParameter("Default", "Key3", tmpbuf, 26, buffer) || + RTMPGetKeyParameter("Default", "Key3Str", tmpbuf, 26, buffer)) + { + KeyLen = strlen(tmpbuf); + switch (KeyLen) + { + case 0: + pAd->PortCfg.SharedKey[2].KeyLen = 0; + break; + case 5: //wep 40 Ascii type + pAd->PortCfg.SharedKey[2].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[2].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key3=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[2].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[2].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key3=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + case 13: //wep 104 Ascii type + pAd->PortCfg.SharedKey[2].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[2].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key3=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[2].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[2].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key3=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + default: + pAd->PortCfg.SharedKey[2].KeyLen = 0; + DBGPRINT(RT_DEBUG_TRACE, "%s::Invalid argument (=%s)\n", __FUNCTION__, tmpbuf); + } + } + //Key4Str + if (RTMPGetKeyParameter("Default", "Key4", tmpbuf, 26, buffer) || + RTMPGetKeyParameter("Default", "Key4Str", tmpbuf, 26, buffer)) + { + KeyLen = strlen(tmpbuf); + switch (KeyLen) + { + case 0: + pAd->PortCfg.SharedKey[3].KeyLen = 0; + break; + case 5: //wep 40 Ascii type + pAd->PortCfg.SharedKey[3].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[3].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key4=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + case 10: //wep 40 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[3].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[3].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key4=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + case 13: //wep 104 Ascii type + pAd->PortCfg.SharedKey[3].KeyLen = KeyLen; + memcpy(pAd->PortCfg.SharedKey[3].Key, tmpbuf, KeyLen); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key4=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Ascii"); + break; + case 26: //wep 104 Hex type + for(i=0; i < KeyLen; i++) + { + if( !isxdigit(*(tmpbuf+i)) ) + { + bIsHex = FALSE; + break; + } + } + + if (bIsHex) + { + pAd->PortCfg.SharedKey[3].KeyLen = KeyLen / 2 ; + AtoH(tmpbuf, pAd->PortCfg.SharedKey[3].Key, KeyLen / 2); + DBGPRINT(RT_DEBUG_TRACE, "%s::(Key4=%s and type=%s)\n", __FUNCTION__, tmpbuf, "Hex"); + } + break; + default: + pAd->PortCfg.SharedKey[3].KeyLen = 0; + DBGPRINT(RT_DEBUG_TRACE, "%s::Invalid argument (=%s)\n", __FUNCTION__, tmpbuf); + } + } + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "--> %s does not have a write method\n", src); + } + + retval=filp_close(srcf,NULL); + if (retval) + { + DBGPRINT(RT_DEBUG_TRACE, "--> Error %d closing %s\n", -retval, src); + } + } + } //if (src && *src) + + set_fs(orgfs); + current->fsuid = orgfsuid; + current->fsgid = orgfsgid; + kfree(buffer); +} +/* + ======================================================================== + + Routine Description: + Reset NIC Asics + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + Reset NIC to initial state AS IS system boot up time. + + ======================================================================== +*/ +VOID RTMPRingCleanUp( + IN PRTMP_ADAPTER pAdapter, + IN UCHAR RingType) +{ + ULONG Count; + PTXD_STRUC pTxD; + PRXD_STRUC pRxD; + PMGMT_STRUC pMgmt; + + Count = 0; + switch (RingType) + { + case TX_RING: + // We have to clean all descriptos in case some error happened with reset + do + { + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->NextTxDoneIndex].va_addr; + + pTxD->Owner = DESC_OWN_HOST; + pTxD->Valid = FALSE; + + pAdapter->NextTxDoneIndex++; + Count++; + if (pAdapter->NextTxDoneIndex >= TX_RING_SIZE) + { + pAdapter->NextTxDoneIndex = 0; + } + + } while (Count < TX_RING_SIZE); // We have to scan all TX ring + + // Check for packet in send tx wait waiting queue + skb_queue_purge(&pAdapter->TxSwQueue0); + skb_queue_purge(&pAdapter->TxSwQueue1); + skb_queue_purge(&pAdapter->TxSwQueue2); + skb_queue_purge(&pAdapter->TxSwQueue3); + + case PRIO_RING: + // We have to clean all descriptos in case some error happened with reset + do + { + pTxD = (PTXD_STRUC) pAdapter->PrioRing[pAdapter->NextPrioDoneIndex].va_addr; + + // We just re-claim these ring spaces. + pTxD->Owner = DESC_OWN_HOST; + pTxD->Valid = FALSE; + + pAdapter->NextPrioDoneIndex++; + Count++; + if (pAdapter->NextPrioDoneIndex >= PRIO_RING_SIZE) + { + pAdapter->NextPrioDoneIndex = 0; + } + + } while (Count < PRIO_RING_SIZE); // We have to scan all Priority Ring + + // Clear managemt buffer ring + while ((pAdapter->PushMgmtIndex != pAdapter->PopMgmtIndex) || (pAdapter->MgmtQueueSize != 0)) + { + pMgmt = (PMGMT_STRUC) &pAdapter->MgmtRing[pAdapter->PopMgmtIndex]; + if (pMgmt->Valid == TRUE) + { + MlmeFreeMemory(pAdapter, pMgmt->pBuffer); + pMgmt->Valid = FALSE; + pAdapter->PopMgmtIndex++; + pAdapter->MgmtQueueSize--; + if (pAdapter->PopMgmtIndex >= MGMT_RING_SIZE) + { + pAdapter->PopMgmtIndex = 0; + } + } + } + pAdapter->RalinkCounters.MgmtRingFullCount = 0; + break; + + case RX_RING: + // We have to clean all descriptos in case some error happened with reset + do + { + pRxD = (PRXD_STRUC) pAdapter->RxRing[pAdapter->CurRxIndex].va_addr; + + // Re-initial Rx ring cell to owned by NIC. + pRxD->Owner = DESC_OWN_NIC; + + pAdapter->CurRxIndex++; + Count++; + if (pAdapter->CurRxIndex >= RX_RING_SIZE) + { + pAdapter->CurRxIndex = 0; + } + + } while (Count < RX_RING_SIZE); // We have to scan all Rx Ring + break; + + default: + break; + + } +} + +/* + ======================================================================== + + Routine Description: + Compare two memory block + + Arguments: + pSrc1 Pointer to first memory address + pSrc2 Pointer to second memory addres + + Return Value: + 0: memory is equal + 1: pSrc1 memory is larger + 2: pSrc2 memory is larger + + Note: + + ======================================================================== +*/ +ULONG RTMPCompareMemory( + IN PVOID pSrc1, + IN PVOID pSrc2, + IN ULONG Length) +{ + PUCHAR pMem1; + PUCHAR pMem2; + ULONG Index = 0; + + pMem1 = (PUCHAR) pSrc1; + pMem2 = (PUCHAR) pSrc2; + + for (Index = 0; Index < Length; Index++) + { + if (pMem1[Index] > pMem2[Index]) + return (1); + else if (pMem1[Index] < pMem2[Index]) + return (2); + } + + // Equal + return (0); +} + +/* + ======================================================================== + + Routine Description: + Initialize port configuration structure + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID PortCfgInit( + IN PRTMP_ADAPTER pAdapter) +{ + UINT i; + + DBGPRINT(RT_DEBUG_TRACE, "--> PortCfgInit\n"); + + pAdapter->PortCfg.UseBGProtection = 0; // 0: AUTO + + pAdapter->PortCfg.CapabilityInfo = 0x0000; + pAdapter->PortCfg.Psm = PWR_ACTIVE; + pAdapter->PortCfg.BeaconPeriod = 100; // in mSec + + pAdapter->PortCfg.CfpMaxDuration = 0; // never mind, decided by AP later + pAdapter->PortCfg.CfpDurRemain = 0; // never mind, decided by AP later + pAdapter->PortCfg.CfpCount = 0; // never mind, decided by AP later + pAdapter->PortCfg.CfpPeriod = 0; // never mind, decided by AP later + pAdapter->PortCfg.AuthMode = Ndis802_11AuthModeOpen; + + for(i = 0; i < SHARE_KEY_NO; i++) { + pAdapter->PortCfg.SharedKey[i].KeyLen = 0; + } + + for(i = 0; i < PAIRWISE_KEY_NO; i++) { + pAdapter->PortCfg.PairwiseKey[i].KeyLen = 0; + } + + for(i = 0; i < GROUP_KEY_NO; i++) { + pAdapter->PortCfg.GroupKey[i].KeyLen = 0; + } + + pAdapter->PortCfg.WepStatus = Ndis802_11EncryptionDisabled; + pAdapter->PortCfg.DefaultKeyId = 0; + pAdapter->PortCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; + + // 802.1x port control + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + pAdapter->PortCfg.LastMicErrorTime = 0; + pAdapter->PortCfg.MicErrCnt = 0; + pAdapter->PortCfg.bBlockAssoc = FALSE; + pAdapter->PortCfg.WpaState = SS_NOTUSE; + + pAdapter->PortCfg.RtsThreshold = 2347; + pAdapter->PortCfg.FragmentThreshold = 2346; + pAdapter->PortCfg.bFragmentZeroDisable = FALSE; + + pAdapter->PortCfg.CurrentTxAntenna = 0xff; // diversity + pAdapter->PortCfg.CurrentRxAntenna = 0xff; // diversity + pAdapter->PortCfg.NumberOfAntenna = 2; + +// pAdapter->PortCfg.TxPowerLevel[0] = 100; +// pAdapter->PortCfg.NumOfTxPowerLevel = 1; + pAdapter->PortCfg.TxPower = 100; //mW + // Krellan: Init to automatic settings, starting at 0 dBm + pAdapter->PortCfg.TxPowerDriver = 0; + pAdapter->PortCfg.TxPowerUser = 0; + pAdapter->PortCfg.TxPowerAuto = TRUE; + + pAdapter->PortCfg.AntennaSupportTx = TRUE; + pAdapter->PortCfg.AntennaSupportRx = TRUE; + pAdapter->PortCfg.AntennaSupportDiversityRx = TRUE; + + pAdapter->PortCfg.RecvDtim = TRUE; + memset(&pAdapter->PortCfg.Bssid, 0, ETH_ALEN); + memset(&pAdapter->PortCfg.Broadcast, 0xff, ETH_ALEN); + pAdapter->PortCfg.Pss = PWR_ACTIVE; + pAdapter->PortCfg.RssiTrigger = 0; + pAdapter->PortCfg.LastRssi = 0; + pAdapter->PortCfg.LastAvgRssi = -95 + RSSI_TO_DBM_OFFSET;// default -95dm + pAdapter->PortCfg.AvgRssi = 0; + pAdapter->PortCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; + pAdapter->PortCfg.AtimWin = 0; + pAdapter->PortCfg.Channel = 1; + + pAdapter->PortCfg.Aid = 1; + + pAdapter->PortCfg.DefaultListenCount = 3;//default listen count; + pAdapter->PortCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_INDEP + + pAdapter->PortCfg.AdhocMode = 0; + + pAdapter->PortCfg.SsidLen = 0; + memset(pAdapter->PortCfg.Ssid, 0, MAX_LEN_OF_SSID); // NOT NULL-terminated + + // global variables mXXXX used in MAC protocol state machines + pAdapter->PortCfg.Mibss = FALSE; + pAdapter->PortCfg.Massoc = FALSE; + pAdapter->PortCfg.Mauth = FALSE; + pAdapter->PortCfg.MallowRFMONTx = FALSE; + + // PHY specification + pAdapter->PortCfg.PhyMode = 0xff; +// RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); // default in 11BG mixed mode +// pAdapter->PortCfg.Channel = FirstChannel(pAdapter); + pAdapter->PortCfg.Dsifs = 10; // in units of usec + pAdapter->PortCfg.TxPreambleInUsed = Rt802_11PreambleLong; // use Long preamble on TX by defaut + + // user desired power mode + pAdapter->PortCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; // Ndis802_11PowerModeFast_PSP; + pAdapter->PortCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; // Ndis802_11PowerModeFast_PSP; + pAdapter->PortCfg.WindowsTxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut + pAdapter->PortCfg.WindowsACCAMEnable = FALSE; +// pAdapter->PortCfg.PacketFilter = NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST; + pAdapter->bAcceptDirect = TRUE; + pAdapter->bAcceptMulticast = FALSE; + pAdapter->bAcceptBroadcast = TRUE; + pAdapter->bAcceptAllMulticast = TRUE; + + // parameters to be used when this STA starts a new ADHOC network + pAdapter->PortCfg.IbssConfig.BeaconPeriod = 100; + pAdapter->PortCfg.IbssConfig.AtimWin = 0; + pAdapter->PortCfg.IbssConfig.Channel = 1; + pAdapter->PortCfg.RfType = RFIC_2525; + pAdapter->PortCfg.LedMode = LED_MODE_DEFAULT; + + pAdapter->PortCfg.IgnoredScanNumber = 0; + pAdapter->bTxBusy = FALSE; + + pAdapter->PortCfg.bHwRadio = TRUE; + pAdapter->PortCfg.bSwRadio = TRUE; + pAdapter->PortCfg.bRadio = TRUE; + pAdapter->PortCfg.bHardwareRadio = FALSE; // Default is OFF + pAdapter->PortCfg.bAutoTxAgc = FALSE; // Default is OFF + pAdapter->PortCfg.bShowHiddenSSID = FALSE; + + // Nitro mode control + pAdapter->PortCfg.EnableTxBurst = 0; + pAdapter->PortCfg.AutoReconnect = TRUE; + + // Save the init time as last scan time, the system should do scan after 2 seconds. + pAdapter->PortCfg.LastScanTime = 0; + + // Default Config change flag + pAdapter->bConfigChanged = FALSE; + + pAdapter->PortCfg.bLocalAdminMAC = TRUE; + + pAdapter->NeedSwapToLittleEndian = TRUE; + + // dynamic BBP R17:sensibity tuning to overcome background noise + pAdapter->PortCfg.BbpTuningEnable = TRUE; // overwritten by E2PROM setting + pAdapter->PortCfg.VgcLowerBound = 0x38; // overwritten by E2PROM setting + pAdapter->PortCfg.BbpTuning.FalseCcaLowerThreshold = 100; + pAdapter->PortCfg.BbpTuning.FalseCcaUpperThreshold = 4; // unit 128, 4*128 = 512 + pAdapter->PortCfg.BbpTuning.VgcDelta = 1; + pAdapter->PortCfg.BbpTuning.VgcUpperBound = BBP_R17_DYNAMIC_UP_BOUND; + + pAdapter->PortCfg.StaWithEtherBridge.Enable = FALSE; + memset(&pAdapter->PortCfg.StaWithEtherBridge.EtherMacAddr, 0xff, ETH_ALEN); + +#ifdef RALINK_ATE + memset(&pAdapter->ate, 0, sizeof(ATE_INFO)); + pAdapter->ate.Mode = ATE_STASTART; + pAdapter->ate.TxCount = TX_RING_SIZE; + pAdapter->ate.TxLength = PRIO_BUFFER_SIZE; + pAdapter->ate.TxRate = RATE_11; + pAdapter->ate.Channel = 1; + memcpy(&pAdapter->ate.Addr1,"001122334455", ETH_ALEN); + memcpy(&pAdapter->ate.Addr2,"001122334455", ETH_ALEN); + memcpy(&pAdapter->ate.Addr3,"001122334455", ETH_ALEN); +#endif //#ifdef RALINK_ATE + + RTMP_IO_READ32(pAdapter, 0, &pAdapter->PortCfg.Rt2560Version); + + DBGPRINT(RT_DEBUG_TRACE, "<-- PortCfgInit\n"); +} + +UCHAR BtoH(char ch) +{ + if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals + if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits + if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits + return(255); +} + +// +// FUNCTION: AtoH(char *, UCHAR *, int) +// +// PURPOSE: Converts ascii string to network order hex +// +// PARAMETERS: +// src - pointer to input ascii string +// dest - pointer to output hex +// destlen - size of dest +// +// COMMENTS: +// +// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair +// into upper nibble and 2nd ascii byte of pair into lower nibble. +// + +void AtoH(char * src, UCHAR * dest, int destlen) +{ + char *srcptr; + PUCHAR destTemp; + + srcptr = src; + destTemp = (PUCHAR) dest; + + while(destlen--) + { + *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. + *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. + destTemp++; + } +} + +/* + ======================================================================== + + Routine Description: + Init timer objects + + Arguments: + pAdapter Pointer to our adapter + pTimer Timer structure + pTimerFunc Function to execute when timer expired + Repeat Ture for period timer + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPInitTimer( + IN PRTMP_ADAPTER pAdapter, + IN PRALINK_TIMER_STRUCT pTimer, + IN PVOID pTimerFunc) +{ + pTimer->State = FALSE; + init_timer(&pTimer->TimerObj); + pTimer->TimerObj.data = (unsigned long)pAdapter; + pTimer->TimerObj.function = pTimerFunc; +} + +/* + ======================================================================== + + Routine Description: + Init timer objects + + Arguments: + pTimer Timer structure + Value Timer value in milliseconds + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPSetTimer( + IN PRTMP_ADAPTER pAdapter, + IN PRALINK_TIMER_STRUCT pTimer, + IN ULONG Value) +{ + pTimer->TimerValue = Value; + pTimer->State = FALSE; + pTimer->TimerObj.expires = jiffies + (Value * HZ)/1000; + add_timer(&pTimer->TimerObj); +} + +/* + ======================================================================== + + Routine Description: + Cancel timer objects + + Arguments: + Adapter Pointer to our adapter + + Return Value: + None + + Note: + Reset NIC to initial state AS IS system boot up time. + + ======================================================================== +*/ +VOID RTMPCancelTimer( + IN PRALINK_TIMER_STRUCT pTimer) +{ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,27)) + del_timer_sync(&pTimer->TimerObj); +#else + del_timer(&pTimer->TimerObj); +#endif +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_main.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_main.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_main.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_main.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1021 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_main.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulL 25th Nov 02 Initial code + * MarkW 8th Dec 04 Baseline code + * MarkW (rt2400) 8th Dec 04 Promisc mode support + * Flavio (rt2400) 8th Dec 04 Elegant irqreturn_t handling + * Flavio (rt2400) 8th Dec 04 Remove local alloc_netdev + * Flavio (rt2400) 8th Dec 04 Extra debug at init time + * Ivo (rt2400) 15th Dec 04 Debug Level Switching + * RobinC 16th Dec 04 support ifpreup scripts + * RobinC 17th Dec 04 Link quality reporting + * MarkW 31st Jan 05 sysfs support for HAL/NetworkMan + * Bruno 31st Jan 05 Network device name module param + * GertjanW 13th Feb 05 Shared IRQ handling fixes + * MeelisR 2nd Mar 05 PCI management fixes + * MichalL 5th Mar 05 BitKeeper slot_name fix + * Tor Petterson 19th Apr 05 Power management: Suspend and Resume + * MarkW 15th Jul 05 Disable File Config under 4KSTACK + * IvD 15th Jul 05 Support File Config with 4KSTACK + ***************************************************************************/ + +#include "rt_config.h" + +unsigned long IrqFlags; + +// Global static variable, Debug level flag +// Don't hide this behind debug define. There should be as little difference between debug and no-debug as possible. +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +int debug = 0; /* Default is off. */ +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Enable level: accepted values: 1 to switch debug on, 0 to switch debug off."); + +static char *ifname = NULL ; +MODULE_PARM(ifname, "s"); +MODULE_PARM_DESC(ifname, "Network device name (default ra%d)"); +#else +//int debug = 0; /* Default is off. */ +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Enable level: accepted values: 1 to switch debug on, 0 to switch debug off."); + +static char *ifname = NULL ; +module_param(ifname, charp, 0); +MODULE_PARM_DESC(ifname, "Network device name (default ra%d)"); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ + +// Following information will be show when you run 'modinfo' +MODULE_AUTHOR("http://rt2x00.serialmonkey.com"); +MODULE_DESCRIPTION("Ralink RT2500 802.11g WLAN driver " DRV_VERSION " " DRV_RELDATE); + +MODULE_LICENSE("GPL"); + +extern const struct iw_handler_def rt2500_iw_handler_def; + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0000 +#define CSR_REG_SIZE 0x0174 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x01ff + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static void +rt2x00_get_drvinfo(struct net_device *net_dev, + struct ethtool_drvinfo *drvinfo) +{ + PRTMP_ADAPTER pAd = net_dev->priv; + + strcpy(drvinfo->driver, NIC_DEVICE_NAME); + strcpy(drvinfo->version, DRV_VERSION); + strcpy(drvinfo->bus_info, pci_name(pAd->pPci_Dev)); +} + +static int +rt2x00_get_regs_len(struct net_device *net_dev) +{ + return CSR_REG_SIZE; +} + +static void +rt2x00_get_regs(struct net_device *net_dev, + struct ethtool_regs *regs, void *data) +{ + PRTMP_ADAPTER pAd = net_dev->priv; + unsigned int counter; + + regs->len = CSR_REG_SIZE; + + for (counter = 0; counter < CSR_REG_SIZE; counter += sizeof(u32)) { + RTMP_IO_READ32(pAd, CSR_REG_BASE + counter, (u32*)data); + data += sizeof(u32); + } +} + +static int +rt2x00_get_eeprom_len(struct net_device *net_dev) +{ + return EEPROM_SIZE; +} + +static int +rt2x00_get_eeprom(struct net_device *net_dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + PRTMP_ADAPTER pAd = net_dev->priv; + unsigned int counter; + + for (counter = eeprom->offset; counter < eeprom->len; counter += sizeof(u16)) { + u16 value = RTMP_EEPROM_READ16(pAd, CSR_REG_BASE + counter); + memcpy(data, &value, sizeof(u16)); + data += sizeof(u16); + } + + return 0; +} + +static struct ethtool_ops rt2x00_ethtool_ops = { + .get_drvinfo = rt2x00_get_drvinfo, + .get_regs_len = rt2x00_get_regs_len, + .get_regs = rt2x00_get_regs, + .get_link = ethtool_op_get_link, + .get_eeprom_len = rt2x00_get_eeprom_len, + .get_eeprom = rt2x00_get_eeprom, +}; +#endif + +static INT __devinit RT2500_init_one ( + IN struct pci_dev *pPci_Dev, + IN const struct pci_device_id *ent) +{ + INT rc; + + // wake up and enable device + if (pci_enable_device (pPci_Dev)) + { + rc = -EIO; + } + else + { + rc = RT2500_probe(pPci_Dev, ent); + if (rc) + pci_disable_device(pPci_Dev); + } + return rc; +} + +// +// PCI device probe & initialization function +// +INT __devinit RT2500_probe( + IN struct pci_dev *pPci_Dev, + IN const struct pci_device_id *ent) +{ + struct net_device *net_dev; + RTMP_ADAPTER *pAd; + CHAR *print_name; + INT chip_id = (int) ent->driver_data; + unsigned long csr_addr; + CSR3_STRUC StaMacReg0; + CSR4_STRUC StaMacReg1; + INT Status = -ENODEV; + + printk("%s %s %s http://rt2x00.serialmonkey.com\n", KERN_INFO DRV_NAME, DRV_VERSION, DRV_RELDATE); + + print_name = pPci_Dev ? pci_name(pPci_Dev) : "rt2500"; + + // alloc_etherdev() will set net_dev->name + net_dev = alloc_etherdev(sizeof(RTMP_ADAPTER)); + if (net_dev == NULL) + { + DBGPRINT(RT_DEBUG_TRACE, "init_ethernet failed\n"); + goto err_out; + } + + SET_MODULE_OWNER(net_dev); + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + SET_NETDEV_DEV(net_dev, &(pPci_Dev->dev)); + SET_ETHTOOL_OPS(net_dev, &rt2x00_ethtool_ops); + #endif + + if (pci_request_regions(pPci_Dev, print_name)) + goto err_out_free_netdev; + + // Interrupt IRQ number + net_dev->irq = pPci_Dev->irq; + + // map physical address to virtual address for accessing register + csr_addr = (unsigned long) ioremap(pci_resource_start(pPci_Dev, 0), pci_resource_len(pPci_Dev, 0)); + if (!csr_addr) + { + DBGPRINT(RT_DEBUG_TRACE, "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + print_name, (ULONG)pci_resource_len(pPci_Dev, 0), pci_resource_start(pPci_Dev, 0)); + goto err_out_free_res; + } + + // Save CSR virtual address and irq to device structure + net_dev->base_addr = (unsigned long)csr_addr; + pAd = net_dev->priv; + pAd->CSRBaseAddress = net_dev->base_addr; + pAd->net_dev = net_dev; + + // Set DMA master + pci_set_master(pPci_Dev); + + // Read MAC address + NICReadAdapterInfo(pAd); + + RTMP_IO_READ32(pAd, CSR3, &StaMacReg0.word); + RTMP_IO_READ32(pAd, CSR4, &StaMacReg1.word); + net_dev->dev_addr[0] = StaMacReg0.field.Byte0; + net_dev->dev_addr[1] = StaMacReg0.field.Byte1; + net_dev->dev_addr[2] = StaMacReg0.field.Byte2; + net_dev->dev_addr[3] = StaMacReg0.field.Byte3; + net_dev->dev_addr[4] = StaMacReg1.field.Byte4; + net_dev->dev_addr[5] = StaMacReg1.field.Byte5; + + pAd->chip_id = chip_id; + pAd->pPci_Dev = pPci_Dev; + + // The chip-specific entries in the device structure. + net_dev->open = RT2500_open; + net_dev->hard_start_xmit = RTMPSendPackets; + net_dev->stop = RT2500_close; + net_dev->get_stats = RT2500_get_ether_stats; + +#if WIRELESS_EXT >= 12 +#if WIRELESS_EXT < 17 + net_dev->get_wireless_stats = RT2500_get_wireless_stats; +#endif + net_dev->wireless_handlers = (struct iw_handler_def *) &rt2500_iw_handler_def; +#endif + + net_dev->set_multicast_list = RT2500_set_rx_mode; + net_dev->do_ioctl = RT2500_ioctl; + net_dev->set_mac_address = rt2500_set_mac_address; + + + // register_netdev() will call dev_alloc_name() for us + // TODO: Remove the following line to keep the default eth%d name + if (ifname == NULL) + strcpy(net_dev->name, "ra%d"); + else + strncpy(net_dev->name, ifname, IFNAMSIZ); + + // Enable RF Tuning timer + RTMPInitTimer(pAd, &pAd->PortCfg.RfTuningTimer, AsicRfTuningExec); + + // Register this device + Status = register_netdev(net_dev); + if (Status) + goto err_out_unmap; + + // Allocate DMA descriptors & buffers + Status = RTMPAllocDMAMemory(pAd); + if (Status != NDIS_STATUS_SUCCESS) + goto err_out_unmap; + + DBGPRINT(RT_DEBUG_TRACE, "%s: at 0x%lx, VA 0x%lx, IRQ %d. \n", + net_dev->name, pci_resource_start(pPci_Dev, 0), (unsigned long)csr_addr, pPci_Dev->irq); + + // Set driver data + pci_set_drvdata(pPci_Dev, net_dev); + + // moved to here by RobinC so if-preup can work + // When driver now loads it is loaded up with "factory" defaults + // All this occurs while the net iface is down + // iwconfig can then be used to configure card BEFORE + // ifconfig ra0 up is applied. + // Note the RT2500STA.dat file will still overwrite settings + // but it is useful for the settings iwconfig doesn't let you at + PortCfgInit(pAd); + + MlmeQueueInit(&pAd->Mlme.Queue); // (never fails) + + // Build channel list for default physical mode + BuildChannelList(pAd); + + return 0; + +err_out_unmap: + iounmap((void *)csr_addr); +err_out_free_res: + pci_release_regions(pPci_Dev); +err_out_free_netdev: + kfree (net_dev); +err_out: + return Status; +} + +INT RT2500_open( + IN struct net_device *net_dev) +{ + PRTMP_ADAPTER pAd = net_dev->priv; + INT status = NDIS_STATUS_SUCCESS; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (!try_module_get(THIS_MODULE)) + { + DBGPRINT(RT_DEBUG_ERROR, "%s: cannot reserve module\n", __FUNCTION__); + return -1; + } +#else + MOD_INC_USE_COUNT; +#endif + + // 2. request interrupt + // Disable interrupts here which is as soon as possible + // This statement should never be true. We might consider to remove it later + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + { + NICDisableInterrupt(pAd); + } + + status = request_irq(pAd->pPci_Dev->irq, &RTMPIsr, SA_SHIRQ, net_dev->name, net_dev); + if (status) + { + goto out_module_put; + } + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); + + // 3. Read MAC address + //NICReadAdapterInfo(pAd); + + DBGPRINT(RT_DEBUG_TRACE, "%s: RT2500_open() irq %d. MAC = %02x:%02x:%02x:%02x:%02x:%02x \n", + net_dev->name, pAd->pPci_Dev->irq, pAd->CurrentAddress[0], pAd->CurrentAddress[1], pAd->CurrentAddress[2], + pAd->CurrentAddress[3], pAd->CurrentAddress[4], pAd->CurrentAddress[5]); + + NICInitTransmit(pAd); + + // load in data from RT2500STA.dat file + // note this will TRASH any preup settings applied + // if the parameter exists in the file + RTMPReadParametersFromFile(pAd); + + // initialize MLME + status = MlmeInit(pAd); + + // Initialize Mlme Memory Handler + // Allocate 20 nonpaged memory pool which size are MAX_LEN_OF_MLME_BUFFER for use + status = MlmeInitMemoryHandler(pAd, 20, MAX_LEN_OF_MLME_BUFFER); + + if(status != NDIS_STATUS_SUCCESS) + { + free_irq(net_dev->irq, net_dev); + goto out_module_put; + } + + // Initialize Asics + NICInitializeAdapter(pAd); + + NICReadEEPROMParameters(pAd); + + NICInitAsicFromEEPROM(pAd); + + // 2nd stage hardware initialization after all parameters are acquired from + // Registry or E2PROM + RTMPSetPhyMode(pAd, PHY_11BG_MIXED); + + // Set the timer to check for link beat. +/* RTMPInitTimer(pAd, &pAd->timer, RT2500_timer); + RTMPSetTimer(pAd, &pAd->timer, DEBUG_TASK_DELAY);*/ + + // Enable interrupt + NICEnableInterrupt(pAd); + + // Start net interface tx /rx + netif_start_queue(net_dev); + + netif_carrier_on(net_dev); + netif_wake_queue(net_dev); + + return 0; + +out_module_put: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + module_put(THIS_MODULE); +#else + MOD_DEC_USE_COUNT; +#endif + + return status; +} + +VOID RT2500_timer( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + +// NICCheckForHang(pAd); + + RTMPSetTimer(pAd, &pAd->timer, DEBUG_TASK_DELAY); +} + +/* + ======================================================================== + + Routine Description: + hard_start_xmit handler + + Arguments: + skb point to sk_buf which upper layer transmit + net_dev point to net_dev + Return Value: + None + + Note: + + ======================================================================== +*/ +INT RTMPSendPackets( + IN struct sk_buff *skb, + IN struct net_device *net_dev) +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PRTMP_ADAPTER pAdapter = net_dev->priv; + + DBGPRINT(RT_DEBUG_INFO, "<==== RTMPSendPackets\n"); + + if (pAdapter->PortCfg.BssType == BSS_MONITOR && pAdapter->PortCfg.MallowRFMONTx != TRUE) + { + dev_kfree_skb_irq(skb); + return 0; + } + + // Drop packets if no associations + if ( pAdapter->PortCfg.BssType != BSS_MONITOR && + !INFRA_ON(pAdapter) && !ADHOC_ON(pAdapter)) + { + // Drop send request since there are no physical connection yet + // Check the association status for infrastructure mode + // And Mibss for Ad-hoc mode setup + dev_kfree_skb_irq(skb); + } + else + { + // This function has to manage NdisSendComplete return call within its routine + // NdisSendComplete will acknowledge upper layer in two steps. + // 1. Within Packet Enqueue, set the NDIS_STATUS_PENDING + // 2. Within TxRingTxDone / PrioRingTxDone call NdisSendComplete with final status + // initial skb->data_len=0, we will use this variable to store data size when fragment(in TKIP) + // and skb->len is actual data len + skb->data_len = skb->len; + Status = RTMPSendPacket(pAdapter,skb); + + if (Status != NDIS_STATUS_SUCCESS) + { + // Errors before enqueue stage + dev_kfree_skb_irq(skb); + } + } + + // Dequeue one frame from SendTxWait queue and process it + // There are two place calling dequeue for TX ring. + // 1. Here, right after queueing the frame. + // 2. At the end of TxRingTxDone service routine. + if ((!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && + (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) && + (!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS))) + { + //RTMPDeQueuePacket(pAdapter, &pAdapter->TxSwQueue0); + // Call dequeue without selected queue, let the subroutine select the right priority + // Tx software queue + RTMPDeQueuePacket(pAdapter); + } + + return 0; +} + +/* + ======================================================================== + + Routine Description: + Interrupt handler + + Arguments: + irq interrupt line + dev_instance Pointer to net_device + rgs store process's context before entering ISR, + this parameter is just for debug purpose. + + Return Value: + VOID + + Note: + + ======================================================================== +*/ +irqreturn_t RTMPIsr( + IN INT irq, + IN VOID *dev_instance, + IN struct pt_regs *rgs) +{ + struct net_device *net_dev = dev_instance; + PRTMP_ADAPTER pAdapter = net_dev->priv; + INTSRC_STRUC IntSource; + int ret = 0; + + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleInterrupt\n"); + + // 1. Disable interrupt + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE) && RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + { + NICDisableInterrupt(pAdapter); + } + + // + // Get the interrupt sources & saved to local variable + // + // RTMP_IO_READ32(pAdapter, CSR7, &IntSource); + RTMP_IO_READ32(pAdapter, CSR7, &IntSource.word); + RTMP_IO_WRITE32(pAdapter, CSR7, IntSource.word); + + // + // Handle interrupt, walk through all bits + // Should start from highest priority interrupt + // The priority can be adjust by altering processing if statement + // + // If required spinlock, each interrupt service routine has to acquire + // and release itself. + // + if (IntSource.field.TbcnExpire) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleTbcnInterrupt\n"); + RTMPHandleTbcnInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.TwakeExpire) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleTwakeupInterrupt\n"); + RTMPHandleTwakeupInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.TatimwExpire) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleTatimInterrupt\n"); + // RTMPHandleTatimInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.EncryptionDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleEncryptionDoneInterrupt\n"); + RTMPHandleEncryptionDoneInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.TxRingTxDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleTxRingTxDoneInterrupt\n"); + RTMPHandleTxRingTxDoneInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.AtimRingTxDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleAtimRingTxDoneInterrupt\n"); + RTMPHandleAtimRingTxDoneInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.PrioRingTxDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandlePrioRingTxDoneInterrupt\n"); + RTMPHandlePrioRingTxDoneInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.DecryptionDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleDecryptionDoneInterrupt\n"); + RTMPHandleDecryptionDoneInterrupt(pAdapter); + ret = 1; + } + + if (IntSource.field.RxDone) + { + DBGPRINT(RT_DEBUG_INFO, "====> RTMPHandleRxDoneInterrupt\n"); + RTMPHandleRxDoneInterrupt(pAdapter); + RTMPHandleEncryptionDoneInterrupt(pAdapter); + ret = 1; + } + + // Do nothing if Reset in progress + if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RESET_IN_PROGRESS)) + { + ret = 1; + goto out; + } + + // + // Re-enable the interrupt (disabled in RTMPIsr) + // + NICEnableInterrupt(pAdapter); + + DBGPRINT(RT_DEBUG_INFO, "<==== RTMPHandleInterrupt\n"); +out: + if(ret) + return IRQ_RETVAL(IRQ_HANDLED); + else + return IRQ_RETVAL(IRQ_NONE); +} + +int rt2500_set_mac_address(struct net_device *net_dev, void *addr) +{ + RTMP_ADAPTER *pAd = net_dev->priv; + struct sockaddr *mac = (struct sockaddr*) addr; + u32 set_mac; + + if(netif_running(net_dev)) + return -EBUSY; + + if(!is_valid_ether_addr(&mac->sa_data[0])) + return -EINVAL; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + BUG_ON(net_dev->addr_len != ETH_ALEN); +#endif + + memcpy(net_dev->dev_addr, mac->sa_data, ETH_ALEN); + memcpy(pAd->CurrentAddress, mac->sa_data, ETH_ALEN); + + memset(&set_mac, 0x00, sizeof(INT)); + set_mac = (net_dev->dev_addr[0]) | + (net_dev->dev_addr[1] << 8) | + (net_dev->dev_addr[2] << 16) | + (net_dev->dev_addr[3] << 24); + + RTMP_IO_WRITE32(pAd, CSR3, set_mac); + + memset(&set_mac, 0x00, sizeof(INT)); + set_mac = (net_dev->dev_addr[4]) | + (net_dev->dev_addr[5] << 8); + + RTMP_IO_WRITE32(pAd, CSR4, set_mac); + + printk(KERN_INFO "***rt2x00***: Info - Mac address changed to: %02x:%02x:%02x:%02x:%02x:%02x.\n", net_dev->dev_addr[0], net_dev->dev_addr[1], net_dev->dev_addr[2], net_dev->dev_addr[3], net_dev->dev_addr[4], net_dev->dev_addr[5]); + + return 0; +} + + +#if WIRELESS_EXT >= 12 +/* + ======================================================================== + + Routine Description: + get wireless statistics + + Arguments: + net_dev Pointer to net_device + + Return Value: + struct iw_statistics + + Note: + This function will be called when query /proc + + ======================================================================== +*/ +struct iw_statistics *RT2500_get_wireless_stats( + IN struct net_device *net_dev) +{ + RTMP_ADAPTER *pAd = net_dev->priv; + + // TODO: All elements are zero before be implemented + + pAd->iw_stats.status = 0; // Status - device dependent for now + + pAd->iw_stats.qual.qual = pAd->Mlme.ChannelQuality;//pAd->Mlme.RoamCqi; // link quality (%retries, SNR, %missed beacons or better...) + pAd->iw_stats.qual.level = pAd->PortCfg.LastRssi - RSSI_TO_DBM_OFFSET; // signal level (dBm) + + pAd->iw_stats.qual.noise = (pAd->PortCfg.LastR17Value > BBP_R17_DYNAMIC_UP_BOUND) ? BBP_R17_DYNAMIC_UP_BOUND : ((ULONG) pAd->PortCfg.LastR17Value); // // noise level (dBm) + pAd->iw_stats.qual.updated = 3; // Flags to know if updated + + pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid + pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe + + // pAd->iw_stats.discard.code, discard.fragment, discard.retries, discard.misc has counted in other place + + return &pAd->iw_stats; +} +#endif + +/* + ======================================================================== + + Routine Description: + return ethernet statistics counter + + Arguments: + net_dev Pointer to net_device + + Return Value: + net_device_stats* + + Note: + + ======================================================================== +*/ +struct net_device_stats *RT2500_get_ether_stats( + IN struct net_device *net_dev) +{ + RTMP_ADAPTER *pAd = net_dev->priv; + + DBGPRINT(RT_DEBUG_INFO, "RT2500_get_ether_stats --->\n"); + + pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.vv.LowPart; // total packets received + pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.vv.LowPart; // total packets transmitted + + pAd->stats.rx_bytes= pAd->RalinkCounters.ReceivedByteCount; // total bytes received + pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; // total bytes transmitted + + pAd->stats.rx_errors = pAd->Counters.RxErrors; // bad packets received + pAd->stats.tx_errors = pAd->Counters.TxErrors; // packet transmit problems + + pAd->stats.rx_dropped = pAd->Counters.RxNoBuffer; // no space in linux buffers + pAd->stats.tx_dropped = pAd->WlanCounters.FailedCount.vv.LowPart; // no space available in linux + + pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.vv.LowPart; // multicast packets received + pAd->stats.collisions = pAd->Counters.OneCollision + pAd->Counters.MoreCollisions; // Collision packets + + pAd->stats.rx_length_errors = 0; + pAd->stats.rx_over_errors = pAd->Counters.RxNoBuffer; // receiver ring buff overflow + pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error + pAd->stats.rx_frame_errors = pAd->Counters.RcvAlignmentErrors; // recv'd frame alignment error + pAd->stats.rx_fifo_errors = pAd->Counters.RxNoBuffer; // recv'r fifo overrun + pAd->stats.rx_missed_errors = 0; // receiver missed packet + + // detailed tx_errors + pAd->stats.tx_aborted_errors = 0; + pAd->stats.tx_carrier_errors = 0; + pAd->stats.tx_fifo_errors = 0; + pAd->stats.tx_heartbeat_errors = 0; + pAd->stats.tx_window_errors = 0; + + // for cslip etc + pAd->stats.rx_compressed = 0; + pAd->stats.tx_compressed = 0; + + return &pAd->stats; +} + +/* + ======================================================================== + + Routine Description: + Set to filter multicast list + + Arguments: + net_dev Pointer to net_device + + Return Value: + VOID + + Note: + + ======================================================================== +*/ +VOID RT2500_set_rx_mode( + IN struct net_device *net_dev) +{ + RTMP_ADAPTER *pAd; + pAd = net_dev->priv; + if (pAd->PortCfg.BssType == BSS_MONITOR) + { + RTMP_IO_WRITE32(pAd, RXCSR0, 0x46); + DBGPRINT(RT_DEBUG_TRACE,"rt2500 acknowledge MONITOR on\n"); + } + else if (net_dev->flags&IFF_PROMISC) + { + pAd->bAcceptPromiscuous = TRUE; + RTMP_IO_WRITE32(pAd, RXCSR0, 0x6e); + DBGPRINT(RT_DEBUG_TRACE,"rt2500 acknowledge PROMISC on\n"); + } + else + { + pAd->bAcceptPromiscuous = FALSE; + RTMP_IO_WRITE32(pAd, RXCSR0, 0x7e); + DBGPRINT(RT_DEBUG_TRACE, "rt2500 acknowledge MONITOR/PROMISC off\n"); + } + +} + +// +// Close driver function +// +INT RT2500_close( + IN struct net_device *net_dev) +{ + RTMP_ADAPTER *pAd = net_dev->priv; + // LONG ioaddr = net_dev->base_addr; + + DBGPRINT(RT_DEBUG_TRACE, "%s: ===> RT2500_close\n", net_dev->name); + + LinkDown(pAd); + + // Stop Mlme state machine + RTMPCancelTimer(&pAd->PortCfg.RfTuningTimer); + MlmeHalt(pAd); + + netif_stop_queue(net_dev); + netif_carrier_off(net_dev); + + // Shut down monitor timer task + //RTMPCancelTimer(&pAd->timer); + + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + { + NICDisableInterrupt(pAd); + } + + // Disable Rx, register value supposed will remain after reset + NICIssueReset(pAd); + + // Free IRQ + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) + { + // Deregister interrupt function + free_irq(net_dev->irq, net_dev); + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + module_put(THIS_MODULE); +#else + MOD_DEC_USE_COUNT; +#endif + + return 0; +} + +// +// Remove driver function +// +static VOID __devexit RT2500_remove_one( + IN struct pci_dev *pPci_Dev) +{ + struct net_device *net_dev = pci_get_drvdata(pPci_Dev); + // RTMP_ADAPTER *pAd = net_dev->priv; + + // Free Ring buffers + RTMPFreeDMAMemory(net_dev->priv); + + // Unregister network device + unregister_netdev(net_dev); + + // Unmap CSR base address + iounmap((void *)(net_dev->base_addr)); + + // release memory regions + pci_release_regions(pPci_Dev); + + // disable the device + pci_disable_device(pPci_Dev); + + // Free pre-allocated net_device memory + kfree(net_dev); +} + +// +// prepare for software suspend +// +#ifdef CONFIG_PM +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) +#ifndef pm_message_t +#define pm_message_t u32 +#endif +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) */ + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,9)) +static u32 suspend_buffer[16]; +#define rt2x00_save_state(__pci) pci_save_state(__pci, suspend_buffer) +#define rt2x00_restore_state(__pci) pci_restore_state(__pci, suspend_buffer) +#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)) */ +#define rt2x00_save_state(__pci) pci_save_state(__pci) +#define rt2x00_restore_state(__pci) pci_restore_state(__pci) +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)) */ + +static int rt2500_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + + + if(pAdapter->PortCfg.bRadio) + MlmeRadioOff(pAdapter); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) + printk(KERN_NOTICE "%s: got suspend request (state %d)\n", + dev->name, state); +#else + printk(KERN_NOTICE "%s: got suspend request (event %d)\n", + dev->name, state.event); +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)) */ + + rt2x00_save_state(pdev); + + NICDisableInterrupt(pAdapter); + MlmeHalt(pAdapter); + + netif_stop_queue(dev); + netif_device_detach(dev); + + return 0; +} + +// +// reactivate after software suspend +// +static int rt2500_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; + int status; + + pci_enable_device(pdev); + + printk(KERN_NOTICE "%s: got resume request\n", dev->name); + + rt2x00_restore_state(pdev); + + NICInitTransmit(pAdapter); + status = MlmeInit(pAdapter); + status = MlmeInitMemoryHandler(pAdapter, 20, MAX_LEN_OF_MLME_BUFFER); + NICInitializeAdapter(pAdapter); + NICEnableInterrupt(pAdapter); + + if(pAdapter->PortCfg.bRadio) + MlmeRadioOn(pAdapter); + else + MlmeRadioOff(pAdapter); + + netif_device_attach(dev); + netif_start_queue(dev); + + return 0; +} + +#endif /* CONFIG_PM */ + +// +// Ralink PCI device table, include all supported chipsets +// +static struct pci_device_id rt2500_pci_tbl[] __devinitdata = +{ + {0x1814, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RT2560A}, + {0,} /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, rt2500_pci_tbl); + +// +// Our PCI driver structure +// +static struct pci_driver rt2500_driver = +{ + name: "rt2500", + id_table: rt2500_pci_tbl, + probe: RT2500_init_one, +#ifdef CONFIG_PM + suspend: rt2500_suspend, + resume: rt2500_resume, +#endif /* CONFIG_PM */ +#if LINUX_VERSION_CODE >= 0x20412 || BIG_ENDIAN == TRUE || RTMP_EMBEDDED == TRUE + remove: __devexit_p(RT2500_remove_one), +#else + remove: __devexit(RT2500_remove_one), +#endif +}; + +// ======================================================================= +// LOAD / UNLOAD sections +// ======================================================================= +// +// Driver module load function +// +static INT __init rt2500_init_module(VOID) +{ + return pci_module_init(&rt2500_driver); +} + +// +// Driver module unload function +// +static VOID __exit rt2500_cleanup_module(VOID) +{ + pci_unregister_driver(&rt2500_driver); +} + +module_init(rt2500_init_module); +module_exit(rt2500_cleanup_module); diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_tkip.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_tkip.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_tkip.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_tkip.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,461 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_tkip.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulW 25th Feb 02 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +// Rotation functions on 32 bit values +#define ROL32( A, n ) ( ((A) << (n)) | ( ((A)>>(32-(n))) ) ) +#define ROR32( A, n ) ROL32( (A), 32-(n) ) + +/* + ======================================================================== + + Routine Description: + Convert from UCHAR[] to ULONG in a portable way + + Arguments: + pMICKey pointer to MIC Key + + Return Value: + None + + Note: + + ======================================================================== +*/ +ULONG RTMPTkipGetUInt32( + IN PUCHAR pMICKey) +{ + ULONG res = 0; + int i; + + for (i = 0; i < 4; i++) + { + res |= (*pMICKey++) << (8 * i); + } + + return res; +} + +/* + ======================================================================== + + Routine Description: + Convert from ULONG to UCHAR[] in a portable way + + Arguments: + pDst pointer to destination for convert ULONG to UCHAR[] + val the value for convert + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPTkipPutUInt32( + IN OUT PUCHAR pDst, + IN ULONG val) +{ + int i; + + for(i = 0; i < 4; i++) + { + *pDst++ = (UCHAR) val; + val >>= 8; + } +} + +/* + ======================================================================== + + Routine Description: + Calculate the MIC Value. + + Arguments: + pAdapter Pointer to our adapter + pSrc Pointer to source data for Calculate MIC Value + Len Indicate the length of the source data + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPTkipAppend( + IN PTKIP_KEY_INFO pTkip, + IN PUCHAR pSrc, + IN UINT nBytes) +{ + register ULONG M, L, R, nBytesInM; + + // load data from memory to register + L = pTkip->L; + R = pTkip->R; + nBytesInM = pTkip->nBytesInM; + M = pTkip->M; + + // Alignment case + if((nBytesInM == 0) && ((((unsigned long)pSrc) & 0x3) == 0)) + { + while(nBytes >= 4) + { +#ifdef BIG_ENDIAN + M = SWAP32(*(ULONG *)pSrc); +#else + M = *(ULONG *)pSrc; +#endif + pSrc += 4; + nBytes -= 4; + + L ^= M; + R ^= ROL32( L, 17 ); + L += R; + R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); + L += R; + R ^= ROL32( L, 3 ); + L += R; + R ^= ROR32( L, 2 ); + L += R; + } + nBytesInM = 0; + M = 0; + + while(nBytes > 0) + { + M |= (*pSrc << (8* nBytesInM)); + + nBytesInM++; + pSrc++; + nBytes--; + + if( nBytesInM >= 4 ) + { + L ^= M; + R ^= ROL32( L, 17 ); + L += R; + R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); + L += R; + R ^= ROL32( L, 3 ); + L += R; + R ^= ROR32( L, 2 ); + L += R; + // Clear the buffer + M = 0; + nBytesInM = 0; + } + } + } + else + { // misAlignment case + while(nBytes > 0) + { + M |= (*pSrc << (8* nBytesInM)); + nBytesInM++; + + pSrc++; + nBytes--; + + if( nBytesInM >= 4 ) + { + L ^= M; + R ^= ROL32( L, 17 ); + L += R; + R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); + L += R; + R ^= ROL32( L, 3 ); + L += R; + R ^= ROR32( L, 2 ); + L += R; + // Clear the buffer + M = 0; + nBytesInM = 0; + } + } + } + + // load data from register to memory + pTkip->M = M; + pTkip->nBytesInM = nBytesInM; + pTkip->L = L; + pTkip->R = R; +} + +/* + ======================================================================== + + Routine Description: + Get the MIC Value. + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + the MIC Value is store in pAdapter->PrivateInfo.MIC + ======================================================================== +*/ +VOID RTMPTkipGetMIC( + IN PTKIP_KEY_INFO pTkip) +{ + static unsigned char Last[] = {"\x5a\x00\x00\x00\x00\x00\x00\x00"}; + + // Append the minimum padding + RTMPTkipAppend(pTkip, Last, 8 - pTkip->nBytesInM); + + // The appendByte function has already computed the result. + RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); + RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); +} + +/* + ======================================================================== + + Routine Description: + Compare MIC value of received MSDU + + Arguments: + pAdapter Pointer to our adapter + pSrc Pointer to the received Plain text data + pDA Pointer to DA address + pSA Pointer to SA address + pMICKey pointer to MIC Key + Len the length of the received plain text data exclude MIC value + + Return Value: + TRUE MIC value matched + FALSE MIC value mismatched + + Note: + + ======================================================================== +*/ +BOOLEAN RTMPTkipCompareMICValue( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN PUCHAR pDA, + IN PUCHAR pSA, + IN PUCHAR pMICKey, + IN UINT Len) +{ + static UCHAR Priority[4] = {"\x00\x00\x00\x00"}; + + // Init MIC value calculation and reset the message + pAdapter->PrivateInfo.Rx.L = RTMPTkipGetUInt32(pMICKey); + pAdapter->PrivateInfo.Rx.R = RTMPTkipGetUInt32(pMICKey + 4); + pAdapter->PrivateInfo.Rx.nBytesInM = 0; + pAdapter->PrivateInfo.Rx.M = 0; + + // DA + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pDA, 6); + // SA + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pSA, 6); + // Priority + 3 bytes of 0 + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, Priority, 4); + + // Calculate MIC value from plain text data + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pSrc, Len); + + // Get MIC value from decrypted plain data + RTMPTkipGetMIC(&pAdapter->PrivateInfo.Rx); + + // Move MIC value from MSDU, this steps should move to data path. + // Since the MIC value might cross MPDUs. + if(!NdisEqualMemory(pAdapter->PrivateInfo.Rx.MIC, pSrc + Len, 8)) + { + INT i; + + DBGPRINT(RT_DEBUG_ERROR, "! TKIP MIC Error !\n"); //MIC error. + DBGPRINT(RT_DEBUG_INFO, "Orig MIC value ="); //MIC error. + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", *(UCHAR*)(pSrc + Len + i)); //MIC error. + } + DBGPRINT(RT_DEBUG_INFO, "\n"); //MIC error. + DBGPRINT(RT_DEBUG_INFO, "Calculated MIC value ="); //MIC error. + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PrivateInfo.Rx.MIC[i]); //MIC error. + } + DBGPRINT(RT_DEBUG_INFO, "\n"); //MIC error. + return (FALSE); + } + return (TRUE); +} + +/* + ======================================================================== + + Routine Description: + Compare MIC value of received MSDU + + Arguments: + pAdapter Pointer to our adapter + pLLC LLC header + pSrc Pointer to the received Plain text data + pDA Pointer to DA address + pSA Pointer to SA address + pMICKey pointer to MIC Key + Len the length of the received plain text data exclude MIC value + + Return Value: + TRUE MIC value matched + FALSE MIC value mismatched + + Note: + + ======================================================================== +*/ +BOOLEAN RTMPTkipCompareMICValueWithLLC( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pLLC, + IN PUCHAR pSrc, + IN PUCHAR pDA, + IN PUCHAR pSA, + IN PUCHAR pMICKey, + IN UINT Len) +{ + static UCHAR Priority[4] = {"\x00\x00\x00\x00"}; + + // Init MIC value calculation and reset the message + pAdapter->PrivateInfo.Rx.L = RTMPTkipGetUInt32(pMICKey); + pAdapter->PrivateInfo.Rx.R = RTMPTkipGetUInt32(pMICKey + 4); + pAdapter->PrivateInfo.Rx.nBytesInM = 0; + pAdapter->PrivateInfo.Rx.M = 0; + + // DA + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pDA, 6); + // SA + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pSA, 6); + // Priority + 3 bytes of 0 + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, Priority, 4); + + // Start with LLC header + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pLLC, 8); + + // Calculate MIC value from plain text data + RTMPTkipAppend(&pAdapter->PrivateInfo.Rx, pSrc, Len); + + // Get MIC value from decrypted plain data + RTMPTkipGetMIC(&pAdapter->PrivateInfo.Rx); + + // Move MIC value from MSDU, this steps should move to data path. + // Since the MIC value might cross MPDUs. + if(!NdisEqualMemory(pAdapter->PrivateInfo.Rx.MIC, pSrc + Len, 8)) + { + INT i; + + DBGPRINT(RT_DEBUG_ERROR, "! TKIP MIC Error !\n"); //MIC error. + DBGPRINT(RT_DEBUG_INFO, "Orig MIC value ="); //MIC error. + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", *(UCHAR *)(pSrc + Len + i)); //MIC error. + } + + DBGPRINT(RT_DEBUG_INFO, "\n"); //MIC error. + DBGPRINT(RT_DEBUG_INFO, "Calculated MIC value ="); //MIC error. + for (i = 0; i < 8; i++) + { + DBGPRINT(RT_DEBUG_INFO, "%02x:", pAdapter->PrivateInfo.Rx.MIC[i]); //MIC error. + } + + DBGPRINT(RT_DEBUG_INFO, "\n"); //MIC error. + return (FALSE); + } + return (TRUE); +} + +/* + ======================================================================== + + Routine Description: + Copy frame from waiting queue into relative ring buffer and set + appropriate ASIC register to kick hardware transmit function + + Arguments: + pAdapter Pointer to our adapter + PNDIS_PACKET Pointer to Ndis Packet for MIC calculation + pEncap Pointer to LLC encap data + LenEncap Total encap length, might be 0 which indicates no encap + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPCalculateMICValue( + IN PRTMP_ADAPTER pAdapter, + IN struct sk_buff *skb, + IN PUCHAR pEncap, + IN INT LenEncap, + IN PWPA_KEY pWpaKey) +{ + PUCHAR pSrc; + static UCHAR Priority[4] = {"\x00\x00\x00\x00"}; + + pSrc = (PUCHAR) skb->data; + + // Init MIC value calculation and reset the message + pAdapter->PrivateInfo.Tx.L = RTMPTkipGetUInt32(pWpaKey->TxMic); + pAdapter->PrivateInfo.Tx.R = RTMPTkipGetUInt32(pWpaKey->TxMic + 4); + pAdapter->PrivateInfo.Tx.nBytesInM = 0; + pAdapter->PrivateInfo.Tx.M = 0; + + // DA & SA field + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pSrc, 12); + + // Priority + 3 bytes of 0 + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, Priority, 4); + + if (LenEncap > 0) + { + // LLC encapsulation + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pEncap, LenEncap); + // Protocol Type + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pSrc + 12, skb->len - 12); + } + else + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pSrc + 14, skb->len - 14); + + // Compute the final MIC Value + RTMPTkipGetMIC(&pAdapter->PrivateInfo.Tx); +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_type.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_type.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_type.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_type.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,109 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_type.h + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulL 2md Jan 03 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef __RTMP_TYPE_H__ +#define __RTMP_TYPE_H__ + +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef unsigned long long UINT64; + +#define PACKED __attribute__ ((packed)) + +// Endian byte swapping codes +#ifdef BIG_ENDIAN + +#define SWAP16(x) \ + ((UINT16)( \ + (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ + (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) + +#define SWAP32(x) \ + ((UINT32)( \ + (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ + (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ + (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ + (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) + +#define SWAP64(x) \ + ((UINT64)( \ + (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ + (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) +#else + +#define SWAP16(x) +#define SWAP32(x) +#define SWAP64(x) +#endif + +#ifdef BIG_ENDIAN + +#define cpu2le64(x) SWAP64((x)) +#define le2cpu64(x) SWAP64((x)) +#define cpu2le32(x) SWAP32((x)) +#define le2cpu32(x) SWAP32((x)) +#define cpu2le16(x) SWAP16((x)) +#define le2cpu16(x) SWAP16((x)) +#define cpu2be64(x) ((UINT64)(x)) +#define be2cpu64(x) ((UINT64)(x)) +#define cpu2be32(x) ((UINT32)(x)) +#define be2cpu32(x) ((UINT32)(x)) +#define cpu2be16(x) ((UINT16)(x)) +#define be2cpu16(x) ((UINT16)(x)) + +#else // Little_Endian + +#define cpu2le64(x) ((UINT64)(x)) +#define le2cpu64(x) ((UINT64)(x)) +#define cpu2le32(x) ((UINT32)(x)) +#define le2cpu32(x) ((UINT32)(x)) +#define cpu2le16(x) ((UINT16)(x)) +#define le2cpu16(x) ((UINT16)(x)) +#define cpu2be64(x) SWAP64((x)) +#define be2cpu64(x) SWAP64((x)) +#define cpu2be32(x) SWAP32((x)) +#define be2cpu32(x) SWAP32((x)) +#define cpu2be16(x) SWAP16((x)) +#define be2cpu16(x) SWAP16((x)) + +#endif // BIG_ENDIAN + +#endif // __RTMP_TYPE_H__ + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_wep.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_wep.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/rtmp_wep.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/rtmp_wep.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,441 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: rtmp_wep.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * PaulW 28th Sep 02 Initial code + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +ULONG FCSTAB_32[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +UCHAR WEPKEY[] = { + //IV + 0x00, 0x11, 0x22, + //WEP KEY + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC + }; + + +/* + ======================================================================== + + Routine Description: + Init WEP function. + + Arguments: + pAdapter Pointer to our adapter + pKey Pointer to the WEP KEY + KeyId WEP Key ID + KeyLen the length of WEP KEY + pDest Pointer to the destination which Encryption data will store in. + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPInitWepEngine( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pKey, + IN UCHAR KeyId, + IN UCHAR KeyLen, + IN OUT PUCHAR pDest) +{ + UINT i; + + pAdapter->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. + memcpy(WEPKEY + 3, pKey, KeyLen); + + for(i = 0; i < 3; i++) + WEPKEY[i] = RandomByte(pAdapter); //Call mlme RandomByte() function. + ARCFOUR_INIT(&pAdapter->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) + + memcpy(pDest, WEPKEY, 3); //Append Init Vector + *(pDest+3) = (KeyId << 6); //Append KEYID + +} + +/* + ======================================================================== + + Routine Description: + Encrypt transimitted data + + Arguments: + pAdapter Pointer to our adapter + pSrc Pointer to the transimitted source data that will be encrypt + pDest Pointer to the destination where entryption data will be store in. + Len Indicate the length of the source data + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPEncryptData( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN PUCHAR pDest, + IN UINT Len) +{ + pAdapter->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAdapter->PrivateInfo.FCSCRC32, pSrc, Len); + ARCFOUR_ENCRYPT(&pAdapter->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); +} + +/* + ======================================================================== + + Routine Description: + Decrypt received data + + Arguments: + pAdapter Pointer to our adapter + pSrc Pointer to the received data + Len the length of the received data + + Return Value: + TRUE Decrypt WEP data success + FALSE Decrypt WEP data failed + + Note: + + ======================================================================== +*/ +BOOLEAN RTMPDecryptData( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pSrc, + IN UINT Len) +{ + ULONG trailfcs; + ULONG crc32; + UCHAR KeyIdx; + + memcpy(WEPKEY, pSrc, 3); //Get WEP IV + + KeyIdx = (*(pSrc + 3) & 0xc0) >> 6; + if (pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen == 0) + return (FALSE); + + memcpy(WEPKEY + 3, pAdapter->PortCfg.SharedKey[KeyIdx].Key, pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen); + ARCFOUR_INIT(&pAdapter->PrivateInfo.WEPCONTEXT, WEPKEY, pAdapter->PortCfg.SharedKey[KeyIdx].KeyLen + 3); + ARCFOUR_DECRYPT(&pAdapter->PrivateInfo.WEPCONTEXT, pSrc, pSrc + 4, Len - 4); + memcpy(&trailfcs, pSrc + Len - 8, 4); + crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pSrc, Len - 8); //Skip last 4 bytes(FCS). + crc32 ^= 0xffffffff; /* complement */ +#ifndef BIG_ENDIAN + if(crc32 != trailfcs) +#else + if(crc32 != SWAP32(trailfcs)) +#endif + { + DBGPRINT(RT_DEBUG_TRACE, "! WEP Data CRC Error !\n"); //CRC error. + return (FALSE); + } + return (TRUE); +} + +/* + ======================================================================== + + Routine Description: + The Stream Cipher Encryption Algorithm "ARCFOUR" initialize + + Arguments: + Ctx Pointer to ARCFOUR CONTEXT (SBOX) + pKey Pointer to the WEP KEY + KeyLen Indicate the length fo the WEP KEY + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID ARCFOUR_INIT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pKey, + IN UINT KeyLen) +{ + UCHAR t, u; + UINT keyindex; + UINT stateindex; + PUCHAR state; + UINT counter; + + state = Ctx->STATE; + Ctx->X = 0; + Ctx->Y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = (UCHAR)counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) + { + t = state[counter]; + stateindex = (stateindex + pKey[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = t; + state[counter] = u; + if (++keyindex >= KeyLen) + keyindex = 0; + } +} + +/* + ======================================================================== + + Routine Description: + Get bytes from ARCFOUR CONTEXT (S-BOX) + + Arguments: + Ctx Pointer to ARCFOUR CONTEXT (SBOX) + + Return Value: + UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) + + Note: + + ======================================================================== +*/ +UCHAR ARCFOUR_BYTE( + IN PARCFOURCONTEXT Ctx) +{ + UINT x; + UINT y; + UCHAR sx, sy; + PUCHAR state; + + state = Ctx->STATE; + x = (Ctx->X + 1) & 0xff; + sx = state[x]; + y = (sx + Ctx->Y) & 0xff; + sy = state[y]; + Ctx->X = x; + Ctx->Y = y; + state[y] = sx; + state[x] = sy; + + return(state[(sx + sy) & 0xff]); + +} + +/* + ======================================================================== + + Routine Description: + The Stream Cipher Decryption Algorithm + + Arguments: + Ctx Pointer to ARCFOUR CONTEXT (SBOX) + pDest Pointer to the Destination + pSrc Pointer to the Source data + Len Indicate the length of the Source data + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID ARCFOUR_DECRYPT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pDest, + IN PUCHAR pSrc, + IN UINT Len) +{ + UINT i; + + for (i = 0; i < Len; i++) + pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); +} + +/* + ======================================================================== + + Routine Description: + The Stream Cipher Encryption Algorithm + + Arguments: + Ctx Pointer to ARCFOUR CONTEXT (SBOX) + pDest Pointer to the Destination + pSrc Pointer to the Source data + Len Indicate the length of the Source dta + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID ARCFOUR_ENCRYPT( + IN PARCFOURCONTEXT Ctx, + IN PUCHAR pDest, + IN PUCHAR pSrc, + IN UINT Len) +{ + UINT i; + + for (i = 0; i < Len; i++) + pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); +} + +/* + ======================================================================== + + Routine Description: + Calculate a new FCS given the current FCS and the new data. + + Arguments: + Fcs the original FCS value + Cp pointer to the data which will be calculate the FCS + Len the length of the data + + Return Value: + ULONG - FCS 32 bits + + Note: + + ======================================================================== +*/ +ULONG RTMP_CALC_FCS32( + IN ULONG Fcs, + IN PUCHAR Cp, + IN INT Len) +{ + while (Len--) + Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); + + return (Fcs); +} + + +/* + ======================================================================== + + Routine Description: + Get last FCS and encrypt it to the destination + + Arguments: + pDest Pointer to the Destination + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID RTMPSetICV( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pDest) +{ + pAdapter->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ + +#ifdef BIG_ENDIAN + pAdapter->PrivateInfo.FCSCRC32 = SWAP32(pAdapter->PrivateInfo.FCSCRC32); +#endif + + ARCFOUR_ENCRYPT(&pAdapter->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAdapter->PrivateInfo.FCSCRC32, 4); +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/sanity.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/sanity.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/sanity.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/sanity.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,831 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: sanity.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN MlmeScanReqSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT UCHAR *BssType, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen, + OUT UCHAR *ScanType) +{ + MLME_SCAN_REQ_STRUCT *Info; + + Info = (MLME_SCAN_REQ_STRUCT *)(Msg); + *BssType = Info->BssType; + *SsidLen = Info->SsidLen; + memcpy(Ssid, Info->Ssid, *SsidLen); + *ScanType = Info->ScanType; + + if ((*BssType == BSS_INFRA || *BssType == BSS_INDEP || *BssType == BSS_ANY) && + (*ScanType == SCAN_ACTIVE || *ScanType == SCAN_PASSIVE)) + return TRUE; + else + { + DBGPRINT(RT_DEBUG_TRACE, "MlmeScanReqSanity fail - wrong BssType or ScanType\n"); + return FALSE; + } +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN MlmeStartReqSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen) +{ + MLME_START_REQ_STRUCT *Info; + + Info = (MLME_START_REQ_STRUCT *)(Msg); + + if (Info->SsidLen > MAX_LEN_OF_SSID) + { + DBGPRINT(RT_DEBUG_TRACE, "MlmeStartReqSanity fail - wrong SSID length\n"); + return FALSE; + } + + *SsidLen = Info->SsidLen; + memcpy(Ssid, Info->Ssid, *SsidLen); + + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN MlmeAssocReqSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *ApAddr, + OUT USHORT *CapabilityInfo, + OUT ULONG *Timeout, + OUT USHORT *ListenIntv) +{ + MLME_ASSOC_REQ_STRUCT *Info; + + Info = (MLME_ASSOC_REQ_STRUCT *)Msg; + *Timeout = Info->Timeout; // timeout + COPY_MAC_ADDR(ApAddr, &Info->Addr); // AP address + *CapabilityInfo = Info->CapabilityInfo; // capability info + *ListenIntv = Info->ListenIntv; + + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN MlmeAuthReqSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr, + OUT ULONG *Timeout, + OUT USHORT *Alg) +{ + MLME_AUTH_REQ_STRUCT *Info; + + Info = (MLME_AUTH_REQ_STRUCT *)Msg; + COPY_MAC_ADDR(Addr, &Info->Addr); + *Timeout = Info->Timeout; + *Alg = Info->Alg; + + if ((*Alg == Ndis802_11AuthModeShared || *Alg == Ndis802_11AuthModeOpen) && !MAC_ADDR_IS_GROUP(*Addr)) + { + return TRUE; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "MlmeAuthReqSanity fail - wrong algorithm\n"); + return FALSE; + } +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerAssocRspSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *CapabilityInfo, + OUT USHORT *Status, + OUT USHORT *Aid, + OUT UCHAR Rates[], + OUT UCHAR *RatesLen, + OUT BOOLEAN *ExtendedRateIeExist) +{ + CHAR IeType, *Ptr; + MACFRAME *Fr = (MACFRAME *)Msg; + PBEACON_EID_STRUCT eid_ptr; + + COPY_MAC_ADDR(Addr2, &Fr->Hdr.Addr2); + Ptr = Fr->Octet; + + memcpy(CapabilityInfo, &Fr->Octet[0], 2); + memcpy(Status, &Fr->Octet[2], 2); + // Mask out unnecessary capability information + *CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; + + if (*Status == MLME_SUCCESS) + { + memcpy(Aid, &Fr->Octet[4], 2); + *Aid = (*Aid) & 0x3fff; // AID is low 14-bit + + // -- get supported rates from payload and advance the pointer + IeType = Fr->Octet[6]; + *RatesLen = Fr->Octet[7]; + if ((IeType != IE_SUPP_RATES) || (*RatesLen > MAX_LEN_OF_SUPPORTED_RATES)) + { + DBGPRINT(RT_DEBUG_TRACE, "PeerAssocRspSanity fail - wrong SupportedRates IE\n"); + return FALSE; + } + else + memcpy(Rates, &Fr->Octet[8], *RatesLen); + + // many AP implement proprietary IEs in non-standard order, we'd better + // tolerate mis-ordered IEs to get best compatibility + *ExtendedRateIeExist = FALSE; + eid_ptr = (PBEACON_EID_STRUCT) &Fr->Octet[8 + (*RatesLen)]; + + // get variable fields from payload and advance the pointer + while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) + { + switch (eid_ptr->Eid) + { + case IE_EXT_SUPP_RATES: + *ExtendedRateIeExist = TRUE; + if ((*RatesLen + eid_ptr->Len) <= MAX_LEN_OF_SUPPORTED_RATES) + { + memcpy(&Rates[*RatesLen], eid_ptr->Octet, eid_ptr->Len); + *RatesLen = (*RatesLen) + eid_ptr->Len; + } + else + { + memcpy(&Rates[*RatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*RatesLen)); + *RatesLen = MAX_LEN_OF_SUPPORTED_RATES; + } + break; + default: + DBGPRINT(RT_DEBUG_TRACE, "PeerAssocRspSanity - ignore unrecognized EID = %d\n", eid_ptr->Eid); + break; + } + + eid_ptr = (PBEACON_EID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); + } + + } + + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerDisassocSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *Reason) +{ + MACFRAME *Fr = (MACFRAME *)Msg; + + COPY_MAC_ADDR(Addr2, &Fr->Hdr.Addr2); + memcpy(Reason, &Fr->Octet[0], 2); + + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerDeauthSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT USHORT *Reason) +{ + MACFRAME *Fr = (MACFRAME *)Msg; + + COPY_MAC_ADDR(Addr2, &Fr->Hdr.Addr2); + memcpy(Reason, &Fr->Octet[0], 2); + + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerAuthSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr, + OUT USHORT *Alg, + OUT USHORT *Seq, + OUT USHORT *Status, + CHAR *ChlgText) +{ + MACFRAME *Fr = (MACFRAME *)Msg; + + COPY_MAC_ADDR(Addr, &Fr->Hdr.Addr2); + memcpy(Alg, &Fr->Octet[0], 2); + memcpy(Seq, &Fr->Octet[2], 2); + memcpy(Status, &Fr->Octet[4], 2); + + if (*Alg == Ndis802_11AuthModeOpen) + { + if (*Seq == 1 || *Seq == 2) + { + return TRUE; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerAuthSanity fail - wrong Seg#\n"); + return FALSE; + } + } + else if (*Alg == Ndis802_11AuthModeShared) + { + if (*Seq == 1 || *Seq == 4) + { + return TRUE; + } + else if (*Seq == 2 || *Seq == 3) + { + memcpy(ChlgText, &Fr->Octet[8], CIPHER_TEXT_LEN); + return TRUE; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerAuthSanity fail - wrong Seg#\n"); + return FALSE; + } + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerAuthSanity fail - wrong algorithm\n"); + return FALSE; + } +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerProbeReqSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen) +// OUT UCHAR Rates[], +// OUT UCHAR *RatesLen) +{ + UCHAR Idx; + UCHAR RateLen; + CHAR IeType; + MACFRAME *Fr = (MACFRAME *)Msg; + + COPY_MAC_ADDR(Addr2, &Fr->Hdr.Addr2); + + if ((Fr->Octet[0] != IE_SSID) || (Fr->Octet[1] > MAX_LEN_OF_SSID)) + { + DBGPRINT(RT_DEBUG_TRACE, "PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",Fr->Octet[0],Fr->Octet[1]); + return FALSE; + } + + *SsidLen = Fr->Octet[1]; + memcpy(Ssid, &Fr->Octet[2], *SsidLen); + +#if 1 + Idx = *SsidLen + 2; + + // -- get supported rates from payload and advance the pointer + IeType = Fr->Octet[Idx]; + RateLen = Fr->Octet[Idx + 1]; + if (IeType != IE_SUPP_RATES) + { + DBGPRINT(RT_DEBUG_TRACE, "PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",Fr->Octet[Idx],Fr->Octet[Idx+1]); + return FALSE; + } + else + { + if ((pAd->PortCfg.AdhocMode == 2) && (RateLen < 8)) + return (FALSE); + } +#endif + return TRUE; +} + +/* + ========================================================================== + Description: + MLME message sanity check + Return: + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +BOOLEAN PeerBeaconAndProbeRspSanity( + IN PRTMP_ADAPTER pAd, + IN VOID *Msg, + IN ULONG MsgLen, + OUT MACADDR *Addr2, + OUT MACADDR *Bssid, + OUT CHAR Ssid[], + OUT UCHAR *SsidLen, + OUT UCHAR *BssType, + OUT USHORT *BeaconPeriod, + OUT UCHAR *Channel, + OUT LARGE_INTEGER *Timestamp, + OUT BOOLEAN *CfExist, + OUT CF_PARM *CfParm, + OUT USHORT *AtimWin, + OUT USHORT *CapabilityInfo, + OUT UCHAR Rate[], + OUT UCHAR *RateLen, + OUT BOOLEAN *ExtendedRateIeExist, + OUT UCHAR *Erp, + OUT UCHAR *DtimCount, + OUT UCHAR *DtimPeriod, + OUT UCHAR *BcastFlag, + OUT UCHAR *MessageToMe, + OUT UCHAR *Legacy, + OUT UCHAR SupRate[], + OUT UCHAR *SupRateLen, + OUT UCHAR ExtRate[], + OUT UCHAR *ExtRateLen, + OUT PNDIS_802_11_VARIABLE_IEs pVIE) +{ + CHAR *Ptr, TimLen; + MACFRAME *Fr; + PBEACON_EID_STRUCT eid_ptr; + UCHAR SubType; + UCHAR Sanity; + + // Add for 3 necessary EID field check + Sanity = 0; + + *ExtendedRateIeExist = FALSE; + *Erp = 0; + + Fr = (MACFRAME *)Msg; + + // get subtype from header + SubType = (UCHAR)Fr->Hdr.SubType; + + // get Addr2 and BSSID from header + COPY_MAC_ADDR(Addr2, &Fr->Hdr.Addr2); + COPY_MAC_ADDR(Bssid, &Fr->Hdr.Addr3); + + Ptr = Fr->Octet; + + // get timestamp from payload and advance the pointer + memcpy(Timestamp, Ptr, TIMESTAMP_LEN); + Ptr += TIMESTAMP_LEN; + + // get beacon interval from payload and advance the pointer + memcpy(BeaconPeriod, Ptr, 2); + Ptr += 2; + + // get capability info from payload and advance the pointer + memcpy(CapabilityInfo, Ptr, 2); + Ptr += 2; + if (CAP_IS_ESS_ON(*CapabilityInfo)) + { + *BssType = BSS_INFRA; + } + else + { + *BssType = BSS_INDEP; + } + + // Mask out unnecessary capability information + *CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; + + eid_ptr = (PBEACON_EID_STRUCT) Ptr; + + // get variable fields from payload and advance the pointer + while(((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) + { + switch(eid_ptr->Eid) + { + case IE_SSID: + // Already has one SSID EID in this beacon, ignore the second one + if (Sanity & 0x1) + break; + if(eid_ptr->Len <= MAX_LEN_OF_SSID) + { + memcpy(Ssid, eid_ptr->Octet, eid_ptr->Len); + memset(Ssid + eid_ptr->Len,0,1); + *SsidLen = eid_ptr->Len; + Sanity |= 0x1; + //DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - ESSID=%s Len=%d\n",Ssid,eid_ptr->Len); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",eid_ptr->Len); + return FALSE; + } + break; + + case IE_SUPP_RATES: + if(eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) + { + int index; + UCHAR rate, i; + PUCHAR eid_rate; + + i = 0; + eid_rate = eid_ptr->Octet; + for (index = 0; index < eid_ptr->Len; index++) + { + rate = eid_rate[index] & 0x7f; // Mask out basic rate set bit + if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22) || + (rate == 12) || (rate == 18) || (rate == 24) || (rate == 36) || + (rate == 48) || (rate == 72) || (rate == 96) || (rate == 108)) + Rate[i++] = eid_rate[index]; // Save rate with basic rate set bit if exists + } + *RateLen = i; + Sanity |= 0x2; + + // Copy supported rate from desired AP's beacon. We are trying to match + // AP's supported and extended rate settings. + memcpy(SupRate, eid_ptr->Octet, eid_ptr->Len); + *SupRateLen = eid_ptr->Len; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",eid_ptr->Len); + return FALSE; + } + break; + + case IE_FH_PARM: + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n"); + break; + + case IE_DS_PARM: + if(eid_ptr->Len == 1) + { + *Channel = *eid_ptr->Octet; + if (ChannelSanity(pAd, *Channel) == 0) + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (ch=%d)\n",*Channel); + return FALSE; + } + Sanity |= 0x4; + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",eid_ptr->Len); + return FALSE; + } + break; + + case IE_CF_PARM: + if(eid_ptr->Len == 6) + { + *CfExist = TRUE; + memcpy(CfParm, eid_ptr->Octet, eid_ptr->Len); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n"); + return FALSE; + } + break; + + case IE_IBSS_PARM: + if(eid_ptr->Len == 2) + { + memcpy(AtimWin, eid_ptr->Octet, eid_ptr->Len); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, "PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n"); + return FALSE; + } + break; + + case IE_TIM: + if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) + { + GetTimBit((PUCHAR)eid_ptr, pAd->PortCfg.Aid, &TimLen, BcastFlag, DtimCount, DtimPeriod, MessageToMe); + } + break; + + // New for WPA + case IE_WPA: + // Check the OUI version, filter out non-standard usage + if (RTMPEqualMemory(eid_ptr->Octet, WPA_OUI, 4)) + { + // Copy to pVIE which will report to microsoft bssid list. + pVIE->ElementID = eid_ptr->Eid; + pVIE->Length = eid_ptr->Len; + memcpy(pVIE->data, eid_ptr->Octet, eid_ptr->Len); + } + DBGPRINT(RT_DEBUG_INFO, "PeerBeaconAndProbeRspSanity - Receive IE_WPA\n"); + break; + + case IE_EXT_SUPP_RATES: + // concatenate all extended rates to Rates[] and RateLen + *ExtendedRateIeExist = TRUE; + if (eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) + { + int index; + UCHAR rate, i; + PUCHAR eid_rate; + + i = *RateLen; + eid_rate = eid_ptr->Octet; + for (index = 0; index < eid_ptr->Len; index++) + { + rate = eid_rate[index] & 0x7f; // Mask out basic rate set bit + if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22) || + (rate == 12) || (rate == 18) || (rate == 24) || (rate == 36) || + (rate == 48) || (rate == 72) || (rate == 96) || (rate == 108)) + Rate[i++] = eid_rate[index]; // Save rate with basic rate set bit if exists + + if (i >= MAX_LEN_OF_SUPPORTED_RATES) + break; + } + *RateLen = i; + // Copy extended rate from desired AP's beacon. We are trying to match + // AP's supported and extended rate settings. + memcpy(ExtRate, eid_ptr->Octet, eid_ptr->Len); + *ExtRateLen = eid_ptr->Len; + } + break; + + case IE_ERP: + if (eid_ptr->Len == 1) + { + *Erp = (UCHAR)eid_ptr->Octet[0]; + } + break; + + default: + DBGPRINT(RT_DEBUG_INFO, "PeerBeaconAndProbeRspSanity - unrecognized EID = %d\n", eid_ptr->Eid); + break; + } + + eid_ptr = (PBEACON_EID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); + } + + + // in 802.11a band, AP may skip this DS IE in their BEACON + if ((pAd->PortCfg.Channel > 14) && ((Sanity & 0x04)==0)) + { + *Channel = pAd->PortCfg.Channel; + Sanity |= 0x04; + } + + if (Sanity != 0x7) + { + DBGPRINT(RT_DEBUG_WARN, "PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity); + return FALSE; + } + else + { + return TRUE; + } + +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +BOOLEAN GetTimBit( + IN CHAR *Ptr, + IN USHORT Aid, + OUT UCHAR *TimLen, + OUT UCHAR *BcastFlag, + OUT UCHAR *DtimCount, + OUT UCHAR *DtimPeriod, + OUT UCHAR *MessageToMe) +{ + UCHAR BitCntl, N1, N2, MyByte, MyBit; + CHAR *IdxPtr; + + IdxPtr = Ptr; + + IdxPtr ++; + *TimLen = *IdxPtr; + + // get DTIM Count from TIM element + IdxPtr ++; + *DtimCount = *IdxPtr; + + // get DTIM Period from TIM element + IdxPtr++; + *DtimPeriod = *IdxPtr; + + // get Bitmap Control from TIM element + IdxPtr++; + BitCntl = *IdxPtr; + + if ((*DtimCount == 0) && (BitCntl & 0x01)) + *BcastFlag = TRUE; + else + *BcastFlag = FALSE; + +#if 1 + // Parse Partial Virtual Bitmap from TIM element + N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# + N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# + + if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) + *MessageToMe = FALSE; + else + { + MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream + MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); + + IdxPtr += (MyByte + 1); + + //if (*IdxPtr) + // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); + + if (*IdxPtr & (0x01 << MyBit)) + *MessageToMe = TRUE; + else + *MessageToMe = FALSE; + } +#else + *MessageToMe = FALSE; +#endif + + return TRUE; +} + + +/*! + * \brief Get legacy bit, right now for 11b it is always 0 + * \param + * \return TRUE if the parameters are OK, FALSE otherwise. Always return TRUE + * \pre + * \post + */ +BOOLEAN GetLegacy( + IN CHAR *Ptr, + OUT UCHAR *Legacy) +{ + *Legacy = 0; + return TRUE; +} + +UCHAR ChannelSanity( + IN PRTMP_ADAPTER pAd, + IN UCHAR channel) +{ + UCHAR index; + + for (index = 0; index < pAd->PortCfg.ChannelListNum; index ++) + { + if (channel == pAd->PortCfg.ChannelList[index]) + return 1; + } + return 0; + +#if 0 + switch (pAd->PortCfg.CountryRegion) + { + case REGION_FCC: // 1 - 11 + if ((channel > 0) && (channel < 12)) + return 1; + break; + + case REGION_IC: // 1 -11 + if ((channel > 0) && (channel < 12)) + return 1; + break; + + case REGION_ETSI: // 1 - 13 + if ((channel > 0) && (channel < 14)) + return 1; + break; + + case REGION_SPAIN: // 10 - 11 + if ((channel > 9) && (channel < 12)) + return 1; + break; + + case REGION_FRANCE: // 10 -13 + if ((channel > 9) && (channel < 14)) + return 1; + break; + + case REGION_MKK: // 14 + if (channel == 14) + return 1; + break; + + case REGION_MKK1: // 1 - 14 + if ((channel > 0) && (channel < 15)) + return 1; + break; + + case REGION_ISRAEL: // 3 - 9 + if ((channel > 2) && (channel < 10)) + return 1; + break; + + default: // Error + return 0; + } + return (0); +#endif +} diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/sync.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/sync.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/sync.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/sync.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1517 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: sync.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + * MarkW 10th Dec 04 Rolled in Ralink 1.4.5.0 +* MarkW 5th Jun 05 Fix no-SSID broadcasting assoc. + ***************************************************************************/ + +#include "rt_config.h" + +// 2.4 Ghz channel plan +UCHAR Ra24Ghz_FCC[] = {1,2,3,4,5,6,7,8,9,10,11}; +UCHAR Ra24Ghz_IC[] = {1,2,3,4,5,6,7,8,9,10,11}; +UCHAR Ra24Ghz_ESTI[]= {1,2,3,4,5,6,7,8,9,10,11,12,13}; +UCHAR Ra24Ghz_SPAIN[] = {10,11}; +UCHAR Ra24Ghz_FRANCE[] = {10,11,12,13}; +UCHAR Ra24Ghz_MKK[] = {14}; +UCHAR Ra24Ghz_MKK1[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14}; +UCHAR Ra24Ghz_ISRAEL[] = {3,4,5,6,7,8,9}; + +// 5 Ghz channel plan +UCHAR Ra5Ghz_UNII[] = {36,40,44,48,52,56,60,64, 149,153,157,161}; +UCHAR Ra5Ghz_MMAC[] = {34,38,42,46}; +UCHAR Ra5Ghz_HyperLAN2[] = {36,40,44,48,52,56,60,64, 100,104,108,112,116,120,124,128,132,136,140}; + +extern UCHAR CipherSuiteWpaNoneTkip[]; +extern UCHAR CipherSuiteWpaNoneTkipLen; + +extern UCHAR CipherSuiteWpaNoneAes[]; +extern UCHAR CipherSuiteWpaNoneAesLen; + +/* + ========================================================================== + Description: + The sync state machine, + Parameters: + Sm - pointer to the state machine + Note: + the state machine looks like the following + + Column 1-2 + SYNC_IDLE JOIN_WAIT_BEACON + MT2_MLME_SCAN_REQ mlme_scan_req_action invalid_state_when_scan + MT2_MLME_JOIN_REQ mlme_join_req_action invalid_state_when_join + MT2_MLME_START_REQ mlme_start_req_action invalid_state_when_start + MT2_PEER_BEACON peer_beacon peer_beacon_at_join_wait_beacon_action + MT2_PEER_PROBE_RSP peer_beacon drop + MT2_PEER_ATIM drop drop + MT2_SCAN_TIMEOUT Drop Drop + MT2_BEACON_TIMEOUT Drop beacon_timeout_at_join_wait_beacon_action + MT2_ATIM_TIMEOUT Drop Drop + MT2_PEER_PROBE_REQ ???? drop + + column 3 + SCAN_LISTEN + MT2_MLME_SCAN_REQ invalid_state_when_scan + MT2_MLME_JOIN_REQ invalid_state_when_join + MT2_MLME_START_REQ invalid_state_when_start + MT2_PEER_BEACON peer_beacon_at_scan_action + MT2_PEER_PROBE_RSP peer_probe_rsp_at_scan_action + MT2_PEER_ATIM drop + MT2_SCAN_TIMEOUT scan_timeout_action + MT2_BEACON_TIMEOUT Drop + MT2_ATIM_TIMEOUT Drop + MT2_PEER_PROBE_REQ drop + ========================================================================== + */ +VOID SyncStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *Sm, + OUT STATE_MACHINE_FUNC Trans[]) +{ + StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); + + // column 1 + StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); + StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); + StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); + StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); +// StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeacon); + StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); + + //column 2 + StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); + StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); + StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); + StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); + StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); + + // column 3 + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); + StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); + + // timer init + RTMPInitTimer(pAd, &pAd->Mlme.SyncAux.BeaconTimer, BeaconTimeout); + RTMPInitTimer(pAd, &pAd->Mlme.SyncAux.ScanTimer, ScanTimeout); +} + +/* + ========================================================================== + Description: + Becaon timeout handler, executed in timer thread + ========================================================================== + */ +VOID BeaconTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + DBGPRINT(RT_DEBUG_TRACE,"SYNC - BeaconTimeout\n"); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + ATIM timeout handler, executed in timer thread + ========================================================================== + */ +VOID AtimTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + DBGPRINT(RT_DEBUG_TRACE,"SYNC - AtimTimeout \n"); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_ATIM_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + Scan timeout handler, executed in timer thread + ========================================================================== + */ +VOID ScanTimeout( + IN unsigned long data) +{ + RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)data; + + DBGPRINT(RT_DEBUG_INFO,"SYNC - Scan Timeout \n"); + MlmeEnqueue(&pAd->Mlme.Queue, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL); + MlmeHandler(pAd); +} + +/* + ========================================================================== + Description: + MLME SCAN req state machine procedure + ========================================================================== + */ +VOID MlmeScanReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType; + ULONG Now; + + // Suspend MSDU transmission here + RTMPSuspendMsduTransmission(pAd); + + // first check the parameter sanity + if (MlmeScanReqSanity(pAd, + Elem->Msg, + Elem->MsgLen, + &BssType, + Ssid, + &SsidLen, + &ScanType)) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - MlmeScanReqAction\n"); + Now = jiffies; + pAd->PortCfg.LastScanTime = Now; + // reset all the timers + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + + // record desired BSS parameters + pAd->Mlme.SyncAux.BssType = BssType; + pAd->Mlme.SyncAux.ScanType = ScanType; + pAd->Mlme.SyncAux.SsidLen = SsidLen; + memcpy(pAd->Mlme.SyncAux.Ssid, Ssid, SsidLen); + + // start from the first channel + pAd->Mlme.SyncAux.Channel = FirstChannel(pAd); + ScanNextChannel(pAd); + } + else + { + printk(KERN_ERR DRV_NAME "SYNC - MlmeScanReqAction() sanity check fail. BUG!!!\n"); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_INVALID_FORMAT); + } +} + +/* + ========================================================================== + Description: + MLME JOIN req state machine procedure + ========================================================================== + */ +VOID MlmeJoinReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + BSS_ENTRY *pBss; + MLME_JOIN_REQ_STRUCT *Info = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - MlmeJoinReqAction(BSS #%d)\n", Info->BssIdx); + + // reset all the timers + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + + pBss = &pAd->Mlme.CntlAux.SsidBssTab.BssEntry[Info->BssIdx]; + + // record the desired SSID & BSSID we're waiting for + COPY_MAC_ADDR(&pAd->Mlme.SyncAux.Bssid, &pBss->Bssid); + memcpy(pAd->Mlme.SyncAux.Ssid, pBss->Ssid, pBss->SsidLen); + pAd->Mlme.SyncAux.SsidLen = pBss->SsidLen; + + // switch channel and waiting for beacon timer + AsicSwitchChannel(pAd, pBss->Channel); + AsicLockChannel(pAd, pBss->Channel); + DBGPRINT(RT_DEBUG_TRACE, "SYNC - Switch to channel %d, SSID %s \n", pBss->Channel, pAd->Mlme.SyncAux.Ssid); + DBGPRINT(RT_DEBUG_TRACE, "SYNC - Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x ...\n", + pAd->Mlme.SyncAux.Bssid.Octet[0], pAd->Mlme.SyncAux.Bssid.Octet[1], + pAd->Mlme.SyncAux.Bssid.Octet[2], pAd->Mlme.SyncAux.Bssid.Octet[3], + pAd->Mlme.SyncAux.Bssid.Octet[4], pAd->Mlme.SyncAux.Bssid.Octet[5]); + RTMPSetTimer(pAd, &pAd->Mlme.SyncAux.BeaconTimer, JOIN_TIMEOUT); + + pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; +} + +/* + ========================================================================== + Description: + MLME START Request state machine procedure, starting an IBSS + ========================================================================== + */ +VOID MlmeStartReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; + + // New for WPA security suites + UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 + NDIS_802_11_VARIABLE_IEs *pVIE = NULL; + LARGE_INTEGER TimeStamp; + BOOLEAN Privacy; +#ifdef SINGLE_ADHOC_LINKUP + ULONG Bssidx; + BOOLEAN CfExist = FALSE; + CF_PARM CfParm; +#endif + + // Init Variable IE structure + pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; + pVIE->Length = 0; + TimeStamp.vv.LowPart = 0; + TimeStamp.vv.HighPart = 0; + + if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) + { + // reset all the timers + RTMPCancelTimer(&pAd->Mlme.SyncAux.ScanTimer); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + + // PortCfg.PrivacyInvoked should have been set via OID_802_11_WEP_STATUS. + // pAd->PortCfg.PrivacyInvoked = FALSE; + + memcpy(pAd->PortCfg.Ssid, Ssid, SsidLen); + pAd->PortCfg.SsidLen = SsidLen; + pAd->PortCfg.BssType = BSS_INDEP; + Privacy = (pAd->PortCfg.WepStatus == Ndis802_11Encryption1Enabled) || + (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) || + (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled); + pAd->PortCfg.CapabilityInfo = CAP_GENERATE(0,1,0,0,Privacy, (pAd->PortCfg.WindowsTxPreamble == Rt802_11PreambleShort)); + pAd->PortCfg.BeaconPeriod = pAd->PortCfg.IbssConfig.BeaconPeriod; + pAd->PortCfg.AtimWin = pAd->PortCfg.IbssConfig.AtimWin; + pAd->PortCfg.Channel = pAd->PortCfg.IbssConfig.Channel; + if ((pAd->PortCfg.PhyMode == PHY_11ABG_MIXED) && (pAd->PortCfg.Channel > 14)) + { + // no 1,2,5.5,11 Mbps when in 5Ghz band + pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen - 4; + memset(pAd->PortCfg.SupportedRates, 0, MAX_LEN_OF_SUPPORTED_RATES); + memcpy(pAd->PortCfg.SupportedRates, &pAd->PortCfg.IbssConfig.SupportedRates[4], MAX_LEN_OF_SUPPORTED_RATES - 4); + } + else + { + pAd->PortCfg.SupportedRatesLen = pAd->PortCfg.IbssConfig.SupportedRatesLen; + memcpy(pAd->PortCfg.SupportedRates, pAd->PortCfg.IbssConfig.SupportedRates, MAX_LEN_OF_SUPPORTED_RATES); + } +// pAd->PortCfg.Pss = PWR_ACTIVE; + + // generate a radom number as BSSID + MacAddrRandomBssid(pAd, &pAd->PortCfg.Bssid); + AsicSetBssid(pAd, &pAd->PortCfg.Bssid); + AsicSwitchChannel(pAd, pAd->PortCfg.Channel); + AsicLockChannel(pAd, pAd->PortCfg.Channel); + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - MlmeStartReqAction(ch= %d,supported rate len= %d)\n", + pAd->PortCfg.Channel, pAd->PortCfg.SupportedRatesLen); + +#ifdef SINGLE_ADHOC_LINKUP + // Add itself as the entry within BSS table + Bssidx = BssTableSearch(&pAd->PortCfg.BssTab, &pAd->PortCfg.Bssid); + if (Bssidx == BSS_NOT_FOUND) + { + Bssidx = BssTableSetEntry(pAd, &pAd->PortCfg.BssTab, &pAd->PortCfg.Bssid, + Ssid, SsidLen, pAd->PortCfg.BssType, pAd->PortCfg.BeaconPeriod, + CfExist, &CfParm, pAd->PortCfg.AtimWin, pAd->PortCfg.CapabilityInfo, + pAd->PortCfg.SupportedRates, pAd->PortCfg.SupportedRatesLen, TRUE, + pAd->PortCfg.Channel, Elem->Rssi, TimeStamp, pVIE); + } +#endif + + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_START_CONF, (USHORT)MLME_SUCCESS); + } + else + { + printk(KERN_ERR DRV_NAME "SYNC - MlmeStartReqAction() sanity check fail. BUG!!!\n"); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_START_CONF, MLME_INVALID_FORMAT); + } +} + +/* + ========================================================================== + Description: + peer sends beacon back when scanning + ========================================================================== + */ +VOID PeerBeaconAtScanAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Bssid, Addr2; + UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, Rates[MAX_LEN_OF_SUPPORTED_RATES], RatesLen, + SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe, Legacy; + CF_PARM CfParm; + USHORT BeaconPeriod, AtimWin, CapabilityInfo; + MACFRAME *Fr; + LARGE_INTEGER TimeStamp; + BOOLEAN CfExist = FALSE; + BOOLEAN ExtendedRateIeExist; + UCHAR Erp; + UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR SupRateLen, ExtRateLen; + + // New for WPA security suites + UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 + NDIS_802_11_VARIABLE_IEs *pVIE = NULL; + + // NdisFillMemory(Ssid, MAX_LEN_OF_SSID, 0x00); + Fr = (MACFRAME *) Elem->Msg; + // Init Variable IE structure + pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; + pVIE->Length = 0; + if (PeerBeaconAndProbeRspSanity(pAd, + Elem->Msg, + Elem->MsgLen, + &Addr2, + &Bssid, Ssid, + &SsidLen, + &BssType, + &BeaconPeriod, + &Channel, + &TimeStamp, + &CfExist, + &CfParm, + &AtimWin, + &CapabilityInfo, + Rates, + &RatesLen, + &ExtendedRateIeExist, + &Erp, + &DtimCount, + &DtimPeriod, + &BcastFlag, + &MessageToMe, + &Legacy, + SupRate, + &SupRateLen, + ExtRate, + &ExtRateLen, + pVIE)) + { + ULONG Idx; + UCHAR Rssi = 0; + UCHAR Noise = 0; + + // This correct im-proper RSSI indication during SITE SURVEY issue. + // Always report bigger RSSI during SCANNING when receiving multiple BEACONs from the same AP. + // This case happens because BEACONs come from adjacent channels, so RSSI become weaker as we + // switch to more far away channels. + Idx = BssTableSearch(&pAd->PortCfg.BssTab, &Bssid); + if (Idx != BSS_NOT_FOUND) + { + Rssi = pAd->PortCfg.BssTab.BssEntry[Idx].Rssi; + Noise = pAd->PortCfg.BssTab.BssEntry[Idx].Noise; + } + if (Elem->Rssi > Rssi) + { + Rssi = Elem->Rssi; + Noise = Elem->Noise; + } + + + DBGPRINT(RT_DEBUG_INFO, "SYNC - PeerBeaconAtScanAction (Subtype=%d, SsidLen=%d, Ssid=%s)\n", Fr->Hdr.SubType, SsidLen,Ssid); + + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; + BssTableSetEntry(pAd, &pAd->PortCfg.BssTab, &Bssid, Ssid, SsidLen, BssType, + BeaconPeriod, CfExist, &CfParm, AtimWin, CapabilityInfo, Rates, + RatesLen, ExtendedRateIeExist, Channel, Rssi, Noise, TimeStamp, pVIE); + } + // sanity check fail, ignored +} + +/* + ========================================================================== + Description: + When waiting joining the (I)BSS, beacon received from external + ========================================================================== + */ +VOID PeerBeaconAtJoinAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Bssid, Addr2; + UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, RatesLen, MessageToMe, + Rates[MAX_LEN_OF_SUPPORTED_RATES], DtimCount, DtimPeriod, BcastFlag, Legacy; + LARGE_INTEGER TimeStamp; + USHORT BeaconPeriod, AtimWin, CapabilityInfo; + CF_PARM Cf; + BOOLEAN CfExist = FALSE, ExtendedRateIeExist; + UCHAR Erp; + UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR SupRateLen, ExtRateLen; + + // New for WPA security suites + UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 + NDIS_802_11_VARIABLE_IEs *pVIE = NULL; + + // Init Variable IE structure + pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; + pVIE->Length = 0; + if (PeerBeaconAndProbeRspSanity(pAd, + Elem->Msg, + Elem->MsgLen, + &Addr2, + &Bssid, + Ssid, + &SsidLen, + &BssType, + &BeaconPeriod, + &Channel, + &TimeStamp, + &CfExist, + &Cf, + &AtimWin, + &CapabilityInfo, + Rates, + &RatesLen, + &ExtendedRateIeExist, + &Erp, + &DtimCount, + &DtimPeriod, + &BcastFlag, + &MessageToMe, + &Legacy, + SupRate, + &SupRateLen, + ExtRate, + &ExtRateLen, + pVIE)) + { + // Disqualify 11b only adhoc when we are in 11g only adhoc mode + if ((BssType == BSS_INDEP) && (pAd->PortCfg.AdhocMode == 2) && (RatesLen < 12)) + return; + + if (MAC_ADDR_EQUAL(&pAd->Mlme.SyncAux.Bssid, &Bssid)) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - receive desired BEACON at JoinWaitBeacon...\n"); + RTMPCancelTimer(&pAd->Mlme.SyncAux.BeaconTimer); + + // Update RSSI to prevent No signal display when cards first initialized + pAd->PortCfg.LastRssi = Elem->Rssi; + pAd->PortCfg.AvgRssi = Elem->Rssi; + + if (pAd->Mlme.SyncAux.SsidLen > 0) + { + memcpy(pAd->PortCfg.Ssid, pAd->Mlme.SyncAux.Ssid, pAd->Mlme.SyncAux.SsidLen); + pAd->PortCfg.SsidLen = pAd->Mlme.SyncAux.SsidLen; + } + else + { + memcpy(pAd->PortCfg.Ssid, Ssid, SsidLen); + pAd->PortCfg.SsidLen = SsidLen; + } + + COPY_MAC_ADDR(&pAd->PortCfg.Bssid, &Bssid); + AsicSetBssid(pAd, &pAd->PortCfg.Bssid); + + pAd->PortCfg.BssType = BssType; + pAd->PortCfg.BeaconPeriod = BeaconPeriod; + pAd->PortCfg.Channel = Channel; + + // filter out non-supported rates + { + int i; + pAd->PortCfg.SupportedRatesLen = 0; + for (i=0;iPortCfg.PhyMode == PHY_11B) && + (Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22)) + { + ///DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Supported Rate[%d] = 0x%02x\n",pAd->PortCfg.SupportedRatesLen, Rates[i])); + pAd->PortCfg.SupportedRates[pAd->PortCfg.SupportedRatesLen] = Rates[i]; + pAd->PortCfg.SupportedRatesLen ++; + } + else if ((Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22) || + (Rate == 12 || Rate == 18 || Rate == 24 || Rate == 36) || + (Rate == 48 || Rate == 72 || Rate == 96 || Rate == 108)) + { + // DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Supported Rate[%d] = 0x%02x\n",pAd->PortCfg.SupportedRatesLen, Rates[i])); + pAd->PortCfg.SupportedRates[pAd->PortCfg.SupportedRatesLen] = Rates[i]; + pAd->PortCfg.SupportedRatesLen ++; + } + } + } + + // Copy AP's supported rate to portcfg for creating assoication request + // Also filter out not supported rate + // Supported rate + { + int i; + pAd->PortCfg.SupRateLen = 0; + for (i = 0; i < SupRateLen; i++) + { + UCHAR Rate = SupRate[i] & 0x7f; + if ((pAd->PortCfg.PhyMode == PHY_11B) && + (Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22)) + { + pAd->PortCfg.SupRate[pAd->PortCfg.SupRateLen] = SupRate[i]; + pAd->PortCfg.SupRateLen ++; + } + else if ((Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22) || + (Rate == 12 || Rate == 18 || Rate == 24 || Rate == 36) || + (Rate == 48 || Rate == 72 || Rate == 96 || Rate == 108)) + { + pAd->PortCfg.SupRate[pAd->PortCfg.SupRateLen] = SupRate[i]; + pAd->PortCfg.SupRateLen ++; + } + } + } + + // Copy AP's supported rate to portcfg for creating assoication request + // Also filter out not supported rate + // Extended rate + if (ExtendedRateIeExist == TRUE) + { + int i; + pAd->PortCfg.ExtRateLen = 0; + for (i = 0; i < ExtRateLen; i++) + { + UCHAR Rate = ExtRate[i] & 0x7f; + if ((pAd->PortCfg.PhyMode == PHY_11B) && + (Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22)) + { + pAd->PortCfg.ExtRate[pAd->PortCfg.ExtRateLen] = ExtRate[i]; + pAd->PortCfg.ExtRateLen ++; + } + else if ((Rate == 2 || Rate == 4 || Rate == 11 || Rate == 22) || + (Rate == 12 || Rate == 18 || Rate == 24 || Rate == 36) || + (Rate == 48 || Rate == 72 || Rate == 96 || Rate == 108)) + { + pAd->PortCfg.ExtRate[pAd->PortCfg.ExtRateLen] = ExtRate[i]; + pAd->PortCfg.ExtRateLen ++; + } + } + } + else + { + pAd->PortCfg.ExtRateLen = 0; + } + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - AP's SupportedRatesLen=%d, set STA's SupportedRateLen=%d\n", + RatesLen, pAd->PortCfg.SupportedRatesLen); + + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; + + // Check for 802.11g information, if 802.11 b/g mixed mode. + // We can't support its short preamble for now. + pAd->PortCfg.CapabilityInfo = CapabilityInfo; + + if ((BssType == BSS_INDEP) && (CAP_IS_IBSS_ON(CapabilityInfo))) + { + pAd->PortCfg.AtimWin = AtimWin; + } + else if (BssType == BSS_INFRA) + { + pAd->PortCfg.CfpPeriod = Cf.CfpPeriod; + pAd->PortCfg.CfpMaxDuration = Cf.CfpMaxDuration; + pAd->PortCfg.CfpDurRemain = Cf.CfpDurRemaining; + pAd->PortCfg.CfpCount = Cf.CfpCount; + pAd->PortCfg.CfpPeriod = Cf.CfpPeriod; + + AsicEnableBssSync(pAd); + } + + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_JOIN_CONF, MLME_SUCCESS); + } + // not to me BEACON, ignored + } + // sanity check fail, ignore this frame +} + +/* + ========================================================================== + Description: + receive BEACON from peer + ========================================================================== + */ +VOID PeerBeacon( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Bssid, Addr2; + CHAR Ssid[MAX_LEN_OF_SSID]; + CF_PARM CfParm; + UCHAR SsidLen, MessageToMe=0, BssType, Channel, Rates[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR RatesLen, DtimCount=0, DtimPeriod=0, BcastFlag=0, Legacy; + USHORT CapabilityInfo, AtimWin, BeaconPeriod; + LARGE_INTEGER TimeStamp; + BOOLEAN CfExist = FALSE; + USHORT TbttNumToNextWakeUp; + BOOLEAN ExtendedRateIeExist; + UCHAR Erp; + UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR SupRateLen, ExtRateLen; + + // New for WPA security suites + UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 + NDIS_802_11_VARIABLE_IEs *pVIE = NULL; + + if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) + return; + + // Init Variable IE structure + pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; + pVIE->Length = 0; + if (PeerBeaconAndProbeRspSanity(pAd, + Elem->Msg, + Elem->MsgLen, + &Addr2, + &Bssid, + Ssid, + &SsidLen, + &BssType, + &BeaconPeriod, + &Channel, + &TimeStamp, + &CfExist, + &CfParm, + &AtimWin, + &CapabilityInfo, + Rates, + &RatesLen, + &ExtendedRateIeExist, + &Erp, + &DtimCount, + &DtimPeriod, + &BcastFlag, + &MessageToMe, + &Legacy, + SupRate, + &SupRateLen, + ExtRate, + &ExtRateLen, + pVIE)) + { + BOOLEAN is_my_bssid, is_my_ssid; + ULONG Bssidx, Now; + BSS_ENTRY *pBss; + + is_my_bssid = (MAC_ADDR_EQUAL(&Bssid, &pAd->PortCfg.Bssid) ? TRUE : FALSE); + is_my_ssid = (((pAd->PortCfg.SsidLen == SsidLen) && RTMPEqualMemory(Ssid, pAd->PortCfg.Ssid, (ULONG) SsidLen)) ? TRUE : FALSE); + // Mask out unnecessary capability information + CapabilityInfo &= SUPPORTED_CAPABILITY_INFO; + + // ignore BEACON not for my SSID + if ((! is_my_ssid) && (! is_my_bssid)) + return; + + // + // Housekeeping "SsidBssTab" table for later-on ROAMing usage. + // + Bssidx = BssTableSearch(&pAd->Mlme.CntlAux.SsidBssTab, &Bssid); + if (Bssidx == BSS_NOT_FOUND) + { + // Return immediately when in transition process when changing association + // Found this bug when doing WHQL ad-hoc test case + if (pAd->PortCfg.SsidLen != pAd->Mlme.CntlAux.SsidLen) + return; + if (!RTMPEqualMemory(pAd->PortCfg.Ssid, pAd->Mlme.CntlAux.Ssid, pAd->PortCfg.SsidLen)) + return; + + // discover new AP of this network, create BSS entry + Bssidx = BssTableSetEntry(pAd, &pAd->Mlme.CntlAux.SsidBssTab, &Bssid, Ssid, SsidLen, + BssType, BeaconPeriod, CfExist, &CfParm, AtimWin, CapabilityInfo, + Rates, RatesLen, ExtendedRateIeExist, Channel, Elem->Rssi, Elem->Noise, TimeStamp, pVIE); + + if (Bssidx == BSS_NOT_FOUND) // return if BSS table full + return; + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - New AP added to SsidBssTab[%d], RSSI=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + Bssidx, Elem->Rssi, Bssid.Octet[0], Bssid.Octet[1], Bssid.Octet[2], + Bssid.Octet[3], Bssid.Octet[4], Bssid.Octet[5]); + } + + // if the ssid matched & bssid unmatched, we should select the bssid with large value. + // This might happened when two STA start at the same time + if (is_my_ssid && (! is_my_bssid) && ADHOC_ON(pAd)) + { + INT i; + // Add to safe guard adhoc wep status mismatch + if (pAd->PortCfg.WepStatus != pAd->Mlme.CntlAux.SsidBssTab.BssEntry[Bssidx].WepStatus) + return; + + // link down the one with smaller BSSID value. + for (i = 0; i < 6; i++) + { + if (Bssid.Octet[i] > pAd->PortCfg.Bssid.Octet[i]) + { + AsicDisableSync(pAd); + memcpy(&pAd->PortCfg.Bssid, &Bssid, 6); + AsicSetBssid(pAd, &pAd->PortCfg.Bssid); + MakeIbssBeacon(pAd); + AsicEnableIbssSync(pAd); + break; + } + } + } + + DBGPRINT(RT_DEBUG_INFO, "SYNC - PeerBeacon from %02x:%02x:%02x:%02x:%02x:%02x - Dtim=%d/%d, Rssi=%02x\n", + Bssid.Octet[0], Bssid.Octet[1], Bssid.Octet[2], + Bssid.Octet[3], Bssid.Octet[4], Bssid.Octet[5], + DtimCount, DtimPeriod, Elem->Rssi); + + Now = jiffies; + pBss = &pAd->Mlme.CntlAux.SsidBssTab.BssEntry[Bssidx]; + pBss->Rssi = Elem->Rssi; // lastest RSSI + pBss->LastBeaconRxTime = Now; // last RX timestamp + + // + // BEACON from my BSSID - either IBSS or INFRA network + // + if (is_my_bssid) + { + // 2002/12/06 - patch Abocom AP bug, which forgets to set "Privacy" bit in + // AssocRsp even though this bit is ON in Beacon. So we update according + // to following Beacon frame. + // pAd->PortCfg.PrivacyInvoked = CAP_IS_PRIVACY_ON(CapabilityInfo); + + pAd->PortCfg.LastBeaconRxTime = Now; +#if 1 + // at least one 11b peer joined. downgrade the MaxTxRate to 11Mbps + // after last 11b peer left for several seconds, we'll auto switch back to 11G rate + // in MlmePeriodicExec() + if (ADHOC_ON(pAd) && (RatesLen <= 4)) + { + // this timestamp is for MlmePeriodicExec() to check if all 11B peers have left + pAd->PortCfg.Last11bBeaconRxTime = Now; + + if (pAd->PortCfg.MaxTxRate > RATE_11) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - 11b peer joined. down-grade to 11b TX rates \n"); + memcpy(pAd->PortCfg.SupportedRates, Rates, MAX_LEN_OF_SUPPORTED_RATES); + pAd->PortCfg.SupportedRatesLen = RatesLen; + MlmeUpdateTxRates(pAd, FALSE); + MakeIbssBeacon(pAd); // supported rates changed + } + } +#endif + // check if RSSI reaches threshold + pAd->PortCfg.LastRssi = (pAd->PortCfg.LastRssi + Elem->Rssi) / 2; + pAd->PortCfg.AvgRssi = (pAd->PortCfg.AvgRssi * 7 + Elem->Rssi) >> 3; + if ((pAd->PortCfg.RssiTriggerMode == RSSI_TRIGGERED_UPON_BELOW_THRESHOLD) && + (pAd->PortCfg.LastRssi < pAd->PortCfg.RssiTrigger)) + { + // NDIS_802_11_RSSI Dbm = pAd->PortCfg.LastRssi - RSSI_TO_DBM_OFFSET; + // DBGPRINT(RT_DEBUG_TRACE, "SYNC - NdisMIndicateStatus *** RSSI %d dBm, less than threshold %d dBm\n", + // Dbm, pAd->PortCfg.RssiTrigger - RSSI_TO_DBM_OFFSET); + } + else if ((pAd->PortCfg.RssiTriggerMode == RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD) && + (pAd->PortCfg.LastRssi > pAd->PortCfg.RssiTrigger)) + { + // NDIS_802_11_RSSI Dbm = pAd->PortCfg.LastRssi - RSSI_TO_DBM_OFFSET; + // DBGPRINT(RT_DEBUG_TRACE, "SYNC - NdisMIndicateStatus *** RSSI %d dBm, greater than threshold %d dBm\n", + // Dbm, pAd->PortCfg.RssiTrigger - RSSI_TO_DBM_OFFSET); + } + + if (INFRA_ON(pAd)) // && (pAd->PortCfg.PhyMode == PHY_11BG_MIXED)) + { + BOOLEAN bUseShortSlot, bUseBGProtection; + + // decide to use/change to - + // 1. long slot (20 us) or short slot (9 us) time + // 2. turn on/off RTS/CTS and/or CTS-to-self protection + // 3. short preamble + bUseShortSlot = (pAd->PortCfg.UseShortSlotTime == TRUE) && CAP_IS_SHORT_SLOT_TIME(CapabilityInfo); + if (bUseShortSlot != pAd->PortCfg.ShortSlotInUsed) + AsicSetSlotTime(pAd, bUseShortSlot); + + bUseBGProtection = (pAd->PortCfg.UseBGProtection == 1) || // always use + ((pAd->PortCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); + if (bUseBGProtection != pAd->PortCfg.BGProtectionInUsed) + { + pAd->PortCfg.BGProtectionInUsed = bUseBGProtection; + DBGPRINT(RT_DEBUG_TRACE, "SYNC - AP changed B/G protection to %d\n", bUseBGProtection); + } + + if ((pAd->PortCfg.TxPreambleInUsed == Rt802_11PreambleShort) && ERP_IS_USE_BARKER_PREAMBLE(Erp)) + { + MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); + DBGPRINT(RT_DEBUG_TRACE, "SYNC - AP forced to use LONG preamble\n"); + } + } + + // only INFRASTRUCTURE mode support power-saving feature + if (INFRA_ON(pAd) && (pAd->PortCfg.Psm == PWR_SAVE)) + { + // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL + // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE + // 3. we have outgoing frames in TxRing or PrioRing, better stay AWAKE + // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE + // 5. otherwise, put PHY back to sleep to save battery. + if (MessageToMe) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - AP backlog unicast-to-me, stay AWAKE, send PSPOLL\n"); + EnqueuePsPoll(pAd); + } + else if (BcastFlag && (DtimCount == 0) && pAd->PortCfg.RecvDtim) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - AP backlog broadcast/multicast, stay AWAKE\n"); + } + else if ((RTMPFreeDescriptorRequest(pAd, TX_RING, TX_RING_SIZE) != NDIS_STATUS_SUCCESS) || + (RTMPFreeDescriptorRequest(pAd, PRIO_RING, PRIO_RING_SIZE) != NDIS_STATUS_SUCCESS)) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - outgoing frame in TxRing/PrioRing, stay AWAKE\n"); + } + else + { + USHORT NextDtim = DtimCount; + + if (NextDtim == 0) + NextDtim = DtimPeriod; + + TbttNumToNextWakeUp = pAd->PortCfg.DefaultListenCount; + if (pAd->PortCfg.RecvDtim && (TbttNumToNextWakeUp > NextDtim)) + TbttNumToNextWakeUp = NextDtim; + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - PHY sleeps for %d Tbcn, Dtim=%d/%d\n", TbttNumToNextWakeUp, DtimCount, DtimPeriod); + AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); + } + } + +#ifndef SINGLE_ADHOC_LINKUP + // At least another peer in this IBSS, declare MediaState as CONNECTED + if (ADHOC_ON(pAd) && (pAd->MediaState == NdisMediaStateDisconnected)) + { + pAd->MediaState = NdisMediaStateConnected; + + // 2003/03/12 - john + // Make sure this entry in "PortCfg.BssTab" table, thus complies to Microsoft's policy that + // "site survey" result should always include the current connected network. + // + Bssidx = BssTableSearch(&pAd->PortCfg.BssTab, &Bssid); + if (Bssidx == BSS_NOT_FOUND) + { + Bssidx = BssTableSetEntry(pAd, &pAd->PortCfg.BssTab, &Bssid, Ssid, SsidLen, + BssType, BeaconPeriod, CfExist, &CfParm, AtimWin, CapabilityInfo, + Rates, RatesLen, ExtendedRateIeExist, Channel, Elem->Rssi, Elem->Noise, TimeStamp, pVIE); + } + } +#endif + } + // not my BSSID, ignore it + } + // sanity check fail, ignore this frame +} + +/* + ========================================================================== + Description: + Receive PROBE REQ from remote peer when operating in IBSS mode + ========================================================================== + */ +VOID PeerProbeReqAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + MACADDR Addr2; + CHAR Ssid[MAX_LEN_OF_SSID]; + UCHAR SsidLen; + MACHDR ProbeRspHdr; + NDIS_STATUS NStatus; + UCHAR *OutBuffer = NULL; + ULONG FrameLen = 0; + LARGE_INTEGER FakeTimestamp; + UCHAR SsidIe = IE_SSID, DsIe = IE_DS_PARM, IbssIe = IE_IBSS_PARM, SuppIe = IE_SUPP_RATES, + DsLen = 1, IbssLen = 2; + UCHAR SupportedRatesLen; + UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; + UCHAR ExtRateIe = IE_EXT_SUPP_RATES, ExtRatesLen; + UCHAR ErpIe[3] = {IE_ERP, 1, 0}; + + if (! ADHOC_ON(pAd)) + return; + + if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, &Addr2, Ssid, &SsidLen)) //, Rates, &RatesLen)) + { + if ((SsidLen == 0) || RTMPEqualMemory(Ssid, pAd->PortCfg.Ssid, (ULONG) SsidLen)) + { + CSR15_STRUC Csr15; + + // we should respond a ProbeRsp only when we're the last BEACON transmitter + // in this ADHOC network. + RTMP_IO_READ32(pAd, CSR15, &Csr15.word); + if (Csr15.field.BeaconSent == 0) + { + DBGPRINT(RT_DEBUG_INFO, "SYNC - NOT last BEACON sender, no PROBE_RSP to %02x:%02x:%02x:%02x:%02x:%02x...\n", + Addr2.Octet[0],Addr2.Octet[1],Addr2.Octet[2],Addr2.Octet[3],Addr2.Octet[4],Addr2.Octet[5] ); + return; + } + + // 2003-12-10 802.11g WIFI spec disallow OFDM rates in 802.11g ADHOC mode + // make sure 1,2,5.5,11 are the firt 4 rates in PortCfg.SupportedRates[] array + if ((pAd->PortCfg.PhyMode == PHY_11BG_MIXED) && (pAd->PortCfg.AdhocMode == 0)) + { + int i; + SupportedRatesLen=0; + for (i=0;iPortCfg.SupportedRatesLen;i++) + { + switch (pAd->PortCfg.SupportedRates[i] & 0x7f) + { + case 2: + case 4: + case 11: + case 22: + SupportedRates[SupportedRatesLen] = pAd->PortCfg.SupportedRates[i]; + SupportedRatesLen ++; + break; + default: + break; + } + } + // error handling - should never happen + if (SupportedRatesLen != 4) + { + SupportedRatesLen = 4; + SupportedRates[0] = 0x82; + SupportedRates[1] = 0x84; + SupportedRates[2] = 0x8b; + SupportedRates[3] = 0x96; + } + } + else + { + SupportedRatesLen = pAd->PortCfg.SupportedRatesLen; + memcpy(SupportedRates, pAd->PortCfg.SupportedRates, SupportedRatesLen); + } + + // allocate and send out ProbeRsp frame + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + pAd->PortCfg.AtimWin = 0; // ?????? + DBGPRINT(RT_DEBUG_TRACE, "SYNC - Send PROBE_RSP to %02x:%02x:%02x:%02x:%02x:%02x...\n", + Addr2.Octet[0],Addr2.Octet[1],Addr2.Octet[2],Addr2.Octet[3],Addr2.Octet[4],Addr2.Octet[5] ); + MgtMacHeaderInit(pAd, &ProbeRspHdr, SUBTYPE_PROBE_RSP, 0, &Addr2, &pAd->PortCfg.Bssid); + + if (SupportedRatesLen <= 8) + { + MakeOutgoingFrame(OutBuffer, &FrameLen, + MAC_HDR_LEN, &ProbeRspHdr, + TIMESTAMP_LEN, &FakeTimestamp, + 2, &pAd->PortCfg.BeaconPeriod, + 2, &pAd->PortCfg.CapabilityInfo, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &SuppIe, + 1, &SupportedRatesLen, + SupportedRatesLen, SupportedRates, + 1, &DsIe, + 1, &DsLen, + 1, &pAd->PortCfg.Channel, + 1, &IbssIe, + 1, &IbssLen, + 2, &pAd->PortCfg.AtimWin, + END_OF_ARGS); + } + else + { + ExtRatesLen = SupportedRatesLen - 8; + SupportedRatesLen = 8; + MakeOutgoingFrame(OutBuffer, &FrameLen, + MAC_HDR_LEN, &ProbeRspHdr, + TIMESTAMP_LEN, &FakeTimestamp, + 2, &pAd->PortCfg.BeaconPeriod, + 2, &pAd->PortCfg.CapabilityInfo, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &SuppIe, + 1, &SupportedRatesLen, + SupportedRatesLen, SupportedRates, + 1, &DsIe, + 1, &DsLen, + 1, &pAd->PortCfg.Channel, + 1, &IbssIe, + 1, &IbssLen, + 2, &pAd->PortCfg.AtimWin, + 3, ErpIe, + 1, &ExtRateIe, + 1, &ExtRatesLen, + ExtRatesLen, &SupportedRates[SupportedRatesLen], + END_OF_ARGS); + } + // If adhoc secruity is set for WPA-None, append the cipher suite IE + if (pAd->PortCfg.AuthMode == Ndis802_11AuthModeWPANone) + { + ULONG tmp; + UCHAR WpaIe = IE_WPA; + + if (pAd->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) // Tkip + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaNoneTkipLen, + CipherSuiteWpaNoneTkipLen, &CipherSuiteWpaNoneTkip[0], + END_OF_ARGS); + FrameLen += tmp; + } + else if (pAd->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) // Aes + { + MakeOutgoingFrame(OutBuffer + FrameLen, &tmp, + 1, &WpaIe, + 1, &CipherSuiteWpaNoneAesLen, + CipherSuiteWpaNoneAesLen, &CipherSuiteWpaNoneAes[0], + END_OF_ARGS); + FrameLen += tmp; + } + } + MiniportMMRequest(pAd, OutBuffer, FrameLen); + } + } +} + +VOID BeaconTimeoutAtJoinAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "SYNC - BeaconTimeoutAtJoinAction\n"); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_JOIN_CONF, MLME_REJ_TIMEOUT); +} + +/* + ========================================================================== + Description: + Scan timeout procedure. basically add channel index by 1 and rescan + ========================================================================== + */ +VOID ScanTimeoutAction( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + pAd->Mlme.SyncAux.Channel = NextChannel(pAd, pAd->Mlme.SyncAux.Channel); + ScanNextChannel(pAd); +} + +/* + ========================================================================== + Description: + Scan next channel + ========================================================================== + */ +VOID ScanNextChannel( + IN PRTMP_ADAPTER pAd) +{ + MACHDR Hdr; + UCHAR SsidIe = IE_SSID, SuppRateIe = IE_SUPP_RATES; + VOID *OutBuffer = NULL; + VOID *OutBuffer2 = NULL; + NDIS_STATUS NStatus; + ULONG FrameLen = 0; + UCHAR SsidLen = 0; + + if (pAd->Mlme.SyncAux.Channel == 0) + { + DBGPRINT(RT_DEBUG_INFO, "SYNC - End of SCAN, restore to channel %d\n",pAd->PortCfg.Channel); + AsicSwitchChannel(pAd, pAd->PortCfg.Channel); + AsicLockChannel(pAd, pAd->PortCfg.Channel); + + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_SUCCESS); + } + else + { + AsicSwitchChannel(pAd, pAd->Mlme.SyncAux.Channel); + + // Total SCAN time still limits within 3 sec (DDK constraint). + // TODO: We need more intelligent rules here to further improve out-of-service issue. + // e.g. temporary stop copying NDIS packet to TxRing until SCAN complete +// if (INFRA_ON(pAd) || ADHOC_ON(pAd)) + + // We need to shorten active scan time in order for WZC connect issue + if (pAd->Mlme.SyncAux.ScanType == SCAN_ACTIVE) + RTMPSetTimer(pAd, &pAd->Mlme.SyncAux.ScanTimer, ACTIVE_SCAN_TIME); + else if (pAd->PortCfg.PhyMode == PHY_11ABG_MIXED) + RTMPSetTimer(pAd, &pAd->Mlme.SyncAux.ScanTimer, MIN_CHANNEL_TIME); + else + RTMPSetTimer(pAd, &pAd->Mlme.SyncAux.ScanTimer, MAX_CHANNEL_TIME); + + MgtMacHeaderInit(pAd, &Hdr, SUBTYPE_PROBE_REQ, 0, &pAd->PortCfg.Broadcast, &pAd->PortCfg.Broadcast); + // There is no need to send broadcast probe request if active scan is in effect. + // The same rulr should apply to passive scan also. + if (pAd->Mlme.SyncAux.ScanType == SCAN_PASSIVE) + { + // Send the first probe request with empty SSID + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_INFO, "SYNC - ScanNextChannel() allocate memory fail\n"); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + + DBGPRINT(RT_DEBUG_INFO, "SYNC - send passive ProbeReq @ channel=%d...\n", pAd->Mlme.SyncAux.Channel); + SsidLen = 0; + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), (UCHAR*)&Hdr, + 1, &SsidIe, + 1, &SsidLen, + 1, &SuppRateIe, + 1, &pAd->PortCfg.SupportedRatesLen, + pAd->PortCfg.SupportedRatesLen, pAd->PortCfg.SupportedRates, + END_OF_ARGS); + + MiniportMMRequest(pAd, OutBuffer, FrameLen); + } + else if (pAd->Mlme.SyncAux.ScanType == SCAN_ACTIVE) + { + // Allocate another for probe scan with SSID + NStatus = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer2); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - ScanNextChannel() allocate memory fail\n"); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); + return; + } + // make another probe scan with SSID from mlme.cntlaux.ssid + SsidLen = pAd->PortCfg.SsidLen; + MakeOutgoingFrame(OutBuffer2, &FrameLen, + sizeof(MACHDR), &Hdr, + 1, &SsidIe, + 1, &SsidLen, + SsidLen, pAd->PortCfg.Ssid, + 1, &SuppRateIe, + 1, &pAd->PortCfg.SupportedRatesLen, + pAd->PortCfg.SupportedRatesLen, pAd->PortCfg.SupportedRates, + END_OF_ARGS); + + MiniportMMRequest(pAd, OutBuffer2, FrameLen); + + DBGPRINT(RT_DEBUG_INFO, "SYNC - send active ProbeReq @ channel=%d with essid=%s\n", pAd->Mlme.SyncAux.Channel, pAd->PortCfg.Ssid); + } + + pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID InvalidStateWhenScan( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "AYNC - InvalidStateWhenScan(state=%d). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_STATE_MACHINE_REJECT); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID InvalidStateWhenJoin( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "InvalidStateWhenJoin(state=%d). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_JOIN_CONF, MLME_STATE_MACHINE_REJECT); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID InvalidStateWhenStart( + IN PRTMP_ADAPTER pAd, + IN MLME_QUEUE_ELEM *Elem) +{ + DBGPRINT(RT_DEBUG_TRACE, "InvalidStateWhenStart(state=%d). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState); + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_START_CONF, MLME_STATE_MACHINE_REJECT); +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID EnqueuePsPoll( + IN PRTMP_ADAPTER pAd) +{ + NDIS_STATUS NState; + PSPOLL_FRAME *PsFr; + + DBGPRINT(RT_DEBUG_TRACE, "SYNC - send PsPoll ...\n"); + + NState = MlmeAllocateMemory(pAd, (PVOID)&PsFr); //Get an unused nonpaged memory + if (NState == NDIS_STATUS_SUCCESS) + { + memcpy((VOID *)PsFr, (VOID *)&pAd->Mlme.PsFr, sizeof(PSPOLL_FRAME)); + MiniportMMRequest(pAd, (VOID *)PsFr, sizeof(PSPOLL_FRAME)); + } +} + +// 2003-04-17 john +// driver force send out a BEACON frame to cover ADHOC mode BEACON starving issue +// that is, in ADHOC mode, driver guarantee itself can send out at least a BEACON +// per a specified duration, even the peer's clock is faster than us and win all the +// hardware-based BEACON TX oppertunity. +// we may remove this software feature once 2560 IC fix this problem in ASIC. +VOID EnqueueBeaconFrame( + IN PRTMP_ADAPTER pAd) +{ + NDIS_STATUS NState; + PTXD_STRUC pTxD = (PTXD_STRUC)pAd->BeaconRing.va_addr; + CHAR *pBeacon; + LARGE_INTEGER Tsf; + + NState = MlmeAllocateMemory(pAd, (PVOID)&pBeacon); //Get an unused nonpaged memory + if (NState == NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_TRACE, "SYNC - driver sent BEACON (len=%d)...\n",pTxD->DataByteCnt); + RTMP_IO_READ32(pAd, CSR17, &Tsf.vv.HighPart); + RTMP_IO_READ32(pAd, CSR16, &Tsf.vv.LowPart); + memcpy(pBeacon, pAd->BeaconRing.va_data_addr, pTxD->DataByteCnt); + memcpy(pBeacon + MAC_HDR_LEN, &Tsf, TIMESTAMP_LEN); + MiniportMMRequest(pAd, (VOID *)pBeacon, pTxD->DataByteCnt); + } +} + +/* + ========================================================================== + Description: + Send out a NULL frame to AP. The prpose is to inform AP this client + current PSM bit. + NOTE: + This routine should only be used in infrastructure mode. + ========================================================================== + */ +VOID EnqueueNullFrame( + IN PRTMP_ADAPTER pAd, + IN UCHAR TxRate) +{ + NDIS_STATUS NState; + MACHDR *NullFr; + + // since TxRate may change, we have to change Duration each time + pAd->Mlme.NullFr.Duration = RTMPCalcDuration(pAd, TxRate, 14); + NState = MlmeAllocateMemory(pAd, (PVOID)&NullFr); //Get an unused nonpaged memory + if (NState == NDIS_STATUS_SUCCESS) + { + memcpy((VOID *)NullFr, (VOID *)&pAd->Mlme.NullFr, sizeof(MACHDR)); + RTMPSendNullFrame(pAd, (VOID *)NullFr, sizeof(MACHDR), TxRate); + } +} + +/* + ========================================================================== + Description: + ========================================================================== + */ +VOID EnqueueProbeRequest( + IN PRTMP_ADAPTER pAd) +{ + NDIS_STATUS NState; + UCHAR SsidIe = IE_SSID, SuppRateIe = IE_SUPP_RATES; + VOID *OutBuffer; + ULONG FrameLen = 0; + MACHDR Hdr; + + DBGPRINT(RT_DEBUG_TRACE, "force out a ProbeRequest ...\n"); + + NState = MlmeAllocateMemory(pAd, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NState == NDIS_STATUS_SUCCESS) + { + MgtMacHeaderInit(pAd, &Hdr, SUBTYPE_PROBE_REQ, 0, &pAd->PortCfg.Broadcast, &pAd->PortCfg.Broadcast); + + // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse + MakeOutgoingFrame(OutBuffer, &FrameLen, + sizeof(MACHDR), &Hdr, + 1, &SsidIe, + 1, &pAd->PortCfg.SsidLen, + pAd->PortCfg.SsidLen, pAd->PortCfg.Ssid, + 1, &SuppRateIe, + 1, &pAd->PortCfg.SupportedRatesLen, + pAd->PortCfg.SupportedRatesLen, pAd->PortCfg.SupportedRates, + END_OF_ARGS); + MiniportMMRequest(pAd, OutBuffer, FrameLen); + } +} + +/* + ========================================================================== + Description: + Update PortCfg->ChannelList[] according to 1) Country Region 2) RF IC type, + and 3) PHY-mode user selected. + The outcome is used by driver when doing site survey. + ========================================================================== + */ +VOID BuildChannelList( + IN PRTMP_ADAPTER pAd) +{ + UCHAR i, index = 0; + memset(pAd->PortCfg.ChannelList, 0, MAX_LEN_OF_CHANNELS); + + // if not 11a-only mode, channel list starts from 2.4Ghz band + if (pAd->PortCfg.PhyMode != PHY_11A) +{ + switch (pAd->PortCfg.CountryRegion) + { + case REGION_FCC: // 1 - 11 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_FCC, sizeof(Ra24Ghz_FCC)); + index += sizeof(Ra24Ghz_FCC); + break; + case REGION_IC: // 1 -11 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_IC, sizeof(Ra24Ghz_IC)); + index += sizeof(Ra24Ghz_IC); + break; + case REGION_ISRAEL: // 3 - 9 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_ISRAEL, sizeof(Ra24Ghz_ISRAEL)); + index += sizeof(Ra24Ghz_ISRAEL); + break; + case REGION_ETSI: // 1 - 13 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_ESTI, sizeof(Ra24Ghz_ESTI)); + index += sizeof(Ra24Ghz_ESTI); + break; + case REGION_SPAIN: // 10 - 11 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_SPAIN, sizeof(Ra24Ghz_SPAIN)); + index += sizeof(Ra24Ghz_SPAIN); + break; + case REGION_FRANCE: // 10 -13 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_FRANCE, sizeof(Ra24Ghz_FRANCE)); + index += sizeof(Ra24Ghz_FRANCE); + break; + case REGION_MKK: // 14 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_MKK, sizeof(Ra24Ghz_MKK)); + index += sizeof(Ra24Ghz_MKK); + break; + case REGION_MKK1: // 1 - 14 + memcpy(&pAd->PortCfg.ChannelList[index], Ra24Ghz_MKK1, sizeof(Ra24Ghz_MKK1)); + index += sizeof(Ra24Ghz_MKK1); + break; + default: // Error. should never happen + break; + } + } + + if ((pAd->PortCfg.PhyMode == PHY_11A) || (pAd->PortCfg.PhyMode == PHY_11ABG_MIXED)) + { +#if 0 + switch (pAd->PortCfg.CountryRegion) + { + case REGION_FCC: // UNII <36,40,44,48,52,56,60,64> <149,153,157,161> + case REGION_IC: // UNII <36,40,44,48,52,56,60,64> <149,153,157,161> + case REGION_ISRAEL: // UNII <36,40,44,48,52,56,60,64> <149,153,157,161> + memcpy(&pAd->PortCfg.ChannelList[index], Ra5Ghz_UNII, sizeof(Ra5Ghz_UNII)); + index += sizeof(Ra5Ghz_UNII); + break; + case REGION_ETSI: // HiperLAN2 <36,40,44,48,52,56,60,64> <100,104,108,112,116,120,124,128,132,136,140> + case REGION_SPAIN: // HiperLAN2 <36,40,44,48,52,56,60,64> <100,104,108,112,116,120,124,128,132,136,140> + case REGION_FRANCE: // HiperLAN2 <36,40,44,48,52,56,60,64> <100,104,108,112,116,120,124,128,132,136,140> + memcpy(&pAd->PortCfg.ChannelList[index], Ra5Ghz_HyperLAN2, sizeof(Ra5Ghz_HyperLAN2)); + index += sizeof(Ra5Ghz_HyperLAN2); + break; + case REGION_MKK: // Japan MMAC <34,38,42,46> + case REGION_MKK1: // Japan MMAC <34,38,42,46> + memcpy(&pAd->PortCfg.ChannelList[index], Ra5Ghz_MMAC, sizeof(Ra5Ghz_MMAC)); + index += sizeof(Ra5Ghz_MMAC); + break; + default: // Error. should never happen + break; + } +#else + // 2003-10-05 john - use UNII temoparaily for all regulation domains for easy test untill + // RF guys confirm the supported channel plans + memcpy(&pAd->PortCfg.ChannelList[index], Ra5Ghz_UNII, sizeof(Ra5Ghz_UNII)); + index += sizeof(Ra5Ghz_UNII); +#endif + } + + pAd->PortCfg.ChannelListNum = index; + DBGPRINT(RT_DEBUG_TRACE,"country code=%d, RFIC=%d, PHY mode=%d, support %d channels\n", + pAd->PortCfg.CountryRegion, pAd->PortCfg.RfType, pAd->PortCfg.PhyMode, pAd->PortCfg.ChannelListNum); + for (i=0;iPortCfg.ChannelList[i]); + } +} + +/* + ========================================================================== + Description: + This routine return the first channel number according to the country + code selection and RF IC selection (signal band or dual band). It is called + whenever driver need to start a site survey of all supported channels. + Return: + ch - the first channel number of current country code setting + ========================================================================== + */ +UCHAR FirstChannel( + IN PRTMP_ADAPTER pAd) +{ + return pAd->PortCfg.ChannelList[0]; +} + +/* + ========================================================================== + Description: + This routine returns the next channel number. This routine is called + during driver need to start a site survey of all supported channels. + Return: + next_channel - the next channel number valid in current country code setting. + Note: + return 0 if no more next channel + ========================================================================== + */ +UCHAR NextChannel( + IN PRTMP_ADAPTER pAd, + IN UCHAR channel) +{ + int i; + UCHAR next_channel = 0; + + for (i = 0; i < (pAd->PortCfg.ChannelListNum - 1); i++) + if (channel == pAd->PortCfg.ChannelList[i]) + { + next_channel = pAd->PortCfg.ChannelList[i+1]; + break; + } + return next_channel; +} + diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/wpa.c linux-2.6.17-ra2/drivers/net/wireless/rt2500/wpa.c --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/wpa.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/wpa.c 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,1417 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: wpa.c + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * JanL 22nd Jul 03 Initial code + * PaulL 28th Nov 03 Modify for supplicant + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#include "rt_config.h" + +UCHAR CipherWpaPskTkip[] = { + 0xDD, 0x16, // RSN IE + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x02, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x02, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x02 // authentication + }; +UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); + +UCHAR CipherWpaPskAes[] = { + 0xDD, 0x16, // RSN IE + 0x00, 0x50, 0xf2, 0x01, // oui + 0x01, 0x00, // Version + 0x00, 0x50, 0xf2, 0x04, // Multicast + 0x01, 0x00, // Number of unicast + 0x00, 0x50, 0xf2, 0x04, // unicast + 0x01, 0x00, // number of authentication method + 0x00, 0x50, 0xf2, 0x02 // authentication + }; +UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); + +/* + ======================================================================== + + Routine Description: + Classify WPA EAP message type + + Arguments: + EAPType Value of EAP message type + MsgType Internal Message definition for MLME state machine + + Return Value: + TRUE Found appropriate message type + FALSE No appropriate message type + + Note: + All these constants are defined in wpa.h + For supplicant, there is only EAPOL Key message avaliable + + ======================================================================== +*/ +BOOLEAN WpaMsgTypeSubst( + IN UCHAR EAPType, + OUT ULONG *MsgType) +{ + switch (EAPType) + { + case EAPPacket: + *MsgType = EAP_MSG_TYPE_EAPPacket; + break; + case EAPOLStart: + *MsgType = EAP_MSG_TYPE_EAPOLStart; + break; + case EAPOLLogoff: + *MsgType = EAP_MSG_TYPE_EAPOLLogoff; + break; + case EAPOLKey: + *MsgType = EAP_MSG_TYPE_EAPOLKey; + break; + case EAPOLASFAlert: + *MsgType = EAP_MSG_TYPE_EAPOLASFAlert; + break; + default: + DBGPRINT(RT_DEBUG_INFO, "WpaMsgTypeSubst : return FALSE; \n"); + return FALSE; + } + return TRUE; +} + +/* + ========================================================================== + Description: + association state machine init, including state transition and timer init + Parameters: + S - pointer to the association state machine + ========================================================================== + */ +VOID WpaPskStateMachineInit( + IN PRTMP_ADAPTER pAd, + IN STATE_MACHINE *S, + OUT STATE_MACHINE_FUNC Trans[]) +{ + StateMachineInit(S, (STATE_MACHINE_FUNC*)Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); + StateMachineSetAction(S, WPA_PSK_IDLE, EAP_MSG_TYPE_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); +} + +/* + ========================================================================== + Description: + This is state machine function. + When receiving EAPOL packets which is for 802.1x key management. + Use both in WPA, and WPAPSK case. + In this function, further dispatch to different functions according to the received packet. 3 categories are : + 1. normal 4-way pairwisekey and 2-way groupkey handshake + 2. MIC error (Countermeasures attack) report packet from STA. + 3. Request for pairwise/group key update from STA + Return: + ========================================================================== +*/ +VOID WpaEAPOLKeyAction( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem) +{ + INT MsgType; + UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; + PKEY_DESCRIPTER pKeyDesc; + + DBGPRINT(RT_DEBUG_TRACE, "-----> WpaEAPOLKeyAction\n"); + // Get 802.11 header first + pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; + +#ifdef BIG_ENDIAN + *(USHORT *)((UCHAR *)pKeyDesc+1) = SWAP16(*(USHORT *)((UCHAR *)pKeyDesc+1)); +#endif + // Sanity check, this should only happen in WPA-PSK mode + if (pAdapter->PortCfg.AuthMode != Ndis802_11AuthModeWPAPSK) + return; + + // 0. Debug print all bit information + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Key Description Version %d\n", pKeyDesc->KeyInfo.KeyDescVer); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Key Type %d\n", pKeyDesc->KeyInfo.KeyType); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Key Index %d\n", pKeyDesc->KeyInfo.KeyIndex); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Install %d\n", pKeyDesc->KeyInfo.Install); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Key Ack %d\n", pKeyDesc->KeyInfo.KeyAck); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Key MIC %d\n", pKeyDesc->KeyInfo.KeyMic); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Secure %d\n", pKeyDesc->KeyInfo.Secure); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Error %d\n", pKeyDesc->KeyInfo.Error); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo Request %d\n", pKeyDesc->KeyInfo.Request); + DBGPRINT(RT_DEBUG_INFO, "KeyInfo DL %d\n", pKeyDesc->KeyInfo.DL); + + // 1. Check EAPOL frame version and type + if ((Elem->Msg[LENGTH_802_11+LENGTH_802_1_H] != EAPOL_VER) || (pKeyDesc->Type != RSN_KEY_DESC)) + { + DBGPRINT(RT_DEBUG_ERROR, " Key descripter does not match with WPA rule \n"); + return; + } + + // 2.Check Version for AES & TKIP + if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) && (pKeyDesc->KeyInfo.KeyDescVer != DESC_TYPE_AES)) + { + DBGPRINT(RT_DEBUG_ERROR, " Key descripter version not match AES \n"); + return; + } + else if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pKeyDesc->KeyInfo.KeyDescVer != DESC_TYPE_TKIP)) + { + DBGPRINT(RT_DEBUG_ERROR, " Key descripter version not match TKIP \n"); + return; + } + + // First validate replay counter, only accept message with larger replay counter + // Let equal pass, some AP start with all zero replay counter + memset(ZeroReplay, 0, LEN_KEY_DESC_REPLAY); + if ((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAdapter->PortCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && + (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) + return; + + // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant + MsgType = EAPOL_MSG_INVALID; + if ((pKeyDesc->KeyInfo.KeyType == 1) && + (pKeyDesc->KeyInfo.KeyIndex == 0) && + (pKeyDesc->KeyInfo.KeyAck == 1) && + (pKeyDesc->KeyInfo.KeyMic == 0) && + (pKeyDesc->KeyInfo.Secure == 0) && + (pKeyDesc->KeyInfo.Error == 0) && + (pKeyDesc->KeyInfo.Request == 0)) + { + MsgType = EAPOL_PAIR_MSG_1; + DBGPRINT(RT_DEBUG_TRACE, "Receive EAPOL Key Pairwise Message 1\n"); + } + else if ((pKeyDesc->KeyInfo.KeyType == 1) && + (pKeyDesc->KeyInfo.KeyIndex == 0) && + (pKeyDesc->KeyInfo.KeyAck == 1) && + (pKeyDesc->KeyInfo.KeyMic == 1) && + (pKeyDesc->KeyInfo.Secure == 0) && + (pKeyDesc->KeyInfo.Error == 0) && + (pKeyDesc->KeyInfo.Request == 0)) + { + MsgType = EAPOL_PAIR_MSG_3; + DBGPRINT(RT_DEBUG_TRACE, "Receive EAPOL Key Pairwise Message 3\n"); + } + else if ((pKeyDesc->KeyInfo.KeyType == 0) && + (pKeyDesc->KeyInfo.KeyIndex != 0) && + (pKeyDesc->KeyInfo.KeyAck == 1) && + (pKeyDesc->KeyInfo.KeyMic == 1) && + (pKeyDesc->KeyInfo.Secure == 1) && + (pKeyDesc->KeyInfo.Error == 0) && + (pKeyDesc->KeyInfo.Request == 0)) + { + MsgType = EAPOL_GROUP_MSG_1; + DBGPRINT(RT_DEBUG_TRACE, "Receive EAPOL Key Group Message 1\n"); + } + +#ifdef BIG_ENDIAN + *(USHORT *)((UCHAR *)pKeyDesc+1) = SWAP16(*(USHORT *)((UCHAR *)pKeyDesc+1)); +#endif + + // We will assume link is up (assoc suceess and port not secured). + // All state has to be able to process message from previous state + switch (pAdapter->PortCfg.WpaState) + { + case SS_START: + if (MsgType == EAPOL_PAIR_MSG_1) + { + WpaPairMsg1Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_WAIT_MSG_3; + } + break; + + case SS_WAIT_MSG_3: + if (MsgType == EAPOL_PAIR_MSG_1) + { + WpaPairMsg1Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_WAIT_MSG_3; + } + else if (MsgType == EAPOL_PAIR_MSG_3) + { + WpaPairMsg3Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_WAIT_GROUP; + } + break; + + case SS_WAIT_GROUP: // When doing group key exchange + case SS_FINISH: // This happened when update group key + if (MsgType == EAPOL_PAIR_MSG_1) + { + WpaPairMsg1Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_WAIT_MSG_3; + // Reset port secured variable + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + } + else if (MsgType == EAPOL_PAIR_MSG_3) + { + WpaPairMsg3Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_WAIT_GROUP; + // Reset port secured variable + pAdapter->PortCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + } + else if (MsgType == EAPOL_GROUP_MSG_1) + { + WpaGroupMsg1Action(pAdapter, Elem); + pAdapter->PortCfg.WpaState = SS_FINISH; + } + break; + + default: + break; + } + + DBGPRINT(RT_DEBUG_TRACE, "<----- WpaEAPOLKeyAction\n"); +} + +/* + ======================================================================== + + Routine Description: + Process Pairwise key 4-way handshaking + + Arguments: + pAdapter Pointer to our adapter + Elem Message body + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID WpaPairMsg1Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem) +{ + PHEADER_802_11 pHeader; + UCHAR PTK[80]; + UCHAR *OutBuffer = NULL; + HEADER_802_11 Header_802_11; + NDIS_STATUS NStatus; + UCHAR AckRate = RATE_2; + USHORT AckDuration = 0; + ULONG FrameLen = 0; + UCHAR EAPHEAD[8] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,0x88,0x8e}; + PEAPOL_PACKET pMsg1; + EAPOL_PACKET Packet; + UCHAR Mic[16]; + + DBGPRINT(RT_DEBUG_TRACE, "WpaPairMsg1Action ----->\n"); + + pHeader = (PHEADER_802_11) Elem->Msg; + + // Save Data Length to pDesc for receiving packet, then put in outgoing frame Data Len fields. + pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; + + // Process message 1 from authenticator + // Key must be Pairwise key, already verified at callee. + // 1. Save Replay counter, it will use to verify message 3 and construct message 2 + memcpy(pAdapter->PortCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); + + // 2. Save ANonce + memcpy(pAdapter->PortCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); + + // TSNonce <--- SNonce + // Generate random SNonce + GenRandom(pAdapter, pAdapter->PortCfg.SNonce); + + // TPTK <--- Calc PTK(ANonce, TSNonce) + WpaCountPTK(pAdapter->PortCfg.PskKey.Key, + pAdapter->PortCfg.ANonce, + pAdapter->PortCfg.Bssid.Octet, + pAdapter->PortCfg.SNonce, + pAdapter->CurrentAddress, + PTK, + LEN_PTK); + + // Save key to PTK entry + memcpy(pAdapter->PortCfg.PTK, PTK, LEN_PTK); + + // ===================================== + // Use Priority Ring & MiniportMMRequest + // ===================================== + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + WpaMacHeaderInit(pAdapter, &Header_802_11, 0, &pAdapter->PortCfg.Bssid); + + // ACK size is 14 include CRC, and its rate is based on real time information + AckRate = pAdapter->PortCfg.ExpectedACKRate[pAdapter->PortCfg.TxRate]; + AckDuration = RTMPCalcDuration(pAdapter, AckRate, 14); + Header_802_11.Controlhead.Duration = pAdapter->PortCfg.Dsifs + AckDuration; + + // Zero message 2 body + memset(&Packet, 0, sizeof(Packet)); + Packet.Version = EAPOL_VER; + Packet.Type = EAPOLKey; + // + // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) + // + Packet.KeyDesc.Type = RSN_KEY_DESC; + // 1. Key descriptor version and appropriate RSN IE + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + Packet.KeyDesc.KeyInfo.KeyDescVer = 2; + Packet.KeyDesc.KeyDataLen[1] = CipherWpaPskAesLen; + memcpy(Packet.KeyDesc.KeyData, CipherWpaPskAes, CipherWpaPskAesLen); + } + else // TKIP + { + Packet.KeyDesc.KeyInfo.KeyDescVer = 1; + Packet.KeyDesc.KeyDataLen[1] = CipherWpaPskTkipLen; + memcpy(Packet.KeyDesc.KeyData, CipherWpaPskTkip, CipherWpaPskTkipLen); + } + // Update packet length after decide Key data payload + Packet.Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; + + // 2. Key Type PeerKey + Packet.KeyDesc.KeyInfo.KeyType = 1; + + // 3. KeyMic field presented + Packet.KeyDesc.KeyInfo.KeyMic = 1; + + // 4. Fill SNonce + memcpy(Packet.KeyDesc.KeyNonce, pAdapter->PortCfg.SNonce, LEN_KEY_DESC_NONCE); + + // 5. Key Replay Count + memcpy(Packet.KeyDesc.ReplayCounter, pAdapter->PortCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); + +#ifdef BIG_ENDIAN + *(USHORT *)(&(Packet.KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(Packet.KeyDesc.KeyInfo))); +#endif + + // Send EAPOL(0, 1, 0, 0, 0, K, 0, TSNonce, 0, MIC(TPTK), 0) + // Out buffer for transmitting message 2 + NStatus = MlmeAllocateMemory(pAdapter, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + // Prepare EAPOL frame for MIC calculation + // Be careful, only EAPOL frame is counted for MIC calculation + MakeOutgoingFrame(OutBuffer, &FrameLen, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // 5. Prepare and Fill MIC value + memset(Mic, 0, sizeof(Mic)); + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + // AES + UCHAR digest[80]; + + HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); + memcpy(Mic, digest, LEN_KEY_DESC_MIC); + } + else + { + INT i; + DBGPRINT(RT_DEBUG_INFO, " PMK = "); + for (i = 0; i < 16; i++) + DBGPRINT(RT_DEBUG_INFO, "%2x-", pAdapter->PortCfg.PskKey.Key[i]); + + DBGPRINT(RT_DEBUG_INFO, "\n PTK = "); + for (i = 0; i < 64; i++) + DBGPRINT(RT_DEBUG_INFO, "%2x-", pAdapter->PortCfg.PTK[i]); + DBGPRINT(RT_DEBUG_INFO, "\n FrameLen = %d\n", FrameLen); + + rt2500_hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, Mic); + } + memcpy(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); + + FrameLen = 0; + // Make Transmitting frame + MakeOutgoingFrame(OutBuffer, &FrameLen, sizeof(MACHDR), &Header_802_11, + sizeof(EAPHEAD), EAPHEAD, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // Send using priority queue + MiniportMMRequest(pAdapter, OutBuffer, FrameLen); + + DBGPRINT(RT_DEBUG_TRACE, "WpaPairMsg1Action <-----\n"); +} + +/* + ======================================================================== + + Routine Description: + Process Pairwise key 4-way handshaking + + Arguments: + pAdapter Pointer to our adapter + Elem Message body + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID WpaPairMsg3Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem) +{ + PHEADER_802_11 pHeader; + UCHAR *OutBuffer = NULL; + HEADER_802_11 Header_802_11; + NDIS_STATUS NStatus; + UCHAR AckRate = RATE_2; + USHORT AckDuration = 0; + ULONG FrameLen = 0; + UCHAR EAPHEAD[8] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,0x88,0x8e}; + EAPOL_PACKET Packet; + PEAPOL_PACKET pMsg3; + PUCHAR pTmp; + UCHAR Mic[16], OldMic[16]; + NDIS_802_11_KEY PeerKey; + + + DBGPRINT(RT_DEBUG_TRACE, "WpaPairMsg3Action ----->\n"); + + pHeader = (PHEADER_802_11) Elem->Msg; + + // Process message 3 frame. + pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; + +#ifdef BIG_ENDIAN + *(USHORT *)(&(pMsg3->KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(pMsg3->KeyDesc.KeyInfo))); +#endif + + // 1. Verify RSN IE & cipher type match + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + if (pMsg3->KeyDesc.KeyInfo.KeyDescVer != 2) + return; + pTmp = (PUCHAR) &CipherWpaPskAes; + } + else // TKIP + { + if (pMsg3->KeyDesc.KeyInfo.KeyDescVer != 1) + return; + pTmp = (PUCHAR) &CipherWpaPskTkip; + } + + // Fix compatibility issue, when AP append nonsense data after auth mode with different size. + // We should qualify this kind of RSN as acceptable + if (!NdisEqualMemory((PUCHAR) &pMsg3->KeyDesc.KeyData[2], pTmp + 2, CipherWpaPskTkipLen - 2)) + { + DBGPRINT(RT_DEBUG_ERROR, " RSN IE mismatched msg 3 of 4-way handshake!!!!!!!!!! \n"); + return; + } + else + DBGPRINT(RT_DEBUG_TRACE, " RSN IE matched in msg 3 of 4-way handshake!!!!!!!!!! \n"); + +#ifdef BIG_ENDIAN + *(USHORT *)(&(pMsg3->KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(pMsg3->KeyDesc.KeyInfo))); +#endif + + // 2. Check MIC value + // Save the MIC and replace with zero + memcpy(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); + memset(pMsg3->KeyDesc.KeyMic, 0, LEN_KEY_DESC_MIC); + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + // AES + UCHAR digest[80]; + + HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Len[1] + 4, pAdapter->PortCfg.PTK, LEN_EAP_MICK, digest); + memcpy(Mic, digest, LEN_KEY_DESC_MIC); + } + else + { + rt2500_hmac_md5(pAdapter->PortCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Len[1] + 4, Mic); + } + + if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) + { + DBGPRINT(RT_DEBUG_ERROR, " MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n"); + return; + } + else + DBGPRINT(RT_DEBUG_TRACE, " MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n"); + + // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger + if (RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAdapter->PortCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) + return; + + // Update new replay counter + memcpy(pAdapter->PortCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); + + // 4. Double check ANonce + if (!NdisEqualMemory(pAdapter->PortCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) + return; + + // 5. Construct Message 4 + // ===================================== + // Use Priority Ring & MiniportMMRequest + // ===================================== + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + WpaMacHeaderInit(pAdapter, &Header_802_11, 0, &pAdapter->PortCfg.Bssid); + + // ACK size is 14 include CRC, and its rate is based on real time information + AckRate = pAdapter->PortCfg.ExpectedACKRate[pAdapter->PortCfg.TxRate]; + AckDuration = RTMPCalcDuration(pAdapter, AckRate, 14); + Header_802_11.Controlhead.Duration = pAdapter->PortCfg.Dsifs + AckDuration; + + // Zero message 4 body + memset(&Packet, 0, sizeof(Packet)); + Packet.Version = EAPOL_VER; + Packet.Type = EAPOLKey; + Packet.Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field + + // + // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) + // + Packet.KeyDesc.Type = RSN_KEY_DESC; + +#ifdef BIG_ENDIAN + *(USHORT *)(&(pMsg3->KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(pMsg3->KeyDesc.KeyInfo))); +#endif + + // Key descriptor version and appropriate RSN IE + Packet.KeyDesc.KeyInfo.KeyDescVer = pMsg3->KeyDesc.KeyInfo.KeyDescVer; + + // Key Type PeerKey + Packet.KeyDesc.KeyInfo.KeyType = 1; + + // KeyMic field presented + Packet.KeyDesc.KeyInfo.KeyMic = 1; + + // Key Replay count + memcpy(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); +#ifdef BIG_ENDIAN + *(USHORT *)&Packet.KeyDesc.KeyInfo = SWAP16(*(USHORT *)&Packet.KeyDesc.KeyInfo); +#endif + + // Out buffer for transmitting message 4 + NStatus = MlmeAllocateMemory(pAdapter, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + // Prepare EAPOL frame for MIC calculation + // Be careful, only EAPOL frame is counted for MIC calculation + MakeOutgoingFrame(OutBuffer, &FrameLen, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // Prepare and Fill MIC value + memset(Mic, 0, sizeof(Mic)); + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + // AES + UCHAR digest[80]; + + HMAC_SHA1(OutBuffer, FrameLen, pAdapter->PortCfg.PTK, LEN_EAP_MICK, digest); + memcpy(Mic, digest, LEN_KEY_DESC_MIC); + } + else + { + rt2500_hmac_md5(pAdapter->PortCfg.PTK, LEN_EAP_MICK, OutBuffer, FrameLen, Mic); + } + memcpy(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); + + FrameLen = 0; + + // Make Transmitting frame + MakeOutgoingFrame(OutBuffer, &FrameLen, sizeof(MACHDR), &Header_802_11, + sizeof(EAPHEAD), EAPHEAD, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // 6. Send Message 4 to authenticator + // Send using priority queue + MiniportMMRequest(pAdapter, OutBuffer, FrameLen); + + // 7. Update PTK + memset(&PeerKey, 0, sizeof(PeerKey)); + PeerKey.Length = sizeof(PeerKey); + PeerKey.KeyIndex = 0xe0000000; + PeerKey.KeyLength = 16; + memcpy(PeerKey.BSSID, pAdapter->PortCfg.Bssid.Octet, 6); + memcpy(&PeerKey.KeyRSC, pMsg3->KeyDesc.KeyRsc, LEN_KEY_DESC_RSC); + memcpy(PeerKey.KeyMaterial, &pAdapter->PortCfg.PTK[32], 32); + // Call Add peer key function + RTMPWPAAddKeyProc(pAdapter, &PeerKey); + + DBGPRINT(RT_DEBUG_TRACE, "WpaPairMsg3Action <-----\n"); +} + + +/* + ======================================================================== + + Routine Description: + Process Group key 2-way handshaking + + Arguments: + pAdapter Pointer to our adapter + Elem Message body + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID WpaGroupMsg1Action( + IN PRTMP_ADAPTER pAdapter, + IN MLME_QUEUE_ELEM *Elem) +{ + PHEADER_802_11 pHeader; + UCHAR *OutBuffer = NULL; + HEADER_802_11 Header_802_11; + NDIS_STATUS NStatus; + UCHAR AckRate = RATE_2; + USHORT AckDuration = 0; + ULONG FrameLen = 0; + UCHAR EAPHEAD[8] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,0x88,0x8e}; + EAPOL_PACKET Packet; + PEAPOL_PACKET pGroup; + UCHAR Mic[16], OldMic[16]; + UCHAR GTK[32], Key[32]; + NDIS_802_11_KEY GroupKey; + + + DBGPRINT(RT_DEBUG_TRACE, "WpaGroupMsg1Action ----->\n"); + + pHeader = (PHEADER_802_11) Elem->Msg; + + // Process Group message 1 frame. + pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; + + // 1. Verify Replay counter + // Check Replay Counter, it has to be larger than last one. No need to be exact one larger + if (RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAdapter->PortCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) + return; + + // Update new replay counter + memcpy(pAdapter->PortCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); + + // 2. Verify MIC is valid + // Save the MIC and replace with zero + memcpy(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); + memset(pGroup->KeyDesc.KeyMic, 0, LEN_KEY_DESC_MIC); + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + // AES + UCHAR digest[80]; + + HMAC_SHA1((PUCHAR) pGroup, pGroup->Len[1] + 4, pAdapter->PortCfg.PTK, LEN_EAP_MICK, digest); + memcpy(Mic, digest, LEN_KEY_DESC_MIC); + } + else + { + rt2500_hmac_md5(pAdapter->PortCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Len[1] + 4, Mic); + } + + if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) + { + DBGPRINT(RT_DEBUG_ERROR, " MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n"); + return; + } + else + DBGPRINT(RT_DEBUG_TRACE, " MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n"); + +#ifdef BIG_ENDIAN + *(USHORT *)(&(pGroup->KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(pGroup->KeyDesc.KeyInfo))); +#endif + + // 3. Decrypt GTK from Key Data + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + if (pGroup->KeyDesc.KeyInfo.KeyDescVer != 2) + return; + // Decrypt AES GTK + AES_GTK_KEY_UNWRAP(&pAdapter->PortCfg.PTK[16], GTK, pGroup->KeyDesc.KeyData); + } + else // TKIP + { + INT i; + + if (pGroup->KeyDesc.KeyInfo.KeyDescVer != 1) + return; + // Decrypt TKIP GTK + // Construct 32 bytes RC4 Key + memcpy(Key, pGroup->KeyDesc.KeyIv, 16); + memcpy(&Key[16], &pAdapter->PortCfg.PTK[16], 16); + ARCFOUR_INIT(&pAdapter->PrivateInfo.WEPCONTEXT, Key, 32); + //discard first 256 bytes + for (i = 0; i < 256; i++) + ARCFOUR_BYTE(&pAdapter->PrivateInfo.WEPCONTEXT); + // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not + ARCFOUR_DECRYPT(&pAdapter->PrivateInfo.WEPCONTEXT, GTK, pGroup->KeyDesc.KeyData, 32); + } + + // 4. Construct Group Message 2 + pAdapter->Sequence = ((pAdapter->Sequence) + 1) & (MAX_SEQ_NUMBER); + WpaMacHeaderInit(pAdapter, &Header_802_11, 1, &pAdapter->PortCfg.Bssid); + + // ACK size is 14 include CRC, and its rate is based on real time information + AckRate = pAdapter->PortCfg.ExpectedACKRate[pAdapter->PortCfg.TxRate]; + AckDuration = RTMPCalcDuration(pAdapter, AckRate, 14); + Header_802_11.Controlhead.Duration = pAdapter->PortCfg.Dsifs + AckDuration; + + // Zero Group message 1 body + memset(&Packet, 0, sizeof(Packet)); + Packet.Version = EAPOL_VER; + Packet.Type = EAPOLKey; + Packet.Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field + + // + // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) + // + Packet.KeyDesc.Type = RSN_KEY_DESC; + + // Key descriptor version and appropriate RSN IE + Packet.KeyDesc.KeyInfo.KeyDescVer = pGroup->KeyDesc.KeyInfo.KeyDescVer; + + // Key Type Group key + Packet.KeyDesc.KeyInfo.KeyType = 0; + + // KeyMic field presented + Packet.KeyDesc.KeyInfo.KeyMic = 1; + + // Secure bit is 1 + Packet.KeyDesc.KeyInfo.Secure = 1; + + // Key Replay count + memcpy(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); + +#ifdef BIG_ENDIAN + *(USHORT *)(&(Packet.KeyDesc.KeyInfo)) = SWAP16(*(USHORT *)(&(Packet.KeyDesc.KeyInfo))); +#endif + + // Out buffer for transmitting group message 2 + NStatus = MlmeAllocateMemory(pAdapter, (PVOID)&OutBuffer); //Get an unused nonpaged memory + if (NStatus != NDIS_STATUS_SUCCESS) + return; + + // Prepare EAPOL frame for MIC calculation + // Be careful, only EAPOL frame is counted for MIC calculation + MakeOutgoingFrame(OutBuffer, &FrameLen, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // Prepare and Fill MIC value + memset(Mic, 0, sizeof(Mic)); + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + // AES + UCHAR digest[80]; + + HMAC_SHA1(OutBuffer, FrameLen, pAdapter->PortCfg.PTK, LEN_EAP_MICK, digest); + memcpy(Mic, digest, LEN_KEY_DESC_MIC); + } + else + { + INT i; + DBGPRINT(RT_DEBUG_INFO, "PTK = "); + for (i = 0; i < 64; i++) + DBGPRINT(RT_DEBUG_INFO, "%2x-", pAdapter->PortCfg.PTK[i]); + DBGPRINT(RT_DEBUG_INFO, "\n FrameLen = %d\n", FrameLen); + + rt2500_hmac_md5(pAdapter->PortCfg.PTK, LEN_EAP_MICK, OutBuffer, FrameLen, Mic); + } + memcpy(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); + + FrameLen = 0; + // Make Transmitting frame + MakeOutgoingFrame(OutBuffer, &FrameLen, sizeof(MACHDR), &Header_802_11, + sizeof(EAPHEAD), EAPHEAD, + Packet.Len[1] + 4, &Packet, + END_OF_ARGS); + + // 5. Copy frame to Tx ring and prepare for encryption + WpaHardEncrypt(pAdapter, OutBuffer, FrameLen); + + // 6 Free allocated memory + MlmeFreeMemory(pAdapter, OutBuffer); + + // 6. Update GTK + memset(&GroupKey, 0, sizeof(GroupKey)); + GroupKey.Length = sizeof(GroupKey); + GroupKey.KeyIndex = 0x20000000 | pGroup->KeyDesc.KeyInfo.KeyIndex; + GroupKey.KeyLength = 16; + memcpy(GroupKey.BSSID, pAdapter->PortCfg.Bssid.Octet, 6); + memcpy(GroupKey.KeyMaterial, GTK, 32); + // Call Add peer key function + RTMPWPAAddKeyProc(pAdapter, &GroupKey); + + DBGPRINT(RT_DEBUG_TRACE, "WpaGroupMsg1Action <-----\n"); +} +/* + ======================================================================== + + Routine Description: + Init WPA MAC header + + Arguments: + pAdapter Pointer to our adapter + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID WpaMacHeaderInit( + IN PRTMP_ADAPTER pAd, + IN OUT PHEADER_802_11 Hdr, + IN UCHAR wep, + IN PMACADDR pAddr1) +{ + memset(Hdr, 0, sizeof(HEADER_802_11)); + Hdr->Controlhead.Frame.Type = BTYPE_DATA; + Hdr->Controlhead.Frame.ToDs = 1; + if (wep == 1) + Hdr->Controlhead.Frame.Wep = 1; + + // Addr1: DA, Addr2: BSSID, Addr3: SA + COPY_MAC_ADDR(&Hdr->Controlhead.Addr1, pAddr1); + COPY_MAC_ADDR(&Hdr->Controlhead.Addr2, &pAd->CurrentAddress); + COPY_MAC_ADDR(&Hdr->Addr3, &pAd->PortCfg.Bssid); + Hdr->Sequence = pAd->Sequence; +} + +/* + ======================================================================== + + Routine Description: + Copy frame from waiting queue into relative ring buffer and set + appropriate ASIC register to kick hardware encryption before really + sent out to air. + + Arguments: + pAdapter Pointer to our adapter + PNDIS_PACKET Pointer to outgoing Ndis frame + NumberOfFrag Number of fragment required + + Return Value: + None + + Note: + + ======================================================================== +*/ +VOID WpaHardEncrypt( + IN PRTMP_ADAPTER pAdapter, + IN PUCHAR pPacket, + IN ULONG Len) +{ + UCHAR FrameGap; + PUCHAR pDest; + PUCHAR pSrc; + UCHAR CipherAlg = CIPHER_NONE; + PTXD_STRUC pTxD; +#ifdef BIG_ENDIAN + TXD_STRUC TxD; + PTXD_STRUC pDestTxD; + PUCHAR pOriginDest; +#endif + ULONG Iv16; + ULONG Iv32; + PWPA_KEY pWpaKey; + UCHAR RetryMode = SHORT_RETRY; + static UCHAR Priority[4] = {"\x00\x00\x00\x00"}; + + // Make sure Tx ring resource won't be used by other threads + spin_lock_irq(&pAdapter->TxRingLock); + + FrameGap = IFS_BACKOFF; // Default frame gap mode + + // outgoing frame always wakeup PHY to prevent frame lost and + // turn off PSM bit to improve performance + if (pAdapter->PortCfg.Psm == PWR_SAVE) + { + MlmeSetPsmBit(pAdapter, PWR_ACTIVE); + } + AsicForceWakeup(pAdapter); + + pAdapter->TxRing[pAdapter->CurEncryptIndex].FrameType = BTYPE_DATA; + + pSrc = pPacket; // Point to start of MSDU + + pWpaKey = (PWPA_KEY) &pAdapter->PortCfg.PairwiseKey[0]; + pWpaKey->Type = PAIRWISE_KEY; + if (pWpaKey == NULL) + { + // No pairwise key, this should not happen + spin_unlock_irq(&pAdapter->TxRingLock); + return; + } + + // Get the Tx Ring descriptor & Dma Buffer address + pDest = (PUCHAR) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_data_addr; +#ifndef BIG_ENDIAN + pTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; +#else + pOriginDest = pDest; + pDestTxD = (PTXD_STRUC) pAdapter->TxRing[pAdapter->CurEncryptIndex].va_addr; + TxD = *pDestTxD; + pTxD = &TxD; + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); +#endif + + if ((pTxD->Owner == DESC_OWN_NIC) || (pTxD->CipherOwn == DESC_OWN_NIC)) + { + // Descriptor owned by NIC. No descriptor avaliable + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + pAdapter->RalinkCounters.TxRingErrCount++; + spin_unlock_irq(&pAdapter->TxRingLock); + return; + } + if (pTxD->Valid == TRUE) + { + // Ndis packet of last round did not cleared. + // This should not happen since caller guaranteed. + // Make sure to release Tx ring resource + pTxD->Valid = FALSE; + +#ifdef BIG_ENDIAN + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; +#endif + + pAdapter->RalinkCounters.TxRingErrCount++; + spin_unlock_irq(&pAdapter->TxRingLock); + return; + } + + // Copy whole frame to Tx ring buffer + memcpy(pDest, pPacket, Len); + pDest += Len; + + if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) + { + INT i; + + i = 0; + // Prepare 8 bytes TKIP encapsulation for MPDU + { + TKIP_IV tkipIv; + + tkipIv.IV32 = 0; // (ensure reserved fields clear) + tkipIv.IV16.field.rc0 = *(pWpaKey->TxTsc + 1); + tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; + tkipIv.IV16.field.rc2 = *pWpaKey->TxTsc; + tkipIv.IV16.field.Rsvd = 0; + tkipIv.IV16.field.ExtIV = 1;// 0: non-extended IV, 1: extended IV + tkipIv.IV16.field.KeyID = 0; + tkipIv.IV32 = *(PULONG)(pWpaKey->TxTsc + 2); + + pTxD->Iv = tkipIv.IV16.word; + + *((PUCHAR) &pTxD->Eiv) = *((PUCHAR) &tkipIv.IV32 + 3); + *((PUCHAR) &pTxD->Eiv + 1) = *((PUCHAR) &tkipIv.IV32 + 2); + *((PUCHAR) &pTxD->Eiv + 2) = *((PUCHAR) &tkipIv.IV32 + 1); + *((PUCHAR) &pTxD->Eiv + 3) = *((PUCHAR) &tkipIv.IV32); + } + + // Increase TxTsc value for next transmission + while (++pWpaKey->TxTsc[i] == 0x0) + { + i++; + if (i == 6) + break; + } + + // Set IV offset + pTxD->IvOffset = LENGTH_802_11; + + // Copy TKey + memcpy(pTxD->Key, pWpaKey->Key, 16); + + // Set Cipher suite + CipherAlg = CIPHER_TKIP; + + // Calculate MIC value + // Init MIC value calculation and reset the message + pAdapter->PrivateInfo.Tx.L = RTMPTkipGetUInt32(pWpaKey->TxMic); + pAdapter->PrivateInfo.Tx.R = RTMPTkipGetUInt32(pWpaKey->TxMic + 4); + pAdapter->PrivateInfo.Tx.nBytesInM = 0; + pAdapter->PrivateInfo.Tx.M = 0; + + // DA & SA field + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pSrc + 4, 12); + + // Priority + 3 bytes of 0 + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, Priority, 4); + + pSrc += LENGTH_802_11; + RTMPTkipAppend(&pAdapter->PrivateInfo.Tx, pSrc, Len - LENGTH_802_11); + RTMPTkipGetMIC(&pAdapter->PrivateInfo.Tx); + // Append MIC + memcpy(pDest, pAdapter->PrivateInfo.Tx.MIC, 8); + Len += 8; + // IV + EIV + ICV which ASIC added after encryption done + Len += 12; + } + else if (pAdapter->PortCfg.WepStatus == Ndis802_11Encryption3Enabled) + { + INT i; + PUCHAR pTmp; + + i = 0; + pTmp = (PUCHAR) &Iv16; + *pTmp = pWpaKey->TxTsc[0]; + *(pTmp + 1) = pWpaKey->TxTsc[1]; + *(pTmp + 2) = 0; + *(pTmp + 3) = 0x20; + + Iv32 = *(PULONG)(&pWpaKey->TxTsc[2]); + + // Increase TxTsc value for next transmission + while (++pWpaKey->TxTsc[i] == 0x0) + { + i++; + if (i == 6) + break; + } + + // Copy IV + memcpy(&pTxD->Iv, &Iv16, 4); + + // Copy EIV + memcpy(&pTxD->Eiv, &Iv32, 4); + + // Set IV offset + pTxD->IvOffset = LENGTH_802_11; + + // Copy TKey + memcpy(pTxD->Key, pWpaKey->Key, 16); + + // Set Cipher suite + CipherAlg = CIPHER_AES; + + // IV + EIV + HW MIC + Len += 16; + } + +#ifdef BIG_ENDIAN + RTMPFrameEndianChange(pAdapter, pOriginDest, DIR_WRITE, FALSE); + RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); + *pDestTxD = TxD; + pTxD = pDestTxD; +#endif + + RTMPWriteTxDescriptor(pTxD, TRUE, CipherAlg, TRUE, FALSE, FALSE, RetryMode, FrameGap, + pAdapter->PortCfg.TxRate, 4, Len, pAdapter->PortCfg.TxPreambleInUsed, 0); + + // Increase & maintain Tx Ring Index + pAdapter->CurEncryptIndex++; + if (pAdapter->CurEncryptIndex >= TX_RING_SIZE) + { + pAdapter->CurEncryptIndex = 0; + } + pAdapter->RalinkCounters.EncryptCount++; + + // Kick Encrypt Control Register at the end of all ring buffer preparation + RTMP_IO_WRITE32(pAdapter, SECCSR1, 0x1); + + // Make sure to release Tx ring resource + spin_unlock_irq(&pAdapter->TxRingLock); +} + +/* + ======================================================================== + + Routine Description: + SHA1 function + + Arguments: + + Return Value: + + Note: + + ======================================================================== +*/ +VOID HMAC_SHA1( + IN UCHAR *text, + IN UINT text_len, + IN UCHAR *key, + IN UINT key_len, + IN UCHAR *digest) +{ + SHA_CTX context; + UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ + UCHAR k_opad[65]; /* outer padding - key XORd with opad */ + INT i; + + // if key is longer than 64 bytes reset it to key=SHA1(key) + if (key_len > 64) + { + SHA_CTX tctx; + SHAInit(&tctx); + SHAUpdate(&tctx, key, key_len); + SHAFinal(&tctx, key); + key_len = 20; + } + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + // XOR key with ipad and opad values + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA1 + SHAInit(&context); /* init context for 1st pass */ + SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ + SHAUpdate(&context, text, text_len); /* then text of datagram */ + SHAFinal(&context, digest); /* finish up 1st pass */ + + //perform outer SHA1 + SHAInit(&context); /* init context for 2nd pass */ + SHAUpdate(&context, k_opad, 64); /* start with outer pad */ + SHAUpdate(&context, digest, 20); /* then results of 1st hash */ + SHAFinal(&context, digest); /* finish up 2nd pass */ +} + +/* + ======================================================================== + + Routine Description: + PRF function + + Arguments: + + Return Value: + + Note: + 802.1i Annex F.9 + + ======================================================================== +*/ +VOID PRF( + IN UCHAR *key, + IN INT key_len, + IN UCHAR *prefix, + IN INT prefix_len, + IN UCHAR *data, + IN INT data_len, + OUT UCHAR *output, + IN INT len) +{ + INT i; + UCHAR input[1024]; + INT currentindex = 0; + INT total_len; + + memcpy(input, prefix, prefix_len); + input[prefix_len] = 0; + memcpy(&input[prefix_len + 1], data, data_len); + total_len = prefix_len + 1 + data_len; + input[total_len] = 0; + total_len++; + for (i = 0; i < (len + 19) / 20; i++) + { + HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); + currentindex += 20; + input[total_len - 1]++; + } +} + +/* + ======================================================================== + + Routine Description: + Count TPTK from PMK + + Arguments: + + Return Value: + Output Store the TPTK + + Note: + + ======================================================================== +*/ +VOID WpaCountPTK( + IN UCHAR *PMK, + IN UCHAR *ANonce, + IN UCHAR *AA, + IN UCHAR *SNonce, + IN UCHAR *SA, + OUT UCHAR *output, + IN UINT len) +{ + UCHAR concatenation[76]; + UINT CurrPos = 0; + UCHAR temp[32]; + UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', + 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; + + memset(temp, 0, sizeof(temp)); + + // Get smaller address + if (RTMPCompareMemory(SA, AA, 6) == 1) + memcpy(concatenation, AA, 6); + else + memcpy(concatenation, SA, 6); + CurrPos += 6; + + // Get larger address + if (RTMPCompareMemory(SA, AA, 6) == 1) + memcpy(&concatenation[CurrPos], SA, 6); + else + memcpy(&concatenation[CurrPos], AA, 6); + CurrPos += 6; + + // Get smaller address + if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) + memcpy(&concatenation[CurrPos], SNonce, 32); + else + memcpy(&concatenation[CurrPos], ANonce, 32); + CurrPos += 32; + + // Get larger address + if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) + memcpy(&concatenation[CurrPos], ANonce, 32); + else + memcpy(&concatenation[CurrPos], SNonce, 32); + CurrPos += 32; + + PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76 , output, len); +} + +/* + ======================================================================== + + Routine Description: + Misc function to Generate random number + + Arguments: + + Return Value: + + Note: + 802.1i Annex F.9 + + ======================================================================== +*/ +VOID GenRandom( + IN PRTMP_ADAPTER pAd, + OUT UCHAR *random) +{ + INT i, curr; + UCHAR local[80], KeyCounter[32]; + UCHAR result[80]; + ULONG CurrentTime; + UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; + + memset(result, 0, 80); + memset(local, 0, 80); + memset(KeyCounter, 0, 32); + memcpy(local, pAd->CurrentAddress, ETH_ALEN); + + for (i = 0; i < 32; i++) + { + curr = ETH_ALEN; + CurrentTime = jiffies; + memcpy(local, pAd->CurrentAddress, ETH_ALEN); + curr += ETH_ALEN; + memcpy(&local[curr], &CurrentTime, sizeof(CurrentTime)); + curr += sizeof(CurrentTime); + memcpy(&local[curr], result, 32); + curr += 32; + memcpy(&local[curr], &i, 2); + curr += 2; + PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); + } + memcpy(random, result, 32); +} + +/* + ======================================================================== + + Routine Description: + Misc function to decrypt AES body + + Arguments: + + Return Value: + + Note: + This function references to RFC 3394 for aes key unwrap algorithm. + + ======================================================================== +*/ +VOID AES_GTK_KEY_UNWRAP( + IN UCHAR *key, + OUT UCHAR *plaintext, + IN UCHAR *ciphertext) +{ + UCHAR A[8], BIN[16], BOUT[16]; + UCHAR R1[8],R2[8]; + UCHAR xor; + INT num_blocks = 2; + INT j; + aes_context aesctx; + + // Initialize + // A = C[0] + memcpy(A, ciphertext, 8); + // R1 = C1 + memcpy(R1, &ciphertext[8], 8); + // R2 = C2 + memcpy(R2, &ciphertext[16], 8); + + aes_set_key(&aesctx, key, 128); + + for (j = 5; j >= 0; j--) + { + xor = num_blocks * j + 2; + memcpy(BIN, A, 8); + BIN[7] = A[7] ^ xor; + memcpy(&BIN[8], R2, 8); + aes_decrypt(&aesctx, BIN, BOUT); + memcpy(A, &BOUT[0], 8); + memcpy(R2, &BOUT[8], 8); + + xor = num_blocks * j + 1; + memcpy(BIN, A, 8); + BIN[7] = A[7] ^ xor; + memcpy(&BIN[8], R1, 8); + aes_decrypt(&aesctx, BIN, BOUT); + memcpy(A, &BOUT[0], 8); + memcpy(R1, &BOUT[8], 8); + } + + // OUTPUT + memcpy(&plaintext[0], R1, 8); + memcpy(&plaintext[8], R2, 8); +} diff -urN linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/wpa.h linux-2.6.17-ra2/drivers/net/wireless/rt2500/wpa.h --- linux-2.6.17-ra.orig/drivers/net/wireless/rt2500/wpa.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-ra2/drivers/net/wireless/rt2500/wpa.h 2006-08-22 22:42:13.000000000 +0200 @@ -0,0 +1,158 @@ +/*************************************************************************** + * RT2400/RT2500 SourceForge Project - http://rt2x00.serialmonkey.com * + * * + * 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. * + * * + * Licensed under the GNU GPL * + * Original code supplied under license from RaLink Inc, 2004. * + ***************************************************************************/ + + /*************************************************************************** + * Module Name: wpa.h + * + * Abstract: + * + * Revision History: + * Who When What + * -------- ----------- ----------------------------- + * MarkW 8th Dec 04 Baseline code + ***************************************************************************/ + +#ifndef __WPA_H__ +#define __WPA_H__ + +//Messages for the wpa state machine, +#define WPA_MACHINE_BASE 21 +#define EAP_MSG_TYPE_EAPPacket 21 +#define EAP_MSG_TYPE_EAPOLStart 22 +#define EAP_MSG_TYPE_EAPOLLogoff 23 +#define EAP_MSG_TYPE_EAPOLKey 24 +#define EAP_MSG_TYPE_EAPOLASFAlert 25 +#define MAX_WPA_PSK_MSG 5 + +// WpaPsk EAPOL Key descripter frame format related length +#define LEN_KEY_DESC_NONCE 32 +#define LEN_KEY_DESC_IV 16 +#define LEN_KEY_DESC_RSC 8 +#define LEN_KEY_DESC_ID 8 +#define LEN_KEY_DESC_REPLAY 8 +#define LEN_KEY_DESC_MIC 16 + +//EPA VERSION +#define EAPOL_VER 1 +#define DESC_TYPE_TKIP 1 +#define DESC_TYPE_AES 2 +#define RSN_KEY_DESC 0xfe + +#define LEN_MASTER_KEY 32 + +// EAPOL EK, MK +#define LEN_EAP_EK 16 +#define LEN_EAP_MICK 16 +#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) +// TKIP key related +#define LEN_TKIP_EK 16 +#define LEN_TKIP_RXMICK 8 +#define LEN_TKIP_TXMICK 8 +#define LEN_AES_EK 16 +#define LEN_AES_KEY LEN_AES_EK +#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) +#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) +#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) +#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) +#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) +#define MAX_LEN_OF_RSNIE 48 + +//EAP Packet Type +#define EAPPacket 0 +#define EAPOLStart 1 +#define EAPOLLogoff 2 +#define EAPOLKey 3 +#define EAPOLASFAlert 4 +#define EAPTtypeMax 5 + +#define EAPOL_MSG_INVALID 0 +#define EAPOL_PAIR_MSG_1 1 +#define EAPOL_PAIR_MSG_3 2 +#define EAPOL_GROUP_MSG_1 3 + +// EAPOL Key Information definition within Key descriptor format +typedef struct PACKED _KEY_INFO +{ +#ifdef BIG_ENDIAN + UCHAR KeyAck:1; + UCHAR Install:1; + UCHAR KeyIndex:2; + UCHAR KeyType:1; + UCHAR KeyDescVer:3; + UCHAR Rsvd:3; + UCHAR DL:1; + UCHAR Request:1; + UCHAR Error:1; + UCHAR Secure:1; + UCHAR KeyMic:1; +#else + UCHAR KeyMic:1; + UCHAR Secure:1; + UCHAR Error:1; + UCHAR Request:1; + UCHAR DL:1; + UCHAR Rsvd:3; + UCHAR KeyDescVer:3; + UCHAR KeyType:1; + UCHAR KeyIndex:2; + UCHAR Install:1; + UCHAR KeyAck:1; +#endif +} KEY_INFO, *PKEY_INFO; + +// EAPOL Key descriptor format +typedef struct PACKED _KEY_DESCRIPTER +{ + UCHAR Type; + KEY_INFO KeyInfo; + UCHAR KeyLength[2]; + UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; + UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; + UCHAR KeyIv[LEN_KEY_DESC_IV]; + UCHAR KeyRsc[LEN_KEY_DESC_RSC]; + UCHAR KeyId[LEN_KEY_DESC_ID]; + UCHAR KeyMic[LEN_KEY_DESC_MIC]; + UCHAR KeyDataLen[2]; + UCHAR KeyData[MAX_LEN_OF_RSNIE]; +} KEY_DESCRIPTER, *PKEY_DESCRIPTER; + +typedef struct PACKED _EAPOL_PACKET +{ + UCHAR Version; + UCHAR Type; + UCHAR Len[2]; + KEY_DESCRIPTER KeyDesc; +} EAPOL_PACKET, *PEAPOL_PACKET; + +// For supplicant state machine states. 802.11i Draft 4.1, p. 97 +// We simplified it +typedef enum _WpaState +{ + SS_NOTUSE, // 0 + SS_START, // 1 + SS_WAIT_MSG_3, // 2 + SS_WAIT_GROUP, // 3 + SS_FINISH, // 4 + SS_KEYUPDATE, // 5 +} WPA_STATE; + +#endif