blob: 8b0243daaf4a85221d64ac7f20c8abd4ec863784 [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: @(#) p2p_rlm.c@@
*/
/*! \file "p2p_rlm.c"
* \brief
*
*/
/*******************************************************************************
* 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"
#include "rlm.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 Init AP Bss
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo)
{
UINT_8 i;
ASSERT(prAdapter);
ASSERT(prBssInfo);
if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)
return;
/* Operation band, channel shall be ready before invoking this function.
* Bandwidth may be ready if other network is connected
*/
prBssInfo->fg40mBwAllowed = FALSE;
prBssInfo->fgAssoc40mBwAllowed = FALSE;
prBssInfo->eBssSCO = CHNL_EXT_SCN;
/* Check if AP can set its bw to 40MHz
* But if any of BSS is setup in 40MHz, the second BSS would prefer to use 20MHz
* in order to remain in SCC case
*/
if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex)) {
prBssInfo->eBssSCO = rlmGetScoForAP(prAdapter, prBssInfo);
if (prBssInfo->eBssSCO != CHNL_EXT_SCN) {
prBssInfo->fg40mBwAllowed = TRUE;
prBssInfo->fgAssoc40mBwAllowed = TRUE;
prBssInfo->ucHtOpInfo1 = (UINT_8)
(((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH);
rlmUpdateBwByChListForAP(prAdapter, prBssInfo);
}
}
/* Filled the VHT BW/S1/S2 and MCS rate set */
if (prBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_VHT) {
for (i = 0; i < 8; i++)
prBssInfo->u2VhtBasicMcsSet |= BITS(2 * i, (2 * i + 1));
prBssInfo->u2VhtBasicMcsSet &= (VHT_CAP_INFO_MCS_MAP_MCS9 << VHT_CAP_INFO_MCS_1SS_OFFSET);
prBssInfo->ucVhtChannelWidth = cnmGetBssMaxBwToChnlBW(prAdapter, prBssInfo->ucBssIndex);
if (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_80P80) {
/* TODO: BW80+80 support */
DBGLOG(RLM, WARN, "BW80+80 not support. Fallback to VHT_OP_CHANNEL_WIDTH_20_40\n");
prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40;
prBssInfo->ucVhtChannelFrequencyS1 = 0;
prBssInfo->ucVhtChannelFrequencyS2 = 0;
} else {
prBssInfo->ucVhtChannelFrequencyS1 =
rlmGetVhtS1ForAP(prAdapter, prBssInfo);
prBssInfo->ucVhtChannelFrequencyS2 = 0;
}
/* If the S1 is invalid, force to change bandwidth */
if (prBssInfo->ucVhtChannelFrequencyS1 == 0)
prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40;
} else {
prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40;
prBssInfo->ucVhtChannelFrequencyS1 = 0;
prBssInfo->ucVhtChannelFrequencyS2 = 0;
}
/*ERROR HANDLE*/
if ((prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_80)
|| (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_160)
|| (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_80P80)) {
if (prBssInfo->ucVhtChannelFrequencyS1 == 0) {
DBGLOG(RLM, INFO, "Wrong AP S1 parameter setting, back to BW20!!!\n");
prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40;
prBssInfo->ucVhtChannelFrequencyS1 = 0;
prBssInfo->ucVhtChannelFrequencyS2 = 0;
}
}
DBGLOG(RLM, INFO, "WLAN AP SCO=%d BW=%d S1=%d S2=%d CH=%d Band=%d\n",
prBssInfo->eBssSCO,
prBssInfo->ucVhtChannelWidth,
prBssInfo->ucVhtChannelFrequencyS1,
prBssInfo->ucVhtChannelFrequencyS2, prBssInfo->ucPrimaryChannel, prBssInfo->eBand);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief For probe response (GO, IBSS) and association response
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo)
{
P_BSS_INFO_T prBssInfo;
P_IE_OBSS_SCAN_PARAM_T prObssScanIe;
P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL;
ASSERT(prAdapter);
ASSERT(prMsduInfo);
prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex);
if (!prBssInfo)
return;
if (!IS_BSS_ACTIVE(prBssInfo))
return;
if (RLM_NET_IS_11N(prBssInfo) && /* !RLM_NET_IS_BOW(prBssInfo) && FIXME. */
prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT &&
(!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) &&
prBssInfo->eBand == BAND_2G4 && prBssInfo->eBssSCO != CHNL_EXT_SCN) {
prObssScanIe = (P_IE_OBSS_SCAN_PARAM_T)
(((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength);
/* Add 20/40 BSS coexistence IE */
prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS;
prObssScanIe->ucLength = sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN;
prObssScanIe->u2ScanPassiveDwell = dot11OBSSScanPassiveDwell;
prObssScanIe->u2ScanActiveDwell = dot11OBSSScanActiveDwell;
prObssScanIe->u2TriggerScanInterval = dot11BSSWidthTriggerScanInterval;
prObssScanIe->u2ScanPassiveTotalPerChnl = dot11OBSSScanPassiveTotalPerChannel;
prObssScanIe->u2ScanActiveTotalPerChnl = dot11OBSSScanActiveTotalPerChannel;
prObssScanIe->u2WidthTransDelayFactor = dot11BSSWidthChannelTransitionDelayFactor;
prObssScanIe->u2ScanActivityThres = dot11OBSSScanActivityThreshold;
ASSERT(IE_SIZE(prObssScanIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN));
prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe);
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief P2P GO.
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo)
{
UINT_8 ucLevel;
BOOLEAN fgBwChange;
ASSERT(prAdapter);
ASSERT(prBssInfo);
fgBwChange = FALSE;
if (prBssInfo->eBssSCO == CHNL_EXT_SCN)
return fgBwChange;
ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO);
if (ucLevel == CHNL_LEVEL0) {
/* Forced to 20MHz, so extended channel is SCN and STA width is zero */
prBssInfo->fgObssActionForcedTo20M = TRUE;
if (prBssInfo->ucHtOpInfo1 != (UINT_8) CHNL_EXT_SCN) {
prBssInfo->ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN;
fgBwChange = TRUE;
}
cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, OBSS_20_40M_TIMEOUT * MSEC_PER_SEC);
}
/* Clear up all channel lists */
prBssInfo->auc2G_20mReqChnlList[0] = 0;
prBssInfo->auc2G_NonHtChnlList[0] = 0;
prBssInfo->auc2G_PriChnlList[0] = 0;
prBssInfo->auc2G_SecChnlList[0] = 0;
prBssInfo->auc5G_20mReqChnlList[0] = 0;
prBssInfo->auc5G_NonHtChnlList[0] = 0;
prBssInfo->auc5G_PriChnlList[0] = 0;
prBssInfo->auc5G_SecChnlList[0] = 0;
return fgBwChange;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb)
{
P_ACTION_20_40_COEXIST_FRAME prRxFrame;
P_IE_20_40_COEXIST_T prCoexist;
P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport;
P_BSS_INFO_T prBssInfo;
P_STA_RECORD_T prStaRec;
PUINT_8 pucIE;
UINT_16 u2IELength, u2Offset;
UINT_8 i, j;
ASSERT(prAdapter);
ASSERT(prSwRfb);
prRxFrame = (P_ACTION_20_40_COEXIST_FRAME) prSwRfb->pvHeader;
prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
if (!(prSwRfb->prStaRec)) {
DBGLOG(P2P, ERROR, "prSwRfb->prStaRec is null.\n");
return;
}
if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || !prStaRec || prStaRec->ucStaState != STA_STATE_3 ||
prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || prSwRfb->prStaRec->ucBssIndex !=
/* HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != */
prStaRec->ucBssIndex) {
return;
}
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
ASSERT(prBssInfo);
if (!IS_BSS_ACTIVE(prBssInfo) ||
prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || prBssInfo->eBssSCO == CHNL_EXT_SCN) {
return;
}
prCoexist = &prRxFrame->rBssCoexist;
if (prCoexist->ucData & (BSS_COEXIST_40M_INTOLERANT | BSS_COEXIST_20M_REQ)) {
ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G);
for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) {
if (prBssInfo->auc2G_20mReqChnlList[i] == prBssInfo->ucPrimaryChannel)
break;
}
if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) {
prBssInfo->auc2G_20mReqChnlList[i] = prBssInfo->ucPrimaryChannel;
prBssInfo->auc2G_20mReqChnlList[0]++;
}
}
/* Process intolerant channel report IE */
pucIE = (PUINT_8) &prRxFrame->rChnlReport;
u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5);
IE_FOR_EACH(pucIE, u2IELength, u2Offset) {
switch (IE_ID(pucIE)) {
case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT:
prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T) pucIE;
if (prChnlReport->ucLength <= 1)
break;
/* To do: process regulatory class. Now we assume 2.4G band */
for (j = 0; j < prChnlReport->ucLength - 1; j++) {
/* Update non-HT channel list */
ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G);
for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; i++) {
if (prBssInfo->auc2G_NonHtChnlList[i] == prChnlReport->aucChannelList[j])
break;
}
if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && (i <= CHNL_LIST_SZ_2G)) {
prBssInfo->auc2G_NonHtChnlList[i] = prChnlReport->aucChannelList[j];
prBssInfo->auc2G_NonHtChnlList[0]++;
}
}
break;
default:
break;
}
} /* end of IE_FOR_EACH */
if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) {
bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex);
rlmSyncOperationParams(prAdapter, prBssInfo);
}
/* Check if OBSS scan exemption response should be sent */
if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ)
rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, P_EVENT_AP_OBSS_STATUS_T prObssStatus)
{
P_BSS_INFO_T prBssInfo;
ASSERT(prAdapter);
ASSERT(prObssStatus);
ASSERT(prObssStatus->ucBssIndex < MAX_BSS_INDEX);
prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prObssStatus->ucBssIndex);
if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)
return;
prBssInfo->fgObssErpProtectMode = (BOOLEAN) prObssStatus->ucObssErpProtectMode;
prBssInfo->eObssHtProtectMode = (ENUM_HT_PROTECT_MODE_T) prObssStatus->ucObssHtProtectMode;
prBssInfo->eObssGfOperationMode = (ENUM_GF_MODE_T) prObssStatus->ucObssGfOperationMode;
prBssInfo->fgObssRifsOperationMode = (BOOLEAN) prObssStatus->ucObssRifsOperationMode;
prBssInfo->fgObssBeaconForcedTo20M = (BOOLEAN) prObssStatus->ucObssBeaconForcedTo20M;
/* Check if Beacon content need to be updated */
rlmUpdateParamsForAP(prAdapter, prBssInfo, TRUE);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX.
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, BOOLEAN fgUpdateBeacon)
{
P_LINK_T prStaList;
P_STA_RECORD_T prStaRec;
BOOLEAN fgErpProtectMode, fgSta40mIntolerant;
BOOLEAN fgUseShortPreamble, fgUseShortSlotTime;
ENUM_HT_PROTECT_MODE_T eHtProtectMode;
ENUM_GF_MODE_T eGfOperationMode;
UINT_8 ucHtOpInfo1;
ASSERT(prAdapter);
ASSERT(prBssInfo);
if (!IS_BSS_ACTIVE(prBssInfo) || prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)
return;
fgErpProtectMode = FALSE;
eHtProtectMode = HT_PROTECT_MODE_NONE;
eGfOperationMode = GF_MODE_NORMAL;
fgSta40mIntolerant = FALSE;
fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed;
fgUseShortSlotTime = TRUE;
ucHtOpInfo1 = (UINT_8) CHNL_EXT_SCN;
prStaList = &prBssInfo->rStaRecOfClientList;
LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) {
if (!prStaRec) {
DBGLOG(P2P, WARN, "NULL STA_REC ptr in BSS client list\n");
bssDumpClientList(prAdapter, prBssInfo);
break;
}
if (prStaRec->fgIsInUse && prStaRec->ucStaState == STA_STATE_3 &&
prStaRec->ucBssIndex == prBssInfo->ucBssIndex) {
if (!(prStaRec->ucPhyTypeSet & (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) {
/* B-only mode, so mode 1 (ERP protection) */
fgErpProtectMode = TRUE;
}
if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) {
/* BG-only or A-only */
eHtProtectMode = HT_PROTECT_MODE_NON_HT;
} else if (prBssInfo->fg40mBwAllowed &&
!(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) {
/* 20MHz-only */
if (eHtProtectMode == HT_PROTECT_MODE_NONE)
eHtProtectMode = HT_PROTECT_MODE_20M;
}
if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF))
eGfOperationMode = GF_MODE_PROTECT;
if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE))
fgUseShortPreamble = FALSE;
#if 1
/*ap mode throughput enhancement
* only 2.4G with B mode client connecion use long slot time
*/
if ((!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))
&& fgErpProtectMode
&& prBssInfo->eBand == BAND_2G4)
fgUseShortSlotTime = FALSE;
#else
if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME))
fgUseShortSlotTime = FALSE;
#endif
if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT)
fgSta40mIntolerant = TRUE;
}
} /* end of LINK_FOR_EACH_ENTRY */
/* Check if HT operation IE about 20/40M bandwidth shall be updated */
if (prBssInfo->eBssSCO != CHNL_EXT_SCN) {
if (/*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant &&
!prBssInfo->fgObssActionForcedTo20M && !prBssInfo->fgObssBeaconForcedTo20M) {
ucHtOpInfo1 = (UINT_8)
(((UINT_32) prBssInfo->eBssSCO) | HT_OP_INFO1_STA_CHNL_WIDTH);
}
}
/* Check if any new parameter may be updated */
if (prBssInfo->fgErpProtectMode != fgErpProtectMode ||
prBssInfo->eHtProtectMode != eHtProtectMode ||
prBssInfo->eGfOperationMode != eGfOperationMode ||
prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 ||
prBssInfo->fgUseShortPreamble != fgUseShortPreamble ||
prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) {
prBssInfo->fgErpProtectMode = fgErpProtectMode;
prBssInfo->eHtProtectMode = eHtProtectMode;
prBssInfo->eGfOperationMode = eGfOperationMode;
prBssInfo->ucHtOpInfo1 = ucHtOpInfo1;
prBssInfo->fgUseShortPreamble = fgUseShortPreamble;
prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime;
if (fgUseShortSlotTime)
prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME;
else
prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME;
rlmSyncOperationParams(prAdapter, prBssInfo);
fgUpdateBeacon = TRUE;
}
/* Update Beacon content if related IE content is changed */
if (fgUpdateBeacon)
bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex);
}
#if 0
/*----------------------------------------------------------------------------*/
/*!
* \brief Initial the channel list from the domain information.
* This function is called after P2P initial and Domain information changed.
* Make sure the device is disconnected while changing domain information.
*
* \param[in] prAdapter Pointer of ADAPTER_T
*
* \return boolean value if probe response frame is
*/
/*----------------------------------------------------------------------------*/
VOID rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter)
{
P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL;
P_DOMAIN_INFO_ENTRY prDomainInfoEntry = (P_DOMAIN_INFO_ENTRY) NULL;
P_DOMAIN_SUBBAND_INFO prDomainSubBand = (P_DOMAIN_SUBBAND_INFO) NULL;
P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL;
UINT_32 u4Idx = 0, u4IdxII = 0;
UINT_8 ucBufferSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE;
#if 0
UINT_8 ucSocialChnlSupport = 0, ucAutoChnl = 0;
#endif
do {
ASSERT_BREAK(prAdapter != NULL);
prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings;
#if 0
ucAutoChnl = prP2pConnSetting->ucOperatingChnl;
#endif
prDomainInfoEntry = rlmDomainGetDomainInfo(prAdapter);
ASSERT_BREAK((prDomainInfoEntry != NULL) && (prP2pConnSetting != NULL));
prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField;
for (u4Idx = 0; u4Idx < MAX_SUBBAND_NUM; u4Idx++) {
prDomainSubBand = &prDomainInfoEntry->rSubBand[u4Idx];
if (((prDomainSubBand->ucBand == BAND_5G) && (!prAdapter->fgEnable5GBand))
|| (prDomainSubBand->ucBand == BAND_NULL)) {
continue;
}
if (ucBufferSize < (P2P_ATTRI_LEN_CHANNEL_ENTRY + prDomainSubBand->ucNumChannels)) {
/* Buffer is not enough to include all supported channels. */
break; /* for */
}
prChannelEntryField->ucRegulatoryClass = prDomainSubBand->ucRegClass;
prChannelEntryField->ucNumberOfChannels = prDomainSubBand->ucNumChannels;
for (u4IdxII = 0; u4IdxII < prDomainSubBand->ucNumChannels; u4IdxII++) {
prChannelEntryField->aucChannelList[u4IdxII] =
prDomainSubBand->ucFirstChannelNum + (u4IdxII * prDomainSubBand->ucChannelSpan);
#if 0
switch (prChannelEntryField->aucChannelList[u4IdxII]) {
case 1:
ucSocialChnlSupport = 1;
break;
case 6:
ucSocialChnlSupport = 6;
break;
case 11:
ucSocialChnlSupport = 11;
break;
default:
break;
}
#endif
}
if (ucBufferSize >= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels))
ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels);
else
break;
prChannelEntryField =
(P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntryField->ucNumberOfChannels);
}
#if 0
if (prP2pConnSetting->ucListenChnl == 0) {
prP2pConnSetting->ucListenChnl = P2P_DEFAULT_LISTEN_CHANNEL;
if (ucSocialChnlSupport != 0) {
/* 1. User Not Set LISTEN channel.
* 2. Social channel is not empty.
*/
prP2pConnSetting->ucListenChnl = ucSocialChnlSupport;
}
}
#endif
/* TODO: 20110921 frog - */
/* If LISTEN channel is not set,
* a random supported channel would be set.
* If no social channel is supported, DEFAULT channel would be set.
*/
prP2pConnSetting->ucRfChannelListSize = P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE - ucBufferSize;
#if 0
if (prP2pConnSetting->ucOperatingChnl == 0) { /* User not set OPERATE channel. */
if (scnQuerySparseChannel(prAdapter, NULL, &ucAutoChnl))
break; /* while */
ucBufferSize = prP2pConnSetting->ucRfChannelListSize;
prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField;
while (ucBufferSize != 0) {
if (prChannelEntryField->ucNumberOfChannels != 0) {
ucAutoChnl = prChannelEntryField->aucChannelList[0];
break; /* while */
}
else {
prChannelEntryField =
(P_CHANNEL_ENTRY_FIELD_T) ((UINT_32) prChannelEntryField
+ P2P_ATTRI_LEN_CHANNEL_ENTRY + (UINT_32)
prChannelEntryField->ucNumberOfChannels);
ucBufferSize -=
(P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels);
}
}
}
#endif
/* We assume user would not set a channel not in the channel list.
* If so, the operating channel still depends on target device supporting capability.
*/
/* TODO: 20110921 frog - */
/* If the Operating channel is not set, a channel from supported channel list is set automatically.
* If there is no supported channel in channel list, a DEFAULT channel is set.
*/
} while (FALSE);
#if 0
prP2pConnSetting->ucOperatingChnl = ucAutoChnl;
#endif
} /* rlmFuncInitialChannelList */
/*----------------------------------------------------------------------------*/
/*!
* \brief Find a common channel list from the local channel list info & target channel list info.
*
* \param[in] prAdapter Pointer of ADAPTER_T
*
* \return boolean value if probe response frame is
*/
/*----------------------------------------------------------------------------*/
VOID
rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter,
IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, IN UINT_8 ucChannelListSize)
{
P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL;
P_CHANNEL_ENTRY_FIELD_T prChannelEntryI =
(P_CHANNEL_ENTRY_FIELD_T) NULL, prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) NULL;
UINT_8 aucCommonChannelList[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE];
UINT_8 ucOriChnlSize = 0, ucNewChnlSize = 0;
do {
ASSERT_BREAK(prAdapter != NULL);
prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings;
prChannelEntryIII = (P_CHANNEL_ENTRY_FIELD_T) aucCommonChannelList;
while (ucChannelListSize > 0) {
prChannelEntryI = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField;
ucOriChnlSize = prP2pConnSetting->ucRfChannelListSize;
while (ucOriChnlSize > 0) {
if (prChannelEntryI->ucRegulatoryClass == prChannelEntryII->ucRegulatoryClass) {
prChannelEntryIII->ucRegulatoryClass = prChannelEntryI->ucRegulatoryClass;
/* TODO: Currently we assume that the regulatory class the same,
* the channels are the same.
*/
kalMemCopy(prChannelEntryIII->aucChannelList,
prChannelEntryII->aucChannelList,
prChannelEntryII->ucNumberOfChannels);
prChannelEntryIII->ucNumberOfChannels = prChannelEntryII->ucNumberOfChannels;
ucNewChnlSize +=
P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryIII->ucNumberOfChannels;
prChannelEntryIII =
(P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryIII +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntryIII->ucNumberOfChannels);
}
ucOriChnlSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryI->ucNumberOfChannels);
prChannelEntryI =
(P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryI +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntryI->ucNumberOfChannels);
}
ucChannelListSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryII->ucNumberOfChannels);
prChannelEntryII = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryII +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntryII->ucNumberOfChannels);
}
kalMemCopy(prP2pConnSetting->aucChannelEntriesField, aucCommonChannelList, ucNewChnlSize);
prP2pConnSetting->ucRfChannelListSize = ucNewChnlSize;
} while (FALSE);
} /* rlmFuncCommonChannelList */
/*----------------------------------------------------------------------------*/
/*!
* \brief
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
UINT_8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN UINT_8 ucChannelNum)
{
UINT_8 ucRegulatoryClass = 0, ucBufferSize = 0;
P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL;
P_CHANNEL_ENTRY_FIELD_T prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) NULL;
UINT_32 u4Idx = 0;
do {
ASSERT_BREAK(prAdapter != NULL);
prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings;
ucBufferSize = prP2pConnSetting->ucRfChannelListSize;
prChannelEntryField = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField;
while (ucBufferSize != 0) {
for (u4Idx = 0; u4Idx < prChannelEntryField->ucNumberOfChannels; u4Idx++) {
if (prChannelEntryField->aucChannelList[u4Idx] == ucChannelNum) {
ucRegulatoryClass = prChannelEntryField->ucRegulatoryClass;
break;
}
}
if (ucRegulatoryClass != 0)
break; /* while */
prChannelEntryField =
(P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntryField +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntryField->ucNumberOfChannels);
ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntryField->ucNumberOfChannels);
}
} while (FALSE);
return ucRegulatoryClass;
} /* rlmFuncFindOperatingClass */
/*----------------------------------------------------------------------------*/
/*!
* \brief
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
BOOLEAN
rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter,
IN UINT_8 ucCheckChnl,
IN PUINT_8 pucSuggestChannel, IN BOOLEAN fgIsSocialChannel, IN BOOLEAN fgIsDefaultChannel)
{
BOOLEAN fgIsResultAvailable = FALSE;
P_CHANNEL_ENTRY_FIELD_T prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) NULL;
P_P2P_CONNECTION_SETTINGS_T prP2pConnSetting = (P_P2P_CONNECTION_SETTINGS_T) NULL;
UINT_8 ucBufferSize = 0, ucIdx = 0, ucChannelSelected = 0;
do {
ASSERT_BREAK(prAdapter != NULL);
if (fgIsDefaultChannel)
ucChannelSelected = P2P_DEFAULT_LISTEN_CHANNEL;
prP2pConnSetting = prAdapter->rWifiVar.prP2PConnSettings;
ucBufferSize = prP2pConnSetting->ucRfChannelListSize;
prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) prP2pConnSetting->aucChannelEntriesField;
while ((ucBufferSize != 0) && (!fgIsResultAvailable)) {
for (ucIdx = 0; ucIdx < prChannelEntry->ucNumberOfChannels; ucIdx++) {
if ((!fgIsSocialChannel) ||
(prChannelEntry->aucChannelList[ucIdx] == 1) ||
(prChannelEntry->aucChannelList[ucIdx] == 6) ||
(prChannelEntry->aucChannelList[ucIdx] == 11)) {
if (prChannelEntry->aucChannelList[ucIdx] <= 11) {
/* 2.4G. */
ucChannelSelected = prChannelEntry->aucChannelList[ucIdx];
} else if ((prChannelEntry->aucChannelList[ucIdx] < 52)
&& (prChannelEntry->aucChannelList[ucIdx] > 14)) {
/* 2.4G + 5G. */
ucChannelSelected = prChannelEntry->aucChannelList[ucIdx];
}
if (ucChannelSelected == ucCheckChnl) {
fgIsResultAvailable = TRUE;
break;
}
}
}
ucBufferSize -= (P2P_ATTRI_LEN_CHANNEL_ENTRY + prChannelEntry->ucNumberOfChannels);
prChannelEntry = (P_CHANNEL_ENTRY_FIELD_T) ((ULONG) prChannelEntry +
P2P_ATTRI_LEN_CHANNEL_ENTRY +
(ULONG) prChannelEntry->ucNumberOfChannels);
}
if ((!fgIsResultAvailable) && (pucSuggestChannel != NULL)) {
DBGLOG(P2P, TRACE,
"The request channel %d is not available, sugguested channel:%d\n",
ucCheckChnl, ucChannelSelected);
/* Given a suggested channel. */
*pucSuggestChannel = ucChannelSelected;
}
} while (FALSE);
return fgIsResultAvailable;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief
*
* \param[in]
*
* \return none
*/
/*----------------------------------------------------------------------------*/
ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo)
{
P_DOMAIN_SUBBAND_INFO prSubband;
P_DOMAIN_INFO_ENTRY prDomainInfo;
UINT_8 ucSecondChannel, i, j;
ENUM_CHNL_EXT_T eSCO;
ENUM_CHNL_EXT_T eTempSCO;
UINT_8 ucMaxBandwidth = MAX_BW_80_80_MHZ; /*chip capability*/
eSCO = CHNL_EXT_SCN;
eTempSCO = CHNL_EXT_SCN;
if (prBssInfo->eBand == BAND_2G4) {
if (prBssInfo->ucPrimaryChannel != 14)
eSCO = (prBssInfo->ucPrimaryChannel > 7) ? CHNL_EXT_SCB : CHNL_EXT_SCA;
} else {
if (regd_is_single_sku_en()) {
if (rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand,
prBssInfo->ucPrimaryChannel))
eSCO = rlmSelectSecondaryChannelType(prAdapter, prBssInfo->eBand,
prBssInfo->ucPrimaryChannel);
} else {
prDomainInfo = rlmDomainGetDomainInfo(prAdapter);
ASSERT(prDomainInfo);
for (i = 0; i < MAX_SUBBAND_NUM; i++) {
prSubband = &prDomainInfo->rSubBand[i];
if (prSubband->ucBand == prBssInfo->eBand) {
for (j = 0; j < prSubband->ucNumChannels; j++) {
if ((prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan)
== prBssInfo->ucPrimaryChannel) {
eSCO = (j & 1) ? CHNL_EXT_SCB : CHNL_EXT_SCA;
break;
}
}
if (j < prSubband->ucNumChannels)
break; /* Found */
}
}
}
}
/* Check if it is boundary channel and 40MHz BW is permitted */
if (eSCO != CHNL_EXT_SCN) {
ucSecondChannel = (eSCO == CHNL_EXT_SCA) ?
(prBssInfo->ucPrimaryChannel + CHNL_SPAN_20) : (prBssInfo->ucPrimaryChannel - CHNL_SPAN_20);
if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel))
eSCO = CHNL_EXT_SCN;
}
/* Overwrite SCO settings by wifi cfg */
if (IS_BSS_P2P(prBssInfo)) {
/* AP mode */
if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings[prBssInfo->u4PrivateData])) {
if (prAdapter->rWifiVar.ucApSco == CHNL_EXT_SCA || prAdapter->rWifiVar.ucApSco == CHNL_EXT_SCB)
eTempSCO = (ENUM_CHNL_EXT_T) prAdapter->rWifiVar.ucApSco;
}
/* P2P mode */
else {
if (prAdapter->rWifiVar.ucP2pGoSco == CHNL_EXT_SCA ||
prAdapter->rWifiVar.ucP2pGoSco == CHNL_EXT_SCB) {
eTempSCO = (ENUM_CHNL_EXT_T) prAdapter->rWifiVar.ucP2pGoSco;
}
}
/* Check again if it is boundary channel and 40MHz BW is permitted */
if (eTempSCO != CHNL_EXT_SCN) {
ucSecondChannel = (eTempSCO == CHNL_EXT_SCA) ?
(prBssInfo->ucPrimaryChannel + 4) : (prBssInfo->ucPrimaryChannel - 4);
if (rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, ucSecondChannel))
eSCO = eTempSCO;
}
}
/* Overwrite SCO settings by wifi cfg bandwidth setting */
if (IS_BSS_P2P(prBssInfo)) {
/* AP mode */
if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings[prBssInfo->u4PrivateData])) {
if (prBssInfo->eBand == BAND_2G4)
ucMaxBandwidth = prAdapter->rWifiVar.ucAp2gBandwidth;
else
ucMaxBandwidth = prAdapter->rWifiVar.ucAp5gBandwidth;
}
/* P2P mode */
else {
if (prBssInfo->eBand == BAND_2G4)
ucMaxBandwidth = prAdapter->rWifiVar.ucP2p2gBandwidth;
else
ucMaxBandwidth = prAdapter->rWifiVar.ucP2p5gBandwidth;
}
if (ucMaxBandwidth < MAX_BW_40MHZ)
eSCO = CHNL_EXT_SCN;
}
return eSCO;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief: Get AP secondary channel offset from cfg80211 or wifi.cfg
*
* \param[in] prAdapter Pointer of ADAPTER_T, prBssInfo Pointer of BSS_INFO_T,
*
* \return ENUM_CHNL_EXT_T AP secondary channel offset
*/
/*----------------------------------------------------------------------------*/
ENUM_CHNL_EXT_T rlmGetScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo)
{
ENUM_BAND_T eBand;
UINT_8 ucChannel;
ENUM_CHNL_EXT_T eSCO;
INT_32 i4DeltaBw;
UINT_32 u4AndOneSCO;
P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL;
prP2pRoleFsmInfo = p2pFuncGetRoleByBssIdx(prAdapter, prBssInfo->ucBssIndex);
if (!prAdapter->rWifiVar.ucApChnlDefFromCfg && prP2pRoleFsmInfo) {
prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo);
eSCO = CHNL_EXT_SCN;
if (cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex) == MAX_BW_40MHZ) {
/* If BW 40, compare S0 and primary channel freq */
if (prP2pConnReqInfo->u4CenterFreq1 > prP2pConnReqInfo->u2PriChnlFreq)
eSCO = CHNL_EXT_SCA;
else
eSCO = CHNL_EXT_SCB;
} else if (cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex) > MAX_BW_40MHZ) {
/* P: PriChnlFreq, A:CHNL_EXT_SCA, B: CHNL_EXT_SCB, -:BW SPAN 5M */
/* --|----|--CenterFreq1--|----|-- */
/* --|----|--CenterFreq1--B----P-- */
/* --|----|--CenterFreq1--P----A-- */
i4DeltaBw = prP2pConnReqInfo->u2PriChnlFreq - prP2pConnReqInfo->u4CenterFreq1;
u4AndOneSCO = CHNL_EXT_SCB;
eSCO = CHNL_EXT_SCA;
if (i4DeltaBw < 0) {
/* --|----|--CenterFreq1--|----|-- */
/* --P----A--CenterFreq1--|----|-- */
/* --B----P--CenterFreq1--|----|-- */
u4AndOneSCO = CHNL_EXT_SCA;
eSCO = CHNL_EXT_SCB;
i4DeltaBw = -i4DeltaBw;
}
i4DeltaBw = i4DeltaBw - (CHANNEL_SPAN_20 >> 1);
if ((i4DeltaBw/CHANNEL_SPAN_20) & 1)
eSCO = u4AndOneSCO;
}
} else {
/* In this case, the first BSS's SCO is 40MHz and known, so AP can
* apply 40MHz bandwidth, but the first BSS's SCO may be changed
* later if its Beacon lost timeout occurs
*/
if (!(cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) &&
eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel &&
eBand == prBssInfo->eBand))
eSCO = rlmDecideScoForAP(prAdapter, prBssInfo);
}
return eSCO;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief: Get AP channel number of Channel Center Frequency Segment 0 from cfg80211 or wifi.cfg
*
* \param[in] prAdapter Pointer of ADAPTER_T, prBssInfo Pointer of BSS_INFO_T,
*
* \return UINT_8 AP channel number of Channel Center Frequency Segment 0
*/
/*----------------------------------------------------------------------------*/
UINT_8 rlmGetVhtS1ForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo)
{
UINT_32 ucFreq1Channel;
UINT_8 ucPrimaryChannel = prBssInfo->ucPrimaryChannel;
P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL;
prP2pRoleFsmInfo = p2pFuncGetRoleByBssIdx(prAdapter, prBssInfo->ucBssIndex);
if (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_20_40)
return 0;
if (!prAdapter->rWifiVar.ucApChnlDefFromCfg && prP2pRoleFsmInfo) {
prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo);
ucFreq1Channel = nicFreq2ChannelNum(prP2pConnReqInfo->u4CenterFreq1 * 1000);
} else
ucFreq1Channel = nicGetVhtS1(ucPrimaryChannel, prBssInfo->ucVhtChannelWidth);
return ucFreq1Channel;
}