blob: 88529f6f070705b5c3182f18cdb6384c485c9509 [file] [edit]
/******************************************************************************
*
* 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.
*
*****************************************************************************/
#include "precomp.h"
/*
* definition for AP selection algrithm
*/
#define BSS_FULL_SCORE (100)
#define CHNL_BSS_NUM_THRESOLD 100
#define BSS_STA_CNT_THRESOLD 30
#define SCORE_PER_AP 1
#define ROAMING_NO_SWING_SCORE_STEP 100
/* MCS9 at BW 160 requires rssi at least -48dbm */
#define BEST_RSSI -48
/* MCS7 at 20BW, MCS5 at 40BW, MCS4 at 80BW, MCS3 at 160BW */
#define GOOD_RSSI_FOR_HT_VHT -64
/* Link speed 1Mbps need at least rssi -94dbm for 2.4G */
#define MINIMUM_RSSI_2G4 -94
/* Link speed 6Mbps need at least rssi -86dbm for 5G */
#define MINIMUM_RSSI_5G -86
/* Real Rssi of a Bss may range in current_rssi - 5 dbm
*to current_rssi + 5 dbm
*/
#define RSSI_DIFF_BETWEEN_BSS 10 /* dbm */
#define LOW_RSSI_FOR_5G_BAND -70 /* dbm */
#define HIGH_RSSI_FOR_5G_BAND -60 /* dbm */
#define WEIGHT_IDX_CHNL_UTIL 2
#define WEIGHT_IDX_SNR 3
#define WEIGHT_IDX_RSSI 2
#define WEIGHT_IDX_SCN_MISS_CNT 2
#define WEIGHT_IDX_PROBE_RSP 1
#define WEIGHT_IDX_CLIENT_CNT 1
#define WEIGHT_IDX_AP_NUM 2
#define WEIGHT_IDX_5G_BAND 0
#define WEIGHT_IDX_BAND_WIDTH 1
#define WEIGHT_IDX_STBC 1
#define WEIGHT_IDX_DEAUTH_LAST 4
#define WEIGHT_IDX_BLACK_LIST 2
#if CFG_SUPPORT_RSN_SCORE
#define WEIGHT_IDX_RSN 2
#endif
#define WEIGHT_IDX_SAA 2
#define CALCULATE_SCORE_BY_PROBE_RSP(prBssDesc) \
(WEIGHT_IDX_PROBE_RSP * \
(prBssDesc->fgSeenProbeResp ? BSS_FULL_SCORE : 0))
#define CALCULATE_SCORE_BY_MISS_CNT(prAdapter, prBssDesc) \
(WEIGHT_IDX_SCN_MISS_CNT * \
(prAdapter->rWifiVar.rScanInfo.u4ScanUpdateIdx - \
prBssDesc->u4UpdateIdx > 3 ? 0 : \
(BSS_FULL_SCORE - (prAdapter->rWifiVar.rScanInfo.u4ScanUpdateIdx - \
prBssDesc->u4UpdateIdx) * 25)))
#define CALCULATE_SCORE_BY_BAND(prAdapter, prBssDesc, cRssi) \
(WEIGHT_IDX_5G_BAND * \
((prBssDesc->eBand == BAND_5G && prAdapter->fgEnable5GBand && \
cRssi > -70) ? BSS_FULL_SCORE : 0))
#define CALCULATE_SCORE_BY_STBC(prAdapter, prBssDesc) \
(WEIGHT_IDX_STBC * \
(prBssDesc->fgMultiAnttenaAndSTBC ? BSS_FULL_SCORE:0))
#define CALCULATE_SCORE_BY_DEAUTH(prBssDesc) \
(WEIGHT_IDX_DEAUTH_LAST * \
(prBssDesc->fgDeauthLastTime ? 0:BSS_FULL_SCORE))
#if CFG_SUPPORT_RSN_SCORE
#define CALCULATE_SCORE_BY_RSN(prBssDesc) \
(WEIGHT_IDX_RSN * (prBssDesc->fgIsRSNSuitableBss ? BSS_FULL_SCORE:0))
#endif
/* Channel Utilization: weight index will be */
static uint16_t scanCalculateScoreByChnlInfo(
struct AIS_SPECIFIC_BSS_INFO *prAisSpecificBssInfo, uint8_t ucChannel)
{
struct ESS_CHNL_INFO *prEssChnlInfo = &prAisSpecificBssInfo->
arCurEssChnlInfo[0];
uint8_t i = 0;
uint16_t u2Score = 0;
for (; i < prAisSpecificBssInfo->ucCurEssChnlInfoNum; i++) {
if (ucChannel == prEssChnlInfo[i].ucChannel) {
#if 0 /* currently, we don't take channel utilization into account */
/* the channel utilization max value is 255.
*great utilization means little weight value.
* the step of weight value is 2.6
*/
u2Score = WEIGHT_IDX_CHNL_UTIL *
(BSS_FULL_SCORE -
(prEssChnlInfo[i].ucUtilization * 10 / 26));
#endif
/* if AP num on this channel is greater than 100,
* the weight will be 0.
* otherwise, the weight value decrease 1
* if AP number increase 1
*/
if (prEssChnlInfo[i].ucApNum <= CHNL_BSS_NUM_THRESOLD)
u2Score += WEIGHT_IDX_AP_NUM * (BSS_FULL_SCORE -
prEssChnlInfo[i].ucApNum *
SCORE_PER_AP);
log_dbg(SCN, TRACE, "channel %d, AP num %d\n",
ucChannel, prEssChnlInfo[i].ucApNum);
break;
}
}
return u2Score;
}
static uint16_t scanCalculateScoreByBandwidth(struct ADAPTER *prAdapter,
struct BSS_DESC *prBssDesc)
{
uint16_t u2Score = 0;
if (prBssDesc->fgIsHTPresent) {
if (prBssDesc->eBand == BAND_2G4)
u2Score = (prBssDesc->eSco == 0) ? 60:100;
else if (prBssDesc->eBand == BAND_5G)
u2Score = (prBssDesc->eSco == 0) ? 60:100;
} else if (prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)
u2Score = 20;
else
u2Score = 10;
log_dbg(SCN, TRACE, "ht %d, eband %d, esco %d, u2Score %d\n",
prBssDesc->fgIsHTPresent, prBssDesc->eBand, prBssDesc->eSco,
u2Score);
return u2Score * WEIGHT_IDX_BAND_WIDTH;
}
static uint16_t scanCalculateScoreByClientCnt(struct BSS_DESC *prBssDesc)
{
uint16_t u2Score = 0;
log_dbg(SCN, TRACE, "Exist bss load %d, sta cnt %d\n",
prBssDesc->fgExsitBssLoadIE, prBssDesc->u2StaCnt);
if (!prBssDesc->fgExsitBssLoadIE || prBssDesc->u2StaCnt >
BSS_STA_CNT_THRESOLD)
return 0;
u2Score = BSS_FULL_SCORE - prBssDesc->u2StaCnt * 3;
return u2Score * WEIGHT_IDX_CLIENT_CNT;
}
#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT
struct NEIGHBOR_AP_T *scanGetNeighborAPEntry(struct LINK *prNeighborApLink,
uint8_t *pucBssid)
{
struct NEIGHBOR_AP_T *prNeighborAP = NULL;
LINK_FOR_EACH_ENTRY(prNeighborAP, prNeighborApLink, rLinkEntry,
struct NEIGHBOR_AP_T)
{
if (EQUAL_MAC_ADDR(prNeighborAP->aucBssid, pucBssid))
return prNeighborAP;
}
return NULL;
}
u_int8_t scanPreferenceIsZero(struct ADAPTER *prAdapter, uint8_t *pucBssid)
{
struct LINK *prNeighborAPLink = &prAdapter->rWifiVar.rAisSpecificBssInfo
.rNeighborApList.rUsingLink;
struct NEIGHBOR_AP_T *prNeighborAP = NULL;
if (prNeighborAPLink->u4NumElem == 0)
return FALSE;
prNeighborAP = scanGetNeighborAPEntry(prNeighborAPLink, pucBssid);
if (prNeighborAP == NULL)
return FALSE;
if (!prNeighborAP->fgPrefPresence)
return FALSE;
if (prNeighborAP->ucPreference > 0)
return FALSE;
return TRUE;
}
#endif
static u_int8_t scanNeedReplaceCandidate(struct ADAPTER *prAdapter,
struct BSS_DESC *prCandBss, struct BSS_DESC *prCurrBss,
uint16_t u2CandScore, uint16_t u2CurrScore)
{
int8_t cCandRssi = RCPI_TO_dBm(prCandBss->ucRCPI);
int8_t cCurrRssi = RCPI_TO_dBm(prCurrBss->ucRCPI);
uint32_t u4UpdateIdx = prAdapter->rWifiVar.rScanInfo.u4ScanUpdateIdx;
uint16_t u2CandMiss = u4UpdateIdx - prCandBss->u4UpdateIdx;
uint16_t u2CurrMiss = u4UpdateIdx - prCurrBss->u4UpdateIdx;
/* 1. No need check score case
* 1.1 Scan missing count of CurrBss is too more,
* but Candidate is suitable, don't replace
*/
if (u2CurrMiss > 2 && u2CurrMiss > u2CandMiss) {
log_dbg(SCN, INFO, "Scan Miss count of CurrBss > 2, and Candidate <= 2\n");
return FALSE;
}
/* 1.2 Scan missing count of Candidate is too more,
* but CurrBss is suitable, replace
*/
if (u2CandMiss > 2 && u2CandMiss > u2CurrMiss) {
log_dbg(SCN, INFO, "Scan Miss count of Candidate > 2, and CurrBss <= 2\n");
return TRUE;
}
/* 1.3 Hard connecting RSSI check */
if ((prCurrBss->eBand == BAND_5G && cCurrRssi < MINIMUM_RSSI_5G) ||
(prCurrBss->eBand == BAND_2G4 && cCurrRssi < MINIMUM_RSSI_2G4))
return FALSE;
else if ((prCandBss->eBand == BAND_5G && cCandRssi < MINIMUM_RSSI_5G) ||
(prCandBss->eBand == BAND_2G4 && cCandRssi < MINIMUM_RSSI_2G4))
return TRUE;
/* 1.4 prefer to select 5G Bss if Rssi of a 5G band BSS is >= -60dbm */
if (prCandBss->eBand != prCurrBss->eBand) {
if (prCurrBss->eBand == BAND_5G) {
/* Current AP is 5G, replace candidate
* AP of current AP is good.
*/
if (cCurrRssi >= HIGH_RSSI_FOR_5G_BAND ||
(cCandRssi < HIGH_RSSI_FOR_5G_BAND &&
cCurrRssi > LOW_RSSI_FOR_5G_BAND))
return TRUE;
else if (cCurrRssi < LOW_RSSI_FOR_5G_BAND &&
cCurrRssi < cCandRssi)
return FALSE;
} else {
/* Candidate AP is 5G, don't replace it
* if it's good enough.
*/
if (cCandRssi >= HIGH_RSSI_FOR_5G_BAND ||
(cCurrRssi < HIGH_RSSI_FOR_5G_BAND &&
cCandRssi > LOW_RSSI_FOR_5G_BAND))
return FALSE;
else if (cCandRssi < LOW_RSSI_FOR_5G_BAND &&
cCandRssi < cCurrRssi)
return TRUE;
}
}
/* 1.5 RSSI of Current Bss is lower than Candidate, don't replace
* If the lower Rssi is greater than -59dbm,
* then no need check the difference
* Otherwise, if difference is greater than 10dbm, select the good RSSI
*/
if (cCandRssi - cCurrRssi >= RSSI_DIFF_BETWEEN_BSS)
return FALSE;
/* RSSI of Candidate Bss is lower than Current, replace */
if (cCurrRssi - cCandRssi >= RSSI_DIFF_BETWEEN_BSS)
return TRUE;
#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT
if (scanPreferenceIsZero(prAdapter, prCurrBss->aucBSSID)) {
log_dbg(SCN, INFO,
"BTM: %s[" MACSTR "] preference value is 0, skip it\n",
prCurrBss->aucSSID, MAC2STR(prCurrBss->aucBSSID));
return FALSE;
}
#endif
/* 2. Check Score */
/* 2.1 Cases that no need to replace candidate */
if (prCandBss->fgIsConnected) {
if ((u2CandScore + ROAMING_NO_SWING_SCORE_STEP) >= u2CurrScore)
return FALSE;
} else if (prCurrBss->fgIsConnected) {
if (u2CandScore >= (u2CurrScore + ROAMING_NO_SWING_SCORE_STEP))
return FALSE;
} else if (u2CandScore >= u2CurrScore)
return FALSE;
/* 2.2 other cases, replace candidate */
return TRUE;
}
static u_int8_t scanSanityCheckBssDesc(struct ADAPTER *prAdapter,
struct BSS_DESC *prBssDesc, enum ENUM_BAND eBand, uint8_t ucChannel,
u_int8_t fgIsFixedChannel)
{
if (!(prBssDesc->ucPhyTypeSet &
(prAdapter->rWifiVar.ucAvailablePhyTypeSet))) {
log_dbg(SCN, WARN,
"SEARCH: Ignore unsupported ucPhyTypeSet = %x\n",
prBssDesc->ucPhyTypeSet);
return FALSE;
}
if (prBssDesc->fgIsUnknownBssBasicRate)
return FALSE;
if (fgIsFixedChannel &&
(eBand != prBssDesc->eBand || ucChannel !=
prBssDesc->ucChannelNum)) {
log_dbg(SCN, INFO, "Fix channel required band %d, channel %d\n",
eBand, ucChannel);
return FALSE;
}
if (!rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand,
prBssDesc->ucChannelNum)) {
log_dbg(SCN, WARN, "Band %d channel %d is not legal\n",
prBssDesc->eBand, prBssDesc->ucChannelNum);
return FALSE;
}
if (CHECK_FOR_TIMEOUT(kalGetTimeTick(), prBssDesc->rUpdateTime,
SEC_TO_SYSTIME(SCN_BSS_DESC_STALE_SEC))) {
log_dbg(SCN, WARN, "BSS "
MACSTR
" description is too old.\n",
MAC2STR(prBssDesc->aucBSSID));
return FALSE;
}
#if CFG_SUPPORT_WAPI
if (prAdapter->rWifiVar.rConnSettings.fgWapiMode) {
if (!wapiPerformPolicySelection(prAdapter, prBssDesc))
return FALSE;
} else
#endif
if (!rsnPerformPolicySelection(prAdapter, prBssDesc))
return FALSE;
if (prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) {
log_dbg(SCN, WARN, "Skip while at counter measure period!!!\n");
return FALSE;
}
return TRUE;
}
static uint16_t scanCalculateScoreByRssi(struct BSS_DESC *prBssDesc)
{
uint16_t u2Score = 0;
int8_t cRssi = RCPI_TO_dBm(prBssDesc->ucRCPI);
if (cRssi >= -20)
u2Score = BSS_FULL_SCORE;
else if (cRssi >= -55)
u2Score = 95;
else if (cRssi >= -65)
u2Score = 80;
else if (cRssi >= -70)
u2Score = 50;
else if (cRssi >= -77)
u2Score = 15;
else if (cRssi >= -88)
u2Score = 10;
else if (cRssi < -88 && cRssi > -100)
u2Score = 5;
else if (cRssi <= -100)
u2Score = 0;
u2Score *= WEIGHT_IDX_RSSI;
return u2Score;
}
static uint16_t scanCalculateScoreByBand(struct ADAPTER *prAdapter,
struct BSS_DESC *prBssDesc, int8_t cRssi)
{
uint16_t u2Score = 0;
struct AIS_FSM_INFO *prAisFsmInfo;
#if CFG_SUPPORT_ROAMING
struct ROAMING_INFO *prRoamingFsmInfo;
#endif
prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo);
#if CFG_SUPPORT_ROAMING
prRoamingFsmInfo = (struct ROAMING_INFO *)
&(prAdapter->rWifiVar.rRoamingInfo);
#endif
if (prBssDesc->eBand == BAND_5G && prAdapter->fgEnable5GBand
&& cRssi > -60
#if CFG_SUPPORT_ROAMING
&& prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE
#endif
&& prAisFsmInfo->u4PostponeIndStartTime == 0)
u2Score = (WEIGHT_IDX_5G_BAND * BSS_FULL_SCORE);
return u2Score;
}
static uint16_t scanCalculateScoreBySaa(struct ADAPTER *prAdapter,
struct BSS_DESC *prBssDesc)
{
uint16_t u2Score = 0;
struct STA_RECORD *prStaRec = (struct STA_RECORD *) NULL;
prStaRec = cnmGetStaRecByAddress(prAdapter, NETWORK_TYPE_AIS,
prBssDesc->aucSrcAddr);
if (prStaRec)
u2Score = WEIGHT_IDX_SAA * (prStaRec->ucTxAuthAssocRetryCount
? 0 : BSS_FULL_SCORE);
else
u2Score = WEIGHT_IDX_SAA * BSS_FULL_SCORE;
return u2Score;
}
/*
* Bss Characteristics to be taken into account when calculate Score:
* Channel Loading Group:
* 1. Client Count (in BSS Load IE).
* 2. AP number on the Channel.
*
* RF Group:
* 1. Channel utilization.
* 2. SNR.
* 3. RSSI.
*
* Misc Group:
* 1. Deauth Last time.
* 2. Scan Missing Count.
* 3. Has probe response in scan result.
*
* Capability Group:
* 1. Prefer 5G band.
* 2. Bandwidth.
* 3. STBC and Multi Anttena.
*/
struct BSS_DESC *scanSearchBssDescByScoreForAis(struct ADAPTER *prAdapter)
{
struct AIS_SPECIFIC_BSS_INFO *prAisSpecificBssInfo = NULL;
struct LINK *prEssLink = NULL;
struct CONNECTION_SETTINGS *prConnSettings = NULL;
struct BSS_DESC *prBssDesc = NULL;
struct BSS_DESC *prCandBssDesc = NULL;
struct BSS_DESC *prCandBssDescForLowRssi = NULL;
uint16_t u2ScoreBand = 0;
uint16_t u2ScoreChnlInfo = 0;
uint16_t u2ScoreStaCnt = 0;
uint16_t u2ScoreProbeRsp = 0;
uint16_t u2ScoreScanMiss = 0;
uint16_t u2ScoreBandwidth = 0;
uint16_t u2ScoreSTBC = 0;
uint16_t u2ScoreDeauth = 0;
uint16_t u2ScoreRssi = 0;
uint16_t u2ScoreTotal = 0;
uint16_t u2ScoreRSN = 0;
uint16_t u2ScoreSaa = 0;
uint16_t u2CandBssScore = 0;
uint16_t u2CandBssScoreForLowRssi = 0;
uint16_t u2BlackListScore = 0;
u_int8_t fgSearchBlackList = FALSE;
u_int8_t fgIsFixedChannel = FALSE;
enum ENUM_BAND eBand = BAND_2G4;
uint8_t ucChannel = 0;
int8_t cRssi = -128;
if (!prAdapter) {
log_dbg(SCN, ERROR, "prAdapter is NULL!\n");
return NULL;
}
prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo;
prConnSettings = &(prAdapter->rWifiVar.rConnSettings);
prEssLink = &prAisSpecificBssInfo->rCurEssLink;
#if CFG_SUPPORT_CHNL_CONFLICT_REVISE
fgIsFixedChannel = cnmAisDetectP2PChannel
(prAdapter, &eBand, &ucChannel);
#else
fgIsFixedChannel =
cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel);
#endif
aisRemoveTimeoutBlacklist(prAdapter);
log_dbg(SCN, INFO, "%s: ConnectionPolicy = %d\n",
__func__,
prConnSettings->eConnectionPolicy);
try_again:
LINK_FOR_EACH_ENTRY(prBssDesc, prEssLink, rLinkEntryEss,
struct BSS_DESC) {
if (prConnSettings->eConnectionPolicy == CONNECT_BY_BSSID &&
EQUAL_MAC_ADDR(prBssDesc->aucBSSID,
prConnSettings->aucBSSID)) {
if (!scanSanityCheckBssDesc(prAdapter, prBssDesc,
eBand, ucChannel, fgIsFixedChannel))
continue;
/* Make sure to match with SSID if supplied.
* Some old dualband APs share a single BSSID
* among different BSSes.
*/
if ((prBssDesc->ucSSIDLen > 0 &&
prConnSettings->ucSSIDLen > 0 &&
EQUAL_SSID(prBssDesc->aucSSID,
prBssDesc->ucSSIDLen,
prConnSettings->aucSSID,
prConnSettings->ucSSIDLen)) ||
prConnSettings->ucSSIDLen == 0)
log_dbg(SCN, LOUD, "%s: BSSID/SSID pair matched\n",
__func__);
else {
log_dbg(SCN, ERROR, "%s: BSSID/SSID pair unmatched ("
MACSTR
")\n", __func__,
MAC2STR(prBssDesc->aucBSSID));
continue;
}
prCandBssDesc = prBssDesc;
break;
} else if (prConnSettings->eConnectionPolicy ==
CONNECT_BY_BSSID_HINT &&
EQUAL_MAC_ADDR(prBssDesc->aucBSSID,
prConnSettings->aucBSSIDHint)) {
if (!scanSanityCheckBssDesc(prAdapter, prBssDesc,
eBand, ucChannel, fgIsFixedChannel))
continue;
prCandBssDesc = prBssDesc;
break;
}
if (!fgSearchBlackList) {
prBssDesc->prBlack =
aisQueryBlackList(prAdapter, prBssDesc);
if (prBssDesc->prBlack) {
if (prBssDesc->prBlack->fgIsInFWKBlacklist ==
TRUE)
log_dbg(SCN, INFO, "%s("
MACSTR
") is in FWK blacklist, skip it\n",
prBssDesc->aucSSID,
MAC2STR(prBssDesc->aucBSSID));
continue;
}
} else if (!prBssDesc->prBlack)
continue;
else {
/* never search FWK blacklist even
* if we are trying blacklist
*/
if (prBssDesc->prBlack->fgIsInFWKBlacklist == TRUE) {
log_dbg(SCN, INFO, "Although trying blacklist, %s("
MACSTR
") is in FWK blacklist, skip it\n",
prBssDesc->aucSSID,
MAC2STR(prBssDesc->aucBSSID));
continue;
}
u2BlackListScore = WEIGHT_IDX_BLACK_LIST *
aisCalculateBlackListScore(prAdapter,
prBssDesc);
}
cRssi = RCPI_TO_dBm(prBssDesc->ucRCPI);
if (!scanSanityCheckBssDesc(prAdapter, prBssDesc, eBand,
ucChannel, fgIsFixedChannel))
continue;
u2ScoreBandwidth =
scanCalculateScoreByBandwidth(prAdapter, prBssDesc);
u2ScoreStaCnt = scanCalculateScoreByClientCnt(prBssDesc);
u2ScoreSTBC = CALCULATE_SCORE_BY_STBC(prAdapter, prBssDesc);
u2ScoreChnlInfo =
scanCalculateScoreByChnlInfo(prAisSpecificBssInfo,
prBssDesc->ucChannelNum);
u2ScoreRssi = scanCalculateScoreByRssi(prBssDesc);
u2ScoreDeauth = CALCULATE_SCORE_BY_DEAUTH(prBssDesc);
u2ScoreProbeRsp = CALCULATE_SCORE_BY_PROBE_RSP(prBssDesc);
u2ScoreScanMiss = CALCULATE_SCORE_BY_MISS_CNT(prAdapter,
prBssDesc);
u2ScoreBand = scanCalculateScoreByBand(prAdapter, prBssDesc,
cRssi);
#if CFG_SUPPORT_RSN_SCORE
u2ScoreRSN = CALCULATE_SCORE_BY_RSN(prBssDesc);
#endif
u2ScoreSaa = scanCalculateScoreBySaa(prAdapter, prBssDesc);
u2ScoreTotal = u2ScoreBandwidth + u2ScoreChnlInfo +
u2ScoreDeauth + u2ScoreProbeRsp + u2ScoreScanMiss +
u2ScoreRssi + u2ScoreStaCnt + u2ScoreSTBC +
u2ScoreBand + u2BlackListScore + u2ScoreRSN +
u2ScoreSaa;
log_dbg(SCN, INFO,
MACSTR
" cRSSI[%d] 5G[%d] Score, Total %d, DE[%d], PR[%d], SM[%d], RSSI[%d], BA[%d] RSN[%d], SAA[%d], BW[%d], CN[%d], ST[%d], CI[%d]\n",
MAC2STR(prBssDesc->aucBSSID), cRssi,
(prBssDesc->eBand == BAND_5G ? 1 : 0), u2ScoreTotal,
u2ScoreDeauth, u2ScoreProbeRsp, u2ScoreScanMiss,
u2ScoreRssi, u2BlackListScore, u2ScoreRSN, u2ScoreSaa,
u2ScoreBandwidth, u2ScoreStaCnt, u2ScoreSTBC,
u2ScoreChnlInfo);
if (!prCandBssDesc ||
scanNeedReplaceCandidate(prAdapter, prCandBssDesc,
prBssDesc, u2CandBssScore, u2ScoreTotal)) {
prCandBssDesc = prBssDesc;
u2CandBssScore = u2ScoreTotal;
}
}
if (prCandBssDesc) {
if (prCandBssDesc->fgIsConnected && !fgSearchBlackList &&
prEssLink->u4NumElem > 0) {
fgSearchBlackList = TRUE;
log_dbg(SCN, INFO, "Can't roam out, try blacklist\n");
goto try_again;
}
if (prConnSettings->eConnectionPolicy == CONNECT_BY_BSSID)
log_dbg(SCN, INFO, "Selected "
MACSTR
" %d base on ssid,when find %s, "
MACSTR
" in %d bssid,fix channel %d.\n",
MAC2STR(prCandBssDesc->aucBSSID),
RCPI_TO_dBm(prCandBssDesc->ucRCPI),
prConnSettings->aucSSID,
MAC2STR(prConnSettings->aucBSSID),
prEssLink->u4NumElem, ucChannel);
else
log_dbg(SCN, INFO,
"Selected "
MACSTR
", cRSSI[%d] 5G[%d] Score %d when find %s, "
MACSTR
" in %d BSSes, fix channel %d.\n",
MAC2STR(prCandBssDesc->aucBSSID),
cRssi = RCPI_TO_dBm(prCandBssDesc->ucRCPI),
(prCandBssDesc->eBand == BAND_5G ? 1 : 0),
u2CandBssScore, prConnSettings->aucSSID,
MAC2STR(prConnSettings->aucBSSID),
prEssLink->u4NumElem, ucChannel);
return prCandBssDesc;
} else if (prCandBssDescForLowRssi) {
log_dbg(SCN, INFO, "Selected " MACSTR
", Score %d when find %s, " MACSTR
" in %d BSSes, fix channel %d.\n",
MAC2STR(prCandBssDescForLowRssi->aucBSSID),
u2CandBssScoreForLowRssi, prConnSettings->aucSSID,
MAC2STR(prConnSettings->aucBSSID), prEssLink->u4NumElem,
ucChannel);
return prCandBssDescForLowRssi;
}
/* if No Candidate BSS is found, try BSSes which are in blacklist */
if (!fgSearchBlackList && prEssLink->u4NumElem > 0) {
fgSearchBlackList = TRUE;
log_dbg(SCN, INFO, "No Bss is found, Try blacklist\n");
goto try_again;
}
log_dbg(SCN, INFO, "Selected None when find %s, " MACSTR
" in %d BSSes, fix channel %d.\n",
prConnSettings->aucSSID, MAC2STR(prConnSettings->aucBSSID),
prEssLink->u4NumElem, ucChannel);
return NULL;
}
void scanGetCurrentEssChnlList(struct ADAPTER *prAdapter)
{
struct BSS_DESC *prBssDesc = NULL;
struct LINK *prBSSDescList =
&prAdapter->rWifiVar.rScanInfo.rBSSDescList;
struct CONNECTION_SETTINGS *prConnSettings = &prAdapter->
rWifiVar.rConnSettings;
struct ESS_CHNL_INFO *prEssChnlInfo = &prAdapter->
rWifiVar.rAisSpecificBssInfo.arCurEssChnlInfo[0];
struct LINK *prCurEssLink = &prAdapter->
rWifiVar.rAisSpecificBssInfo.rCurEssLink;
uint8_t aucChnlBitMap[30] = {0,};
uint8_t aucChnlApNum[215] = {0,};
uint8_t aucChnlUtil[215] = {0,};
uint8_t ucByteNum = 0;
uint8_t ucBitNum = 0;
uint8_t ucChnlCount = 0;
uint8_t j = 0;
if (prConnSettings->ucSSIDLen == 0) {
log_dbg(SCN, INFO, "No Ess are expected to connect\n");
return;
}
kalMemZero(prEssChnlInfo, CFG_MAX_NUM_OF_CHNL_INFO *
sizeof(struct ESS_CHNL_INFO));
while (!LINK_IS_EMPTY(prCurEssLink)) {
prBssDesc =
LINK_PEEK_HEAD(prCurEssLink,
struct BSS_DESC, rLinkEntryEss);
LINK_REMOVE_KNOWN_ENTRY(prCurEssLink,
&prBssDesc->rLinkEntryEss);
}
LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry,
struct BSS_DESC) {
if (prBssDesc->ucChannelNum > 214)
continue;
/* Statistic AP num for each channel */
if (aucChnlApNum[prBssDesc->ucChannelNum] < 255)
aucChnlApNum[prBssDesc->ucChannelNum]++;
if (aucChnlUtil[prBssDesc->ucChannelNum] <
prBssDesc->ucChnlUtilization)
aucChnlUtil[prBssDesc->ucChannelNum] =
prBssDesc->ucChnlUtilization;
if (!EQUAL_SSID(prConnSettings->aucSSID,
prConnSettings->ucSSIDLen,
prBssDesc->aucSSID, prBssDesc->ucSSIDLen))
continue;
/* Record same BSS list */
LINK_INSERT_HEAD(prCurEssLink, &prBssDesc->rLinkEntryEss);
ucByteNum = prBssDesc->ucChannelNum / 8;
ucBitNum = prBssDesc->ucChannelNum % 8;
if (aucChnlBitMap[ucByteNum] & BIT(ucBitNum))
continue;
aucChnlBitMap[ucByteNum] |= BIT(ucBitNum);
prEssChnlInfo[ucChnlCount].ucChannel = prBssDesc->ucChannelNum;
ucChnlCount++;
if (ucChnlCount >= CFG_MAX_NUM_OF_CHNL_INFO)
break;
}
prAdapter->rWifiVar.rAisSpecificBssInfo.ucCurEssChnlInfoNum =
ucChnlCount;
for (j = 0; j < ucChnlCount; j++) {
uint8_t ucChnl = prEssChnlInfo[j].ucChannel;
prEssChnlInfo[j].ucApNum = aucChnlApNum[ucChnl];
prEssChnlInfo[j].ucUtilization = aucChnlUtil[ucChnl];
}
#if 0
/* Sort according to AP number */
for (j = 0; j < ucChnlCount; j++) {
for (i = j + 1; i < ucChnlCount; i++)
if (prEssChnlInfo[j].ucApNum >
prEssChnlInfo[i].ucApNum) {
struct ESS_CHNL_INFO rTemp = prEssChnlInfo[j];
prEssChnlInfo[j] = prEssChnlInfo[i];
prEssChnlInfo[i] = rTemp;
}
}
#endif
log_dbg(SCN, INFO, "Find %s in %d BSSes, result %d\n",
prConnSettings->aucSSID, prBSSDescList->u4NumElem,
prCurEssLink->u4NumElem);
}