| /* |
| ************************************************************************* |
| * Ralink Tech Inc. |
| * 5F., No.36, Taiyuan St., Jhubei City, |
| * Hsinchu County 302, |
| * Taiwan, R.O.C. |
| * |
| * (c) Copyright 2002-2007, Ralink Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 2 of the License, or * |
| * (at your option) any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the * |
| * Free Software Foundation, Inc., * |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| * * |
| ************************************************************************* |
| |
| Module Name: |
| sanity.c |
| |
| Abstract: |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| John Chang 2004-09-01 add WMM support |
| */ |
| #include "../rt_config.h" |
| |
| extern u8 CISCO_OUI[]; |
| |
| extern u8 WPA_OUI[]; |
| extern u8 RSN_OUI[]; |
| extern u8 WME_INFO_ELEM[]; |
| extern u8 WME_PARM_ELEM[]; |
| extern u8 Ccx2QosInfo[]; |
| extern u8 RALINK_OUI[]; |
| extern u8 BROADCOM_OUI[]; |
| extern u8 WPS_OUI[]; |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN MlmeAddBAReqSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, unsigned long MsgLen, u8 *pAddr2) |
| { |
| struct rt_mlme_addba_req *pInfo; |
| |
| pInfo = (struct rt_mlme_addba_req *)Msg; |
| |
| if ((MsgLen != sizeof(struct rt_mlme_addba_req))) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); |
| return FALSE; |
| } |
| |
| if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); |
| return FALSE; |
| } |
| |
| if ((pInfo->pAddr[0] & 0x01) == 0x01) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN MlmeDelBAReqSanity(struct rt_rtmp_adapter *pAd, void * Msg, unsigned long MsgLen) |
| { |
| struct rt_mlme_delba_req *pInfo; |
| pInfo = (struct rt_mlme_delba_req *)Msg; |
| |
| if ((MsgLen != sizeof(struct rt_mlme_delba_req))) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); |
| return FALSE; |
| } |
| |
| if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); |
| return FALSE; |
| } |
| |
| if ((pInfo->TID & 0xf0)) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); |
| return FALSE; |
| } |
| |
| if (NdisEqualMemory |
| (pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, |
| MAC_ADDR_LEN) == 0) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| BOOLEAN PeerAddBAReqActionSanity(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, u8 *pAddr2) |
| { |
| struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) pMsg; |
| struct rt_frame_addba_req * pAddFrame; |
| pAddFrame = (struct rt_frame_addba_req *) (pMsg); |
| if (MsgLen < (sizeof(struct rt_frame_addba_req))) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", |
| MsgLen)); |
| return FALSE; |
| } |
| /* we support immediate BA. */ |
| *(u16 *) (&pAddFrame->BaParm) = |
| cpu2le16(*(u16 *) (&pAddFrame->BaParm)); |
| pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); |
| pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); |
| |
| if (pAddFrame->BaParm.BAPolicy != IMMED_BA) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", |
| pAddFrame->BaParm.BAPolicy)); |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", |
| pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, |
| pAddFrame->BaParm.AMSDUSupported)); |
| return FALSE; |
| } |
| /* we support immediate BA. */ |
| if (pAddFrame->BaParm.TID & 0xfff0) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", |
| pAddFrame->BaParm.TID)); |
| return FALSE; |
| } |
| COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); |
| return TRUE; |
| } |
| |
| BOOLEAN PeerAddBARspActionSanity(struct rt_rtmp_adapter *pAd, |
| void * pMsg, unsigned long MsgLen) |
| { |
| struct rt_frame_addba_rsp * pAddFrame; |
| |
| pAddFrame = (struct rt_frame_addba_rsp *) (pMsg); |
| if (MsgLen < (sizeof(struct rt_frame_addba_rsp))) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", |
| MsgLen)); |
| return FALSE; |
| } |
| /* we support immediate BA. */ |
| *(u16 *) (&pAddFrame->BaParm) = |
| cpu2le16(*(u16 *) (&pAddFrame->BaParm)); |
| pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); |
| pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); |
| |
| if (pAddFrame->BaParm.BAPolicy != IMMED_BA) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", |
| pAddFrame->BaParm.BAPolicy)); |
| return FALSE; |
| } |
| /* we support immediate BA. */ |
| if (pAddFrame->BaParm.TID & 0xfff0) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", |
| pAddFrame->BaParm.TID)); |
| return FALSE; |
| } |
| return TRUE; |
| |
| } |
| |
| BOOLEAN PeerDelBAActionSanity(struct rt_rtmp_adapter *pAd, |
| u8 Wcid, void * pMsg, unsigned long MsgLen) |
| { |
| /*struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *)pMsg; */ |
| struct rt_frame_delba_req * pDelFrame; |
| if (MsgLen != (sizeof(struct rt_frame_delba_req))) |
| return FALSE; |
| |
| if (Wcid >= MAX_LEN_OF_MAC_TABLE) |
| return FALSE; |
| |
| pDelFrame = (struct rt_frame_delba_req *) (pMsg); |
| |
| *(u16 *) (&pDelFrame->DelbaParm) = |
| cpu2le16(*(u16 *) (&pDelFrame->DelbaParm)); |
| pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); |
| |
| if (pDelFrame->DelbaParm.TID & 0xfff0) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN PeerBeaconAndProbeRspSanity(struct rt_rtmp_adapter *pAd, void * Msg, unsigned long MsgLen, u8 MsgChannel, u8 *pAddr2, u8 *pBssid, char Ssid[], u8 * pSsidLen, u8 * pBssType, u16 * pBeaconPeriod, u8 * pChannel, u8 * pNewChannel, OUT LARGE_INTEGER * pTimestamp, struct rt_cf_parm * pCfParm, u16 * pAtimWin, u16 * pCapabilityInfo, u8 * pErp, u8 * pDtimCount, u8 * pDtimPeriod, u8 * pBcastFlag, u8 * pMessageToMe, u8 SupRate[], u8 * pSupRateLen, u8 ExtRate[], u8 * pExtRateLen, u8 * pCkipFlag, u8 * pAironetCellPowerLimit, struct rt_edca_parm *pEdcaParm, struct rt_qbss_load_parm *pQbssLoad, struct rt_qos_capability_parm *pQosCapability, unsigned long * pRalinkIe, u8 * pHtCapabilityLen, u8 * pPreNHtCapabilityLen, struct rt_ht_capability_ie * pHtCapability, u8 * AddHtInfoLen, struct rt_add_ht_info_ie * AddHtInfo, u8 * NewExtChannelOffset, /* Ht extension channel offset(above or below) */ |
| u16 * LengthVIE, |
| struct rt_ndis_802_11_variable_ies *pVIE) |
| { |
| u8 *Ptr; |
| u8 TimLen; |
| struct rt_frame_802_11 * pFrame; |
| struct rt_eid * pEid; |
| u8 SubType; |
| u8 Sanity; |
| /*u8 ECWMin, ECWMax; */ |
| /*MAC_CSR9_STRUC Csr9; */ |
| unsigned long Length = 0; |
| |
| /* For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel */ |
| /* 1. If the AP is 11n enabled, then check the control channel. */ |
| /* 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!) */ |
| u8 CtrlChannel = 0; |
| |
| /* Add for 3 necessary EID field check */ |
| Sanity = 0; |
| |
| *pAtimWin = 0; |
| *pErp = 0; |
| *pDtimCount = 0; |
| *pDtimPeriod = 0; |
| *pBcastFlag = 0; |
| *pMessageToMe = 0; |
| *pExtRateLen = 0; |
| *pCkipFlag = 0; /* Default of CkipFlag is 0 */ |
| *pAironetCellPowerLimit = 0xFF; /* Default of AironetCellPowerLimit is 0xFF */ |
| *LengthVIE = 0; /* Set the length of VIE to init value 0 */ |
| *pHtCapabilityLen = 0; /* Set the length of VIE to init value 0 */ |
| if (pAd->OpMode == OPMODE_STA) |
| *pPreNHtCapabilityLen = 0; /* Set the length of VIE to init value 0 */ |
| *AddHtInfoLen = 0; /* Set the length of VIE to init value 0 */ |
| *pRalinkIe = 0; |
| *pNewChannel = 0; |
| *NewExtChannelOffset = 0xff; /*Default 0xff means no such IE */ |
| pCfParm->bValid = FALSE; /* default: no IE_CF found */ |
| pQbssLoad->bValid = FALSE; /* default: no IE_QBSS_LOAD found */ |
| pEdcaParm->bValid = FALSE; /* default: no IE_EDCA_PARAMETER found */ |
| pQosCapability->bValid = FALSE; /* default: no IE_QOS_CAPABILITY found */ |
| |
| pFrame = (struct rt_frame_802_11 *) Msg; |
| |
| /* get subtype from header */ |
| SubType = (u8)pFrame->Hdr.FC.SubType; |
| |
| /* get Addr2 and BSSID from header */ |
| COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); |
| COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); |
| |
| Ptr = pFrame->Octet; |
| Length += LENGTH_802_11; |
| |
| /* get timestamp from payload and advance the pointer */ |
| NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); |
| |
| pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); |
| pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); |
| |
| Ptr += TIMESTAMP_LEN; |
| Length += TIMESTAMP_LEN; |
| |
| /* get beacon interval from payload and advance the pointer */ |
| NdisMoveMemory(pBeaconPeriod, Ptr, 2); |
| Ptr += 2; |
| Length += 2; |
| |
| /* get capability info from payload and advance the pointer */ |
| NdisMoveMemory(pCapabilityInfo, Ptr, 2); |
| Ptr += 2; |
| Length += 2; |
| |
| if (CAP_IS_ESS_ON(*pCapabilityInfo)) |
| *pBssType = BSS_INFRA; |
| else |
| *pBssType = BSS_ADHOC; |
| |
| pEid = (struct rt_eid *) Ptr; |
| |
| /* get variable fields from payload and advance the pointer */ |
| while ((Length + 2 + pEid->Len) <= MsgLen) { |
| /* */ |
| /* Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. */ |
| /* */ |
| if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", |
| (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); |
| break; |
| } |
| |
| switch (pEid->Eid) { |
| case IE_SSID: |
| /* Already has one SSID EID in this beacon, ignore the second one */ |
| if (Sanity & 0x1) |
| break; |
| if (pEid->Len <= MAX_LEN_OF_SSID) { |
| NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); |
| *pSsidLen = pEid->Len; |
| Sanity |= 0x1; |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n", |
| pEid->Len)); |
| return FALSE; |
| } |
| break; |
| |
| case IE_SUPP_RATES: |
| if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) { |
| Sanity |= 0x2; |
| NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); |
| *pSupRateLen = pEid->Len; |
| |
| /* TODO: 2004-09-14 not a good design here, cause it exclude extra rates */ |
| /* from ScanTab. We should report as is. And filter out unsupported */ |
| /* rates in MlmeAux. */ |
| /* Check against the supported rates */ |
| /* RTMPCheckRates(pAd, SupRate, pSupRateLen); */ |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n", |
| pEid->Len)); |
| return FALSE; |
| } |
| break; |
| |
| case IE_HT_CAP: |
| if (pEid->Len >= SIZE_HT_CAP_IE) /*Note: allow extension! */ |
| { |
| NdisMoveMemory(pHtCapability, pEid->Octet, |
| sizeof(struct rt_ht_capability_ie)); |
| *pHtCapabilityLen = SIZE_HT_CAP_IE; /* Nnow we only support 26 bytes. */ |
| |
| *(u16 *) (&pHtCapability->HtCapInfo) = |
| cpu2le16(*(u16 *) |
| (&pHtCapability->HtCapInfo)); |
| *(u16 *) (&pHtCapability->ExtHtCapInfo) = |
| cpu2le16(*(u16 *) |
| (&pHtCapability->ExtHtCapInfo)); |
| |
| { |
| *pPreNHtCapabilityLen = 0; /* Nnow we only support 26 bytes. */ |
| |
| Ptr = (u8 *)pVIE; |
| NdisMoveMemory(Ptr + *LengthVIE, |
| &pEid->Eid, |
| pEid->Len + 2); |
| *LengthVIE += (pEid->Len + 2); |
| } |
| } else { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", |
| pEid->Len)); |
| } |
| |
| break; |
| case IE_ADD_HT: |
| if (pEid->Len >= sizeof(struct rt_add_ht_info_ie)) { |
| /* This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only */ |
| /* copy first sizeof(struct rt_add_ht_info_ie) */ |
| NdisMoveMemory(AddHtInfo, pEid->Octet, |
| sizeof(struct rt_add_ht_info_ie)); |
| *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; |
| |
| CtrlChannel = AddHtInfo->ControlChan; |
| |
| *(u16 *) (&AddHtInfo->AddHtInfo2) = |
| cpu2le16(*(u16 *) |
| (&AddHtInfo->AddHtInfo2)); |
| *(u16 *) (&AddHtInfo->AddHtInfo3) = |
| cpu2le16(*(u16 *) |
| (&AddHtInfo->AddHtInfo3)); |
| |
| { |
| Ptr = (u8 *)pVIE; |
| NdisMoveMemory(Ptr + *LengthVIE, |
| &pEid->Eid, |
| pEid->Len + 2); |
| *LengthVIE += (pEid->Len + 2); |
| } |
| } else { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); |
| } |
| |
| break; |
| case IE_SECONDARY_CH_OFFSET: |
| if (pEid->Len == 1) { |
| *NewExtChannelOffset = pEid->Octet[0]; |
| } else { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); |
| } |
| |
| break; |
| case IE_FH_PARM: |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); |
| break; |
| |
| case IE_DS_PARM: |
| if (pEid->Len == 1) { |
| *pChannel = *pEid->Octet; |
| |
| { |
| if (ChannelSanity(pAd, *pChannel) == 0) { |
| |
| return FALSE; |
| } |
| } |
| |
| Sanity |= 0x4; |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n", |
| pEid->Len)); |
| return FALSE; |
| } |
| break; |
| |
| case IE_CF_PARM: |
| if (pEid->Len == 6) { |
| pCfParm->bValid = TRUE; |
| pCfParm->CfpCount = pEid->Octet[0]; |
| pCfParm->CfpPeriod = pEid->Octet[1]; |
| pCfParm->CfpMaxDuration = |
| pEid->Octet[2] + 256 * pEid->Octet[3]; |
| pCfParm->CfpDurRemaining = |
| pEid->Octet[4] + 256 * pEid->Octet[5]; |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); |
| return FALSE; |
| } |
| break; |
| |
| case IE_IBSS_PARM: |
| if (pEid->Len == 2) { |
| NdisMoveMemory(pAtimWin, pEid->Octet, |
| pEid->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((char *)pEid, pAd->StaActive.Aid, |
| &TimLen, pBcastFlag, pDtimCount, |
| pDtimPeriod, pMessageToMe); |
| } |
| break; |
| case IE_CHANNEL_SWITCH_ANNOUNCEMENT: |
| if (pEid->Len == 3) { |
| *pNewChannel = pEid->Octet[1]; /*extract new channel number */ |
| } |
| break; |
| |
| /* New for WPA */ |
| /* CCX v2 has the same IE, we need to parse that too */ |
| /* Wifi WMM use the same IE vale, need to parse that too */ |
| /* case IE_WPA: */ |
| case IE_VENDOR_SPECIFIC: |
| /* Check Broadcom/Atheros 802.11n OUI version, for HT Capability IE. */ |
| /* This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. */ |
| /*if (NdisEqualMemory(pEid->Octet, BROADCOM_OUI, 3) && (pEid->Len >= 4)) |
| { |
| if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 30)) |
| { |
| { |
| NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(struct rt_ht_capability_ie)); |
| *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. |
| } |
| } |
| if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 26)) |
| { |
| { |
| NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(struct rt_add_ht_info_ie)); |
| *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; // Nnow we only support 26 bytes. |
| } |
| } |
| } |
| */ |
| /* Check the OUI version, filter out non-standard usage */ |
| if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) |
| && (pEid->Len == 7)) { |
| /**pRalinkIe = pEid->Octet[3]; */ |
| if (pEid->Octet[3] != 0) |
| *pRalinkIe = pEid->Octet[3]; |
| else |
| *pRalinkIe = 0xf0000000; /* Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. */ |
| } |
| /* This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. */ |
| |
| /* Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, */ |
| /* Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE */ |
| else if ((*pHtCapabilityLen == 0) |
| && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, |
| 3) && (pEid->Len >= 4) |
| && (pAd->OpMode == OPMODE_STA)) { |
| if ((pEid->Octet[3] == OUI_PREN_HT_CAP) |
| && (pEid->Len >= 30) |
| && (*pHtCapabilityLen == 0)) { |
| NdisMoveMemory(pHtCapability, |
| &pEid->Octet[4], |
| sizeof |
| (struct rt_ht_capability_ie)); |
| *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; |
| } |
| |
| if ((pEid->Octet[3] == OUI_PREN_ADD_HT) |
| && (pEid->Len >= 26)) { |
| NdisMoveMemory(AddHtInfo, |
| &pEid->Octet[4], |
| sizeof(struct rt_add_ht_info_ie)); |
| *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; |
| } |
| } else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) { |
| /* Copy to pVIE which will report to microsoft bssid list. */ |
| Ptr = (u8 *)pVIE; |
| NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, |
| pEid->Len + 2); |
| *LengthVIE += (pEid->Len + 2); |
| } else |
| if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) |
| && (pEid->Len == 24)) { |
| u8 *ptr; |
| int i; |
| |
| /* parsing EDCA parameters */ |
| pEdcaParm->bValid = TRUE; |
| pEdcaParm->bQAck = FALSE; /* pEid->Octet[0] & 0x10; */ |
| pEdcaParm->bQueueRequest = FALSE; /* pEid->Octet[0] & 0x20; */ |
| pEdcaParm->bTxopRequest = FALSE; /* pEid->Octet[0] & 0x40; */ |
| pEdcaParm->EdcaUpdateCount = |
| pEid->Octet[6] & 0x0f; |
| pEdcaParm->bAPSDCapable = |
| (pEid->Octet[6] & 0x80) ? 1 : 0; |
| ptr = &pEid->Octet[8]; |
| for (i = 0; i < 4; i++) { |
| u8 aci = (*ptr & 0x60) >> 5; /* b5~6 is AC INDEX */ |
| pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); /* b5 is ACM */ |
| pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; /* b0~3 is AIFSN */ |
| pEdcaParm->Cwmin[aci] = *(ptr + 1) & 0x0f; /* b0~4 is Cwmin */ |
| pEdcaParm->Cwmax[aci] = *(ptr + 1) >> 4; /* b5~8 is Cwmax */ |
| pEdcaParm->Txop[aci] = *(ptr + 2) + 256 * (*(ptr + 3)); /* in unit of 32-us */ |
| ptr += 4; /* point to next AC */ |
| } |
| } else |
| if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) |
| && (pEid->Len == 7)) { |
| /* parsing EDCA parameters */ |
| pEdcaParm->bValid = TRUE; |
| pEdcaParm->bQAck = FALSE; /* pEid->Octet[0] & 0x10; */ |
| pEdcaParm->bQueueRequest = FALSE; /* pEid->Octet[0] & 0x20; */ |
| pEdcaParm->bTxopRequest = FALSE; /* pEid->Octet[0] & 0x40; */ |
| pEdcaParm->EdcaUpdateCount = |
| pEid->Octet[6] & 0x0f; |
| pEdcaParm->bAPSDCapable = |
| (pEid->Octet[6] & 0x80) ? 1 : 0; |
| |
| /* use default EDCA parameter */ |
| pEdcaParm->bACM[QID_AC_BE] = 0; |
| pEdcaParm->Aifsn[QID_AC_BE] = 3; |
| pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; |
| pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; |
| pEdcaParm->Txop[QID_AC_BE] = 0; |
| |
| pEdcaParm->bACM[QID_AC_BK] = 0; |
| pEdcaParm->Aifsn[QID_AC_BK] = 7; |
| pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; |
| pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; |
| pEdcaParm->Txop[QID_AC_BK] = 0; |
| |
| pEdcaParm->bACM[QID_AC_VI] = 0; |
| pEdcaParm->Aifsn[QID_AC_VI] = 2; |
| pEdcaParm->Cwmin[QID_AC_VI] = |
| CW_MIN_IN_BITS - 1; |
| pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; |
| pEdcaParm->Txop[QID_AC_VI] = 96; /* AC_VI: 96*32us ~= 3ms */ |
| |
| pEdcaParm->bACM[QID_AC_VO] = 0; |
| pEdcaParm->Aifsn[QID_AC_VO] = 2; |
| pEdcaParm->Cwmin[QID_AC_VO] = |
| CW_MIN_IN_BITS - 2; |
| pEdcaParm->Cwmax[QID_AC_VO] = |
| CW_MAX_IN_BITS - 1; |
| pEdcaParm->Txop[QID_AC_VO] = 48; /* AC_VO: 48*32us ~= 1.5ms */ |
| } |
| |
| break; |
| |
| case IE_EXT_SUPP_RATES: |
| if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) { |
| NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); |
| *pExtRateLen = pEid->Len; |
| |
| /* TODO: 2004-09-14 not a good design here, cause it exclude extra rates */ |
| /* from ScanTab. We should report as is. And filter out unsupported */ |
| /* rates in MlmeAux. */ |
| /* Check against the supported rates */ |
| /* RTMPCheckRates(pAd, ExtRate, pExtRateLen); */ |
| } |
| break; |
| |
| case IE_ERP: |
| if (pEid->Len == 1) { |
| *pErp = (u8)pEid->Octet[0]; |
| } |
| break; |
| |
| case IE_AIRONET_CKIP: |
| /* 0. Check Aironet IE length, it must be larger or equal to 28 */ |
| /* Cisco AP350 used length as 28 */ |
| /* Cisco AP12XX used length as 30 */ |
| if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) |
| break; |
| |
| /* 1. Copy CKIP flag byte to buffer for process */ |
| *pCkipFlag = *(pEid->Octet + 8); |
| break; |
| |
| case IE_AP_TX_POWER: |
| /* AP Control of Client Transmit Power */ |
| /*0. Check Aironet IE length, it must be 6 */ |
| if (pEid->Len != 0x06) |
| break; |
| |
| /* Get cell power limit in dBm */ |
| if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) |
| *pAironetCellPowerLimit = *(pEid->Octet + 4); |
| break; |
| |
| /* WPA2 & 802.11i RSN */ |
| case IE_RSN: |
| /* There is no OUI for version anymore, check the group cipher OUI before copying */ |
| if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) { |
| /* Copy to pVIE which will report to microsoft bssid list. */ |
| Ptr = (u8 *)pVIE; |
| NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, |
| pEid->Len + 2); |
| *LengthVIE += (pEid->Len + 2); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| Length = Length + 2 + pEid->Len; /* Eid[1] + Len[1]+ content[Len] */ |
| pEid = (struct rt_eid *) ((u8 *) pEid + 2 + pEid->Len); |
| } |
| |
| /* For some 11a AP. it did not have the channel EID, patch here */ |
| { |
| u8 LatchRfChannel = MsgChannel; |
| if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) { |
| if (CtrlChannel != 0) |
| *pChannel = CtrlChannel; |
| else |
| *pChannel = LatchRfChannel; |
| Sanity |= 0x4; |
| } |
| } |
| |
| if (Sanity != 0x7) { |
| DBGPRINT(RT_DEBUG_LOUD, |
| ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", |
| Sanity)); |
| return FALSE; |
| } else { |
| return TRUE; |
| } |
| |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| ========================================================================== |
| */ |
| BOOLEAN MlmeScanReqSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 * pBssType, |
| char Ssid[], |
| u8 * pSsidLen, u8 * pScanType) |
| { |
| struct rt_mlme_scan_req *Info; |
| |
| Info = (struct rt_mlme_scan_req *)(Msg); |
| *pBssType = Info->BssType; |
| *pSsidLen = Info->SsidLen; |
| NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); |
| *pScanType = Info->ScanType; |
| |
| if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC |
| || *pBssType == BSS_ANY) |
| && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE)) { |
| return TRUE; |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); |
| return FALSE; |
| } |
| } |
| |
| /* IRQL = DISPATCH_LEVEL */ |
| u8 ChannelSanity(struct rt_rtmp_adapter *pAd, u8 channel) |
| { |
| int i; |
| |
| for (i = 0; i < pAd->ChannelListNum; i++) { |
| if (channel == pAd->ChannelList[i].Channel) |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN PeerDeauthSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 *pAddr2, u16 * pReason) |
| { |
| struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg; |
| |
| COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); |
| NdisMoveMemory(pReason, &pFrame->Octet[0], 2); |
| |
| return TRUE; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN PeerAuthSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 *pAddr, |
| u16 * pAlg, |
| u16 * pSeq, |
| u16 * pStatus, char * pChlgText) |
| { |
| struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg; |
| |
| COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); |
| NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); |
| NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); |
| NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); |
| |
| if (*pAlg == AUTH_MODE_OPEN) { |
| if (*pSeq == 1 || *pSeq == 2) { |
| return TRUE; |
| } else { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("PeerAuthSanity fail - wrong Seg#\n")); |
| return FALSE; |
| } |
| } else if (*pAlg == AUTH_MODE_KEY) { |
| if (*pSeq == 1 || *pSeq == 4) { |
| return TRUE; |
| } else if (*pSeq == 2 || *pSeq == 3) { |
| NdisMoveMemory(pChlgText, &pFrame->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 MlmeAuthReqSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 *pAddr, |
| unsigned long * pTimeout, u16 * pAlg) |
| { |
| struct rt_mlme_auth_req *pInfo; |
| |
| pInfo = (struct rt_mlme_auth_req *)Msg; |
| COPY_MAC_ADDR(pAddr, pInfo->Addr); |
| *pTimeout = pInfo->Timeout; |
| *pAlg = pInfo->Alg; |
| |
| if (((*pAlg == AUTH_MODE_KEY) || (*pAlg == AUTH_MODE_OPEN) |
| ) && ((*pAddr & 0x01) == 0)) { |
| 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 |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN MlmeAssocReqSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 *pApAddr, |
| u16 * pCapabilityInfo, |
| unsigned long * pTimeout, u16 * pListenIntv) |
| { |
| struct rt_mlme_assoc_req *pInfo; |
| |
| pInfo = (struct rt_mlme_assoc_req *)Msg; |
| *pTimeout = pInfo->Timeout; /* timeout */ |
| COPY_MAC_ADDR(pApAddr, pInfo->Addr); /* AP address */ |
| *pCapabilityInfo = pInfo->CapabilityInfo; /* capability info */ |
| *pListenIntv = pInfo->ListenIntv; |
| |
| return TRUE; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| MLME message sanity check |
| Return: |
| TRUE if all parameters are OK, FALSE otherwise |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| BOOLEAN PeerDisassocSanity(struct rt_rtmp_adapter *pAd, |
| void * Msg, |
| unsigned long MsgLen, |
| u8 *pAddr2, u16 * pReason) |
| { |
| struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg; |
| |
| COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); |
| NdisMoveMemory(pReason, &pFrame->Octet[0], 2); |
| |
| return TRUE; |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Sanity check NetworkType (11b, 11g or 11a) |
| |
| Arguments: |
| pBss - Pointer to BSS table. |
| |
| Return Value: |
| Ndis802_11DS .......(11b) |
| Ndis802_11OFDM24....(11g) |
| Ndis802_11OFDM5.....(11a) |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity(struct rt_bss_entry *pBss) |
| { |
| NDIS_802_11_NETWORK_TYPE NetWorkType; |
| u8 rate, i; |
| |
| NetWorkType = Ndis802_11DS; |
| |
| if (pBss->Channel <= 14) { |
| /* */ |
| /* First check support Rate. */ |
| /* */ |
| for (i = 0; i < pBss->SupRateLen; i++) { |
| rate = pBss->SupRate[i] & 0x7f; /* Mask out basic rate set bit */ |
| if ((rate == 2) || (rate == 4) || (rate == 11) |
| || (rate == 22)) { |
| continue; |
| } else { |
| /* */ |
| /* Otherwise (even rate > 108) means Ndis802_11OFDM24 */ |
| /* */ |
| NetWorkType = Ndis802_11OFDM24; |
| break; |
| } |
| } |
| |
| /* */ |
| /* Second check Extend Rate. */ |
| /* */ |
| if (NetWorkType != Ndis802_11OFDM24) { |
| for (i = 0; i < pBss->ExtRateLen; i++) { |
| rate = pBss->SupRate[i] & 0x7f; /* Mask out basic rate set bit */ |
| if ((rate == 2) || (rate == 4) || (rate == 11) |
| || (rate == 22)) { |
| continue; |
| } else { |
| /* */ |
| /* Otherwise (even rate > 108) means Ndis802_11OFDM24 */ |
| /* */ |
| NetWorkType = Ndis802_11OFDM24; |
| break; |
| } |
| } |
| } |
| } else { |
| NetWorkType = Ndis802_11OFDM5; |
| } |
| |
| if (pBss->HtCapabilityLen != 0) { |
| if (NetWorkType == Ndis802_11OFDM5) |
| NetWorkType = Ndis802_11OFDM5_N; |
| else |
| NetWorkType = Ndis802_11OFDM24_N; |
| } |
| |
| return NetWorkType; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Check the validity of the received EAPoL frame |
| Return: |
| TRUE if all parameters are OK, |
| FALSE otherwise |
| ========================================================================== |
| */ |
| BOOLEAN PeerWpaMessageSanity(struct rt_rtmp_adapter *pAd, |
| struct rt_eapol_packet * pMsg, |
| unsigned long MsgLen, |
| u8 MsgType, struct rt_mac_table_entry *pEntry) |
| { |
| u8 mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; |
| BOOLEAN bReplayDiff = FALSE; |
| BOOLEAN bWPA2 = FALSE; |
| struct rt_key_info EapolKeyInfo; |
| u8 GroupKeyIndex = 0; |
| |
| NdisZeroMemory(mic, sizeof(mic)); |
| NdisZeroMemory(digest, sizeof(digest)); |
| NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); |
| NdisZeroMemory((u8 *)& EapolKeyInfo, sizeof(EapolKeyInfo)); |
| |
| NdisMoveMemory((u8 *)& EapolKeyInfo, |
| (u8 *)& pMsg->KeyDesc.KeyInfo, sizeof(struct rt_key_info)); |
| |
| *((u16 *) & EapolKeyInfo) = cpu2le16(*((u16 *) & EapolKeyInfo)); |
| |
| /* Choose WPA2 or not */ |
| if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) |
| || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) |
| bWPA2 = TRUE; |
| |
| /* 0. Check MsgType */ |
| if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("The message type is invalid(%d)! \n", MsgType)); |
| return FALSE; |
| } |
| /* 1. Replay counter check */ |
| if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) /* For supplicant */ |
| { |
| /* First validate replay counter, only accept message with larger replay counter. */ |
| /* Let equal pass, some AP start with all zero replay counter */ |
| u8 ZeroReplay[LEN_KEY_DESC_REPLAY]; |
| |
| NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); |
| if ((RTMPCompareMemory |
| (pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, |
| LEN_KEY_DESC_REPLAY) != 1) |
| && |
| (RTMPCompareMemory |
| (pMsg->KeyDesc.ReplayCounter, ZeroReplay, |
| LEN_KEY_DESC_REPLAY) != 0)) { |
| bReplayDiff = TRUE; |
| } |
| } else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) /* For authenticator */ |
| { |
| /* check Replay Counter coresponds to MSG from authenticator, otherwise discard */ |
| if (!NdisEqualMemory |
| (pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, |
| LEN_KEY_DESC_REPLAY)) { |
| bReplayDiff = TRUE; |
| } |
| } |
| /* Replay Counter different condition */ |
| if (bReplayDiff) { |
| /* send wireless event - for replay counter different */ |
| if (pAd->CommonCfg.bWirelessEvent) |
| RTMPSendWirelessEvent(pAd, |
| IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, |
| pEntry->Addr, pEntry->apidx, 0); |
| |
| if (MsgType < EAPOL_GROUP_MSG_1) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", |
| MsgType)); |
| } else { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Replay Counter Different in group msg %d of 2-way handshake!\n", |
| (MsgType - EAPOL_PAIR_MSG_4))); |
| } |
| |
| hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, |
| LEN_KEY_DESC_REPLAY); |
| hex_dump("Current replay counter ", pEntry->R_Counter, |
| LEN_KEY_DESC_REPLAY); |
| return FALSE; |
| } |
| /* 2. Verify MIC except Pairwise Msg1 */ |
| if (MsgType != EAPOL_PAIR_MSG_1) { |
| u8 rcvd_mic[LEN_KEY_DESC_MIC]; |
| |
| /* Record the received MIC for check later */ |
| NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, |
| LEN_KEY_DESC_MIC); |
| NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); |
| |
| if (EapolKeyInfo.KeyDescVer == DESC_TYPE_TKIP) /* TKIP */ |
| { |
| HMAC_MD5(pEntry->PTK, LEN_EAP_MICK, (u8 *)pMsg, |
| MsgLen, mic, MD5_DIGEST_SIZE); |
| } else if (EapolKeyInfo.KeyDescVer == DESC_TYPE_AES) /* AES */ |
| { |
| HMAC_SHA1(pEntry->PTK, LEN_EAP_MICK, (u8 *)pMsg, |
| MsgLen, digest, SHA1_DIGEST_SIZE); |
| NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); |
| } |
| |
| if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) { |
| /* send wireless event - for MIC different */ |
| if (pAd->CommonCfg.bWirelessEvent) |
| RTMPSendWirelessEvent(pAd, |
| IW_MIC_DIFF_EVENT_FLAG, |
| pEntry->Addr, |
| pEntry->apidx, 0); |
| |
| if (MsgType < EAPOL_GROUP_MSG_1) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MIC Different in pairwise msg %d of 4-way handshake!\n", |
| MsgType)); |
| } else { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MIC Different in group msg %d of 2-way handshake!\n", |
| (MsgType - EAPOL_PAIR_MSG_4))); |
| } |
| |
| hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); |
| hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); |
| |
| return FALSE; |
| } |
| } |
| /* 1. Decrypt the Key Data field if GTK is included. */ |
| /* 2. Extract the context of the Key Data field if it exist. */ |
| /* The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is clear. */ |
| /* The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. */ |
| if (CONV_ARRARY_TO_u16(pMsg->KeyDesc.KeyDataLen) > 0) { |
| /* Decrypt this field */ |
| if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) |
| || (MsgType == EAPOL_GROUP_MSG_1)) { |
| if ((EapolKeyInfo.KeyDescVer == DESC_TYPE_AES)) { |
| /* AES */ |
| AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, |
| CONV_ARRARY_TO_u16(pMsg-> |
| KeyDesc. |
| KeyDataLen), |
| pMsg->KeyDesc.KeyData); |
| } else { |
| int i; |
| u8 Key[32]; |
| /* Decrypt TKIP GTK */ |
| /* Construct 32 bytes RC4 Key */ |
| NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); |
| NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); |
| ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, |
| 32); |
| /*discard first 256 bytes */ |
| for (i = 0; i < 256; i++) |
| ARCFOUR_BYTE(&pAd->PrivateInfo. |
| WEPCONTEXT); |
| /* Decrypt GTK. Becareful, there is no ICV to check the result is correct or not */ |
| ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, |
| KEYDATA, pMsg->KeyDesc.KeyData, |
| CONV_ARRARY_TO_u16(pMsg-> |
| KeyDesc. |
| KeyDataLen)); |
| } |
| |
| if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) |
| GroupKeyIndex = EapolKeyInfo.KeyIndex; |
| |
| } else if ((MsgType == EAPOL_PAIR_MSG_2) |
| || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) { |
| NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, |
| CONV_ARRARY_TO_u16(pMsg->KeyDesc. |
| KeyDataLen)); |
| } else { |
| |
| return TRUE; |
| } |
| |
| /* Parse Key Data field to */ |
| /* 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) */ |
| /* 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 */ |
| /* 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) */ |
| if (!RTMPParseEapolKeyData(pAd, KEYDATA, |
| CONV_ARRARY_TO_u16(pMsg->KeyDesc. |
| KeyDataLen), |
| GroupKeyIndex, MsgType, bWPA2, |
| pEntry)) { |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| |
| } |