1418 lines
40 KiB
C
1418 lines
40 KiB
C
/*
|
|
***************************************************************************
|
|
* Ralink Tech Inc.
|
|
* 4F, No. 2 Technology 5th Rd.
|
|
* Science-based Industrial Park
|
|
* Hsin-chu, Taiwan, R.O.C.
|
|
*
|
|
* (c) Copyright 2002-2006, Ralink Technology, Inc.
|
|
*
|
|
* All rights reserved. Ralink's source code is an unpublished work and the
|
|
* use of a copyright notice does not imply otherwise. This source code
|
|
* contains confidential trade secret material of Ralink Tech. Any attemp
|
|
* or participation in deciphering, decoding, reverse engineering or in any
|
|
* way altering the source code is stricitly prohibited, unless the prior
|
|
* written consent of Ralink Technology, Inc. is obtained.
|
|
***************************************************************************
|
|
|
|
Module Name:
|
|
mesh_link_mng.c
|
|
|
|
Abstract:
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- ---------- ----------------------------------------------
|
|
Fonchi 2007-07-23 For mesh (802.11s) support.
|
|
*/
|
|
#ifdef MESH_SUPPORT
|
|
|
|
|
|
#include "rt_config.h"
|
|
#include "mesh_def.h"
|
|
#include "mesh_sanity.h"
|
|
|
|
BOOLEAN MeshPeerBeaconAndProbeSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *Msg,
|
|
IN ULONG MsgLen,
|
|
OUT PUCHAR pHostName,
|
|
OUT PUCHAR pHostNameLen,
|
|
OUT PUCHAR pMeshId,
|
|
OUT PUCHAR pMeshIdLen,
|
|
OUT PMESH_CONFIGURAION_IE pMeshConfiguration)
|
|
{
|
|
CHAR *Ptr;
|
|
PFRAME_802_11 pFrame;
|
|
PEID_STRUCT pEid;
|
|
UCHAR SubType;
|
|
ULONG Length = 0;
|
|
|
|
pFrame = (PFRAME_802_11)Msg;
|
|
|
|
/* get subtype from header */
|
|
SubType = (UCHAR)pFrame->Hdr.FC.SubType;
|
|
|
|
/*hex_dump("Beacon", Msg, MsgLen); */
|
|
|
|
Ptr = (PCHAR)pFrame->Octet;
|
|
Length += LENGTH_802_11;
|
|
|
|
/* skip timestamp from payload and advance the pointer */
|
|
Ptr += TIMESTAMP_LEN;
|
|
Length += TIMESTAMP_LEN;
|
|
|
|
/* skip beacon interval from payload and advance the pointer */
|
|
Ptr += 2;
|
|
Length += 2;
|
|
|
|
/* skip capability info from payload and advance the pointer */
|
|
Ptr += 2;
|
|
Length += 2;
|
|
|
|
pEid = (PEID_STRUCT) Ptr;
|
|
|
|
/* get variable fields from payload and advance the pointer */
|
|
while ((Length + 2 + pEid->Len) <= MsgLen)
|
|
{
|
|
switch(pEid->Eid)
|
|
{
|
|
case IE_VENDOR_SPECIFIC:
|
|
if (NdisEqualMemory(pEid->Octet, MeshOUI, 3))
|
|
{
|
|
PUCHAR ptr = (PUCHAR)(pEid->Octet + 3);
|
|
*pHostNameLen = pEid->Len -3;
|
|
NdisMoveMemory(pHostName, ptr, *pHostNameLen);
|
|
}
|
|
break;
|
|
|
|
case IE_MESH_ID:
|
|
NdisMoveMemory(pMeshId, pEid->Octet, pEid->Len);
|
|
*pMeshIdLen = pEid->Len;
|
|
break;
|
|
|
|
case IE_MESH_CONFIGURATION:
|
|
{
|
|
PUCHAR ptr;
|
|
NdisMoveMemory(&pMeshConfiguration->Version, pEid->Octet, 1);
|
|
|
|
if (RTMPEqualMemory(pEid->Octet + 1, MeshOUI, 3))
|
|
NdisMoveMemory(&pMeshConfiguration->PathSelProtocolId, pEid->Octet + 4, 1);
|
|
|
|
if (RTMPEqualMemory(pEid->Octet + 5, MeshOUI, 3))
|
|
NdisMoveMemory(&pMeshConfiguration->PathSelMetricId, pEid->Octet + 8, 1);
|
|
|
|
ptr = (PUCHAR)&pEid->Octet[0];
|
|
NdisMoveMemory(&pMeshConfiguration->CPI, ptr + 13, 4);
|
|
pMeshConfiguration->CPI = le2cpu32(*(UINT32 *)(&pMeshConfiguration->CPI));
|
|
|
|
NdisMoveMemory(&pMeshConfiguration->MeshCapability.word, ptr + 17, 2);
|
|
pMeshConfiguration->MeshCapability.word = le2cpu16(*(UINT16 *)(&pMeshConfiguration->MeshCapability.word));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
#ifdef RELEASE_EXCLUDE
|
|
DBGPRINT(RT_DEBUG_INFO, ("MeshPeerBeaconAndProbeSanity - unrecognized EID = %d\n", pEid->Eid));
|
|
#endif /* RELEASE_EXCLUDE */
|
|
break;
|
|
}
|
|
|
|
Length = Length + 2 + pEid->Len; /* Eid[1] + Len[1]+ content[Len] */
|
|
pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshLinkMngOpenSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT16 *pCapabilityInfo,
|
|
OUT UCHAR SupRate[],
|
|
OUT PUCHAR pSupRateLen,
|
|
OUT PUCHAR pMeshIdLen,
|
|
OUT PUCHAR pMeshId,
|
|
OUT PUCHAR pMeshSelPathId,
|
|
OUT PUCHAR pMeshSelMetricId,
|
|
OUT UINT32 *pCPI,
|
|
OUT PMESH_CAPABILITY pMeshCapabilty,
|
|
OUT UINT16 *pPeerLinkId,
|
|
OUT PMESH_SECURITY_CAPABILITY_IE pMscIe,
|
|
OUT PUCHAR pMsaIe,
|
|
OUT PUCHAR pMsaIeLen,
|
|
OUT PUCHAR pRsnIe,
|
|
OUT PUCHAR pRsnIeLen,
|
|
OUT BOOLEAN *pbWmmCapable,
|
|
OUT HT_CAPABILITY_IE *pHtCapability,
|
|
OUT UCHAR *pHtCapabilityLen)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UCHAR WPA1_OUI[4]={0x00,0x50,0xF2,0x01};
|
|
UCHAR WPA2_OUI[3]={0x00,0x0F,0xAC};
|
|
|
|
*pMsaIeLen = 0;
|
|
*pRsnIeLen = 0;
|
|
|
|
NdisMoveMemory(pCapabilityInfo, pMsg, 2);
|
|
pMsg += 2;
|
|
MsgLen -= 2;
|
|
*pbWmmCapable = FALSE;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_SUPP_RATES:
|
|
if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0))
|
|
{
|
|
NdisMoveMemory(SupRate, eid_ptr->Octet, eid_ptr->Len);
|
|
#ifdef RELEASE_EXCLUDE
|
|
DBGPRINT(RT_DEBUG_INFO, ("%s - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n", __FUNCTION__, eid_ptr->Len, SupRate[0]));
|
|
DBGPRINT(RT_DEBUG_INFO, ("SupRate[1]=%x %x %x %x %x %x %x\n",
|
|
SupRate[1], SupRate[2], SupRate[3], SupRate[4], SupRate[5], SupRate[6], SupRate[7]));
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
*pSupRateLen = eid_ptr->Len;
|
|
}
|
|
else
|
|
{
|
|
/* HT rate not ready yet. return true temporarily. */
|
|
/*DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocReqSanity - wrong IE_SUPP_RATES\n")); */
|
|
*pSupRateLen = 8;
|
|
SupRate[0] = 0x82;
|
|
SupRate[1] = 0x84;
|
|
SupRate[2] = 0x8b;
|
|
SupRate[3] = 0x96;
|
|
SupRate[4] = 0x12;
|
|
SupRate[5] = 0x24;
|
|
SupRate[6] = 0x48;
|
|
SupRate[7] = 0x6c;
|
|
#ifdef RELEASE_EXCLUDE
|
|
DBGPRINT(RT_DEBUG_INFO, ("PeerAssocReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len));
|
|
#endif /* RELEASE_EXCLUDE */
|
|
/*return FALSE; */
|
|
}
|
|
break;
|
|
|
|
case IE_EXT_SUPP_RATES:
|
|
if (eid_ptr->Len + *pSupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
|
|
{
|
|
NdisMoveMemory(&SupRate[*pSupRateLen], eid_ptr->Octet, eid_ptr->Len);
|
|
*pSupRateLen = (*pSupRateLen) + eid_ptr->Len;
|
|
}
|
|
else
|
|
{
|
|
NdisMoveMemory(&SupRate[*pSupRateLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pSupRateLen));
|
|
*pSupRateLen = MAX_LEN_OF_SUPPORTED_RATES;
|
|
}
|
|
break;
|
|
|
|
case IE_WPA:
|
|
case IE_WPA2:
|
|
if (NdisEqualMemory(eid_ptr->Octet, WME_INFO_ELEM, 6) && (eid_ptr->Len == 7))
|
|
{
|
|
*pbWmmCapable = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (pAd->MeshTab.wdev.AuthMode < Ndis802_11AuthModeWPA)
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("The AuthMode isn't WPA!!!%d \n",pAd->MeshTab.wdev.AuthMode));
|
|
break;
|
|
}
|
|
|
|
/* If this IE did not begins with "0x00:0x50:0xf2:0x01" or "0x00:0x0f:0xac", it would be proprietary. So we ignore it. */
|
|
if (!NdisEqualMemory(eid_ptr->Octet, WPA1_OUI, sizeof(WPA1_OUI))
|
|
&& !NdisEqualMemory(&eid_ptr->Octet[2], WPA2_OUI, sizeof(WPA2_OUI)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("Not RSN IE, maybe proprietary IE!!!\n"));
|
|
break;
|
|
}
|
|
|
|
if (/*(eid_ptr->Len <= MAX_LEN_OF_RSNIE) && */(eid_ptr->Len > MIN_LEN_OF_RSNIE))
|
|
{
|
|
NdisMoveMemory(pRsnIe, eid_ptr, eid_ptr->Len + 2);
|
|
*pRsnIeLen = eid_ptr->Len + 2;
|
|
}
|
|
else
|
|
{
|
|
*pRsnIeLen = 0;
|
|
DBGPRINT(RT_DEBUG_TRACE, ("The received the length(%d) of RSN_IE is invalid\n",eid_ptr->Len));
|
|
break;
|
|
}
|
|
DBGPRINT(RT_DEBUG_TRACE, ("Link Msg - RSNIE(%d), and its len(%d)!!!\n", eid_ptr->Eid, *pRsnIeLen));
|
|
break;
|
|
|
|
case IE_MESH_ID:
|
|
if (eid_ptr->Len < MAX_MESH_ID_LEN)
|
|
NdisMoveMemory(pMeshId, eid_ptr->Octet, eid_ptr->Len);
|
|
break;
|
|
|
|
case IE_MESH_CONFIGURATION:
|
|
if (NdisEqualMemory(eid_ptr->Octet + 1, MeshOUI, 3))
|
|
NdisMoveMemory(pMeshSelPathId, eid_ptr->Octet + 4, 1);
|
|
|
|
if (NdisEqualMemory(eid_ptr->Octet + 5, MeshOUI, 3))
|
|
NdisMoveMemory(pMeshSelMetricId, eid_ptr->Octet + 8, 1);
|
|
|
|
NdisMoveMemory(pCPI, eid_ptr->Octet + 13, 4);
|
|
*pCPI = le2cpu32(*(UINT32 *)pCPI);
|
|
NdisMoveMemory(&pMeshCapabilty->word, eid_ptr->Octet + 17, 2);
|
|
pMeshCapabilty->word = le2cpu16(*(UINT16 *)(&pMeshCapabilty->word));
|
|
break;
|
|
|
|
case IE_MESH_PEER_LINK_MANAGEMENT:
|
|
if ((*eid_ptr->Octet == SUBTYPE_PEER_LINK_OPEN) /* subtype 1 means Peer-Link-Open frame. */
|
|
&& (eid_ptr->Len == LenPeerLinkMngIE[SUBTYPE_PEER_LINK_OPEN])) /* Length of Peer-Link-open must be 3. */
|
|
{
|
|
NdisMoveMemory(pPeerLinkId, eid_ptr->Octet + 1, 2);
|
|
*pPeerLinkId = le2cpu16(*pPeerLinkId);
|
|
}
|
|
break;
|
|
|
|
case IE_MESH_MSCIE:
|
|
if (eid_ptr->Len == 7) /* its Length MUST be 7 */
|
|
{
|
|
NdisMoveMemory(pMscIe, eid_ptr->Octet, eid_ptr->Len);
|
|
}
|
|
break;
|
|
|
|
case IE_MESH_MSAIE:
|
|
if (eid_ptr->Len >= sizeof(MSA_HANDSHAKE_IE))
|
|
{
|
|
NdisMoveMemory(pMsaIe, eid_ptr->Octet, eid_ptr->Len);
|
|
*pMsaIeLen = eid_ptr->Len;
|
|
}
|
|
break;
|
|
|
|
case IE_HT_CAP:
|
|
if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE))
|
|
{
|
|
NdisMoveMemory(pHtCapability, eid_ptr->Octet, SIZE_HT_CAP_IE);
|
|
|
|
*(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo));
|
|
*(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo));
|
|
|
|
*pHtCapabilityLen = SIZE_HT_CAP_IE;
|
|
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocReqSanity - IE_HT_CAP\n"));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshLinkMngCfnSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT16 *pCapabilityInfo,
|
|
OUT UINT16 *pStatusCode,
|
|
OUT UINT16 *pAid,
|
|
OUT UCHAR SupRate[],
|
|
OUT PUCHAR pSupRateLen,
|
|
OUT PUCHAR pMeshIdLen,
|
|
OUT PUCHAR pMeshId,
|
|
OUT PUCHAR pMeshSelPathId,
|
|
OUT PUCHAR pMeshSelMetricId,
|
|
OUT UINT32 *pCPI,
|
|
OUT PMESH_CAPABILITY pMeshCapabilty,
|
|
OUT UINT16 *pLocalLinkId,
|
|
OUT UINT16 *pPeerLinkId,
|
|
OUT PMESH_SECURITY_CAPABILITY_IE pMscIe,
|
|
OUT PUCHAR pMsaIe,
|
|
OUT PUCHAR pMsaIeLen,
|
|
OUT PUCHAR pRsnIe,
|
|
OUT PUCHAR pRsnIeLen,
|
|
OUT HT_CAPABILITY_IE *pHtCapability,
|
|
OUT UCHAR *pHtCapabilityLen)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UCHAR WPA1_OUI[4]={0x00,0x50,0xF2,0x01};
|
|
UCHAR WPA2_OUI[3]={0x00,0x0F,0xAC};
|
|
|
|
*pMsaIeLen = 0;
|
|
*pRsnIeLen = 0;
|
|
|
|
NdisMoveMemory(pCapabilityInfo, pMsg, 2);
|
|
pMsg += 2;
|
|
MsgLen -= 2;
|
|
|
|
NdisMoveMemory(pStatusCode, pMsg, 2);
|
|
pMsg += 2;
|
|
MsgLen -= 2;
|
|
|
|
NdisMoveMemory(pAid, pMsg, 2);
|
|
pMsg += 2;
|
|
MsgLen -= 2;
|
|
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_SUPP_RATES:
|
|
if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0))
|
|
{
|
|
NdisMoveMemory(SupRate, eid_ptr->Octet, eid_ptr->Len);
|
|
#ifdef RELEASE_EXCLUDE
|
|
DBGPRINT(RT_DEBUG_INFO, ("%s - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n", __FUNCTION__, eid_ptr->Len, SupRate[0]));
|
|
DBGPRINT(RT_DEBUG_INFO, ("SupRate[1]=%x %x %x %x %x %x %x\n",
|
|
SupRate[1], SupRate[2], SupRate[3], SupRate[4], SupRate[5], SupRate[6], SupRate[7]));
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
*pSupRateLen = eid_ptr->Len;
|
|
}
|
|
else
|
|
{
|
|
/* HT rate not ready yet. return true temporarily. */
|
|
/*DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocReqSanity - wrong IE_SUPP_RATES\n")); */
|
|
*pSupRateLen = 8;
|
|
SupRate[0] = 0x82;
|
|
SupRate[1] = 0x84;
|
|
SupRate[2] = 0x8b;
|
|
SupRate[3] = 0x96;
|
|
SupRate[4] = 0x12;
|
|
SupRate[5] = 0x24;
|
|
SupRate[6] = 0x48;
|
|
SupRate[7] = 0x6c;
|
|
#ifdef RELEASE_EXCLUDE
|
|
DBGPRINT(RT_DEBUG_INFO, ("PeerAssocReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len));
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
/*return FALSE; */
|
|
}
|
|
break;
|
|
|
|
case IE_EXT_SUPP_RATES:
|
|
if (eid_ptr->Len + *pSupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
|
|
{
|
|
NdisMoveMemory(&SupRate[*pSupRateLen], eid_ptr->Octet, eid_ptr->Len);
|
|
*pSupRateLen = (*pSupRateLen) + eid_ptr->Len;
|
|
}
|
|
else
|
|
{
|
|
NdisMoveMemory(&SupRate[*pSupRateLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pSupRateLen));
|
|
*pSupRateLen = MAX_LEN_OF_SUPPORTED_RATES;
|
|
}
|
|
break;
|
|
|
|
case IE_WPA:
|
|
case IE_WPA2:
|
|
if (pAd->MeshTab.wdev.AuthMode < Ndis802_11AuthModeWPA)
|
|
break;
|
|
|
|
/* If this IE did not begins with "0x00:0x50:0xf2:0x01" or "0x00:0x0f:0xac", it would be proprietary. So we ignore it. */
|
|
if (!NdisEqualMemory(eid_ptr->Octet, WPA1_OUI, sizeof(WPA1_OUI))
|
|
&& !NdisEqualMemory(&eid_ptr->Octet[2], WPA2_OUI, sizeof(WPA2_OUI)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("Not RSN IE, maybe proprietary IE!!!\n"));
|
|
break;
|
|
}
|
|
|
|
if (/*(eid_ptr->Len <= MAX_LEN_OF_RSNIE) && */(eid_ptr->Len > MIN_LEN_OF_RSNIE))
|
|
{
|
|
NdisMoveMemory(pRsnIe, eid_ptr, eid_ptr->Len + 2);
|
|
*pRsnIeLen = eid_ptr->Len + 2;
|
|
}
|
|
else
|
|
{
|
|
*pRsnIeLen = 0;
|
|
DBGPRINT(RT_DEBUG_TRACE, ("The received the length(%d) of RSN_IE is invalid\n",eid_ptr->Len));
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case IE_MESH_ID:
|
|
if (eid_ptr->Len < MAX_MESH_ID_LEN)
|
|
NdisMoveMemory(pMeshId, eid_ptr->Octet, eid_ptr->Len);
|
|
break;
|
|
|
|
case IE_MESH_CONFIGURATION:
|
|
if (NdisEqualMemory(eid_ptr->Octet + 1, MeshOUI, 3))
|
|
{
|
|
*pMeshSelPathId = eid_ptr->Octet[4];
|
|
}
|
|
if (NdisEqualMemory(eid_ptr->Octet + 5, MeshOUI, 3))
|
|
{
|
|
*pMeshSelMetricId = eid_ptr->Octet[8];
|
|
}
|
|
NdisMoveMemory(pCPI, eid_ptr->Octet + 13, 4);
|
|
*pCPI = le2cpu32(*pCPI);
|
|
NdisMoveMemory(&pMeshCapabilty->word, eid_ptr->Octet + 17, 2);
|
|
pMeshCapabilty->word = le2cpu16(pMeshCapabilty->word);
|
|
break;
|
|
|
|
case IE_MESH_PEER_LINK_MANAGEMENT:
|
|
{
|
|
if ((eid_ptr->Octet[0] == SUBTYPE_PEER_LINK_CONFIRM) /* subtype 1 means Peer-Link-Confirm frame. */
|
|
&& (eid_ptr->Len == LenPeerLinkMngIE[SUBTYPE_PEER_LINK_CONFIRM])) /* Length of Peer-Link-close must be 3. */
|
|
{
|
|
NdisMoveMemory(pLocalLinkId, eid_ptr->Octet + 1, 2);
|
|
*pLocalLinkId = le2cpu16(*(UINT16 *)(pLocalLinkId));
|
|
NdisMoveMemory(pPeerLinkId, eid_ptr->Octet + 3, 2);
|
|
*pPeerLinkId = le2cpu16(*(UINT16 *)(pPeerLinkId));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IE_MESH_MSCIE:
|
|
if (eid_ptr->Len == 7) /* its Length MUST be 7 */
|
|
{
|
|
NdisMoveMemory(pMscIe,eid_ptr->Octet, eid_ptr->Len);
|
|
}
|
|
break;
|
|
|
|
case IE_MESH_MSAIE:
|
|
if (eid_ptr->Len >= sizeof(MSA_HANDSHAKE_IE))
|
|
{
|
|
NdisMoveMemory(pMsaIe,eid_ptr->Octet, eid_ptr->Len);
|
|
*pMsaIeLen = eid_ptr->Len;
|
|
}
|
|
break;
|
|
|
|
case IE_HT_CAP:
|
|
if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE))
|
|
{
|
|
NdisMoveMemory(pHtCapability, eid_ptr->Octet, SIZE_HT_CAP_IE);
|
|
|
|
*(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo));
|
|
*(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo));
|
|
|
|
*pHtCapabilityLen = SIZE_HT_CAP_IE;
|
|
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocReqSanity - IE_HT_CAP\n"));
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshLinkMngClsSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT16 *pLocalLinkId,
|
|
OUT UINT16 *pPeerLinkId,
|
|
OUT UINT16 *pReasonCode)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_PEER_LINK_MANAGEMENT:
|
|
{
|
|
if ((eid_ptr->Octet[0] == SUBTYPE_PEER_LINK_CLOSE) /* subtype 1 means Peer-Link-Close frame. */
|
|
&& (eid_ptr->Len == LenPeerLinkMngIE[SUBTYPE_PEER_LINK_CLOSE])) /* Length of Peer-Link-close must be 7. */
|
|
{
|
|
NdisMoveMemory(pLocalLinkId, eid_ptr->Octet + 1, 2);
|
|
*pLocalLinkId = le2cpu16(*(UINT16 *)(pLocalLinkId));
|
|
NdisMoveMemory(pPeerLinkId, eid_ptr->Octet + 3, 2);
|
|
*pPeerLinkId = le2cpu16(*(UINT16 *)(pPeerLinkId));
|
|
NdisMoveMemory(pReasonCode, eid_ptr->Octet + 5, 2);
|
|
*pReasonCode = le2cpu16(*(UINT16 *)(pReasonCode));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshPathSelMultipathNoticeSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT8 *pFlag,
|
|
OUT PUCHAR pMeshSA)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_MULITI_PATH_NOTICE_IE:
|
|
{
|
|
if (eid_ptr->Len == 7) /* Length must be 7. */
|
|
{
|
|
NdisMoveMemory(pFlag, eid_ptr->Octet, 1);
|
|
NdisMoveMemory(pMeshSA, eid_ptr->Octet + 1, MAC_ADDR_LEN);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN MeshChannelSwitchAnnouncementSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT8 *pChSwMode,
|
|
OUT UINT8 *pNewCh,
|
|
OUT UINT32 *pNewCPI,
|
|
OUT UINT8 *pChSwCnt,
|
|
OUT PUCHAR pMeshSA)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_CHANNEL_SWITCH_ANNOUNCEMENT:
|
|
{
|
|
if (eid_ptr->Len == 13) /* Length must be 7. */
|
|
{
|
|
NdisMoveMemory(pChSwMode, eid_ptr->Octet, 1);
|
|
NdisMoveMemory(pNewCh, eid_ptr->Octet + 1, 1);
|
|
NdisMoveMemory(pNewCPI, eid_ptr->Octet + 2, 4);
|
|
*pNewCPI = le2cpu32(*pNewCPI);
|
|
NdisMoveMemory(pChSwCnt, eid_ptr->Octet + 6, 1);
|
|
NdisMoveMemory(pMeshSA, eid_ptr->Octet + 7, MAC_ADDR_LEN);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Check sanity RSN IE and get PMKID offset.
|
|
Return:
|
|
TRUE if match
|
|
FALSE otherwise
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN MeshValidateRSNIE(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pRsnIe,
|
|
IN USHORT peerRsnIeLen,
|
|
OUT UCHAR *PureRsnLen,
|
|
OUT UCHAR *PmkIdLen)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
PUCHAR pBufTmp;
|
|
USHORT Count;
|
|
UCHAR offset = 0;
|
|
BOOLEAN isValid = FALSE;
|
|
BOOLEAN RsnEid = IE_WPA;
|
|
|
|
/* Check if both MPs are RSNIE */
|
|
if (pAd->MeshTab.wdev.AuthMode < Ndis802_11AuthModeWPA)
|
|
{
|
|
if (peerRsnIeLen == 0)
|
|
{
|
|
/* Don't check it */
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the local MP has no RSNIE \n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (peerRsnIeLen == 0)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the peer MP has no RSNIE \n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* hex_dump("Peer RSNIE", pRsnIe, peerRsnIeLen); */
|
|
eid_ptr = (PEID_STRUCT)pRsnIe;
|
|
|
|
if (pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA2PSK ||
|
|
pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA2
|
|
#ifdef WPA3_SUPPORT
|
|
|| (pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA3SAE)
|
|
#endif
|
|
)
|
|
RsnEid = IE_WPA2;
|
|
|
|
if (eid_ptr->Eid != IE_WPA && eid_ptr->Eid != IE_WPA2)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE has unknown element ID(%d) \n", eid_ptr->Eid));
|
|
return FALSE;
|
|
}
|
|
|
|
if (eid_ptr->Len < sizeof(RSNIE2))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, its length is too short(%d)\n", eid_ptr->Len));
|
|
return FALSE;
|
|
}
|
|
|
|
*PureRsnLen = 0;
|
|
*PmkIdLen = 0;
|
|
|
|
/* Store STA RSN_IE capability */
|
|
pBufTmp = (PUCHAR)&eid_ptr->Octet[0];
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the offset of group cipher */
|
|
/* If WPA2, skip version(2-bytes) */
|
|
/* If WPA, skip OUI(4-bytes) and version(2-bytes) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
offset = (eid_ptr->Eid == IE_WPA2) ? 2 : 6;
|
|
|
|
/* Check group cipher */
|
|
if (MeshCheckGroupCipher(pAd, pBufTmp + offset, RsnEid))
|
|
{
|
|
/* skip group cipher, then point to pairwise-cipher-count */
|
|
offset += 4;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the group cipher isn't supported\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Store pairwise-cipher-count */
|
|
NdisMoveMemory(&Count, pBufTmp + offset, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
|
|
if (Count > 0)
|
|
{
|
|
/* skip pairwise-cipher-count, then point to pairwise-cipher-suite-list */
|
|
offset += sizeof(USHORT);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the count of piarwise-cipher is invalid(%d)\n", Count));
|
|
return FALSE;
|
|
}
|
|
|
|
/* clear this flag */
|
|
isValid = FALSE;
|
|
while (Count > 0)
|
|
{
|
|
if ((isValid == FALSE) && (MeshCheckPairwiseCipher(pAd, pBufTmp + offset, RsnEid)))
|
|
{
|
|
isValid = TRUE;
|
|
}
|
|
|
|
offset += 4;
|
|
Count--;
|
|
}
|
|
|
|
if (!isValid)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the pairwise cipher isn't supported\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Store AKM-suite-count */
|
|
NdisMoveMemory(&Count, pBufTmp + offset, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
|
|
if (Count > 0)
|
|
{
|
|
/* skip AKM-suite-count, then pointer to AKM-suite-list */
|
|
offset += sizeof(USHORT);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the count of AKM-suite is invalid(%d)\n", Count));
|
|
return FALSE;
|
|
}
|
|
|
|
/* clear this flag */
|
|
isValid = FALSE;
|
|
while (Count > 0)
|
|
{
|
|
if ((isValid == FALSE) && (MeshCheckAKMSuite(pAd, pBufTmp + offset, RsnEid)))
|
|
{
|
|
isValid = TRUE;
|
|
}
|
|
|
|
offset += 4;
|
|
Count--;
|
|
}
|
|
|
|
if (!isValid)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("MeshValidateRSNIE, the AKM suite isn't supported\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MeshValidateRSNIE is completed \n"));
|
|
|
|
/* Check if the remaining length is larger than the size of RSN capability(2-bytes). */
|
|
if (eid_ptr->Len - offset >= 2)
|
|
{
|
|
/* skip RSN capability(2-bytes) */
|
|
offset += sizeof(USHORT);
|
|
}
|
|
|
|
*PureRsnLen = offset; /* the length is the RSNIE except elementID, length and PMKID */
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* decide PMKID length */
|
|
/* If PMKID exists, the remaining length shall be */
|
|
/* 18 = PMKID_count(2-bytes) + one PMKID(16-bytes) or */
|
|
/* 34 = PMKID_count(2-bytes) + two PMKIDs(32-bytes) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (eid_ptr->Len - offset >= 2)
|
|
{
|
|
NdisMoveMemory(&Count, pBufTmp + offset, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
offset += sizeof(USHORT);
|
|
|
|
if (Count == 2 && (eid_ptr->Len - offset == (2*LEN_PMKID)))
|
|
*PmkIdLen = 2*LEN_PMKID;
|
|
else if (Count == 1 && (eid_ptr->Len - offset == LEN_PMKID))
|
|
*PmkIdLen = LEN_PMKID;
|
|
else
|
|
*PmkIdLen = 0;
|
|
|
|
if (*PmkIdLen > 0)
|
|
{
|
|
DBGPRINT(RT_DEBUG_TRACE, ("MeshValidateRSNIE, %d PMKID exist and its len is %d \n", Count, (eid_ptr->Len - offset)));
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Check sanity of group cipher selector
|
|
Return:
|
|
TRUE if match
|
|
FALSE otherwise
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN MeshCheckGroupCipher(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pData,
|
|
IN UCHAR Eid)
|
|
{
|
|
|
|
/* WPA and WPA2 format not the same in RSN_IE */
|
|
if (Eid == IE_WPA2)
|
|
{
|
|
/* skip version(2-bytes) */
|
|
if (NdisEqualMemory(pData, &pAd->MeshTab.RSN_IE[2], 4))
|
|
return TRUE;
|
|
}
|
|
else if (Eid == IE_WPA)
|
|
{
|
|
/* skip OUI(4-bytes) and version(2-bytes) */
|
|
if (NdisEqualMemory(pData, &pAd->MeshTab.RSN_IE[6], 4))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Check sanity of unicast cipher selector.
|
|
Return:
|
|
TRUE if match
|
|
FALSE otherwise
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN MeshCheckPairwiseCipher(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pData,
|
|
IN UCHAR Eid)
|
|
{
|
|
PUCHAR pTmp;
|
|
USHORT Count;
|
|
|
|
pTmp = &pAd->MeshTab.RSN_IE[0];
|
|
|
|
if(Eid == IE_WPA2)
|
|
/* skip Version(2),Multicast cipter(4) 2+4==6 */
|
|
pTmp += 6;
|
|
else
|
|
/*skip OUI(4),Vesrion(2),Multicast cipher(4) 4+2+4==10 */
|
|
pTmp += 10;/*point to number of unicast */
|
|
|
|
NdisMoveMemory(&Count, pTmp, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
pTmp += sizeof(USHORT);/*pointer to unicast cipher */
|
|
|
|
while (Count > 0)
|
|
{
|
|
if(RTMPEqualMemory(pData, pTmp, 4))
|
|
return TRUE;
|
|
else
|
|
{
|
|
pTmp += 4;
|
|
Count--;
|
|
}
|
|
}
|
|
return FALSE;/* do not match the unicast cipher */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Check invalidity of authentication method selection.
|
|
Return:
|
|
TRUE if match
|
|
FALSE otherwise
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN MeshCheckAKMSuite(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN PUCHAR pData,
|
|
IN UCHAR Eid)
|
|
{
|
|
PUCHAR pTmp;
|
|
USHORT Count;
|
|
|
|
pTmp = &pAd->MeshTab.RSN_IE[0];
|
|
|
|
if(Eid == IE_WPA2)
|
|
/* skip Version(2),Multicast cipter(4) 2+4==6 */
|
|
pTmp +=6;
|
|
else
|
|
/*skip OUI(4),Vesrion(2),Multicast cipher(4) 4+2+4==10 */
|
|
pTmp += 10;/*point to number of unicast */
|
|
|
|
NdisMoveMemory(&Count, pTmp, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
pTmp += sizeof(USHORT);/*pointer to unicast cipher */
|
|
|
|
/* Skip all unicast cipher suite */
|
|
while (Count > 0)
|
|
{
|
|
/* Skip OUI */
|
|
pTmp += 4;
|
|
Count--;
|
|
}
|
|
|
|
NdisMoveMemory(&Count, pTmp, sizeof(USHORT));
|
|
#ifdef RT_BIG_ENDIAN
|
|
Count = SWAP16(Count);
|
|
#endif
|
|
pTmp += sizeof(USHORT);/*pointer to AKM cipher */
|
|
|
|
while (Count > 0)
|
|
{
|
|
if(RTMPEqualMemory(pData, pTmp, 4))
|
|
return TRUE;
|
|
else
|
|
{
|
|
pTmp += 4;
|
|
Count--;
|
|
}
|
|
}
|
|
return FALSE;/* do not match the AKM */
|
|
|
|
}
|
|
|
|
UINT16 MeshValidateOpenAndCfnPeerLinkMsg(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR state,
|
|
IN PMESH_LINK_ENTRY pMeshLinkEntry,
|
|
IN PUCHAR pRcvdMscIe,
|
|
IN PUCHAR pRcvdMsaIe,
|
|
IN UCHAR RcvdMsaIeLen,
|
|
IN PUCHAR pRcvdRsnIe,
|
|
IN UCHAR RcvdRsnIeLen,
|
|
IN UCHAR pure_rsn_len,
|
|
IN UCHAR pmkid_len)
|
|
{
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* MSCIE is identical to the MSCIE included in the peer link */
|
|
/* open (or confirm) frame received from the candidate peer MP. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (!RTMPEqualMemory(pRcvdMscIe, (PUCHAR)&pMeshLinkEntry->RcvdMscIe, sizeof(MESH_SECURITY_CAPABILITY_IE)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The MSCIE is different between peer link open and confirm frame \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* The Handshake Control field of MSAIE is identical to that */
|
|
/* included in the received peer link open (or confirm) frame. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (!RTMPEqualMemory(pRcvdMsaIe, pMeshLinkEntry->RcvdMsaIe, sizeof(MESH_HANDSHAKE_CONTROL)))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Handshake Control field of MSAIE is different between peer link open and confirm frame \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
if (pAd->MeshTab.wdev.AuthMode >= Ndis802_11AuthModeWPA)
|
|
{
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* RSNIE is identical to the RSNIE included in the peer link */
|
|
/* confirm frame received from the candidate peer MP, except the PMKID list. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (pure_rsn_len != pMeshLinkEntry->RcvdRSNIE_Len ||
|
|
!RTMPEqualMemory(pRcvdRsnIe + 2, pMeshLinkEntry->RcvdRSNIE, pure_rsn_len))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The RSNIE is different between candidate MP's link open and confirm frame \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the local MP shall verify that the PMK-MAName value contained in the received */
|
|
/* peer link confirm frame identifies the key chosen by the key selection procedure, */
|
|
/* or is empty if Initial MSA Authentication shall occur. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (pmkid_len > 0 && pMeshLinkEntry->RcvdPMKID_Len > 0)
|
|
{
|
|
UCHAR pmkid_offset = RcvdRsnIeLen - pmkid_len;
|
|
|
|
if (pmkid_len != pMeshLinkEntry->RcvdPMKID_Len ||
|
|
!NdisEqualMemory(pRcvdRsnIe + pmkid_offset, pMeshLinkEntry->RcvdPMKID, pmkid_len))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The result of Key Selection is different between candidate MP's link open and confirm frame\n"));
|
|
hex_dump("Receive PMKID ", pRcvdRsnIe + pmkid_offset, pmkid_len);
|
|
hex_dump("Desired PMKID ", pMeshLinkEntry->RcvdPMKID, pMeshLinkEntry->RcvdPMKID_Len);
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
|
|
}
|
|
}
|
|
else if (pmkid_len == 0 && pMeshLinkEntry->RcvdPMKID_Len == 0)
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The PMKID is different between candidate MP's link open and confirm frame\n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* If the candidate peer MP is the selector MP, the values in the Selected AKM Suite and */
|
|
/* Selected Pairwise Cipher Suite fields are identical to the values received in peer link frame. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (!pMeshLinkEntry->bValidLocalMpAsSelector)
|
|
{
|
|
UCHAR akm_offset = 0, cipher_offset = 0;
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the Selected AKM offset - */
|
|
/* skip the Handshake Control field(1) + MA_ID(6) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
akm_offset = sizeof(MESH_HANDSHAKE_CONTROL) + MAC_ADDR_LEN;
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the Selected Pairwise-cipher offset - */
|
|
/* skip the Handshake Control field(1) + MA_ID(6) + Selected_AKM(4) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
cipher_offset = sizeof(MESH_HANDSHAKE_CONTROL) + MAC_ADDR_LEN + LEN_OUI_SUITE;
|
|
|
|
if (!RTMPEqualMemory(pRcvdMsaIe + akm_offset, &pMeshLinkEntry->RcvdMsaIe[akm_offset], LEN_OUI_SUITE))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected AKM Suite of MSAIE is different between peer link open and confirm frame \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
if (!RTMPEqualMemory(pRcvdMsaIe + cipher_offset, &pMeshLinkEntry->RcvdMsaIe[cipher_offset], LEN_OUI_SUITE))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected Pairwise Cipher Suite of MSAIE is different between peer link open and confirm frame \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the local MP shall verify that the MA-ID value received in the peer link confirm */
|
|
/* frame matches the result of the 802.1X role selection procedure. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
{
|
|
UCHAR LocalMaAddr[MAC_ADDR_LEN];
|
|
UCHAR PeerMaAddr[MAC_ADDR_LEN];
|
|
|
|
if (pMeshLinkEntry->bValidLocalMpAsAuthenticator)
|
|
NdisMoveMemory(LocalMaAddr, pAd->MeshTab.wdev.if_addr, MAC_ADDR_LEN);
|
|
else
|
|
NdisMoveMemory(LocalMaAddr, pMeshLinkEntry->PeerMacAddr, MAC_ADDR_LEN);
|
|
|
|
if (state == SUBTYPE_PEER_LINK_CONFIRM)
|
|
NdisMoveMemory(PeerMaAddr, pRcvdMsaIe + 1, MAC_ADDR_LEN);
|
|
else
|
|
NdisMoveMemory(PeerMaAddr, &pMeshLinkEntry->RcvdMsaIe[1], MAC_ADDR_LEN);
|
|
|
|
if (!NdisEqualMemory(LocalMaAddr, PeerMaAddr, MAC_ADDR_LEN))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The MA-ID of MSAIE doesn't match \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
}
|
|
|
|
|
|
return MLME_SUCCESS;
|
|
}
|
|
|
|
UINT16 MeshCheckPeerMsaIeCipherValidity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR state,
|
|
IN PMESH_LINK_ENTRY pMeshLinkEntry,
|
|
IN PUCHAR pRcvdMsaIe)
|
|
{
|
|
if (pAd->MeshTab.wdev.AuthMode >= Ndis802_11AuthModeWPA)
|
|
{
|
|
UCHAR akm_offset = 0, cipher_offset = 0;
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the Selected AKM offset - */
|
|
/* skip the Handshake Control field(1) + MA_ID(6) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
akm_offset = sizeof(MESH_HANDSHAKE_CONTROL) + MAC_ADDR_LEN;
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* the Selected Pairwise-cipher offset - */
|
|
/* skip the Handshake Control field(1) + MA_ID(6) + Selected_AKM(4) */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
cipher_offset = akm_offset + LEN_OUI_SUITE;
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* Verify that the AKM suite and pairwise cipher suite selected */
|
|
/* in the MSAIE are among those supported by the local MP if */
|
|
/* 1. the local MP is not the Selector MP and received peer link open frame */
|
|
/* 2. received peer link confirm frame */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if (((state == SUBTYPE_PEER_LINK_OPEN) && (!pMeshLinkEntry->bValidLocalMpAsSelector)) ||
|
|
(state == SUBTYPE_PEER_LINK_CONFIRM))
|
|
{
|
|
UCHAR RsnEid = IE_WPA;
|
|
|
|
if (pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA2PSK ||
|
|
pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA2
|
|
#ifdef WPA3_SUPPORT
|
|
|| (pAd->MeshTab.wdev.AuthMode == Ndis802_11AuthModeWPA3SAE)
|
|
#endif
|
|
)
|
|
RsnEid = IE_WPA2;
|
|
|
|
if (!MeshCheckPairwiseCipher(pAd, &pRcvdMsaIe[cipher_offset], RsnEid))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected Pairwise Cipher isn't supported by local MP\n"));
|
|
return MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS;
|
|
}
|
|
|
|
if (!MeshCheckAKMSuite(pAd, &pRcvdMsaIe[akm_offset], RsnEid))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected AKM isn't supported by local MP \n"));
|
|
return MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS;
|
|
}
|
|
|
|
/* verify peer AKM and pairwise-cipher OK, update them to local MSAIE */
|
|
if (state == SUBTYPE_PEER_LINK_OPEN)
|
|
NdisMoveMemory(&pMeshLinkEntry->LocalMsaIe[akm_offset], &pRcvdMsaIe[akm_offset], 2*LEN_OUI_SUITE);
|
|
|
|
}
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* Upon reception of a peer link confirm frame, */
|
|
/* If the local MP is the selector MP, it shall verify that the selected AKM suite and pairwise cipher */
|
|
/* suite values match its selections that have been sent to the candidate peer MP in the peer link open */
|
|
/* frame. */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
if ((state == SUBTYPE_PEER_LINK_CONFIRM) && (pMeshLinkEntry->bValidLocalMpAsSelector))
|
|
{
|
|
if (!NdisEqualMemory(&pRcvdMsaIe[akm_offset], &pMeshLinkEntry->LocalMsaIe[akm_offset], LEN_OUI_SUITE))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected AKM in P.L. confirm frame isn't supported by local Selector MP \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
|
|
if (!NdisEqualMemory(&pRcvdMsaIe[cipher_offset], &pMeshLinkEntry->LocalMsaIe[cipher_offset], LEN_OUI_SUITE))
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("The Selected Pairwise Cipher in P.L. confirm frame isn't supported by local Selector MP \n"));
|
|
return MESH_SECURITY_FAILED_VERIFICATION;
|
|
}
|
|
}
|
|
}
|
|
|
|
return MLME_SUCCESS;
|
|
|
|
}
|
|
|
|
BOOLEAN MeshPathRequestSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT8 *pFlag,
|
|
OUT UINT8 *pHopCount,
|
|
OUT UINT8 *pTTL,
|
|
OUT UINT32 *pID,
|
|
OUT PUCHAR pOrigMac,
|
|
OUT UINT32 *pOrigDsn,
|
|
OUT PUCHAR pProxyMac,
|
|
OUT UINT32 *pLifeTime,
|
|
OUT UINT32 *pMetric,
|
|
OUT UINT8 *pDestCount,
|
|
OUT PMESH_DEST_ENTRY pDestEntry)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UINT8 VarOffset = 0;
|
|
UINT8 EntryCount = 0;
|
|
MESH_PREQ_FLAG PreqFlag;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_PREQ:
|
|
{
|
|
NdisMoveMemory(pFlag, eid_ptr->Octet, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pHopCount, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pTTL, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pID, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pID = le2cpu32(*pID);
|
|
NdisMoveMemory(pOrigMac, eid_ptr->Octet + VarOffset, MAC_ADDR_LEN);
|
|
VarOffset += MAC_ADDR_LEN;
|
|
NdisMoveMemory(pOrigDsn, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pOrigDsn = le2cpu32(*pOrigDsn);
|
|
PreqFlag = (MESH_PREQ_FLAG)(*pFlag);
|
|
if (PreqFlag.field.AE == 1)
|
|
{
|
|
NdisMoveMemory(pProxyMac, eid_ptr->Octet + VarOffset, MAC_ADDR_LEN);
|
|
VarOffset += MAC_ADDR_LEN;
|
|
}
|
|
NdisMoveMemory(pLifeTime, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pLifeTime = le2cpu32(*pLifeTime);
|
|
NdisMoveMemory(pMetric, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pMetric = le2cpu32(*pMetric);
|
|
NdisMoveMemory(pDestCount, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
EntryCount = (*pDestCount);
|
|
if (EntryCount >= 1)
|
|
NdisMoveMemory(pDestEntry, eid_ptr->Octet + VarOffset, 11*EntryCount);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshPathResponseSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT8 *pFlag,
|
|
OUT UINT8 *pHopCount,
|
|
OUT UINT8 *pTTL,
|
|
OUT PUCHAR pDestMac,
|
|
OUT UINT32 *pDesDsn,
|
|
OUT PUCHAR pProxyMac,
|
|
OUT UINT32 *pLifeTime,
|
|
OUT UINT32 *pMetric,
|
|
OUT PUCHAR pOrigMac,
|
|
OUT UINT32 *pOrigDsn,
|
|
OUT UINT8 *pDependMPCount,
|
|
OUT PMESH_DEPENDENT_ENTRY pDependEntry)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UINT8 VarOffset = 0;
|
|
UINT8 EntryCount = 0;
|
|
MESH_PREP_FLAG PrepFlag;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_PREP:
|
|
{
|
|
NdisMoveMemory(pFlag, eid_ptr->Octet, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pHopCount, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pTTL, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pDestMac, eid_ptr->Octet + VarOffset, MAC_ADDR_LEN);
|
|
VarOffset += MAC_ADDR_LEN;
|
|
NdisMoveMemory(pDesDsn, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pDesDsn = le2cpu32(*pDesDsn);
|
|
PrepFlag = (MESH_PREP_FLAG)(*pFlag);
|
|
if (PrepFlag.field.AE == 1)
|
|
{
|
|
NdisMoveMemory(pProxyMac, eid_ptr->Octet + VarOffset, MAC_ADDR_LEN);
|
|
VarOffset += MAC_ADDR_LEN;
|
|
}
|
|
NdisMoveMemory(pLifeTime, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pLifeTime = le2cpu32(*pLifeTime);
|
|
NdisMoveMemory(pMetric, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pMetric = le2cpu32(*pMetric);
|
|
NdisMoveMemory(pOrigMac, eid_ptr->Octet + VarOffset, MAC_ADDR_LEN);
|
|
VarOffset += MAC_ADDR_LEN;
|
|
NdisMoveMemory(pOrigDsn, eid_ptr->Octet + VarOffset, 4);
|
|
VarOffset += 4;
|
|
*pOrigDsn = le2cpu32(*pOrigDsn);
|
|
NdisMoveMemory(pDependMPCount, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
EntryCount = (*pDependMPCount);
|
|
if (EntryCount >= 1)
|
|
NdisMoveMemory(pDependEntry, eid_ptr->Octet + VarOffset, 10*EntryCount);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshPathErrorSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT UINT8 *pFlag,
|
|
OUT UINT8 *pDestNum,
|
|
OUT PMESH_PERR_ENTRY pErrorEntry)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UINT8 VarOffset = 0;
|
|
UINT8 EntryCount = 0;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_PREP:
|
|
{
|
|
NdisMoveMemory(pFlag, eid_ptr->Octet, 1);
|
|
VarOffset += 1;
|
|
NdisMoveMemory(pDestNum, eid_ptr->Octet + VarOffset, 1);
|
|
VarOffset += 1;
|
|
EntryCount = (*pDestNum);
|
|
if (EntryCount >= 1)
|
|
NdisMoveMemory(pErrorEntry, eid_ptr->Octet + VarOffset, 10*EntryCount);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN MeshLinkMetricReportSanity(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN VOID *pMsg,
|
|
IN ULONG MsgLen,
|
|
OUT PUINT32 pLinkMetric)
|
|
{
|
|
PEID_STRUCT eid_ptr;
|
|
UINT32 LinkMetric;
|
|
|
|
eid_ptr = (PEID_STRUCT)pMsg;
|
|
|
|
while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pMsg + MsgLen))
|
|
{
|
|
switch(eid_ptr->Eid)
|
|
{
|
|
case IE_MESH_LINK_METRIC_REPORT:
|
|
{
|
|
if (eid_ptr->Len == 4)
|
|
{
|
|
NdisMoveMemory(&LinkMetric, eid_ptr->Octet, eid_ptr->Len);
|
|
*pLinkMetric = le2cpu32(LinkMetric);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif /* MESH_SUPPORT */
|