Files
Linux_Drivers/osdrv/extdrv/wireless/mediatek/mt7603/common/pmf.c
forum_service 213c880673 add driver of tp、wiegand-gpio and wireless
Change-Id: Ie3c11d9d85cf1a05042f5690ac711856fe8b1ad7
2023-12-22 09:56:05 +08:00

1827 lines
53 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.
***************************************************************************/
/****************************************************************************
Abstract:
IEEE P802.11w
***************************************************************************/
#ifdef DOT11W_PMF_SUPPORT
#ifdef RELEASE_EXCLUDE
/*
PMF algorithem encryption support
* Mode 0: All packets do software encryption
* Mode 1: Data packets do hardware encryption, management packet do software encryption.
chipset | Mode Type
---------------------------
RT2XXX | 0
RT3050 | 0
RT3052 | 0
RT3062 | 0
RT3070 | 0
RT3090 | 0
RT3350 | 0
RT3352 | 1
RT3562 | 0
RT3572 | 0
RT3573 | 0
RT3593 | 1
RT3883 | 1
RT5XXX | 1
@AP
Mapping table from profile to RSNIE of Beacon
-----------------------------------------------------------------------------------------------
| Setting by profile or iwpriv ||Action after APStartUp||Beacon Capability & AKM |
|-------------------------------------------||----------------------||------------------------|
|Desired_MFPC|Desired_MFPR|Desired_PMFSHA256|| MFPC |MFPR |PMFSHA256|| MFPC|MFPR | SHA1|SHA256|
|-------------------------------------------||----------------------||------------------------|
| 0 | 0 | 0 || 0 | 0 | 0 || 0 | 0 | 1 | 0 |
| 0 | 0 | 1 || 0 | 0 | 0 || 0 | 0 | 1 | 1 |
| 1 | 0 | 0 || 1 | 0 | 0 || 1 | 0 | 1 | 0 |
| 1 | 0 | 1 || 1 | 0 | 1 || 1 | 0 | 1 | 1 |
| 0/1 | 1 | 0/1 || 1 | 1 | 1 || 1 | 1 | 0 | 1 |
-----------------------------------------------------------------------------------------------
@STA
Mapping table from profile to RSNIE of Beacon
-----------------------------------------------------------------------------------------------
| Setting by profile or iwpriv ||Beacon Capability & AKM || || 4-Way |
|-------------------------------------------||------------------------|| PMF || |
|Desired_MFPC|Desired_MFPR|Desired_PMFSHA256|| MFPC|MFPR | SHA1|SHA256|| Connection || SHA256 |
|-------------------------------------------||------------------------||------------||--------|
| 0 | 0 | 0 || 0 | 0 | 1 | 0 || 0 || 0 |
| 0 | 0 | 1 || 0 | 0 | 1 | 1 || 0 || 1 |
| 1 | 0 | 0 || 1 | 0 | 1 | 0 || 1 || 0 |
| 1 | 0 | 1 || 1 | 0 | 1 | 1 || 1 || 1 |
| 0/1 | 1 | 0/1 || 1 | 1 | 0 | 1 || 1 || 1 |
-----------------------------------------------------------------------------------------------
*/
#endif /* RELEASE_EXCLUDE */
#include "rt_config.h"
/* The definition in IEEE 802.11w - Table 7-32 Cipher suite selectors */
UCHAR OUI_PMF_BIP_CIPHER[4]= {0x00, 0x0F, 0xAC, 0x06};
/* The definition in IEEE 802.11w - Table 7-34 AKM suite selectors */
UCHAR OUI_PMF_8021X_AKM[4]= {0x00, 0x0F, 0xAC, 0x05};
UCHAR OUI_PMF_PSK_AKM[4]= {0x00, 0x0F, 0xAC, 0x06};
UCHAR PMF_MMIE_BUFFER[18]= {0x4C, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#define SAQ_IDLE 0
#define SAQ_RETRY 1
#define SAQ_SENDING 2
VOID PMF_PeerAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Action = Elem->Msg[LENGTH_802_11+1];
DBGPRINT(RT_DEBUG_WARN, ("[PMF]%s : PMF_PeerAction Action=%d\n", __FUNCTION__, Action));
switch (Action) {
case ACTION_SAQ_REQUEST:
PMF_PeerSAQueryReqAction(pAd, Elem);
break;
case ACTION_SAQ_RESPONSE:
PMF_PeerSAQueryRspAction(pAd, Elem);
break;
}
}
VOID PMF_MlmeSAQueryReq(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry)
{
PUCHAR pOutBuffer = NULL;
HEADER_802_11 SAQReqHdr;
UINT32 FrameLen = 0;
UCHAR SACategoryType, SAActionType;
//UINT ccmp_len = LEN_CCMP_HDR + LEN_CCMP_MIC;
//UCHAR ccmp_buf[ccmp_len];
PPMF_CFG pPmfCfg = NULL;
if (!pEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is NULL\n", __FUNCTION__));
return;
}
if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE)))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is not PMF capable, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pEntry->Addr)));
return;
}
if (pEntry->SAQueryStatus == SAQ_SENDING)
return;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
pPmfCfg = &pAd->ApCfg.MBSSID[pEntry->func_tb_idx].PmfCfg;
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
pPmfCfg = &pAd->StaCfg.PmfCfg;
}
#endif /* CONFIG_STA_SUPPORT */
if (pPmfCfg)
{
/* Send the SA Query Request */
os_alloc_mem(NULL, (UCHAR **)&pOutBuffer, MAX_LEN_OF_MLME_BUFFER);
if(pOutBuffer == NULL)
return;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
MgtMacHeaderInit(pAd, &SAQReqHdr, SUBTYPE_ACTION, 0, pEntry->Addr,
pAd->ApCfg.MBSSID[pEntry->func_tb_idx].wdev.bssid,
pAd->ApCfg.MBSSID[pEntry->func_tb_idx].wdev.bssid);
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
MgtMacHeaderInit(pAd, &SAQReqHdr, SUBTYPE_ACTION, 0, pEntry->Addr,
pAd->CurrentAddress,
pEntry->Addr);
}
#endif /* CONFIG_STA_SUPPORT */
pEntry->TransactionID++;
SACategoryType = CATEGORY_SA;
SAActionType = ACTION_SAQ_REQUEST;
MakeOutgoingFrame(pOutBuffer, (ULONG *) &FrameLen,
sizeof(HEADER_802_11), &SAQReqHdr,
1, &SACategoryType,
1, &SAActionType,
2, &pEntry->TransactionID,
END_OF_ARGS);
if (pEntry->SAQueryStatus == SAQ_IDLE) {
RTMPSetTimer(&pEntry->SAQueryTimer, 1000); /* 1000ms */
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s -- SAQueryTimer\n", __FUNCTION__));
}
pEntry->SAQueryStatus = SAQ_SENDING;
RTMPSetTimer(&pEntry->SAQueryConfirmTimer, 200); /* 200ms */
/* transmit the frame */
MiniportMMRequest(pAd, QID_MGMT, pOutBuffer, FrameLen);
os_free_mem(NULL, pOutBuffer);
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - Send SA Query Request to STA(%02x:%02x:%02x:%02x:%02x:%02x)\n",
__FUNCTION__, PRINT_MAC(pEntry->Addr)));
}
}
VOID PMF_PeerSAQueryReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Action = Elem->Msg[LENGTH_802_11+1];
if (Action == ACTION_SAQ_REQUEST)
{
PMAC_TABLE_ENTRY pEntry;
PFRAME_802_11 pHeader;
USHORT TransactionID;
PUCHAR pOutBuffer = NULL;
HEADER_802_11 SAQRspHdr;
UINT32 FrameLen = 0;
UCHAR SACategoryType, SAActionType;
//UINT ccmp_len = LEN_CCMP_HDR + LEN_CCMP_MIC;
//UCHAR ccmp_buf[ccmp_len];
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Receive SA Query Request\n", __FUNCTION__));
pHeader = (PFRAME_802_11) Elem->Msg;
pEntry = MacTableLookup(pAd, pHeader->Hdr.Addr2);
if (!pEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is not found, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
return;
}
if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE)))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is not PMF capable, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
return;
}
NdisMoveMemory(&TransactionID, &Elem->Msg[LENGTH_802_11+2], sizeof(USHORT));
/* Response the SA Query */
os_alloc_mem(NULL, (UCHAR **)&pOutBuffer, MAX_LEN_OF_MLME_BUFFER);
if(pOutBuffer == NULL)
return;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
MgtMacHeaderInit(pAd, &SAQRspHdr, SUBTYPE_ACTION, 0, pHeader->Hdr.Addr2,
pAd->ApCfg.MBSSID[pEntry->func_tb_idx].wdev.bssid,
pAd->ApCfg.MBSSID[pEntry->func_tb_idx].wdev.bssid);
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
MgtMacHeaderInit(pAd, &SAQRspHdr, SUBTYPE_ACTION, 0, pHeader->Hdr.Addr2,
pAd->CurrentAddress,
pHeader->Hdr.Addr2);
}
#endif /* CONFIG_STA_SUPPORT */
SACategoryType = CATEGORY_SA;
SAActionType = ACTION_SAQ_RESPONSE;
MakeOutgoingFrame(pOutBuffer, (ULONG *) &FrameLen,
sizeof(HEADER_802_11), &SAQRspHdr,
1, &SACategoryType,
1, &SAActionType,
2, &TransactionID,
END_OF_ARGS);
/* transmit the frame */
MiniportMMRequest(pAd, QID_MGMT, pOutBuffer, FrameLen);
os_free_mem(NULL, pOutBuffer);
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - Send SA Query Response to STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(SAQRspHdr.Addr1)));
}
}
VOID PMF_PeerSAQueryRspAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Action = Elem->Msg[LENGTH_802_11+1];
if (Action == ACTION_SAQ_RESPONSE)
{
PMAC_TABLE_ENTRY pEntry;
PFRAME_802_11 pHeader;
USHORT TransactionID;
BOOLEAN Cancelled;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Receive SA Query Response\n", __FUNCTION__));
pHeader = (PFRAME_802_11) Elem->Msg;
pEntry = MacTableLookup(pAd, pHeader->Hdr.Addr2);
if (!pEntry)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is not found, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
return;
}
if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE)))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Entry is not PMF capable, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
return;
}
NdisMoveMemory(&TransactionID, &Elem->Msg[LENGTH_802_11+2], sizeof(USHORT));
if (pEntry->TransactionID == TransactionID)
{
pEntry->SAQueryStatus = SAQ_IDLE;
RTMPCancelTimer(&pEntry->SAQueryTimer, &Cancelled);
RTMPCancelTimer(&pEntry->SAQueryConfirmTimer, &Cancelled);
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - Compare TransactionID correctly, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
}
else
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - Compare TransactionID wrong, STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pHeader->Hdr.Addr2)));
}
}
}
VOID PMF_SAQueryTimeOut(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
MAC_TABLE_ENTRY *pEntry = (MAC_TABLE_ENTRY *)FunctionContext;
if (pEntry)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER*)pEntry->pAd;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - STA(%02x:%02x:%02x:%02x:%02x:%02x)\n",
__FUNCTION__, PRINT_MAC(pEntry->Addr)));
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
MacTableDeleteEntry(pAd, pEntry->wcid, pEntry->Addr);
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
BOOLEAN Cancelled;
MLME_DISASSOC_REQ_STRUCT DisassocReq;
RTMPCancelTimer(&pEntry->SAQueryTimer, &Cancelled);
RTMPCancelTimer(&pEntry->SAQueryConfirmTimer, &Cancelled);
DisassocParmFill(pAd, &DisassocReq,
pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE,
MT2_MLME_DISASSOC_REQ,
sizeof (MLME_DISASSOC_REQ_STRUCT),
&DisassocReq, 0);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
}
#endif /* CONFIG_STA_SUPPORT */
}
}
VOID PMF_SAQueryConfirmTimeOut(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
MAC_TABLE_ENTRY *pEntry = (MAC_TABLE_ENTRY *)FunctionContext;
if (pEntry)
{
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pEntry->pAd;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s - STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", __FUNCTION__, PRINT_MAC(pEntry->Addr)));
pEntry->SAQueryStatus = SAQ_RETRY;
PMF_MlmeSAQueryReq(pAd, pEntry);
}
}
VOID PMF_ConstructBIPAad(
IN PUCHAR pHdr,
OUT UCHAR *aad_hdr)
{
UINT8 aad_len = 0;
/* Frame control -
Retry bit (bit 11) masked to 0
PwrMgt bit (bit 12) masked to 0
MoreData bit (bit 13) masked to 0 */
aad_hdr[0] = (*pHdr);
aad_hdr[1] = (*(pHdr + 1)) & 0xc7;
aad_len = 2;
/* Append Addr 1, 2 & 3 */
NdisMoveMemory(&aad_hdr[aad_len], pHdr + 4, 3 * MAC_ADDR_LEN);
aad_len += (3 * MAC_ADDR_LEN);
}
BOOLEAN PMF_CalculateBIPMIC(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pAadHdr,
IN PUCHAR pFrameBuf,
IN UINT32 FrameLen,
IN PUCHAR pKey,
OUT PUCHAR pBipMic)
{
UCHAR *m_buf;
UINT32 total_len;
UCHAR cmac_output[16];
UINT mlen = AES_KEY128_LENGTH;
/* Allocate memory for MIC calculation */
os_alloc_mem(NULL, (PUCHAR *)&m_buf, MGMT_DMA_BUFFER_SIZE);
if (m_buf == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : out of resource.\n", __FUNCTION__));
return FALSE;
}
/* Initialize the buffer */
NdisZeroMemory(m_buf, MGMT_DMA_BUFFER_SIZE);
/* Construct the concatenation */
NdisMoveMemory(m_buf, pAadHdr, LEN_PMF_BIP_AAD_HDR);
total_len = LEN_PMF_BIP_AAD_HDR;
/* Append the Mgmt frame into the concatenation */
NdisMoveMemory(&m_buf[total_len], pFrameBuf, FrameLen);
total_len += FrameLen;
/* Compute AES-128-CMAC over the concatenation */
AES_CMAC(m_buf, total_len, pKey, 16, cmac_output, &mlen);
/* Truncate the first 64-bits */
NdisMoveMemory(pBipMic, cmac_output, LEN_PMF_BIP_MIC);
os_free_mem(NULL, m_buf);
return TRUE;
}
VOID PMF_DerivePTK(
IN PRTMP_ADAPTER pAd,
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'};
/* initiate the concatenation input */
NdisZeroMemory(temp, sizeof(temp));
NdisZeroMemory(concatenation, 76);
/* Get smaller address */
if (RTMPCompareMemory(SA, AA, 6) == 1)
NdisMoveMemory(concatenation, AA, 6);
else
NdisMoveMemory(concatenation, SA, 6);
CurrPos += 6;
/* Get larger address */
if (RTMPCompareMemory(SA, AA, 6) == 1)
NdisMoveMemory(&concatenation[CurrPos], SA, 6);
else
NdisMoveMemory(&concatenation[CurrPos], AA, 6);
/* store the larger mac address for backward compatible of
ralink proprietary STA-key issue */
NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN);
CurrPos += 6;
/* Get smaller Nonce */
if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
NdisMoveMemory(&concatenation[CurrPos], temp, 32);
else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
else
NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
CurrPos += 32;
/* Get larger Nonce */
if (RTMPCompareMemory(ANonce, SNonce, 32) == 0)
NdisMoveMemory(&concatenation[CurrPos], temp, 32);
else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1)
NdisMoveMemory(&concatenation[CurrPos], ANonce, 32);
else
NdisMoveMemory(&concatenation[CurrPos], SNonce, 32);
CurrPos += 32;
hex_dump("[PMF]PMK", PMK, LEN_PMK);
hex_dump("[PMF]concatenation=", concatenation, 76);
/* Calculate a key material through FT-KDF */
KDF(PMK, LEN_PMK, Prefix, 22, concatenation, 76, output, len);
}
/*
========================================================================
Routine Description:
Derive IGTK randomly
IGTK, a hierarchy consisting of a single key to provide integrity
protection for broadcast and multicast Robust Management frames
Arguments:
Return Value:
Note:
It's defined in IEEE 802.11w 8.5.1.3a
========================================================================
*/
VOID PMF_DeriveIGTK(
IN PRTMP_ADAPTER pAd,
OUT UCHAR *output)
{
INT i;
for(i = 0; i < LEN_TK; i++)
output[i] = RandomByte(pAd);
}
/*
========================================================================
Routine Description:
Insert IGTK KDE. The field shall be included in pair-Msg3-WPA2 and
group-Msg1-WPA2.
Arguments:
Return Value:
Note:
========================================================================
*/
VOID PMF_InsertIGTKKDE(
IN PRTMP_ADAPTER pAd,
IN INT apidx,
IN PUCHAR pFrameBuf,
OUT PULONG pFrameLen)
{
PPMF_IGTK_KDE igtk_kde_ptr;
UINT8 idx = 0;
PPMF_CFG pPmfCfg = NULL;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
pPmfCfg = &pAd->ApCfg.MBSSID[apidx].PmfCfg;
#endif /* CONFIG_AP_SUPPORT */
if (!pPmfCfg)
return;
/* Construct the common KDE format */
WPA_ConstructKdeHdr(KDE_IGTK, LEN_PMF_IGTK_KDE, pFrameBuf);
/* Prepare the IGTK KDE */
igtk_kde_ptr = (PPMF_IGTK_KDE)(pFrameBuf + LEN_KDE_HDR);
NdisZeroMemory(igtk_kde_ptr, LEN_PMF_IGTK_KDE);
/* Bits 0-11 define a value in the range 0-4095.
Bits 12 - 15 are reserved and set to 0 on transmission and ignored on reception.
The IGTK Key ID is either 4 or 5. The remaining Key IDs are reserved. */
igtk_kde_ptr->KeyID[0] = pPmfCfg->IGTK_KeyIdx;
idx = (pPmfCfg->IGTK_KeyIdx == 5) ? 1 : 0;
/* Fill in the IPN field */
NdisMoveMemory(igtk_kde_ptr->IPN, &pPmfCfg->IPN[idx][0], LEN_WPA_TSC);
/* Fill uin the IGTK field */
NdisMoveMemory(igtk_kde_ptr->IGTK, &pPmfCfg->IGTK[idx][0], LEN_AES_GTK);
/* Update the total output length */
*pFrameLen = *pFrameLen + LEN_KDE_HDR + LEN_PMF_IGTK_KDE;
return;
}
/*
========================================================================
Routine Description:
Extract IGTK KDE.
Arguments:
Return Value:
Note:
========================================================================
*/
BOOLEAN PMF_ExtractIGTKKDE(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pBuf,
IN INT buf_len)
{
PPMF_IGTK_KDE igtk_kde_ptr;
UINT8 idx = 0;
UINT8 offset = 0;
PPMF_CFG pPmfCfg = NULL;
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
pPmfCfg = &pAd->StaCfg.PmfCfg;
#endif /* CONFIG_STA_SUPPORT */
if (pPmfCfg == NULL)
return FALSE;
igtk_kde_ptr = (PPMF_IGTK_KDE) pBuf;
pPmfCfg->IGTK_KeyIdx = igtk_kde_ptr->KeyID[0];
if (pPmfCfg->IGTK_KeyIdx == 5)
idx = 1;
offset += 2;
NdisMoveMemory(&pPmfCfg->IPN[idx][0], igtk_kde_ptr->IPN, LEN_WPA_TSC);
offset += LEN_WPA_TSC;
if ((buf_len - offset) == LEN_AES_GTK)
{
NdisMoveMemory(&pPmfCfg->IGTK[idx][0], igtk_kde_ptr->IGTK, LEN_AES_GTK);
}
else
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : the IGTK length(%d) is invalid\n",
__FUNCTION__, (buf_len - offset)));
return FALSE;
}
DBGPRINT(RT_DEBUG_TRACE, ("%s : IGTK_Key_ID=%d\n",
__FUNCTION__, pPmfCfg->IGTK_KeyIdx));
return TRUE;
}
/*
========================================================================
Routine Description:
Build Group Management Cipher in RSN-IE.
It only shall be called by RTMPMakeRSNIE.
Arguments:
pAd - pointer to our pAdapter context
ElementID - indicate the WPA1 or WPA2
apidx - indicate the interface index
Return Value:
Note:
========================================================================
*/
#ifdef WPA3_SUPPORT
VOID PMF_MakeRsnIeGMgmtCipher(
IN PRTMP_ADAPTER pAd,
IN UCHAR ElementID,
IN UINT32 AKMSuite,
IN P_RSN_INFO_T pRsnInfo,
IN UCHAR apidx,
OUT PUCHAR pRsnIe,
OUT UCHAR *rsn_len)
{
PUINT8 pBuf;
/* it could be ignored in WPA1 mode */
if (ElementID == WpaIe)
return;
pBuf = (pRsnIe + (*rsn_len));
if (AKMSuite == RSN_AKM_SUITE_SAE || AKMSuite == RSN_AKM_SUITE_OWE) {
/* Fill Group Management Cipher field */
NdisMoveMemory(pBuf, &pRsnInfo->u4GroupMgmtKeyCipherSuite, sizeof(UINT32));
(*rsn_len) += (sizeof(UINT32));
}
}
#else
VOID PMF_MakeRsnIeGMgmtCipher(
IN PRTMP_ADAPTER pAd,
IN UCHAR ElementID,
IN UCHAR apidx,
OUT PUCHAR pRsnIe,
OUT UCHAR *rsn_len)
{
PUINT8 pBuf;
BOOLEAN MFP_Enabled = FALSE;
/* it could be ignored in WPA1 mode */
if (ElementID == WpaIe)
return;
pBuf = (pRsnIe + (*rsn_len));
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd) {
if (apidx < pAd->ApCfg.BssidNum) {
BSS_STRUCT *pMbss = &pAd->ApCfg.MBSSID[apidx];
MFP_Enabled = pMbss->PmfCfg.MFPC;
}
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd) {
MFP_Enabled = pAd->StaCfg.PmfCfg.MFPC;
}
#endif /* CONFIG_STA_SUPPORT */
/* default group management cipher suite in an RSNA with
Management Frame Protection enabled. */
if (MFP_Enabled)
{
NdisMoveMemory(pBuf, OUI_PMF_BIP_CIPHER, LEN_OUI_SUITE);
(*rsn_len) += sizeof(LEN_OUI_SUITE);
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: Insert BIP to the group management cipher of RSNIE\n", __FUNCTION__));
}
}
#endif
/*
========================================================================
Routine Description:
Arguments:
Return Value:
Note:
========================================================================
*/
NTSTATUS PMF_RsnCapableValidation(
IN PRTMP_ADAPTER pAd,
IN PUINT8 pRsnie,
IN UINT rsnie_len,
IN BOOLEAN self_MFPC,
IN BOOLEAN self_MFPR,
IN PMAC_TABLE_ENTRY pEntry)
{
UINT8 count;
PUINT8 pBuf = NULL;
BOOLEAN peer_MFPC = FALSE, peer_MFPR = FALSE;
/* Check the peer's MPFC and MPFR -
Refer to Table 8-1a, IEEE 802.11W to check the PMF policy */
if ((pBuf = WPA_ExtractSuiteFromRSNIE(pRsnie, rsnie_len, RSN_CAP_INFO, &count)) == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : Peer's MPFC isn't used.\n", __FUNCTION__));
if (self_MFPR)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : PMF policy violation.\n", __FUNCTION__));
return PMF_POLICY_VIOLATION;
}
}
else
{
RSN_CAPABILITIES RsnCap;
NdisMoveMemory(&RsnCap, pBuf, sizeof(RSN_CAPABILITIES));
RsnCap.word = cpu2le16(RsnCap.word);
peer_MFPC = RsnCap.field.MFPC;
peer_MFPR = RsnCap.field.MFPR;
if ((self_MFPC == TRUE) && (peer_MFPC == FALSE ))
{
if ((self_MFPR == TRUE) && (peer_MFPR == FALSE))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : PMF policy violation for case 4\n", __FUNCTION__));
return PMF_POLICY_VIOLATION;
}
if (peer_MFPR == TRUE)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : PMF policy violation for case 7\n", __FUNCTION__));
return PMF_POLICY_VIOLATION;
}
}
if ((self_MFPC == TRUE) && (peer_MFPC == TRUE))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: PMF Connection \n", __FUNCTION__));
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE);
}
}
/* SHA1 or SHA256 */
if ((self_MFPC == TRUE)
&& (pBuf = WPA_ExtractSuiteFromRSNIE(pRsnie, rsnie_len, AKM_SUITE, &count)) != NULL)
{
UCHAR OUI_WPA2_1X_SHA256[4] = {0x00, 0x0F, 0xAC, 0x05};
UCHAR OUI_WPA2_PSK_SHA256[4] = {0x00, 0x0F, 0xAC, 0x06};
while (count > 0)
{
if(RTMPEqualMemory(pBuf,OUI_WPA2_1X_SHA256,4) || RTMPEqualMemory(pBuf,OUI_WPA2_PSK_SHA256,4) )
{
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_USE_SHA256);
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : SHA256 Support\n", __FUNCTION__));
}
pBuf += 4;
count--;
}
}
return PMF_STATUS_SUCCESS;
}
/*
========================================================================
Routine Description:
Decide if the frame is PMF Robust frame
Arguments:
pHdr : pointer to the 802.11 header
pFrame : point to frame body. It exclude the 802.11 header
frame_len : the frame length without 802.11 header
Return Value:
NOT_ROBUST_FRAME
UNICAST_ROBUST_FRAME
GROUP_ROBUST_FRAME
Note:
========================================================================
*/
INT PMF_RobustFrameClassify(
IN PHEADER_802_11 pHdr,
IN PUCHAR pFrame,
IN UINT frame_len,
IN PUCHAR pData,
IN BOOLEAN IsRx)
{
PMAC_TABLE_ENTRY pEntry = (PMAC_TABLE_ENTRY)pData;
if ((pHdr->FC.Type != FC_TYPE_MGMT) || (frame_len <= 0))
return NORMAL_FRAME;
/* Classify the frame */
switch (pHdr->FC.SubType)
{
case SUBTYPE_DISASSOC:
case SUBTYPE_DEAUTH:
break;
case SUBTYPE_ACTION:
{
if ((IsRx == FALSE)
|| (IsRx && (pHdr->FC.Wep == 0)))
{
UCHAR Category = (UCHAR) (pHdr->Octet[0]);
switch (Category)
{
/* Refer to IEEE 802.11w Table7-24 */
case CATEGORY_SPECTRUM:
case CATEGORY_QOS:
case CATEGORY_DLS:
case CATEGORY_BA:
case CATEGORY_RM:
case CATEGORY_FT:
case CATEGORY_SA:
case CATEGORY_PD:
case CATEGORY_VSP:
break;
default:
return NORMAL_FRAME;
}
}
break;
}
default:
return NORMAL_FRAME;
}
if (pHdr->Addr1[0] & 0x01) /* Broadcast frame */
{
UINT8 offset_mmie;
if (frame_len <= (LEN_PMF_MMIE + 2))
return NOT_ROBUST_GROUP_FRAME;
/* The offset of MMIE */
offset_mmie = frame_len - (LEN_PMF_MMIE + 2);
/* check if this is a group Robust frame */
if (((*(pFrame + offset_mmie)) == IE_PMF_MMIE) &&
((*(pFrame + offset_mmie + 1)) == LEN_PMF_MMIE))
return GROUP_ROBUST_FRAME;
else
return NOT_ROBUST_GROUP_FRAME;
}
/* Unicast frame */
else if (((IsRx == TRUE) && (pHdr->FC.Wep == 1)) || (IsRx == FALSE))
return UNICAST_ROBUST_FRAME;
else if (pEntry == NULL)
return NORMAL_FRAME;
else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE) && (pHdr->FC.Wep == 0) && (IsRx == TRUE))
return NOT_ROBUST_UNICAST_FRAME;
else if (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
return NORMAL_FRAME;
return ERROR_FRAME;
}
INT PMF_EncryptUniRobustFrameAction(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pMgmtFrame,
IN UINT mgmt_len)
{
PMAC_TABLE_ENTRY pEntry = NULL;
PHEADER_802_11 pHdr = (PHEADER_802_11)pMgmtFrame;
INT data_len;
PUCHAR pBuf;
INT Status;
/* Check if the length is valid */
data_len = mgmt_len - (LENGTH_802_11 + LEN_CCMP_HDR + LEN_CCMP_MIC);
if (data_len <= 0)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : The payload length(%d) is invalid\n",
__FUNCTION__, data_len));
return PMF_UNICAST_ENCRYPT_FAILURE;
}
/* Look up the entry through Address 1 of 802.11 header */
pEntry = MacTableLookup(pAd, pHdr->Addr1);
if (pEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : The entry doesn't exist\n", __FUNCTION__));
return PMF_UNICAST_ENCRYPT_FAILURE;
}
/* check the PMF capable for this entry */
if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE) == FALSE)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : the entry no PMF capable !\n", __FUNCTION__));
return PMF_UNICAST_ENCRYPT_FAILURE;
}
/* Allocate a buffer for building PMF packet */
Status = MlmeAllocateMemory(pAd, &pBuf);
if (Status != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : allocate PMF buffer fail!\n", __FUNCTION__));
return PMF_UNICAST_ENCRYPT_FAILURE;
}
/* Construct and insert 8-bytes CCMP header to MPDU header */
RTMPConstructCCMPHdr(0, pEntry->PmfTxTsc, pBuf);
NdisMoveMemory(pBuf + LEN_CCMP_HDR,
&pHdr->Octet[0],
data_len);
// Encrypt the MPDU data by software
RTMPSoftEncryptCCMP(pAd,
(PUCHAR)pHdr,
pEntry->PmfTxTsc,
pEntry->PairwiseKey.Key,
pBuf + LEN_CCMP_HDR,
data_len);
data_len += (LEN_CCMP_HDR + LEN_CCMP_MIC);
NdisMoveMemory(&pHdr->Octet[0], pBuf, data_len);
/* TSC increment for next transmittion */
INC_TX_TSC(pEntry->PmfTxTsc, LEN_WPA_TSC);
MlmeFreeMemory(pAd, pBuf);
return PMF_STATUS_SUCCESS;
}
INT PMF_DecryptUniRobustFrameAction(
IN PRTMP_ADAPTER pAd,
INOUT PUCHAR pMgmtFrame,
IN UINT mgmt_len)
{
PMAC_TABLE_ENTRY pEntry = NULL;
PHEADER_802_11 pHeader = (PHEADER_802_11)pMgmtFrame;
PUCHAR pDate = pMgmtFrame + LENGTH_802_11;
UINT16 data_len = mgmt_len - LENGTH_802_11;
/* Check if the length is valid */
if (data_len <= LEN_CCMP_HDR + LEN_CCMP_MIC)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : The payload length(%d) is invalid\n",
__FUNCTION__, data_len));
return PMF_UNICAST_DECRYPT_FAILURE;
}
/* Look up the entry through Address 2 of 802.11 header */
pEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : the entry doesn't exist !\n", __FUNCTION__));
return PMF_STATUS_SUCCESS;
}
/* check the PMF capable for this entry */
if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE) == FALSE)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : the entry no PMF capable !\n", __FUNCTION__));
return PMF_UNICAST_DECRYPT_FAILURE;
}
if (RTMPSoftDecryptCCMP(pAd,
pMgmtFrame,
&pEntry->PairwiseKey,
pDate,
&data_len) == FALSE)
{
return PMF_UNICAST_DECRYPT_FAILURE;
}
return PMF_STATUS_SUCCESS;
}
INT PMF_EncapBIPAction(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pMgmtFrame,
IN UINT mgmt_len)
{
PHEADER_802_11 pHdr = (PHEADER_802_11)pMgmtFrame;
PPMF_CFG pPmfCfg = NULL;
PPMF_MMIE pMMIE;
INT idx = 0;
PUCHAR pKey = NULL;
UCHAR aad_hdr[LEN_PMF_BIP_AAD_HDR];
UCHAR BIP_MIC[LEN_PMF_BIP_MIC];
PUCHAR pFrameBody = &pHdr->Octet[0];
UINT32 body_len = mgmt_len - LENGTH_802_11;
/* Sanity check the total frame body length */
if (body_len <= (2 + LEN_PMF_MMIE))
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : the total length(%d) is too short\n",
__FUNCTION__, body_len));
return PMF_ENCAP_BIP_FAILURE;
}
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
pPmfCfg = &pAd->ApCfg.MBSSID[MAIN_MBSSID].PmfCfg;
}
#endif /* CONFIG_AP_SUPPORT */
/* Sanity check */
if (pPmfCfg == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : No related PMF configuation\n", __FUNCTION__));
return PMF_ENCAP_BIP_FAILURE;
}
if (pPmfCfg && pPmfCfg->MFPC == FALSE)
{
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s : PMF is disabled \n", __FUNCTION__));
return PMF_ENCAP_BIP_FAILURE;
}
/* Pointer to the position of MMIE */
pMMIE = (PPMF_MMIE)(pMgmtFrame + (mgmt_len - LEN_PMF_MMIE));
/* Select the IGTK currently active for transmission of frames to
the intended group of recipients and construct the MMIE (see 7.3.2.55)
with the MIC field masked to zero and the KeyID field set to the
corresponding IGTK KeyID value. */
if (pPmfCfg->IGTK_KeyIdx == 5)
idx = 1;
pKey = &pPmfCfg->IGTK[idx][0];
NdisZeroMemory(pMMIE, LEN_PMF_MMIE);
/* Bits 0-11 define a value in the range 0-4095.
Bits 12 - 15 are reserved and set to 0 on transmission and ignored on reception.
The IGTK Key ID is either 4 or 5. The remaining Key IDs are reserved. */
pMMIE->KeyID[0] = pPmfCfg->IGTK_KeyIdx;
NdisMoveMemory(pMMIE->IPN, &pPmfCfg->IPN[idx][0], LEN_WPA_TSC);
/* The transmitter shall insert a monotonically increasing non-neg-
ative integer into the MMIE IPN field. */
INC_TX_TSC(pPmfCfg->IPN[idx], LEN_WPA_TSC);
/* Compute AAD */
PMF_ConstructBIPAad((PUCHAR)pHdr, aad_hdr);
/* Calculate BIP MIC */
PMF_CalculateBIPMIC(pAd, aad_hdr, pFrameBody, body_len, pKey, BIP_MIC);
#if 0
if (pAd->chipCap.FlgPMFEncrtptMode != PMF_ENCRYPT_MODE_2)
{
/* Fill into the MMIE MIC field */
NdisMoveMemory(pMMIE->MIC, BIP_MIC, LEN_PMF_BIP_MIC);
}
#else
/* Fill into the MMIE MIC field */
NdisMoveMemory(pMMIE->MIC, BIP_MIC, LEN_PMF_BIP_MIC);
#endif
/* BIP doesn't need encrypt frame */
pHdr->FC.Wep = 0;
return PMF_STATUS_SUCCESS;
}
INT PMF_ExtractBIPAction(
IN PRTMP_ADAPTER pAd,
INOUT PUCHAR pMgmtFrame,
IN UINT mgmt_len)
{
PPMF_CFG pPmfCfg = NULL;
PMAC_TABLE_ENTRY pEntry = NULL;
PHEADER_802_11 pHeader = (PHEADER_802_11)pMgmtFrame;
PPMF_MMIE pMMIE;
INT idx = 0;
PUCHAR pKey = NULL;
UCHAR aad_hdr[LEN_PMF_BIP_AAD_HDR];
UCHAR rcvd_mic[LEN_PMF_BIP_MIC];
UCHAR cal_mic[LEN_PMF_BIP_MIC];
UINT32 body_len = mgmt_len - LENGTH_802_11;
/* Sanity check the total frame body length */
if (body_len <= (2 + LEN_PMF_MMIE))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : the total length(%d) is too short\n",
__FUNCTION__, body_len));
return PMF_EXTRACT_BIP_FAILURE;
}
/* Look up the entry through Address 2 of 802.11 header */
pEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : the entry doesn't exist !\n", __FUNCTION__));
return PMF_STATUS_SUCCESS;
}
/* check the PMF capable for this entry */
if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE) == FALSE)
{
DBGPRINT(RT_DEBUG_ERROR,("%s : the entry no PMF capable !\n", __FUNCTION__));
return PMF_EXTRACT_BIP_FAILURE;
}
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
pPmfCfg = &pAd->ApCfg.MBSSID[pEntry->func_tb_idx].PmfCfg;
}
#endif // CONFIG_AP_SUPPORT //
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
pPmfCfg = &pAd->StaCfg.PmfCfg;
}
#endif // CONFIG_STA_SUPPORT //
/* Pointer to the position of MMIE */
pMMIE = (PPMF_MMIE)(pMgmtFrame + (mgmt_len - LEN_PMF_MMIE));
/* Select the IGTK currently active for transmission of frames to
the intended group of recipients and construct the MMIE (see 7.3.2.55)
with the MIC field masked to zero and the KeyID field set to the
corresponding IGTK KeyID value. */
if (pMMIE->KeyID[0] == 5)
idx = 1;
pKey = &pPmfCfg->IGTK[idx][0];
/* store the MIC value of the received frame */
NdisMoveMemory(rcvd_mic, pMMIE->MIC, LEN_PMF_BIP_MIC);
NdisZeroMemory(pMMIE->MIC, LEN_PMF_BIP_MIC);
/* Compute AAD */
PMF_ConstructBIPAad((PUCHAR)pMgmtFrame, aad_hdr);
/* Calculate BIP MIC */
PMF_CalculateBIPMIC(pAd, aad_hdr,
pMgmtFrame + LENGTH_802_11,
body_len, pKey, cal_mic);
if (!NdisEqualMemory(rcvd_mic, cal_mic, LEN_PMF_BIP_MIC))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s : MIC Different !\n", __FUNCTION__));
return PMF_EXTRACT_BIP_FAILURE;
}
return PMF_STATUS_SUCCESS;
}
BOOLEAN PMF_PerformTxFrameAction(
IN PRTMP_ADAPTER pAd,
OUT PNDIS_PACKET pPacket)
{
PHEADER_802_11 pHeader_802_11;
PACKET_INFO PacketInfo;
PUCHAR pSrcBufVA;
UINT SrcBufLen;
#if !defined(MT7603) && !defined(MT7628)
UINT8 TXWISize = pAd->chipCap.TXWISize;
#endif
UINT8 tx_hw_hdr_len = pAd->chipCap.tx_hw_hdr_len;
INT FrameType;
INT ret = 0;
PMAC_TABLE_ENTRY pEntry = NULL;
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
if (pSrcBufVA == NULL)
return NORMAL_FRAME;
// TODO: shiang-7603
pHeader_802_11 = (HEADER_802_11 *) (pSrcBufVA + tx_hw_hdr_len);
pEntry = MacTableLookup(pAd, pHeader_802_11->Addr1);
if(pEntry == NULL)
return TRUE;
if (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
return TRUE;
FrameType = PMF_RobustFrameClassify(
(PHEADER_802_11)pHeader_802_11,
(PUCHAR)(pHeader_802_11 + LENGTH_802_11),
(SrcBufLen - LENGTH_802_11),
(PUCHAR) pEntry,
FALSE);
switch (FrameType)
{
case ERROR_FRAME:
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: ERROR FRAME\n", __FUNCTION__));
return FALSE;
case NORMAL_FRAME:
case NOT_ROBUST_GROUP_FRAME:
case NOT_ROBUST_UNICAST_FRAME:
break;
case UNICAST_ROBUST_FRAME:
{
int tailroom =0 ;
/*Not tx PMF for no capapble */
if (NULL != pEntry) {
if (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE)) {
DBGPRINT(RT_DEBUG_WARN, ("[PMF]%s: Not tx PMF for no capapble\n", __func__));
break;
}
}
tailroom = GET_OS_PKT_END(pPacket) - GET_OS_PKT_DATATAIL(pPacket);
pHeader_802_11->FC.Wep = 1;
/* Format: Mac header|CCMP header|Data|MIC|FCS */
if (tailroom < (LEN_CCMP_HDR + LEN_CCMP_MIC))
{
int headroom =GET_OS_PKT_DATAPTR(pPacket) - GET_OS_PKT_HEAD(pPacket) ;
pPacket = OS_PKT_COPY_EXPAND(pPacket, headroom, (LEN_CCMP_HDR + LEN_CCMP_MIC));
}
OS_PKT_TAIL_BUF_EXTEND(pPacket, (LEN_CCMP_HDR + LEN_CCMP_MIC));
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
if (pSrcBufVA == NULL)
return NORMAL_FRAME;
#if defined(MT7603) || defined(MT7628)
// TODO: shiang-7603
pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + tx_hw_hdr_len);
ret = PMF_EncryptUniRobustFrameAction(pAd,
(PUCHAR)pHeader_802_11,
(SrcBufLen - tx_hw_hdr_len));
#else
pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWISize);
ret = PMF_EncryptUniRobustFrameAction(pAd,
(PUCHAR)pHeader_802_11,
(SrcBufLen - TXINFO_SIZE - TXWISize));
#endif
break;
}
case GROUP_ROBUST_FRAME:
{
ret = PMF_EncapBIPAction(pAd,
(PUCHAR)pHeader_802_11,
SrcBufLen);
break;
}
}
if (ret == PMF_STATUS_SUCCESS)
return TRUE;
else
return FALSE;
}
/*
========================================================================
Routine Description:
Arguments:
Return Value:
Note:
========================================================================
*/
BOOLEAN PMF_PerformRxFrameAction(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk)
{
INT FrameType;
PUCHAR pMgmtFrame;
UINT mgmt_len;
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PMAC_TABLE_ENTRY pEntry = NULL;
pMgmtFrame = (PUCHAR)pHeader;
mgmt_len = pRxBlk->MPDUtotalByteCnt;
if (pRxBlk->wcid < MAX_LEN_OF_MAC_TABLE)
pEntry = &pAd->MacTab.Content[pRxBlk->wcid];
else
{
#ifdef CONFIG_STA_SUPPORT
if (INFRA_ON(pAd))
{
if ((pHeader->Addr1[0] & 0x01) &&
(pHeader->FC.Type == FC_TYPE_MGMT) &&
((pHeader->FC.SubType == SUBTYPE_DISASSOC) || (pHeader->FC.SubType == SUBTYPE_DEAUTH)))
{
pEntry = MacTableLookup(pAd, pHeader->Addr2);
if (!pEntry)
return TRUE;
else
{
if (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
return TRUE;
}
}
else
{
return TRUE;
}
}
else
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
if (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
{
#ifdef CONFIG_STA_SUPPORT
if (INFRA_ON(pAd))
{
if ((pHeader->Addr1[0] & 0x01) &&
(pHeader->FC.Type == FC_TYPE_MGMT) &&
((pHeader->FC.SubType == SUBTYPE_DISASSOC) || (pHeader->FC.SubType == SUBTYPE_DEAUTH)))
{
pEntry = MacTableLookup(pAd, pHeader->Addr2);
if (!pEntry)
return TRUE;
}
else
return TRUE;
}
else
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
FrameType = PMF_RobustFrameClassify(pHeader,
(PUCHAR)(pMgmtFrame + LENGTH_802_11),
(mgmt_len - LENGTH_802_11),
(PUCHAR) pEntry,
TRUE);
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
switch (FrameType)
{
case ERROR_FRAME:
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: ERROR FRAME\n", __FUNCTION__));
return FALSE;
case NORMAL_FRAME:
case NOT_ROBUST_GROUP_FRAME:
break;
case NOT_ROBUST_UNICAST_FRAME:
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: ERROR FRAME\n", __FUNCTION__));
return FALSE;
case UNICAST_ROBUST_FRAME:
{
if (pAd->chipCap.hif_type != HIF_MT)
{
if (PMF_DecryptUniRobustFrameAction(pAd,
pMgmtFrame,
mgmt_len) != PMF_STATUS_SUCCESS)
return FALSE;
pRxBlk->MPDUtotalByteCnt -= (LEN_CCMP_HDR + LEN_CCMP_MIC);
}
break;
}
case GROUP_ROBUST_FRAME:
{
if (pAd->chipCap.hif_type != HIF_MT)
{
if (PMF_ExtractBIPAction(pAd,
pMgmtFrame,
mgmt_len) != PMF_STATUS_SUCCESS)
return FALSE;
pRxBlk->MPDUtotalByteCnt -= (2 + LEN_PMF_MMIE);
}
break;
}
}
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
switch (FrameType)
{
case ERROR_FRAME:
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: ERROR FRAME\n", __FUNCTION__));
return FALSE;
case NORMAL_FRAME:
break;
case NOT_ROBUST_UNICAST_FRAME:
if (((pHeader->FC.SubType == SUBTYPE_DISASSOC) || (pHeader->FC.SubType == SUBTYPE_DEAUTH))
&& CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
{
PMF_MlmeSAQueryReq(pAd, pEntry);
return FALSE;
}
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s: ERROR FRAME\n", __FUNCTION__));
return FALSE;
case NOT_ROBUST_GROUP_FRAME:
if ((pEntry) && CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_PMF_CAPABLE))
return FALSE;
else
break;
case UNICAST_ROBUST_FRAME:
{
if (pAd->chipCap.hif_type != HIF_MT)
{
if (PMF_DecryptUniRobustFrameAction(pAd,
pMgmtFrame,
mgmt_len) != PMF_STATUS_SUCCESS)
return FALSE;
pRxBlk->MPDUtotalByteCnt -= (LEN_CCMP_HDR + LEN_CCMP_MIC);
}
break;
}
case GROUP_ROBUST_FRAME:
{
if (PMF_ExtractBIPAction(pAd,
pMgmtFrame,
mgmt_len) != PMF_STATUS_SUCCESS)
return FALSE;
pRxBlk->MPDUtotalByteCnt -= (2 + LEN_PMF_MMIE);
break;
}
}
}
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
/*
========================================================================
Routine Description:
Protection Management Frame Capable
Protection Management Frame Required
Arguments:
Return Value:
Note:
RSNA policy selection in a ESS: IEEE P802.11w Table 8-1a
RSNA policy selection in an IBSS: IEEE P802.11w Table 8-1b
========================================================================
*/
void rtmp_read_pmf_parameters_from_file(
IN PRTMP_ADAPTER pAd,
IN RTMP_STRING *tmpbuf,
IN RTMP_STRING *pBuffer)
{
RTMP_STRING *macptr;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
INT apidx;
POS_COOKIE pObj;
pObj = (POS_COOKIE) pAd->OS_Cookie;
for (apidx = 0; apidx < pAd->ApCfg.BssidNum; apidx++)
{
pAd->ApCfg.MBSSID[apidx].PmfCfg.Desired_MFPC = FALSE;
pAd->ApCfg.MBSSID[apidx].PmfCfg.Desired_MFPR = FALSE;
pAd->ApCfg.MBSSID[apidx].PmfCfg.Desired_PMFSHA256 = FALSE;
}
/* Protection Management Frame Capable */
if (RTMPGetKeyParameter("PMFMFPC", tmpbuf, 32, pBuffer, TRUE))
{
for (apidx = 0, macptr = rstrtok(tmpbuf,";"); (macptr && apidx < pAd->ApCfg.BssidNum); macptr = rstrtok(NULL,";"), apidx++)
{
pObj->ioctl_if = apidx;
Set_PMFMFPC_Proc(pAd, macptr);
}
}
/* Protection Management Frame Required */
if (RTMPGetKeyParameter("PMFMFPR", tmpbuf, 32, pBuffer, TRUE))
{
for (apidx = 0, macptr = rstrtok(tmpbuf,";"); (macptr && apidx < pAd->ApCfg.BssidNum); macptr = rstrtok(NULL,";"), apidx++)
{
pObj->ioctl_if = apidx;
Set_PMFMFPR_Proc(pAd, macptr);
}
}
if (RTMPGetKeyParameter("PMFSHA256", tmpbuf, 32, pBuffer, TRUE))
{
for (apidx = 0, macptr = rstrtok(tmpbuf,";"); (macptr && apidx < pAd->ApCfg.BssidNum); macptr = rstrtok(NULL,";"), apidx++)
{
pObj->ioctl_if = apidx;
Set_PMFSHA256_Proc(pAd, macptr);
}
}
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
pAd->StaCfg.PmfCfg.Desired_MFPC = FALSE;
pAd->StaCfg.PmfCfg.Desired_MFPR = FALSE;
pAd->StaCfg.PmfCfg.Desired_PMFSHA256 = FALSE;
/* Protection Management Frame Capable */
if (RTMPGetKeyParameter("PMFMFPC", tmpbuf, 32, pBuffer, TRUE))
Set_PMFMFPC_Proc(pAd, tmpbuf);
/* Protection Management Frame Required */
if (RTMPGetKeyParameter("PMFMFPR", tmpbuf, 32, pBuffer, TRUE))
Set_PMFMFPR_Proc(pAd, tmpbuf);
if (RTMPGetKeyParameter("PMFSHA256", tmpbuf, 32, pBuffer, TRUE))
Set_PMFSHA256_Proc(pAd, tmpbuf);
}
#endif /* CONFIG_STA_SUPPORT */
}
/*
========================================================================
Routine Description: Protection Management Frame Capable
Arguments:
Return Value:
Note:
RSNA policy selection in a ESS: IEEE P802.11w Table 8-1a
RSNA policy selection in an IBSS: IEEE P802.11w Table 8-1b
========================================================================
*/
INT Set_PMFMFPC_Proc (
IN PRTMP_ADAPTER pAd,
IN RTMP_STRING *arg)
{
if(strlen(arg) == 0)
return FALSE;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
POS_COOKIE pObj;
pObj = (POS_COOKIE) pAd->OS_Cookie;
if (simple_strtol(arg, 0, 10))
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPC = TRUE;
else
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPC = FALSE;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: apidx=%d, Desired MFPC=%d\n", __FUNCTION__
, pObj->ioctl_if, pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPC));
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (simple_strtol(arg, 0, 10))
pAd->StaCfg.PmfCfg.Desired_MFPC = TRUE;
else
{
pAd->StaCfg.PmfCfg.Desired_MFPC = FALSE;
#if 1 //also clear run time flags
pAd->StaCfg.PmfCfg.MFPC = FALSE;
pAd->StaCfg.PmfCfg.MFPR = FALSE;
//dont need to clear the SHA256
#endif
}
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: Desired MFPC=%d\n", __FUNCTION__
, pAd->StaCfg.PmfCfg.Desired_MFPC));
#if 1 //check the security dependency
{
if ((pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA2PSK
#ifdef WPA3_SUPPORT
|| pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA3SAE || pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA2PSKWPA3SAE
#endif
) && (pAd->StaCfg.wdev.WepStatus == Ndis802_11AESEnable))
{
pAd->StaCfg.PmfCfg.PMFSHA256 = pAd->StaCfg.PmfCfg.Desired_PMFSHA256;
if (pAd->StaCfg.PmfCfg.Desired_MFPC)
{
pAd->StaCfg.PmfCfg.MFPC = TRUE;
pAd->StaCfg.PmfCfg.MFPR = pAd->StaCfg.PmfCfg.Desired_MFPR;
if (pAd->StaCfg.PmfCfg.MFPR)
pAd->StaCfg.PmfCfg.PMFSHA256 = TRUE;
}
} else if (pAd->StaCfg.PmfCfg.Desired_MFPC) {
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: Security is not WPA2/WPA2PSK AES\n", __FUNCTION__));
}
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: MFPC=%d, MFPR=%d, SHA256=%d\n",
__FUNCTION__, pAd->StaCfg.PmfCfg.MFPC, pAd->StaCfg.PmfCfg.MFPR,
pAd->StaCfg.PmfCfg.PMFSHA256));
}
#endif
}
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
/*
========================================================================
Routine Description: Protection Management Frame Required
Arguments:
Return Value:
Note:
RSNA policy selection in a ESS: IEEE P802.11w Table 8-1a
RSNA policy selection in an IBSS: IEEE P802.11w Table 8-1b
========================================================================
*/
INT Set_PMFMFPR_Proc (
IN PRTMP_ADAPTER pAd,
IN RTMP_STRING *arg)
{
if(strlen(arg) == 0)
return FALSE;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
POS_COOKIE pObj;
pObj = (POS_COOKIE) pAd->OS_Cookie;
if (simple_strtol(arg, 0, 10))
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPR = TRUE;
else
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPR = FALSE;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: apidx=%d, Desired MFPR=%d\n", __FUNCTION__
, pObj->ioctl_if, pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_MFPR));
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (simple_strtol(arg, 0, 10))
pAd->StaCfg.PmfCfg.Desired_MFPR = TRUE;
else
{
pAd->StaCfg.PmfCfg.Desired_MFPR = FALSE;
#if 1 //also clear run time flags
//only close the MFPR
pAd->StaCfg.PmfCfg.MFPR = FALSE;
#endif
}
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: Desired MFPR=%d\n", __FUNCTION__
, pAd->StaCfg.PmfCfg.Desired_MFPR));
#if 1 //check the security dependency
{
if ((pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA2PSK
#ifdef WPA3_SUPPORT
|| pAd->StaCfg.wdev.AuthMode == Ndis802_11AuthModeWPA3SAE
#endif
) && (pAd->StaCfg.wdev.WepStatus == Ndis802_11AESEnable)) {
pAd->StaCfg.PmfCfg.PMFSHA256 = pAd->StaCfg.PmfCfg.Desired_PMFSHA256;
if (pAd->StaCfg.PmfCfg.Desired_MFPC)
{
pAd->StaCfg.PmfCfg.MFPC = TRUE;
pAd->StaCfg.PmfCfg.MFPR = pAd->StaCfg.PmfCfg.Desired_MFPR;
if (pAd->StaCfg.PmfCfg.MFPR)
pAd->StaCfg.PmfCfg.PMFSHA256 = TRUE;
}
} else if (pAd->StaCfg.PmfCfg.Desired_MFPC) {
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: Security is not WPA2/WPA2PSK AES\n", __FUNCTION__));
}
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: MFPC=%d, MFPR=%d, SHA256=%d\n",
__FUNCTION__, pAd->StaCfg.PmfCfg.MFPC, pAd->StaCfg.PmfCfg.MFPR,
pAd->StaCfg.PmfCfg.PMFSHA256));
}
#endif
}
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
INT Set_PMFSHA256_Proc (
IN PRTMP_ADAPTER pAd,
IN RTMP_STRING *arg)
{
if(strlen(arg) == 0)
return FALSE;
#ifdef CONFIG_AP_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_AP(pAd)
{
POS_COOKIE pObj;
pObj = (POS_COOKIE) pAd->OS_Cookie;
if (simple_strtol(arg, 0, 10))
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_PMFSHA256 = TRUE;
else
pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_PMFSHA256 = FALSE;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: apidx=%d, Desired PMFSHA256=%d\n", __FUNCTION__
, pObj->ioctl_if, pAd->ApCfg.MBSSID[pObj->ioctl_if].PmfCfg.Desired_PMFSHA256));
}
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
{
if (simple_strtol(arg, 0, 10))
pAd->StaCfg.PmfCfg.Desired_PMFSHA256 = TRUE;
else
pAd->StaCfg.PmfCfg.Desired_PMFSHA256 = FALSE;
DBGPRINT(RT_DEBUG_ERROR, ("[PMF]%s:: Desired PMFSHA256=%d\n", __FUNCTION__
, pAd->StaCfg.PmfCfg.Desired_PMFSHA256));
}
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
}
#endif /* DOT11W_PMF_SUPPORT */