blob: cc0bc86a91ac213fdab7075da321c76448205aab [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
** Id: mgmt/rsn.c#3
*/
/*! \file "rsn.c"
* \brief This file including the 802.11i, wpa and wpa2(rsn) related function.
*
* This file provided the macros and functions library support the wpa/rsn ie parsing,
* cipher and AKM check to help the AP seleced deciding, tkip mic error handler and rsn PMKID support.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "precomp.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to parse RSN IE.
*
* \param[in] prInfoElem Pointer to the RSN IE
* \param[out] prRsnInfo Pointer to the BSSDescription structure to store the
** RSN information from the given RSN IE
*
* \retval TRUE - Succeeded
* \retval FALSE - Failed
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prRsnInfo)
{
UINT_32 i;
INT_32 u4RemainRsnIeLen;
UINT_16 u2Version;
UINT_16 u2Cap = 0;
UINT_32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP;
UINT_16 u2PairSuiteCount = 0;
UINT_16 u2AuthSuiteCount = 0;
PUINT_8 pucPairSuite = NULL;
PUINT_8 pucAuthSuite = NULL;
PUINT_8 cp;
DEBUGFUNC("rsnParseRsnIE");
ASSERT(prInfoElem);
ASSERT(prRsnInfo);
/* Verify the length of the RSN IE. */
if (prInfoElem->ucLength < 2) {
DBGLOG(RSN, TRACE, "RSN IE length too short (length=%d)\n", prInfoElem->ucLength);
return FALSE;
}
/* Check RSN version: currently, we only support version 1. */
WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version);
if (u2Version != 1) {
DBGLOG(RSN, TRACE, "Unsupported RSN IE version: %d\n", u2Version);
return FALSE;
}
cp = (PUCHAR)&prInfoElem->u4GroupKeyCipherSuite;
u4RemainRsnIeLen = (INT_32) prInfoElem->ucLength - 2;
do {
if (u4RemainRsnIeLen == 0)
break;
/* Parse the Group Key Cipher Suite field. */
if (u4RemainRsnIeLen < 4) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in group cipher suite (IE len: %d)\n", prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_32(cp, &u4GroupSuite);
cp += 4;
u4RemainRsnIeLen -= 4;
if (u4RemainRsnIeLen == 0)
break;
/* Parse the Pairwise Key Cipher Suite Count field. */
if (u4RemainRsnIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_16(cp, &u2PairSuiteCount);
cp += 2;
u4RemainRsnIeLen -= 2;
/* Parse the Pairwise Key Cipher Suite List field. */
i = (UINT_32) u2PairSuiteCount * 4;
if (u4RemainRsnIeLen < (INT_32) i) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
pucPairSuite = cp;
cp += i;
u4RemainRsnIeLen -= (INT_32) i;
if (u4RemainRsnIeLen == 0)
break;
/* Parse the Authentication and Key Management Cipher Suite Count field. */
if (u4RemainRsnIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount);
cp += 2;
u4RemainRsnIeLen -= 2;
/* Parse the Authentication and Key Management Cipher Suite List field. */
i = (UINT_32) u2AuthSuiteCount * 4;
if (u4RemainRsnIeLen < (INT_32) i) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
pucAuthSuite = cp;
cp += i;
u4RemainRsnIeLen -= (INT_32) i;
if (u4RemainRsnIeLen == 0)
break;
/* Parse the RSN u2Capabilities field. */
if (u4RemainRsnIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_16(cp, &u2Cap);
} while (FALSE);
/* Save the RSN information for the BSS. */
prRsnInfo->ucElemId = ELEM_ID_RSN;
prRsnInfo->u2Version = u2Version;
prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite;
DBGLOG(RSN, LOUD, "RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n",
u2Version, (UCHAR) (u4GroupSuite & 0x000000FF),
(UCHAR) ((u4GroupSuite >> 8) & 0x000000FF),
(UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF));
if (pucPairSuite) {
/* The information about the pairwise key cipher suites is present. */
if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES)
u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES;
prRsnInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount;
for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) {
WLAN_GET_FIELD_32(pucPairSuite, &prRsnInfo->au4PairwiseKeyCipherSuite[i]);
pucPairSuite += 4;
DBGLOG(RSN, LOUD,
"RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n",
(UINT_8) i,
(UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF));
}
} else {
/* The information about the pairwise key cipher suites is not present. */
/* Use the default chipher suite for RSN: CCMP. */
prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1;
prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP;
DBGLOG(RSN, LOUD,
"RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n",
(UCHAR) (prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF));
}
if (pucAuthSuite) {
/* The information about the authentication and key management suites */
/* is present. */
if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES)
u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES;
prRsnInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount;
for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) {
WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]);
pucAuthSuite += 4;
DBGLOG(RSN, LOUD, "RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n",
(UINT_8) i,
(UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF));
}
} else {
/* The information about the authentication and key management suites */
/* is not present. Use the default AKM suite for RSN. */
prRsnInfo->u4AuthKeyMgtSuiteCount = 1;
prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X;
DBGLOG(RSN, LOUD, "RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n",
(UCHAR) (prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF),
(UCHAR) ((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF));
}
prRsnInfo->u2RsnCap = u2Cap;
prRsnInfo->fgRsnCapPresent = TRUE;
DBGLOG(RSN, LOUD, "RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap);
return TRUE;
} /* rsnParseRsnIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to parse WPA IE.
*
* \param[in] prInfoElem Pointer to the WPA IE.
* \param[out] prWpaInfo Pointer to the BSSDescription structure to store the
* WPA information from the given WPA IE.
*
* \retval TRUE Succeeded.
* \retval FALSE Failed.
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, OUT P_RSN_INFO_T prWpaInfo)
{
UINT_32 i;
INT_32 u4RemainWpaIeLen;
UINT_16 u2Version;
UINT_16 u2Cap = 0;
UINT_32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP;
UINT_16 u2PairSuiteCount = 0;
UINT_16 u2AuthSuiteCount = 0;
PUCHAR pucPairSuite = NULL;
PUCHAR pucAuthSuite = NULL;
PUCHAR cp;
BOOLEAN fgCapPresent = FALSE;
DEBUGFUNC("rsnParseWpaIE");
ASSERT(prInfoElem);
ASSERT(prWpaInfo);
/* Verify the length of the WPA IE. */
if (prInfoElem->ucLength < 6) {
DBGLOG(RSN, TRACE, "WPA IE length too short (length=%d)\n", prInfoElem->ucLength);
return FALSE;
}
/* Check WPA version: currently, we only support version 1. */
WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version);
if (u2Version != 1) {
DBGLOG(RSN, TRACE, "Unsupported WPA IE version: %d\n", u2Version);
return FALSE;
}
cp = (PUCHAR) &prInfoElem->u4GroupKeyCipherSuite;
u4RemainWpaIeLen = (INT_32) prInfoElem->ucLength - 6;
do {
if (u4RemainWpaIeLen == 0)
break;
/* WPA_OUI : 4
* Version : 2
* GroupSuite : 4
* PairwiseCount: 2
* PairwiseSuite: 4 * pairSuiteCount
* AuthCount : 2
* AuthSuite : 4 * authSuiteCount
* Cap : 2
*/
/* Parse the Group Key Cipher Suite field. */
if (u4RemainWpaIeLen < 4) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in group cipher suite (IE len: %d)\n", prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_32(cp, &u4GroupSuite);
cp += 4;
u4RemainWpaIeLen -= 4;
if (u4RemainWpaIeLen == 0)
break;
/* Parse the Pairwise Key Cipher Suite Count field. */
if (u4RemainWpaIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_16(cp, &u2PairSuiteCount);
cp += 2;
u4RemainWpaIeLen -= 2;
/* Parse the Pairwise Key Cipher Suite List field. */
i = (UINT_32) u2PairSuiteCount * 4;
if (u4RemainWpaIeLen < (INT_32) i) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
pucPairSuite = cp;
cp += i;
u4RemainWpaIeLen -= (INT_32) i;
if (u4RemainWpaIeLen == 0)
break;
/* Parse the Authentication and Key Management Cipher Suite Count field. */
if (u4RemainWpaIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount);
cp += 2;
u4RemainWpaIeLen -= 2;
/* Parse the Authentication and Key Management Cipher Suite List field. */
i = (UINT_32) u2AuthSuiteCount * 4;
if (u4RemainWpaIeLen < (INT_32) i) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n",
prInfoElem->ucLength);
return FALSE;
}
pucAuthSuite = cp;
cp += i;
u4RemainWpaIeLen -= (INT_32) i;
if (u4RemainWpaIeLen == 0)
break;
/* Parse the WPA u2Capabilities field. */
if (u4RemainWpaIeLen < 2) {
DBGLOG(RSN, TRACE,
"Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", prInfoElem->ucLength);
return FALSE;
}
fgCapPresent = TRUE;
WLAN_GET_FIELD_16(cp, &u2Cap);
u4RemainWpaIeLen -= 2;
} while (FALSE);
/* Save the WPA information for the BSS. */
prWpaInfo->ucElemId = ELEM_ID_WPA;
prWpaInfo->u2Version = u2Version;
prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite;
DBGLOG(RSN, LOUD, "WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n",
u2Version, (UCHAR) (u4GroupSuite & 0x000000FF),
(UCHAR) ((u4GroupSuite >> 8) & 0x000000FF),
(UCHAR) ((u4GroupSuite >> 16) & 0x000000FF), (UCHAR) ((u4GroupSuite >> 24) & 0x000000FF));
if (pucPairSuite) {
/* The information about the pairwise key cipher suites is present. */
if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES)
u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES;
prWpaInfo->u4PairwiseKeyCipherSuiteCount = (UINT_32) u2PairSuiteCount;
for (i = 0; i < (UINT_32) u2PairSuiteCount; i++) {
WLAN_GET_FIELD_32(pucPairSuite, &prWpaInfo->au4PairwiseKeyCipherSuite[i]);
pucPairSuite += 4;
DBGLOG(RSN, LOUD,
"WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n",
(UINT_8) i,
(UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & 0x000000FF));
}
} else {
/* The information about the pairwise key cipher suites is not present. */
/* Use the default chipher suite for WPA: TKIP. */
prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1;
prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP;
DBGLOG(RSN, LOUD,
"WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n",
(UCHAR) (prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF));
}
if (pucAuthSuite) {
/* The information about the authentication and key management suites */
/* is present. */
if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES)
u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES;
prWpaInfo->u4AuthKeyMgtSuiteCount = (UINT_32) u2AuthSuiteCount;
for (i = 0; i < (UINT_32) u2AuthSuiteCount; i++) {
WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]);
pucAuthSuite += 4;
DBGLOG(RSN, LOUD, "WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n",
(UINT_8) i,
(UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF));
}
} else {
/* The information about the authentication and key management suites */
/* is not present. Use the default AKM suite for WPA. */
prWpaInfo->u4AuthKeyMgtSuiteCount = 1;
prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X;
DBGLOG(RSN, LOUD, "WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n",
(UCHAR) (prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF),
(UCHAR) ((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF));
}
if (fgCapPresent) {
prWpaInfo->fgRsnCapPresent = TRUE;
prWpaInfo->u2RsnCap = u2Cap;
DBGLOG(RSN, LOUD, "WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap);
} else {
prWpaInfo->fgRsnCapPresent = FALSE;
prWpaInfo->u2RsnCap = 0;
}
return TRUE;
} /* rsnParseWpaIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to search the desired pairwise
* cipher suite from the MIB Pairwise Cipher Suite
* configuration table.
*
* \param[in] u4Cipher The desired pairwise cipher suite to be searched
* \param[out] pu4Index Pointer to the index of the desired pairwise cipher in
* the table
*
* \retval TRUE - The desired pairwise cipher suite is found in the table.
* \retval FALSE - The desired pairwise cipher suite is not found in the
* table.
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN UINT_32 u4Cipher, OUT PUINT_32 pu4Index)
{
UINT_8 i;
P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry;
DEBUGFUNC("rsnSearchSupportedCipher");
ASSERT(pu4Index);
for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) {
prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i];
if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher &&
prEntry->dot11RSNAConfigPairwiseCipherEnabled) {
*pu4Index = i;
return TRUE;
}
}
return FALSE;
} /* rsnSearchSupportedCipher */
/*----------------------------------------------------------------------------*/
/*!
* \brief Whether BSS RSN is matched from upper layer set.
*
* \param[in] prAdapter Pointer to the Adapter structure, BSS RSN Information
*
* \retval BOOLEAN
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo)
{
UINT_8 i = 0;
DEBUGFUNC("rsnIsSuitableBSS");
do {
if ((prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite & 0x000000FF) !=
GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite)) {
DBGLOG(RSN, TRACE, "Break by GroupKeyCipherSuite\n");
break;
}
for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) {
if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4PairwiseKeyCipherSuite[0] & 0x000000FF) !=
GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i]))
&& (i == prBssRsnInfo->u4PairwiseKeyCipherSuiteCount - 1)) {
DBGLOG(RSN, TRACE, "Break by PairwiseKeyCipherSuite\n");
break;
}
}
for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) {
if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo.au4AuthKeyMgtSuite[0] & 0x000000FF) !=
GET_SELECTOR_TYPE(prBssRsnInfo->au4AuthKeyMgtSuite[0]))
&& (i == prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1)) {
DBGLOG(RSN, TRACE, "Break by AuthKeyMgtSuite\n");
break;
}
}
return TRUE;
} while (FALSE);
return FALSE;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to search the desired
* authentication and key management (AKM) suite from the
* MIB Authentication and Key Management Suites table.
*
* \param[in] u4AkmSuite The desired AKM suite to be searched
* \param[out] pu4Index Pointer to the index of the desired AKM suite in the
* table
*
* \retval TRUE The desired AKM suite is found in the table.
* \retval FALSE The desired AKM suite is not found in the table.
*
* \note
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN UINT_32 u4AkmSuite, OUT PUINT_32 pu4Index)
{
UINT_8 i;
P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry;
DEBUGFUNC("rsnSearchAKMSuite");
ASSERT(pu4Index);
for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) {
prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i];
if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite &&
prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) {
*pu4Index = i;
return TRUE;
}
}
return FALSE;
} /* rsnSearchAKMSuite */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to perform RSNA or TSN policy
* selection for a given BSS.
*
* \param[in] prBss Pointer to the BSS description
*
* \retval TRUE - The RSNA/TSN policy selection for the given BSS is
* successful. The selected pairwise and group cipher suites
* are returned in the BSS description.
* \retval FALSE - The RSNA/TSN policy selection for the given BSS is failed.
* The driver shall not attempt to join the given BSS.
*
* \note The Encrypt status matched score will save to bss for final ap select.
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss)
{
#if CFG_SUPPORT_802_11W
INT_32 i;
UINT_32 j;
#else
UINT_32 i, j;
#endif
BOOLEAN fgSuiteSupported;
UINT_32 u4PairwiseCipher = 0;
UINT_32 u4GroupCipher = 0;
UINT_32 u4AkmSuite = 0;
P_RSN_INFO_T prBssRsnInfo;
UINT_8 ucBssIndex;
BOOLEAN fgIsWpsActive = (BOOLEAN) FALSE;
DEBUGFUNC("rsnPerformPolicySelection");
ASSERT(prBss);
DBGLOG(RSN, TRACE, "rsnPerformPolicySelection\n");
/* Todo:: */
ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex;
prBss->u4RsnSelectedPairwiseCipher = 0;
prBss->u4RsnSelectedGroupCipher = 0;
prBss->u4RsnSelectedAKMSuite = 0;
prBss->ucEncLevel = 0;
prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE;
#if CFG_SUPPORT_WPS
fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo);
/* CR1640, disable the AP select privacy check */
if (fgIsWpsActive &&
(prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) &&
(prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) {
DBGLOG(RSN, INFO, "-- Skip the Protected BSS check\n");
return TRUE;
}
#endif
/* Protection is not required in this BSS. */
if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0) {
if (secEnabledInAis(prAdapter) == FALSE) {
DBGLOG(RSN, INFO, "-- No Protected BSS\n");
return TRUE;
}
DBGLOG(RSN, INFO, "-- Protected BSS but No need\n");
return FALSE;
}
/* Protection is required in this BSS. */
if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) {
if (secEnabledInAis(prAdapter) == FALSE) {
DBGLOG(RSN, INFO, "-- Protected BSS\n");
return FALSE;
}
}
if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA ||
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK ||
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) {
if (prBss->fgIEWPA) {
prBssRsnInfo = &prBss->rWPAInfo;
} else {
DBGLOG(RSN, INFO, "WPA Information Element does not exist.\n");
return FALSE;
}
} else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 ||
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) {
if (prBss->fgIERSN) {
prBssRsnInfo = &prBss->rRSNInfo;
} else {
DBGLOG(RSN, INFO, "RSN Information Element does not exist.\n");
return FALSE;
}
} else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != ENUM_ENCRYPTION1_ENABLED) {
/* If the driver is configured to use WEP only, ignore this BSS. */
DBGLOG(RSN, INFO, "-- Not WEP-only legacy BSS\n");
return FALSE;
} else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED) {
/* If the driver is configured to use WEP only, use this BSS. */
DBGLOG(RSN, INFO, "-- WEP-only legacy BSS\n");
return TRUE;
}
if (!rsnIsSuitableBSS(prAdapter, prBssRsnInfo)) {
DBGLOG(RSN, INFO, "RSN info check no matched\n");
return FALSE;
}
if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 &&
GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == CIPHER_SUITE_NONE) {
/* Since the pairwise cipher use the same cipher suite as the group
* cipher in the BSS, we check the group cipher suite against the
* current encryption status.
*/
fgSuiteSupported = FALSE;
switch (prBssRsnInfo->u4GroupKeyCipherSuite) {
case WPA_CIPHER_SUITE_CCMP:
case RSN_CIPHER_SUITE_CCMP:
if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION3_ENABLED)
fgSuiteSupported = TRUE;
break;
case WPA_CIPHER_SUITE_TKIP:
case RSN_CIPHER_SUITE_TKIP:
if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION2_ENABLED)
fgSuiteSupported = TRUE;
break;
case WPA_CIPHER_SUITE_WEP40:
case WPA_CIPHER_SUITE_WEP104:
if (prAdapter->rWifiVar.rConnSettings.eEncStatus == ENUM_ENCRYPTION1_ENABLED)
fgSuiteSupported = TRUE;
break;
}
if (fgSuiteSupported) {
u4PairwiseCipher = WPA_CIPHER_SUITE_NONE;
u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite;
}
#if DBG
else {
DBGLOG(RSN, TRACE,
"Inproper encryption status %d for group-key-only BSS\n",
prAdapter->rWifiVar.rConnSettings.eEncStatus);
}
#endif
} else {
fgSuiteSupported = FALSE;
DBGLOG(RSN, TRACE,
"eEncStatus %d %lu 0x%lx\n", prAdapter->rWifiVar.rConnSettings.eEncStatus,
prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, prBssRsnInfo->au4PairwiseKeyCipherSuite[0]);
/* Select pairwise/group ciphers */
switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) {
case ENUM_ENCRYPTION3_ENABLED:
for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) {
if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])
== CIPHER_SUITE_CCMP) {
u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i];
}
}
u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite;
break;
case ENUM_ENCRYPTION2_ENABLED:
for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) {
if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])
== CIPHER_SUITE_TKIP) {
u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i];
}
}
if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_CCMP)
DBGLOG(RSN, TRACE, "Cannot join CCMP BSS\n");
else
u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite;
break;
case ENUM_ENCRYPTION1_ENABLED:
for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) {
if (GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])
== CIPHER_SUITE_WEP40 ||
GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[i])
== CIPHER_SUITE_WEP104) {
u4PairwiseCipher = prBssRsnInfo->au4PairwiseKeyCipherSuite[i];
}
}
if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) ==
CIPHER_SUITE_CCMP ||
GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == CIPHER_SUITE_TKIP) {
DBGLOG(RSN, TRACE, "Cannot join CCMP/TKIP BSS\n");
} else {
u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite;
}
break;
default:
break;
}
}
/* Exception handler */
/* If we cannot find proper pairwise and group cipher suites to join the */
/* BSS, do not check the supported AKM suites. */
if (u4PairwiseCipher == 0 || u4GroupCipher == 0) {
DBGLOG(RSN, TRACE, "Failed to select pairwise/group cipher (0x%08lx/0x%08lx)\n",
u4PairwiseCipher, u4GroupCipher);
return FALSE;
}
#if CFG_ENABLE_WIFI_DIRECT
if ((prAdapter->fgIsP2PRegistered) &&
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P)) {
if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP ||
u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) {
DBGLOG(RSN, TRACE,
"Failed to select pairwise/group cipher for P2P network (0x%08lx/0x%08lx)\n",
u4PairwiseCipher, u4GroupCipher);
return FALSE;
}
}
#endif
#if CFG_ENABLE_BT_OVER_WIFI
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_BOW) {
if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP ||
u4GroupCipher != RSN_CIPHER_SUITE_CCMP || u4AkmSuite != RSN_AKM_SUITE_PSK) {
DBGLOG(RSN, TRACE,
"Failed to select pairwise/group cipher for BT over Wi-Fi network (0x%08lx/0x%08lx)\n",
u4PairwiseCipher, u4GroupCipher);
return FALSE;
}
}
#endif
/* Verify if selected pairwisse cipher is supported */
fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i);
/* Verify if selected group cipher is supported */
if (fgSuiteSupported)
fgSuiteSupported = rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i);
if (!fgSuiteSupported) {
DBGLOG(RSN, TRACE,
"Failed to support selected pairwise/group cipher (0x%08lx/0x%08lx)\n",
u4PairwiseCipher, u4GroupCipher);
return FALSE;
}
/* Select AKM */
/* If the driver cannot support any authentication suites advertised in
* the given BSS, we fail to perform RSNA policy selection.
*/
/* Attempt to find any overlapping supported AKM suite. */
#if CFG_SUPPORT_802_11W
if (i != 0)
for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) {
#else
for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) {
#endif
if (rsnSearchAKMSuite(prAdapter, prBssRsnInfo->au4AuthKeyMgtSuite[i], &j)) {
u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i];
break;
}
}
if (u4AkmSuite == 0) {
DBGLOG(RSN, TRACE, "Cannot support any AKM suites\n");
return FALSE;
}
DBGLOG(RSN, TRACE,
"Selected pairwise/group cipher: %02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n",
(UINT_8) (u4PairwiseCipher & 0x000000FF),
(UINT_8) ((u4PairwiseCipher >> 8) & 0x000000FF),
(UINT_8) ((u4PairwiseCipher >> 16) & 0x000000FF),
(UINT_8) ((u4PairwiseCipher >> 24) & 0x000000FF),
(UINT_8) (u4GroupCipher & 0x000000FF), (UINT_8) ((u4GroupCipher >> 8) & 0x000000FF),
(UINT_8) ((u4GroupCipher >> 16) & 0x000000FF), (UINT_8) ((u4GroupCipher >> 24) & 0x000000FF));
DBGLOG(RSN, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n",
(UINT_8) (u4AkmSuite & 0x000000FF),
(UINT_8) ((u4AkmSuite >> 8) & 0x000000FF),
(UINT_8) ((u4AkmSuite >> 16) & 0x000000FF), (UINT_8) ((u4AkmSuite >> 24) & 0x000000FF));
#if CFG_SUPPORT_802_11W
DBGLOG(RSN, TRACE, "[MFP] MFP setting = %lu\n ", kalGetMfpSetting(prAdapter->prGlueInfo));
if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) {
if (!prBssRsnInfo->fgRsnCapPresent) {
DBGLOG(RSN, TRACE, "[MFP] Skip RSN IE, No MFP Required Capability.\n");
return FALSE;
} else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) {
DBGLOG(RSN, TRACE, "[MFP] Skip RSN IE, No MFP Required\n");
return FALSE;
}
prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = TRUE;
} else if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) {
DBGLOG(RSN, TRACE, "[MFP] Should not set the MFP option, need to check!\n");
ASSERT(FALSE);
} else {
if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) {
DBGLOG(RSN, INFO, "[MFP] Try to join even MFP Required bit set\n");
return FALSE;
}
prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = FALSE;
}
DBGLOG(RSN, TRACE, "[MFP] fgMgmtProtection = %d\n ", prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection);
prAdapter->rWifiVar.rAisSpecificBssInfo.fgAPApplyPmfReq = FALSE;
if (prBssRsnInfo->fgRsnCapPresent && (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR))
prAdapter->rWifiVar.rAisSpecificBssInfo.fgAPApplyPmfReq = TRUE;
#endif
if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP) {
prBss->ucEncLevel = 3;
} else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP) {
prBss->ucEncLevel = 2;
} else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 ||
GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) {
prBss->ucEncLevel = 1;
} else {
ASSERT(FALSE);
}
prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher;
prBss->u4RsnSelectedGroupCipher = u4GroupCipher;
prBss->u4RsnSelectedAKMSuite = u4AkmSuite;
return TRUE;
} /* rsnPerformPolicySelection */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to generate WPA IE for beacon frame.
*
* \param[in] pucIeStartAddr Pointer to put the generated WPA IE.
*
* \return The append WPA-None IE length
* \note
* Called by: JOIN module, compose beacon IE
*/
/*----------------------------------------------------------------------------*/
VOID rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
{
UINT_32 i;
P_WPA_INFO_ELEM_T prWpaIE;
UINT_32 u4Suite;
UINT_16 u2SuiteCount;
PUINT_8 cp, cp2;
UINT_8 ucExpendedLen = 0;
PUINT_8 pucBuffer;
UINT_8 ucBssIndex;
DEBUGFUNC("rsnGenerateWpaNoneIE");
ASSERT(prMsduInfo);
if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE)
return;
ucBssIndex = prMsduInfo->ucBssIndex;
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType != NETWORK_TYPE_AIS)
return;
pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength);
ASSERT(pucBuffer);
prWpaIE = (P_WPA_INFO_ELEM_T) (pucBuffer);
/* Start to construct a WPA IE. */
/* Fill the Element ID field. */
prWpaIE->ucElemId = ELEM_ID_WPA;
/* Fill the OUI and OUI Type fields. */
prWpaIE->aucOui[0] = 0x00;
prWpaIE->aucOui[1] = 0x50;
prWpaIE->aucOui[2] = 0xF2;
prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA;
/* Fill the Version field. */
WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */
ucExpendedLen = 6;
/* Fill the Pairwise Key Cipher Suite List field. */
u2SuiteCount = 0;
cp = (PUINT_8) &prWpaIE->aucPairwiseKeyCipherSuite1[0];
if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i))
u4Suite = WPA_CIPHER_SUITE_CCMP;
else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i))
u4Suite = WPA_CIPHER_SUITE_TKIP;
else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, &i))
u4Suite = WPA_CIPHER_SUITE_WEP104;
else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, &i))
u4Suite = WPA_CIPHER_SUITE_WEP40;
else
u4Suite = WPA_CIPHER_SUITE_TKIP;
WLAN_SET_FIELD_32(cp, u4Suite);
u2SuiteCount++;
ucExpendedLen += 4;
cp += 4;
/* Fill the Group Key Cipher Suite field as the same in pair-wise key. */
WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite);
ucExpendedLen += 4;
/* Fill the Pairwise Key Cipher Suite Count field. */
WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount);
ucExpendedLen += 2;
cp2 = cp;
/* Fill the Authentication and Key Management Suite List field. */
u2SuiteCount = 0;
cp += 2;
if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i))
u4Suite = WPA_AKM_SUITE_802_1X;
else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i))
u4Suite = WPA_AKM_SUITE_PSK;
else
u4Suite = WPA_AKM_SUITE_NONE;
/* This shall be the only available value for current implementation */
ASSERT(u4Suite == WPA_AKM_SUITE_NONE);
WLAN_SET_FIELD_32(cp, u4Suite);
u2SuiteCount++;
ucExpendedLen += 4;
cp += 4;
/* Fill the Authentication and Key Management Suite Count field. */
WLAN_SET_FIELD_16(cp2, u2SuiteCount);
ucExpendedLen += 2;
/* Fill the Length field. */
prWpaIE->ucLength = (UINT_8) ucExpendedLen;
/* Increment the total IE length for the Element ID and Length fields. */
prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer);
} /* rsnGenerateWpaNoneIE */
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to generate WPA IE for
* associate request frame.
*
* \param[in] prCurrentBss The Selected BSS description
*
* \retval The append WPA IE length
*
* \note
* Called by: AIS module, Associate request
*/
/*----------------------------------------------------------------------------*/
VOID rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
{
PUCHAR cp;
PUINT_8 pucBuffer;
UINT_8 ucBssIndex;
P_BSS_INFO_T prBssInfo;
P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo;
DEBUGFUNC("rsnGenerateWPAIE");
ASSERT(prMsduInfo);
pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength);
ASSERT(pucBuffer);
ucBssIndex = prMsduInfo->ucBssIndex;
prBssInfo = prAdapter->aprBssInfo[ucBssIndex];
prP2pSpecificBssInfo = prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData];
/* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */
/* return; */
#if CFG_ENABLE_WIFI_DIRECT
if ((prAdapter->fgIsP2PRegistered &&
GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P &&
kalP2PGetTkipCipher(prAdapter->prGlueInfo, (UINT_8) prBssInfo->u4PrivateData)) ||
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS &&
(prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA ||
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) {
#else
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS &&
(prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA ||
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK)) {
#endif
if (prAdapter->fgIsP2PRegistered && prP2pSpecificBssInfo && (prP2pSpecificBssInfo->u2WpaIeLen != 0)) {
kalMemCopy(pucBuffer, prP2pSpecificBssInfo->aucWpaIeBuffer, prP2pSpecificBssInfo->u2WpaIeLen);
prMsduInfo->u2FrameLength += prP2pSpecificBssInfo->u2WpaIeLen;
return;
}
/* Construct a WPA IE for association request frame. */
WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA;
WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED;
WPA_IE(pucBuffer)->aucOui[0] = 0x00;
WPA_IE(pucBuffer)->aucOui[1] = 0x50;
WPA_IE(pucBuffer)->aucOui[2] = 0xF2;
WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA;
WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1);
#if CFG_ENABLE_WIFI_DIRECT
if (prAdapter->fgIsP2PRegistered
&& GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) {
WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, WPA_CIPHER_SUITE_TKIP);
} else
#endif
WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite,
prAdapter->prAisBssInfo->u4RsnSelectedGroupCipher);
cp = (PUCHAR) &WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0];
WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1);
#if CFG_ENABLE_WIFI_DIRECT
if (prAdapter->fgIsP2PRegistered
&& GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) {
WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP);
} else
#endif
WLAN_SET_FIELD_32(cp, prAdapter->prAisBssInfo->u4RsnSelectedPairwiseCipher);
cp += 4;
WLAN_SET_FIELD_16(cp, 1);
cp += 2;
#if CFG_ENABLE_WIFI_DIRECT
if (prAdapter->fgIsP2PRegistered
&& GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) {
WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK);
} else
#endif
WLAN_SET_FIELD_32(cp, prAdapter->prAisBssInfo->u4RsnSelectedAKMSuite);
cp += 4;
WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED;
prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer);
}
} /* rsnGenerateWPAIE */
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to generate RSN IE for
* associate request frame.
*
* \param[in] prMsduInfo The Selected BSS description
*
* \retval The append RSN IE length
*
* \note
* Called by: AIS module, P2P module, BOW module Associate request
*/
/*----------------------------------------------------------------------------*/
VOID rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
{
UINT_32 u4Entry;
PUCHAR cp;
/* UINT_8 ucExpendedLen = 0; */
PUINT_8 pucBuffer;
UINT_8 ucBssIndex;
P_BSS_INFO_T prBssInfo;
P_STA_RECORD_T prStaRec;
DEBUGFUNC("rsnGenerateRSNIE");
ASSERT(prMsduInfo);
pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength);
ASSERT(pucBuffer);
/* Todo:: network id */
ucBssIndex = prMsduInfo->ucBssIndex;
prBssInfo = prAdapter->aprBssInfo[ucBssIndex];
ASSERT(prBssInfo);
if (
#if CFG_ENABLE_WIFI_DIRECT
((prAdapter->fgIsP2PRegistered) &&
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P)
&& (kalP2PGetCcmpCipher(prAdapter->prGlueInfo, (UINT_8) prBssInfo->u4PrivateData))) ||
#endif
#if CFG_ENABLE_BT_OVER_WIFI
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_BOW)
||
#endif
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType ==
NETWORK_TYPE_AIS /* prCurrentBss->fgIERSN */ &&
((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2)
|| (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK)))) {
/* Construct a RSN IE for association request frame. */
RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN;
RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED;
WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); /* Version */
WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite,
GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->
u4RsnSelectedGroupCipher); /* Group key suite */
cp = (PUCHAR) &RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0];
WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1);
WLAN_SET_FIELD_32(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u4RsnSelectedPairwiseCipher);
cp += 4;
WLAN_SET_FIELD_16(cp, 1); /* AKM suite count */
cp += 2;
/* AKM suite */
WLAN_SET_FIELD_32(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u4RsnSelectedAKMSuite);
cp += 4;
#if CFG_SUPPORT_802_11W
/* Capabilities */
WLAN_SET_FIELD_16(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u2RsnSelectedCapInfo);
DBGLOG(RSN, TRACE,
"Gen RSN IE = %x\n", GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u2RsnSelectedCapInfo);
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS) {
if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) {
WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); /* Capabilities */
DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC & MFPR\n");
} else if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == RSN_AUTH_MFP_OPTIONAL) {
WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); /* Capabilities */
DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC\n");
} else {
DBGLOG(RSN, TRACE, "!RSN_AUTH_MFP - No MFPC!\n");
}
} else if ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) &&
(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eCurrentOPMode ==
(UINT_8) OP_MODE_ACCESS_POINT)) {
/* AP PMF */
/* for AP mode, keep origin RSN IE content w/o update */
}
#else
/* Capabilities */
WLAN_SET_FIELD_16(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u2RsnSelectedCapInfo);
#endif
cp += 2;
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS)
prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS
&& rsnSearchPmkidEntry(prAdapter, prStaRec->aucMacAddr, &u4Entry)) {
#if 0
DBGLOG(RSN, TRACE, ("Add Pmk at assoc req\n"));
DBGLOG(RSN, TRACE, ("addr " MACSTR" PMKID "MACSTR"\n",
MAC2STR(prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arBSSID),
MAC2STR(prAdapter->
rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].rBssidInfo.arPMKID)));
#endif
if (prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].fgPmkidExist) {
RSN_IE(pucBuffer)->ucLength = 38;
WLAN_SET_FIELD_16(cp, 1); /* PMKID count */
cp += 2;
DBGLOG(RSN, TRACE,
"BSSID " MACSTR " ind=%lu\n", MAC2STR(prStaRec->aucMacAddr), u4Entry);
DBGLOG(RSN, TRACE,
"use PMKID " MACSTR "\n",
MAC2STR(prAdapter->rWifiVar.rAisSpecificBssInfo.arPmkidCache[u4Entry].
rBssidInfo.arPMKID));
kalMemCopy(cp,
(PVOID) prAdapter->rWifiVar.rAisSpecificBssInfo.
arPmkidCache[u4Entry].rBssidInfo.arPMKID, sizeof(PARAM_PMKID_VALUE));
/* ucExpendedLen = 40; */
} else {
WLAN_SET_FIELD_16(cp, 0); /* PMKID count */
/* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */
#if CFG_SUPPORT_802_11W
cp += 2;
RSN_IE(pucBuffer)->ucLength += 2;
#endif
}
} else {
WLAN_SET_FIELD_16(cp, 0); /* PMKID count */
/* ucExpendedLen = ELEM_ID_RSN_LEN_FIXED + 2; */
#if CFG_SUPPORT_802_11W
if ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS)
&& prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection
&& (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED)
/* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */
) {
cp += 2;
RSN_IE(pucBuffer)->ucLength += 2;
}
#endif
}
#if CFG_SUPPORT_802_11W
if ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_AIS)
&& prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection
&& (kalGetMfpSetting(prAdapter->prGlueInfo) != RSN_AUTH_MFP_DISABLED)
/* (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) */
) {
WLAN_SET_FIELD_32(cp, RSN_CIPHER_SUITE_AES_128_CMAC);
cp += 4;
RSN_IE(pucBuffer)->ucLength += 4;
}
#endif
prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer);
}
} /* rsnGenerateRSNIE */
/*----------------------------------------------------------------------------*/
/*!
* \brief Parse the given IE buffer and check if it is WFA IE and return Type and
* SubType for further process.
*
* \param[in] pucBuf Pointer to the buffer of WFA Information Element.
* \param[out] pucOuiType Pointer to the storage of OUI Type.
* \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and Version.
* \retval TRUE Parse IE ok
* \retval FALSE Parse IE fail
*/
/*----------------------------------------------------------------------------*/
BOOLEAN
rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter,
IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion)
{
UINT_8 aucWfaOui[] = VENDOR_OUI_WFA;
P_IE_WFA_T prWfaIE;
ASSERT(pucBuf);
ASSERT(pucOuiType);
ASSERT(pu2SubTypeVersion);
prWfaIE = (P_IE_WFA_T) pucBuf;
do {
if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) {
break;
} else if (prWfaIE->aucOui[0] != aucWfaOui[0] ||
prWfaIE->aucOui[1] != aucWfaOui[1] || prWfaIE->aucOui[2] != aucWfaOui[2]) {
break;
}
*pucOuiType = prWfaIE->ucOuiType;
WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion);
return TRUE;
} while (FALSE);
return FALSE;
} /* end of rsnParseCheckForWFAInfoElem() */
#if CFG_SUPPORT_AAA
/*----------------------------------------------------------------------------*/
/*!
* \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK
*
* \param[in] prAdapter Pointer to Adapter
* \param[in] prSwRfb Pointer to the rx buffer
* \param[in] pIE Pointer rthe buffer of Information Element.
* \param[out] prStatusCode Pointer to the return status code.
* \retval none
*/
/*----------------------------------------------------------------------------*/
void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe,
P_STA_RECORD_T prStaRec, PUINT_16 pu2StatusCode)
{
RSN_INFO_T rRsnIe;
P_BSS_INFO_T prBssInfo;
UINT_8 i;
UINT_16 statusCode;
ASSERT(prAdapter);
ASSERT(prIe);
ASSERT(prStaRec);
ASSERT(pu2StatusCode);
*pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT;
if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) {
if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1)
|| (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) {
*pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER;
return;
}
if (rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP) {
*pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER;
return;
}
if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1)
|| (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) {
*pu2StatusCode = STATUS_CODE_INVALID_AKMP;
return;
}
DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n");
*pu2StatusCode = WLAN_STATUS_SUCCESS;
#if CFG_SUPPORT_802_11W
/* AP PMF */
/* 1st check: if already PMF connection, reject assoc req: error 30 ASSOC_REJECTED_TEMPORARILY */
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
*pu2StatusCode = STATUS_CODE_ASSOC_REJECTED_TEMPORARILY;
return;
}
/* if RSN capability not exist, just return */
if (!rRsnIe.fgRsnCapPresent) {
*pu2StatusCode = WLAN_STATUS_SUCCESS;
return;
}
prStaRec->rPmfCfg.fgMfpc = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPC) ? 1 : 0;
prStaRec->rPmfCfg.fgMfpr = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPR) ? 1 : 0;
for (i = 0; i < rRsnIe.u4AuthKeyMgtSuiteCount; i++) {
if ((rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_802_1X_SHA256) ||
(rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_PSK_SHA256)) {
DBGLOG(RSN, INFO, "STA SHA256 support\n");
prStaRec->rPmfCfg.fgSha256 = TRUE;
break;
}
}
DBGLOG(RSN, INFO, "STA Assoc req mfpc:%d, mfpr:%d, sha256:%d, bssIndex:%d, applyPmf:%d\n",
prStaRec->rPmfCfg.fgMfpc, prStaRec->rPmfCfg.fgMfpr,
prStaRec->rPmfCfg.fgSha256, prStaRec->ucBssIndex, prStaRec->rPmfCfg.fgApplyPmf);
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
/* if PMF validation fail, return success as legacy association */
statusCode = rsnPmfCapableValidation(prAdapter, prBssInfo, prStaRec);
*pu2StatusCode = statusCode;
#endif
}
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to generate an authentication event to NDIS.
*
* \param[in] u4Flags Authentication event: \n
* PARAM_AUTH_REQUEST_REAUTH 0x01 \n
* PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n
* PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n
* PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgFlags)
{
P_PARAM_AUTH_EVENT_T prAuthEvent;
DEBUGFUNC("rsnGenMicErrorEvent");
prAuthEvent = (P_PARAM_AUTH_EVENT_T) prAdapter->aucIndicationEventBuffer;
/* Status type: Authentication Event */
prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION;
/* Authentication request */
prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T);
kalMemCopy((PVOID) prAuthEvent->arRequest[0].arBssid, (PVOID) prAdapter->prAisBssInfo->aucBSSID, MAC_ADDR_LEN);
if (fgFlags == TRUE)
prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR;
else
prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR;
kalIndicateStatusAndComplete(prAdapter->prGlueInfo,
WLAN_STATUS_MEDIA_SPECIFIC_INDICATION,
(PVOID) prAuthEvent,
sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T));
} /* rsnGenMicErrorEvent */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to handle TKIP MIC failures.
*
* \param[in] adapter_p Pointer to the adapter object data area.
* \param[in] prSta Pointer to the STA which occur MIC Error
* \param[in] fgErrorKeyType type of error key
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType)
{
/* UINT_32 u4RsnaCurrentMICFailTime; */
/* P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; */
DEBUGFUNC("rsnTkipHandleMICFailure");
ASSERT(prAdapter);
#if 1
rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType);
/* Generate authentication request event. */
DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType);
#else
ASSERT(prSta);
prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
/* Record the MIC error occur time. */
GET_CURRENT_SYSTIME(&u4RsnaCurrentMICFailTime);
/* Generate authentication request event. */
DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", fgErrorKeyType);
/* If less than 60 seconds have passed since a previous TKIP MIC failure,
* disassociate from the AP and wait for 60 seconds before (re)associating
* with the same AP.
*/
if (prAisSpecBssInfo->u4RsnaLastMICFailTime != 0 &&
!CHECK_FOR_TIMEOUT(u4RsnaCurrentMICFailTime,
prAisSpecBssInfo->u4RsnaLastMICFailTime, SEC_TO_SYSTIME(TKIP_COUNTERMEASURE_SEC))) {
/* If less than 60 seconds expired since last MIC error, we have to
* block traffic.
*/
DBGLOG(RSN, INFO, "Start blocking traffic!\n");
rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType);
secFsmEventStartCounterMeasure(prAdapter, prSta);
} else {
rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType);
DBGLOG(RSN, INFO, "First TKIP MIC error!\n");
}
COPY_SYSTIME(prAisSpecBssInfo->u4RsnaLastMICFailTime, u4RsnaCurrentMICFailTime);
#endif
} /* rsnTkipHandleMICFailure */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to select a list of BSSID from
* the scan results for PMKID candidate list.
*
* \param[in] prBssDesc the BSS Desc at scan result list
* \param[out] pu4CandidateCount Pointer to the number of selected candidates.
* It is set to zero if no BSSID matches our requirement.
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc)
{
P_CONNECTION_SETTINGS_T prConnSettings;
P_BSS_INFO_T prAisBssInfo;
DEBUGFUNC("rsnSelectPmkidCandidateList");
ASSERT(prBssDesc);
prConnSettings = &prAdapter->rWifiVar.rConnSettings;
prAisBssInfo = prAdapter->prAisBssInfo;
/* Search a BSS with the same SSID from the given BSS description set. */
/* DBGLOG(RSN, TRACE, ("Check scan result ["MACSTR"]\n", */
/* MAC2STR(prBssDesc->aucBSSID))); */
if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen,
prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) {
DBGLOG(RSN, TRACE, "-- SSID not matched\n");
return;
}
#if 0
if ((prBssDesc->u2BSSBasicRateSet &
~(rPhyAttributes[prAisBssInfo->ePhyType].u2SupportedRateSet)) || prBssDesc->fgIsUnknownBssBasicRate) {
DBGLOG(RSN, TRACE, "-- Rate set not matched\n");
return;
}
if (/* prBssDesc->u4RsnSelectedPairwiseCipher != prAisBssInfo->u4RsnSelectedPairwiseCipher || */
prBssDesc->u4RsnSelectedGroupCipher != prAisBssInfo->u4RsnSelectedGroupCipher
/* || prBssDesc->u4RsnSelectedAKMSuite != prAisBssInfo->u4RsnSelectedAKMSuite */) {
DBGLOG(RSN, TRACE, "-- Encrypt status not matched for PMKID\n");
return;
}
#endif
rsnUpdatePmkidCandidateList(prAdapter, prBssDesc);
} /* rsnSelectPmkidCandidateList */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to select a list of BSSID from
* the scan results for PMKID candidate list.
*
* \param[in] prBssDesc the BSS DESC at scan result list
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc)
{
UINT_32 i;
P_CONNECTION_SETTINGS_T prConnSettings;
P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo;
DEBUGFUNC("rsnUpdatePmkidCandidateList");
ASSERT(prBssDesc);
prConnSettings = &prAdapter->rWifiVar.rConnSettings;
prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen,
prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) {
DBGLOG(RSN, TRACE, "-- SSID not matched\n");
return;
}
for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) {
if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))
return;
}
/* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16),
* then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache
*/
if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE)
prAisSpecBssInfo->u4PmkidCandicateCount--;
i = prAisSpecBssInfo->u4PmkidCandicateCount;
COPY_MAC_ADDR((PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, (PVOID) prBssDesc->aucBSSID);
if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) {
prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1;
DBGLOG(RSN, TRACE, "Add " MACSTR " with pre-auth to candidate list\n",
MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid));
} else {
prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0;
DBGLOG(RSN, TRACE, "Add " MACSTR " without pre-auth to candidate list\n",
MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid));
}
prAisSpecBssInfo->u4PmkidCandicateCount++;
} /* rsnUpdatePmkidCandidateList */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to search the desired entry in
* PMKID cache according to the BSSID
*
* \param[in] pucBssid Pointer to the BSSID
* \param[out] pu4EntryIndex Pointer to place the found entry index
*
* \retval TRUE, if found one entry for specified BSSID
* \retval FALSE, if not found
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBssid, OUT PUINT_32 pu4EntryIndex)
{
UINT_32 i;
P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo;
DEBUGFUNC("rsnSearchPmkidEntry");
ASSERT(pucBssid);
ASSERT(pu4EntryIndex);
prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE)
return FALSE;
ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE);
/* Search for desired BSSID */
for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) {
if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, pucBssid, MAC_ADDR_LEN))
break;
}
/* If desired BSSID is found, then set the PMKID */
if (i < prAisSpecBssInfo->u4PmkidCacheCount) {
*pu4EntryIndex = i;
return TRUE;
}
return FALSE;
} /* rsnSearchPmkidEntry */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to check if there is difference
* between PMKID candicate list and PMKID cache. If there
* is new candicate that no cache entry is available, then
* add a new entry for the new candicate in the PMKID cache
* and set the PMKID indication flag to TRUE.
*
* \retval TRUE, if new member in the PMKID candicate list
* \retval FALSe, if no new member in the PMKID candicate list
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter)
{
P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo;
UINT_32 i; /* Index for PMKID candicate */
UINT_32 j; /* Indix for PMKID cache */
BOOLEAN status = FALSE;
DEBUGFUNC("rsnCheckPmkidCandicate");
prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
/* Check for each candicate */
for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) {
for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) {
if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID,
prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN)) {
/* DBGLOG(RSN, TRACE, (MACSTR" at PMKID cache!!\n",
* MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)));
*/
break;
}
}
/* No entry found in PMKID cache for the candicate, add new one */
if (j == prAisSpecBssInfo->u4PmkidCacheCount
&& prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) {
DBGLOG(RSN, TRACE,
"Add " MACSTR " to PMKID cache!!\n",
MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid));
kalMemCopy((PVOID) prAisSpecBssInfo->
arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].rBssidInfo.arBSSID,
(PVOID) prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, MAC_ADDR_LEN);
prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount].fgPmkidExist = FALSE;
prAisSpecBssInfo->u4PmkidCacheCount++;
status = TRUE;
}
}
return status;
} /* rsnCheckPmkidCandicate */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to wait a duration to indicate the pre-auth AP candicate
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
{
DBGLOG(RSN, EVENT, "Security - Time to indicate the PMKID cand.\n");
/* If the authentication mode is WPA2 and indication PMKID flag
* is available, then we indicate the PMKID candidate list to NDIS and
* clear the flag, indicatePMKID
*/
if (prAdapter->prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED &&
prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) {
rsnGeneratePmkidIndication(prAdapter);
}
} /* end of rsnIndicatePmkidCand() */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to check the BSS Desc at scan result
* with pre-auth cap at wpa2 mode. If there
* is candicate that no cache entry is available, then
* add a new entry for the new candicate in the PMKID cache
* and set the PMKID indication flag to TRUE.
*
* \param[in] prBss The BSS Desc at scan result
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss)
{
P_BSS_INFO_T prAisBssInfo;
P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo;
P_CONNECTION_SETTINGS_T prConnSettings;
DEBUGFUNC("rsnCheckPmkidCandicate");
ASSERT(prBss);
prConnSettings = &prAdapter->rWifiVar.rConnSettings;
prAisBssInfo = prAdapter->prAisBssInfo;
prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) &&
(prConnSettings->eAuthMode == AUTH_MODE_WPA2)) {
rsnSelectPmkidCandidateList(prAdapter, prBss);
/* Set indication flag of PMKID to TRUE, and then connHandleNetworkConnection() */
/* will indicate this later */
if (rsnCheckPmkidCandicate(prAdapter)) {
DBGLOG(RSN, TRACE, "Prepare a timer to indicate candidate PMKID Candidate\n");
cnmTimerStopTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer);
cnmTimerStartTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer,
SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC));
}
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to generate an PMKID candidate list
* indication to NDIS.
*
* \param[in] prAdapter Pointer to the adapter object data area.
* \param[in] u4Flags PMKID candidate list event:
* PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter)
{
P_PARAM_STATUS_INDICATION_T prStatusEvent;
P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent;
P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo;
UINT_8 i, j = 0, count = 0;
UINT_32 u4LenOfUsedBuffer;
DEBUGFUNC("rsnGeneratePmkidIndication");
ASSERT(prAdapter);
prStatusEvent = (P_PARAM_STATUS_INDICATION_T) prAdapter->aucIndicationEventBuffer;
/* Status type: PMKID Candidatelist Event */
prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST;
ASSERT(prStatusEvent);
prPmkidEvent = (P_PARAM_PMKID_CANDIDATE_LIST_T) (&prStatusEvent->eStatusType + 1);
ASSERT(prPmkidEvent);
prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prAisSpecificBssInfo);
for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) {
for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) {
if (EQUAL_MAC_ADDR(prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID,
prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) &&
(prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == TRUE)) {
break;
}
}
if (count >= CFG_MAX_PMKID_CACHE)
break;
if (j == prAisSpecificBssInfo->u4PmkidCacheCount) {
kalMemCopy((PVOID) prPmkidEvent->arCandidateList[count].arBSSID,
(PVOID) prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, PARAM_MAC_ADDR_LEN);
prPmkidEvent->arCandidateList[count].u4Flags =
prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags;
DBGLOG(RSN, TRACE,
MACSTR " %lu\n",
MAC2STR(prPmkidEvent->arCandidateList[count].arBSSID),
prPmkidEvent->arCandidateList[count].u4Flags);
count++;
}
}
/* PMKID Candidate List */
prPmkidEvent->u4Version = 1;
prPmkidEvent->u4NumCandidates = count;
DBGLOG(RSN, TRACE, "rsnGeneratePmkidIndication #%lu\n", prPmkidEvent->u4NumCandidates);
u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(UINT_32)) +
(count * sizeof(PARAM_PMKID_CANDIDATE_T));
/* dumpMemory8((PUINT_8)prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer); */
kalIndicateStatusAndComplete(prAdapter->prGlueInfo,
WLAN_STATUS_MEDIA_SPECIFIC_INDICATION,
(PVOID) prAdapter->aucIndicationEventBuffer, u4LenOfUsedBuffer);
} /* rsnGeneratePmkidIndication */
#if CFG_SUPPORT_WPS2
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to generate WSC IE for
* associate request frame.
*
* \param[in] prCurrentBss The Selected BSS description
*
* \retval The append WSC IE length
*
* \note
* Called by: AIS module, Associate request
*/
/*----------------------------------------------------------------------------*/
VOID rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo)
{
PUINT_8 pucBuffer;
ASSERT(prAdapter);
ASSERT(prMsduInfo);
if (prMsduInfo->ucBssIndex != prAdapter->prAisBssInfo->ucBssIndex)
return;
pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength);
/* ASSOC INFO IE ID: 221 :0xDD */
if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) {
kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE,
prAdapter->prGlueInfo->u2WSCAssocInfoIELen);
prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen;
}
}
#endif
#if CFG_SUPPORT_802_11W
/*----------------------------------------------------------------------------*/
/*!
* \brief to check if the Bip Key installed or not
*
* \param[in]
* prAdapter
*
* \return
* TRUE
* FALSE
*/
/*----------------------------------------------------------------------------*/
UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
{
/* caution: prStaRec might be null ! */
if (prStaRec) {
if (GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType == (UINT_8) NETWORK_TYPE_AIS) {
return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled;
} else if ((GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) &&
(GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eCurrentOPMode ==
OP_MODE_ACCESS_POINT)) {
DBGLOG(RSN, INFO, "AP-STA PMF capable:%d\n", prStaRec->rPmfCfg.fgApplyPmf);
return prStaRec->rPmfCfg.fgApplyPmf;
} else {
return FALSE;
}
} else
return FALSE;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to check the Sa query timeout.
*
*
* \note
* Called by: AIS module, Handle by Sa Quert timeout
*/
/*----------------------------------------------------------------------------*/
UINT_8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter)
{
P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo;
UINT_32 now;
prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prBssSpecInfo);
GET_CURRENT_SYSTIME(&now);
if (CHECK_FOR_TIMEOUT(now, prBssSpecInfo->u4SaQueryStart, TU_TO_MSEC(1000))) {
DBGLOG(RSN, INFO, "association SA Query timed out\n");
prBssSpecInfo->ucSaQueryTimedOut = 1;
kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE,
prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN);
prBssSpecInfo->pucSaQueryTransId = NULL;
prBssSpecInfo->u4SaQueryCount = 0;
cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer);
#if 1
if (prAdapter->prAisBssInfo->eConnectionState ==
PARAM_MEDIA_STATE_CONNECTED /* STA_STATE_3 == prStaRec->ucStaState */) {
P_MSG_AIS_ABORT_T prAisAbortMsg;
prAisAbortMsg =
(P_MSG_AIS_ABORT_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T));
if (!prAisAbortMsg)
return 0;
prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT;
prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_DISASSOCIATED;
prAisAbortMsg->fgDelayIndication = FALSE;
mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prAisAbortMsg, MSG_SEND_METHOD_BUF);
}
#else
/* Re-connect */
kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0);
#endif
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to start the 802.11w sa query timer.
*
*
* \note
* Called by: AIS module, Handle Rx mgmt request
*/
/*----------------------------------------------------------------------------*/
void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
{
P_BSS_INFO_T prBssInfo;
P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo;
P_MSDU_INFO_T prMsduInfo;
P_ACTION_SA_QUERY_FRAME prTxFrame;
UINT_16 u2PayloadLen;
PUINT_8 pucTmp = NULL;
UINT_8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN];
prBssInfo = prAdapter->prAisBssInfo;
ASSERT(prBssInfo);
prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prBssSpecInfo);
DBGLOG(RSN, INFO, "MFP: Start Sa Query\n");
if (prBssInfo->prStaRecOfAP == NULL) {
DBGLOG(RSN, INFO, "MFP: unassociated AP!\n");
return;
}
if (prBssSpecInfo->u4SaQueryCount > 0 && rsnCheckSaQueryTimeout(prAdapter)) {
DBGLOG(RSN, INFO, "MFP: u4SaQueryCount count =%lu\n", prBssSpecInfo->u4SaQueryCount);
return;
}
prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
if (!prMsduInfo)
return;
prTxFrame = (P_ACTION_SA_QUERY_FRAME)
((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP))
prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID);
COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr);
COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID);
prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST;
if (prBssSpecInfo->u4SaQueryCount == 0)
GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart);
if (prBssSpecInfo->u4SaQueryCount) {
pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE);
if (!pucTmp) {
DBGLOG(RSN, INFO, "MFP: Fail to alloc tmp buffer for backup sa query id\n");
cnmMgtPktFree(prAdapter, prMsduInfo);
return;
}
kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId,
prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN);
}
kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE,
prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN);
ucTransId[0] = (UINT_8) (kalRandomNumber() & 0xFF);
ucTransId[1] = (UINT_8) (kalRandomNumber() & 0xFF);
kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
prBssSpecInfo->u4SaQueryCount++;
prBssSpecInfo->pucSaQueryTransId =
kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, VIR_MEM_TYPE);
if (!prBssSpecInfo->pucSaQueryTransId) {
kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN);
DBGLOG(RSN, INFO, "MFP: Fail to alloc buffer for sa query id list\n");
cnmMgtPktFree(prAdapter, prMsduInfo);
return;
}
if (pucTmp) {
kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp,
(prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN);
kalMemCopy(&prBssSpecInfo->pucSaQueryTransId[(prBssSpecInfo->u4SaQueryCount -
1) * ACTION_SA_QUERY_TR_ID_LEN], ucTransId,
ACTION_SA_QUERY_TR_ID_LEN);
kalMemFree(pucTmp, VIR_MEM_TYPE, (prBssSpecInfo->u4SaQueryCount - 1) * ACTION_SA_QUERY_TR_ID_LEN);
} else {
kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
}
u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
/* 4 <3> Update information of MSDU_INFO_T */
TX_SET_MMPDU(prAdapter,
prMsduInfo,
prBssInfo->prStaRecOfAP->ucBssIndex,
prBssInfo->prStaRecOfAP->ucIndex,
WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) {
DBGLOG(RSN, INFO, "Set MSDU_OPT_PROTECTED_FRAME\n");
nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
}
/* 4 Enqueue the frame to send this action frame. */
nicTxEnqueueMsdu(prAdapter, prMsduInfo);
DBGLOG(RSN, INFO, "Set SA Query timer %lu (%d Tu)\n", prBssSpecInfo->u4SaQueryCount, 201);
cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, TU_TO_MSEC(201));
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to start the 802.11w sa query.
*
*
* \note
* Called by: AIS module, Handle Rx mgmt request
*/
/*----------------------------------------------------------------------------*/
void rsnStartSaQuery(IN P_ADAPTER_T prAdapter)
{
P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo;
prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prBssSpecInfo);
if (prBssSpecInfo->u4SaQueryCount == 0)
rsnStartSaQueryTimer(prAdapter, (ULONG) NULL);
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to stop the 802.11w sa query.
*
*
* \note
* Called by: AIS module, Handle Rx mgmt request
*/
/*----------------------------------------------------------------------------*/
void rsnStopSaQuery(IN P_ADAPTER_T prAdapter)
{
P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo;
prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prBssSpecInfo);
cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer);
kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE,
prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN);
prBssSpecInfo->pucSaQueryTransId = NULL;
prBssSpecInfo->u4SaQueryCount = 0;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to process the 802.11w sa query action frame.
*
*
* \note
* Called by: AIS module, Handle Rx mgmt request
*/
/*----------------------------------------------------------------------------*/
void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
{
P_BSS_INFO_T prBssInfo;
P_MSDU_INFO_T prMsduInfo;
P_ACTION_SA_QUERY_FRAME prRxFrame = NULL;
UINT_16 u2PayloadLen;
P_STA_RECORD_T prStaRec;
P_ACTION_SA_QUERY_FRAME prTxFrame;
prBssInfo = prAdapter->prAisBssInfo;
ASSERT(prBssInfo);
if (!prSwRfb)
return;
prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
if (!prRxFrame)
return;
prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
if (!prStaRec) /* Todo:: for not AIS check */
return;
DBGLOG(RSN, INFO, "IEEE 802.11: Received SA Query Request from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == PARAM_MEDIA_STATE_DISCONNECTED) {
DBGLOG(RSN, INFO, "IEEE 802.11: Ignore SA Query Request from unassociated STA "
MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
return;
}
DBGLOG(RSN, INFO, "IEEE 802.11: Sending SA Query Response to " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
if (!prMsduInfo)
return;
prTxFrame = (P_ACTION_SA_QUERY_FRAME)
((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP))
prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID);
COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr);
COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID);
prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE;
kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
/* 4 <3> Update information of MSDU_INFO_T */
TX_SET_MMPDU(prAdapter,
prMsduInfo,
prBssInfo->prStaRecOfAP->ucBssIndex,
prBssInfo->prStaRecOfAP->ucIndex,
WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) {
DBGLOG(RSN, INFO, "Set MSDU_OPT_PROTECTED_FRAME\n");
nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
}
#if 0
/* 4 Update information of MSDU_INFO_T */
prMsduInfo->ucPacketType = HIF_TX_PACKET_TYPE_MGMT; /* Management frame */
prMsduInfo->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex;
prMsduInfo->ucNetworkType = prBssInfo->ucNetTypeIndex;
prMsduInfo->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN;
prMsduInfo->fgIs802_1x = FALSE;
prMsduInfo->fgIs802_11 = TRUE;
prMsduInfo->u2FrameLength = WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen;
prMsduInfo->ucPID = nicAssignPID(prAdapter);
prMsduInfo->pfTxDoneHandler = NULL;
prMsduInfo->fgIsBasicRate = FALSE;
#endif
/* 4 Enqueue the frame to send this action frame. */
nicTxEnqueueMsdu(prAdapter, prMsduInfo);
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to process the 802.11w sa query action frame.
*
*
* \note
* Called by: AIS module, Handle Rx mgmt request
*/
/*----------------------------------------------------------------------------*/
void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
{
P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo;
P_ACTION_SA_QUERY_FRAME prRxFrame;
P_STA_RECORD_T prStaRec;
UINT_32 i;
prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
ASSERT(prBssSpecInfo);
prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) {
DBGLOG(RSN, INFO, "IEEE 802.11: Too short SA Query Action frame (len=%lu)\n",
(unsigned long)prSwRfb->u2PacketLen);
return;
}
if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) {
rsnSaQueryRequest(prAdapter, prSwRfb);
return;
}
if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) {
DBGLOG(RSN, INFO, "IEEE 802.11: Unexpected SA Query Action %d\n", prRxFrame->ucAction);
return;
}
DBGLOG(RSN, INFO, "IEEE 802.11: Received SA Query Response from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
/* MLME-SAQuery.confirm */
for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) {
if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId +
i * ACTION_SA_QUERY_TR_ID_LEN, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0)
break;
}
if (i >= prBssSpecInfo->u4SaQueryCount) {
DBGLOG(RSN, INFO, "IEEE 802.11: No matching SA Query transaction identifier found\n");
return;
}
DBGLOG(RSN, INFO, "Reply to pending SA Query received\n");
rsnStopSaQuery(prAdapter);
}
#endif
#if CFG_SUPPORT_AAA
#define WPS_DEV_OUI_WFA 0x0050f204
#define ATTR_RESPONSE_TYPE 0x103b
#define ATTR_VERSION 0x104a
#define ATTR_VENDOR_EXT 0x1049
#define WPS_VENDOR_ID_WFA 14122
VOID rsnGenerateWSCIEForAssocRsp(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo)
{
P_WIFI_VAR_T prWifiVar = NULL;
P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
UINT_16 u2IELen = 0;
ASSERT(prAdapter);
ASSERT(prMsduInfo);
ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucBssIndex));
prWifiVar = &(prAdapter->rWifiVar);
ASSERT(prWifiVar);
DBGLOG(RSN, TRACE, "WPS: Building WPS IE for (Re)Association Response");
prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
if (prP2pBssInfo->eNetworkType != NETWORK_TYPE_P2P)
return;
u2IELen = kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 3, (UINT_8) prP2pBssInfo->u4PrivateData);
kalP2PGenWSC_IE(prAdapter->prGlueInfo,
3,
(PUINT_8) ((ULONG) prMsduInfo->prPacket +
(ULONG) prMsduInfo->u2FrameLength),
(UINT_8) prP2pBssInfo->u4PrivateData);
prMsduInfo->u2FrameLength += (UINT_16) kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 3,
(UINT_8) prP2pBssInfo->u4PrivateData);
}
#endif
#if CFG_SUPPORT_802_11W
/* AP PMF */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to validate setting if PMF connection capable or not
* If AP MFPC=1, and STA MFPC=1, we let this as PMF connection
*
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
UINT_16 rsnPmfCapableValidation(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec)
{
BOOLEAN selfMfpc, selfMfpr, peerMfpc, peerMfpr;
selfMfpc = prBssInfo->rApPmfCfg.fgMfpc;
selfMfpr = prBssInfo->rApPmfCfg.fgMfpr;
peerMfpc = prStaRec->rPmfCfg.fgMfpc;
peerMfpr = prStaRec->rPmfCfg.fgMfpr;
DBGLOG(RSN, INFO, "AP mfpc:%d, mfpr:%d / STA mfpc:%d, mfpr:%d\n",
selfMfpc, selfMfpr, peerMfpc, peerMfpr);
if ((selfMfpc == TRUE) && (peerMfpc == FALSE)) {
if ((selfMfpr == TRUE) && (peerMfpr == FALSE)) {
DBGLOG(RSN, ERROR, "PMF policy violation for case 4\n");
return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
}
if (peerMfpr == TRUE) {
DBGLOG(RSN, ERROR, "PMF policy violation for case 7\n");
return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
}
}
if ((selfMfpc == TRUE) && (peerMfpc == TRUE)) {
DBGLOG(RSN, ERROR, "PMF Connection\n");
prStaRec->rPmfCfg.fgApplyPmf = TRUE;
}
return STATUS_CODE_SUCCESSFUL;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to generate TIMEOUT INTERVAL IE for association resp
* Add Timeout interval IE (56) when PMF invalid association
*
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID rsnPmfGenerateTimeoutIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo)
{
IE_TIMEOUT_INTERVAL_T *prTimeout;
P_STA_RECORD_T prStaRec = NULL;
ASSERT(prAdapter);
ASSERT(prMsduInfo);
prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
if (!prStaRec)
return;
prTimeout = (IE_TIMEOUT_INTERVAL_T *)
(((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength);
/* only when PMF connection, and association error code is 30 */
if ((rsnCheckBipKeyInstalled(prAdapter, prStaRec) == TRUE) &&
(prStaRec->u2StatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY)) {
DBGLOG(RSN, INFO, "rsnPmfGenerateTimeoutIE TRUE\n");
prTimeout->ucId = ELEM_ID_TIMEOUT_INTERVAL;
prTimeout->ucLength = ELEM_MAX_LEN_TIMEOUT_IE;
prTimeout->ucType = IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK;
prTimeout->u4Value = 1<<10;
prMsduInfo->u2FrameLength += IE_SIZE(prTimeout);
}
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to check the Sa query timeout.
* check if total retry time is greater than 1000ms
*
* \retval 1: retry max timeout. 0: not timeout
* \note
* Called by: AAA module, Handle by Sa Query timeout
*/
/*----------------------------------------------------------------------------*/
UINT_8 rsnApCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
{
P_BSS_INFO_T prBssInfo;
UINT_32 now;
GET_CURRENT_SYSTIME(&now);
if (CHECK_FOR_TIMEOUT(now, prStaRec->rPmfCfg.u4SAQueryStart, TU_TO_MSEC(1000))) {
DBGLOG(RSN, INFO, "association SA Query timed out\n");
/* XXX PMF TODO how to report STA REC disconnect?? */
/* when SAQ retry count timeout, clear this STA */
prStaRec->rPmfCfg.ucSAQueryTimedOut = 1;
prStaRec->rPmfCfg.u2TransactionID = 0;
prStaRec->rPmfCfg.u4SAQueryCount = 0;
cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
/* refer to p2pRoleFsmRunEventRxDeauthentication*/
if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) {
if (bssRemoveClient(prAdapter, prBssInfo, prStaRec)) {
/* Indicate disconnect to Host. */
p2pFuncDisconnect(prAdapter, prBssInfo, prStaRec, FALSE, 0);
/* Deactive BSS if PWR is IDLE and no peer */
if (IS_NET_PWR_STATE_IDLE(prAdapter, prBssInfo->ucBssIndex) &&
(bssGetClientCount(prAdapter, prBssInfo) == 0)) {
/* All Peer disconnected !! Stop BSS now!! */
p2pFuncStopComplete(prAdapter, prBssInfo);
}
}
}
return 1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to start the 802.11w sa query timer.
* This routine is triggered every 201ms, and every time enter function, check max timeout
*
* \note
* Called by: AAA module, Handle TX SAQ request
*/
/*----------------------------------------------------------------------------*/
void rsnApStartSaQueryTimer(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ULONG ulParamPtr)
{
P_BSS_INFO_T prBssInfo;
P_MSDU_INFO_T prMsduInfo;
P_ACTION_SA_QUERY_FRAME prTxFrame;
UINT_16 u2PayloadLen;
ASSERT(prStaRec);
DBGLOG(RSN, INFO, "MFP: AP Start Sa Query timer\n");
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
if (prStaRec->rPmfCfg.u4SAQueryCount > 0 && rsnApCheckSaQueryTimeout(prAdapter, prStaRec)) {
DBGLOG(RSN, INFO, "MFP: retry max timeout, u4SaQueryCount count =%lu\n",
prStaRec->rPmfCfg.u4SAQueryCount);
return;
}
prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
if (!prMsduInfo)
return;
prTxFrame = (P_ACTION_SA_QUERY_FRAME)
((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec))
prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr);
COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucBSSID);
COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID);
prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST;
if (prStaRec->rPmfCfg.u4SAQueryCount == 0)
GET_CURRENT_SYSTIME(&prStaRec->rPmfCfg.u4SAQueryStart);
/* if retry, transcation id ++ */
if (prStaRec->rPmfCfg.u4SAQueryCount) {
prStaRec->rPmfCfg.u2TransactionID++;
} else {
/* if first SAQ request, random pick transaction id */
prStaRec->rPmfCfg.u2TransactionID = (UINT_16) (kalRandomNumber() & 0xFFFF);
}
DBGLOG(RSN, INFO, "SAQ transaction id:%d\n", prStaRec->rPmfCfg.u2TransactionID);
/* trnsform U16 to U8 array */
prTxFrame->ucTransId[0] = ((prStaRec->rPmfCfg.u2TransactionID & 0xff00) >> 8);
prTxFrame->ucTransId[1] = ((prStaRec->rPmfCfg.u2TransactionID & 0x00ff) >> 0);
prStaRec->rPmfCfg.u4SAQueryCount++;
u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
/* 4 <3> Update information of MSDU_INFO_T */
TX_SET_MMPDU(prAdapter,
prMsduInfo,
prStaRec->ucBssIndex,
prStaRec->ucIndex,
WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
DBGLOG(RSN, INFO, "SAQ Set MSDU_OPT_PROTECTED_FRAME\n");
nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
}
/* 4 Enqueue the frame to send this action frame. */
nicTxEnqueueMsdu(prAdapter, prMsduInfo);
DBGLOG(RSN, INFO, "AP Set SA Query timer %lu (%d Tu)\n", prStaRec->rPmfCfg.u4SAQueryCount, 201);
cnmTimerStartTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer, TU_TO_MSEC(201));
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to start the 802.11w TX SA query.
*
*
* \note
* Called by: AAA module, Handle Tx action frame request
*/
/*----------------------------------------------------------------------------*/
void rsnApStartSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
{
ASSERT(prStaRec);
DBGLOG(RSN, INFO, "rsnApStartSaQuery\n");
if (prStaRec) {
cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
cnmTimerInitTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer,
(PFN_MGMT_TIMEOUT_FUNC)rsnApStartSaQueryTimer, (ULONG) prStaRec);
}
if (prStaRec->rPmfCfg.u4SAQueryCount == 0)
rsnApStartSaQueryTimer(prAdapter, prStaRec, (ULONG) NULL);
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to stop the 802.11w SA query.
*
*
* \note
* Called by: AAA module, stop TX SAQ if receive correct SAQ response
*/
/*----------------------------------------------------------------------------*/
void rsnApStopSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
{
ASSERT(prStaRec);
cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
prStaRec->rPmfCfg.u2TransactionID = 0;
prStaRec->rPmfCfg.u4SAQueryCount = 0;
prStaRec->rPmfCfg.ucSAQueryTimedOut = 0;
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to process the 802.11w sa query action frame.
*
*
* \note
* Called by: AAA module, Handle Rx action request
*/
/*----------------------------------------------------------------------------*/
void rsnApSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
{
P_BSS_INFO_T prBssInfo;
P_MSDU_INFO_T prMsduInfo;
P_ACTION_SA_QUERY_FRAME prRxFrame = NULL;
UINT_16 u2PayloadLen;
P_STA_RECORD_T prStaRec;
P_ACTION_SA_QUERY_FRAME prTxFrame;
if (!prSwRfb)
return;
prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
if (!prStaRec) /* Todo:: for not AIS check */
return;
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
ASSERT(prBssInfo);
prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
if (!prRxFrame)
return;
DBGLOG(RSN, INFO, "IEEE 802.11: AP Received SA Query Request from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
if (!rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
DBGLOG(RSN, INFO, "IEEE 802.11: AP Ignore SA Query Request non-PMF STA "
MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
return;
}
DBGLOG(RSN, INFO, "IEEE 802.11: Sending SA Query Response to " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
if (!prMsduInfo)
return;
/* drop cipher mismatch */
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) ||
HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) {
/* if cipher mismatch, or incorrect encrypt, just drop */
DBGLOG(RSN, ERROR, "drop SAQ req CM/CLM=1\n");
return;
}
}
prTxFrame = (P_ACTION_SA_QUERY_FRAME)
((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
DBGLOG(RSN, INFO, "AP SAQ resp set FC PF bit\n");
}
COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr);
COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucBSSID);
COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID);
prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE;
kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
/* 4 <3> Update information of MSDU_INFO_T */
TX_SET_MMPDU(prAdapter,
prMsduInfo,
prStaRec->ucBssIndex,
prStaRec->ucIndex,
WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
DBGLOG(RSN, INFO, "AP SAQ resp set MSDU_OPT_PROTECTED_FRAME\n");
nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
}
/* 4 Enqueue the frame to send this action frame. */
nicTxEnqueueMsdu(prAdapter, prMsduInfo);
}
/*----------------------------------------------------------------------------*/
/*!
*
* \brief This routine is called to process the 802.11w sa query action frame.
*
*
* \note
* Called by: AAA module, Handle Rx action request
*/
/*----------------------------------------------------------------------------*/
void rsnApSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
{
P_ACTION_SA_QUERY_FRAME prRxFrame;
P_STA_RECORD_T prStaRec;
UINT_16 u2SwapTrID;
prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
if (!prStaRec) {
DBGLOG(RSN, WARN, "NULL prStaRec!\n");
return;
}
DBGLOG(RSN, TRACE, "AP PMF SAQ action enter from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) {
DBGLOG(RSN, INFO, "IEEE 802.11: Too short SA Query Action frame (len=%lu)\n",
(unsigned long)prSwRfb->u2PacketLen);
return;
}
if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) {
rsnApSaQueryRequest(prAdapter, prSwRfb);
return;
}
if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) {
DBGLOG(RSN, INFO, "IEEE 802.11: Unexpected SA Query Action %d\n", prRxFrame->ucAction);
return;
}
DBGLOG(RSN, INFO, "IEEE 802.11: Received SA Query Response from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
/* MLME-SAQuery.confirm */
/* transform to network byte order */
u2SwapTrID = htons(prStaRec->rPmfCfg.u2TransactionID);
if (kalMemCmp((UINT_8 *)&u2SwapTrID, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) {
DBGLOG(RSN, INFO, "AP Reply to SA Query received\n");
rsnApStopSaQuery(prAdapter, prStaRec);
} else {
DBGLOG(RSN, INFO, "IEEE 802.11: AP No matching SA Query transaction identifier found\n");
}
}
#endif /* CFG_SUPPORT_802_11W */