wlan: Add support for PER based roaming #2
In congested environments, it could be possible that in station
mode client gets good RSSI from AP however it's not able to
transfer data at good rates. DUT should roam to a better AP if
available, if it faces congestion in home channel.
Following changes are added for this functionality:
1. Add changes to monitor Rx and Tx rates to trigger roam scan
in case data rates are low below a preconfigured value.
2. Implement a new AP selection algorithm which will consider AP
capabilty, channel conditions and RSSI to select new bss.
Add required protocol changes for same.
Change-Id: I394c15b54ea95aa08f648f33383cb0a364278585
CRs-Fixed: 1031345
diff --git a/CORE/SME/inc/csrApi.h b/CORE/SME/inc/csrApi.h
index 7f7820a..93e9963 100644
--- a/CORE/SME/inc/csrApi.h
+++ b/CORE/SME/inc/csrApi.h
@@ -402,6 +402,9 @@
tANI_U8 MFPRequired;
tANI_U8 MFPCapable;
#endif
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ tANI_BOOLEAN isPERRoamScan;
+#endif
}tCsrScanResultFilter;
@@ -1181,6 +1184,13 @@
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
tANI_BOOLEAN isRoamOffloadScanEnabled;
tANI_BOOLEAN bFastRoamInConIniFeatureEnabled;
+ v_BOOL_t isPERRoamEnabled;
+ v_BOOL_t isPERRoamCCAEnabled;
+ v_U32_t rateUpThreshold;
+ v_U32_t rateDownThreshold;
+ v_U32_t waitPeriodForNextPERScan;
+ v_U32_t PERtimerThreshold;
+ v_U32_t PERroamTriggerPercent;
#endif
#endif
diff --git a/CORE/SME/inc/csrInternal.h b/CORE/SME/inc/csrInternal.h
index 9729f6e..daf16c9 100644
--- a/CORE/SME/inc/csrInternal.h
+++ b/CORE/SME/inc/csrInternal.h
@@ -623,6 +623,13 @@
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
tANI_U8 isRoamOffloadScanEnabled;
tANI_BOOLEAN bFastRoamInConIniFeatureEnabled;
+ v_BOOL_t isPERRoamEnabled;
+ v_BOOL_t isPERRoamCCAEnabled;
+ tANI_U32 rateUpThreshold;
+ tANI_U32 rateDownThreshold;
+ tANI_U32 waitPeriodForNextPERScan;
+ tANI_U32 PERtimerThreshold;
+ tANI_U32 PERroamTriggerPercent;
#endif
#endif
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 264c37b..06c738c 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -1906,6 +1906,16 @@
void * txFailIndCallback);
#endif /* WLAN_FEATURE_RMC */
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+VOS_STATUS sme_set_per_roam_rxconfig (tHalHandle hHal, v_U8_t sessionId,
+ v_U16_t minRate, v_U16_t maxRate, v_U8_t minPercentage,
+ v_U16_t minPktRequired, v_U64_t waitPeriodForNextPERScan);
+
+VOS_STATUS sme_unset_per_roam_rxconfig (tHalHandle hHal);
+
+void sme_PERRoamScanStartStop(void *hHal, tANI_U8 start);
+#endif
+
/* ---------------------------------------------------------------------------
\fn sme_DHCPStartInd
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index ec93e5e..ced64e7 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -1932,8 +1932,21 @@
pMac->roam.configParam.nRoamScanHomeAwayTime = pParam->nRoamScanHomeAwayTime;
#endif
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
- pMac->roam.configParam.isRoamOffloadScanEnabled = pParam->isRoamOffloadScanEnabled;
- pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = pParam->bFastRoamInConIniFeatureEnabled;
+ pMac->roam.configParam.isRoamOffloadScanEnabled =
+ pParam->isRoamOffloadScanEnabled;
+ pMac->roam.configParam.bFastRoamInConIniFeatureEnabled =
+ pParam->bFastRoamInConIniFeatureEnabled;
+ pMac->roam.configParam.isPERRoamEnabled =
+ pParam->isPERRoamEnabled;
+ pMac->roam.configParam.rateUpThreshold = pParam->rateUpThreshold;
+ pMac->roam.configParam.rateDownThreshold = pParam->rateDownThreshold;
+ pMac->roam.configParam.waitPeriodForNextPERScan =
+ pParam->waitPeriodForNextPERScan;
+ pMac->roam.configParam.PERtimerThreshold = pParam->PERtimerThreshold;
+ pMac->roam.configParam.isPERRoamCCAEnabled =
+ pParam->isPERRoamCCAEnabled;
+ pMac->roam.configParam.PERroamTriggerPercent =
+ pParam->PERroamTriggerPercent;
#endif
#ifdef FEATURE_WLAN_LFR
pMac->roam.configParam.isFastRoamIniFeatureEnabled = pParam->isFastRoamIniFeatureEnabled;
@@ -2141,6 +2154,17 @@
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
pParam->isRoamOffloadScanEnabled = pMac->roam.configParam.isRoamOffloadScanEnabled;
pParam->bFastRoamInConIniFeatureEnabled = pMac->roam.configParam.bFastRoamInConIniFeatureEnabled;
+ pParam->isPERRoamEnabled =
+ pMac->roam.configParam.isPERRoamEnabled;
+ pParam->rateUpThreshold = pMac->roam.configParam.rateUpThreshold;
+ pParam->rateDownThreshold = pMac->roam.configParam.rateDownThreshold;
+ pParam->waitPeriodForNextPERScan =
+ pMac->roam.configParam.waitPeriodForNextPERScan;
+ pParam->PERtimerThreshold = pMac->roam.configParam.PERtimerThreshold;
+ pParam->isPERRoamCCAEnabled =
+ pMac->roam.configParam.isPERRoamCCAEnabled;
+ pParam->PERroamTriggerPercent =
+ pMac->roam.configParam.PERroamTriggerPercent;
#endif
#ifdef FEATURE_WLAN_LFR
pParam->isFastRoamIniFeatureEnabled = pMac->roam.configParam.isFastRoamIniFeatureEnabled;
@@ -8287,8 +8311,11 @@
tpCsrNeighborRoamControlInfo pNeighborRoamInfo = &pMac->roam.neighborRoamInfo;
tCsrRoamInfo roamInfo;
tANI_U32 roamId = 0;
-
- if ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode )
+ tANI_U32 current_timestamp, max_time = -1;
+ tANI_U32 candidateApCnt, oldestIndex;
+ tANI_U8 nilMac[6] = {0};
+
+ if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode)
{
smsLog( pMac, LOGW, "CSR SmeReassocReq Successful" );
result = eCsrReassocSuccess;
@@ -8301,6 +8328,73 @@
/* Need to dig more on indicating events to SME QoS module */
sme_QosCsrEventInd(pMac, pSmeJoinRsp->sessionId, SME_QOS_CSR_HANDOFF_COMPLETE, NULL);
csrRoamComplete( pMac, result, pSmeJoinRsp);
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ /* Add previous BSSID to blacklist ; this will be in blacklised for
+ * some period and score of this AP will be reduced if black listed
+ * to avoid ping pong */
+ if (pMac->PERroamCandidatesCnt)
+ {
+ current_timestamp = jiffies_to_msecs(jiffies);
+ for (candidateApCnt = 0; candidateApCnt <
+ SIR_PER_ROAM_MAX_CANDIDATE_CNT; candidateApCnt++)
+ {
+ /* Find one blank entry */
+ if (sirCompareMacAddr(nilMac,
+ pMac->previousRoamApInfo[candidateApCnt].bssAddr))
+ {
+ vos_mem_copy(pMac->previousRoamApInfo[candidateApCnt].
+ bssAddr,
+ pNeighborRoamInfo->prevConnProfile.bssid,
+ sizeof(tSirMacAddr));
+ pMac->previousRoamApInfo[candidateApCnt].timeStamp =
+ current_timestamp;
+ smsLog(pMac, LOG1, FL("added bssid=" MAC_ADDRESS_STR " at index %d"),
+ MAC_ADDR_ARRAY(
+ pNeighborRoamInfo->prevConnProfile.bssid),
+ candidateApCnt);
+ break;
+ }
+ /* if already in the list */
+ if (sirCompareMacAddr(pMac->previousRoamApInfo
+ [candidateApCnt].bssAddr,
+ pNeighborRoamInfo->prevConnProfile.bssid) &&
+ ((current_timestamp -
+ pMac->previousRoamApInfo[candidateApCnt].timeStamp) >
+ pMac->PERroamTimeout))
+ {
+ vos_mem_copy(pMac->previousRoamApInfo[candidateApCnt].
+ bssAddr,
+ pNeighborRoamInfo->prevConnProfile.bssid,
+ sizeof(tSirMacAddr));
+ pMac->previousRoamApInfo[candidateApCnt].timeStamp =
+ current_timestamp;
+ break;
+ } else
+ {
+ /* find oldest BSSID entry in the blacklist */
+ if (max_time <
+ pMac->previousRoamApInfo[candidateApCnt].timeStamp)
+ {
+ max_time =
+ pMac->previousRoamApInfo[candidateApCnt].timeStamp;
+ oldestIndex = candidateApCnt;
+ }
+ }
+ }
+ if (candidateApCnt == SIR_PER_ROAM_MAX_CANDIDATE_CNT)
+ {
+ smsLog(pMac, LOGW,
+ "%s: Clearing out oldest roam results bssid="
+ MAC_ADDRESS_STR,
+ __func__,
+ MAC_ADDR_ARRAY(pMac->previousRoamApInfo[oldestIndex].bssAddr));
+ pMac->previousRoamApInfo[oldestIndex].timeStamp = current_timestamp;
+ vos_mem_copy(pMac->previousRoamApInfo[oldestIndex].bssAddr,
+ pNeighborRoamInfo->prevConnProfile.bssid,
+ sizeof(tSirMacAddr));
+ }
+ }
+#endif
}
else
#endif
@@ -16594,7 +16688,9 @@
eHalStatus csrRoamOffloadScan(tpAniSirGlobal pMac, tANI_U8 command, tANI_U8 reason)
{
vos_msg_t msg;
+ vos_msg_t PERroamScanConfigMsg = {0};
tSirRoamOffloadScanReq *pRequestBuf;
+ tSirPERRoamOffloadScanReq *PERRoamReqBuf;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo = &pMac->roam.neighborRoamInfo;
tCsrRoamSession *pSession = NULL;
tANI_U8 i,j,num_channels = 0, ucDot11Mode;
@@ -16880,6 +16976,7 @@
/* MAWC feature */
pRequestBuf->MAWCEnabled =
pMac->roam.configParam.MAWCEnabled;
+
#ifdef FEATURE_WLAN_ESE
pRequestBuf->IsESEEnabled = pMac->roam.configParam.isEseIniFeatureEnabled;
#endif
@@ -17078,6 +17175,52 @@
}
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG, "Roam Scan Offload Command %d, Reason %d", command, reason);
+
+ if (sme_IsFeatureSupportedByFW(PER_BASED_ROAMING) &&
+ (command != ROAM_SCAN_OFFLOAD_STOP))
+ {
+
+ /* PER ROAM SCAN */
+ PERRoamReqBuf = vos_mem_malloc(sizeof(*PERRoamReqBuf));
+ if (!PERRoamReqBuf)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: Not able to allocate mem for PERRoamReqBuf", __func__);
+ return eHAL_STATUS_FAILURE;
+ }
+ /* PER Roam Config */
+ PERRoamReqBuf->rateUpThreshold =
+ pMac->roam.configParam.rateUpThreshold;
+ PERRoamReqBuf->rateDownThreshold =
+ pMac->roam.configParam.rateDownThreshold;
+ PERRoamReqBuf->waitPeriodForNextPERScan =
+ pMac->roam.configParam.waitPeriodForNextPERScan;
+ PERRoamReqBuf->PERtimerThreshold =
+ pMac->roam.configParam.PERtimerThreshold;
+ PERRoamReqBuf->isPERRoamCCAEnabled =
+ pMac->roam.configParam.isPERRoamCCAEnabled;
+ PERRoamReqBuf->PERroamTriggerPercent =
+ pMac->roam.configParam.PERroamTriggerPercent;
+ PERRoamReqBuf->sessionId = sessionId;
+
+ PERroamScanConfigMsg.type = WDA_PER_ROAM_SCAN_OFFLOAD_REQ;
+ PERroamScanConfigMsg.reserved = 0;
+ PERroamScanConfigMsg.bodyptr = PERRoamReqBuf;
+ if (!VOS_IS_STATUS_SUCCESS(vos_mq_post_message(VOS_MODULE_ID_WDA,
+ &PERroamScanConfigMsg))) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Not able to post WDA_PER_ROAM_SCAN_OFFLOAD_REQ msg to WDA"));
+ vos_mem_free(PERRoamReqBuf);
+ return eHAL_STATUS_FAILURE;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG,
+ FL("rateUpThreshold =%x rateDownThreshold =%x waitPeriodForNextPERScan=%u PERtimerThreshold=%u"),
+ PERRoamReqBuf->rateUpThreshold,
+ PERRoamReqBuf->rateDownThreshold,
+ PERRoamReqBuf->waitPeriodForNextPERScan,
+ PERRoamReqBuf->PERtimerThreshold);
+ }
+
return status;
}
diff --git a/CORE/SME/src/csr/csrApiScan.c b/CORE/SME/src/csr/csrApiScan.c
index 79fe04a..3c5aa4b 100644
--- a/CORE/SME/src/csr/csrApiScan.c
+++ b/CORE/SME/src/csr/csrApiScan.c
@@ -2043,6 +2043,259 @@
return (ret);
}
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+
+/* Calculate channel weight based on other APs RSSI and count for
+ * PER based roaming */
+static tANI_U32 GetPERRoamRssiCountWeight(tANI_S32 rssi, tANI_S32 count)
+{
+ tANI_S32 rssiWeight=0;
+ tANI_S32 countWeight=0;
+ tANI_S32 rssicountWeight=0;
+
+ rssiWeight = ROAMING_RSSI_WEIGHT * (rssi - MIN_RSSI)
+ /(MAX_RSSI - MIN_RSSI);
+
+ if(rssiWeight > ROAMING_RSSI_WEIGHT)
+ rssiWeight = ROAMING_RSSI_WEIGHT;
+ else if (rssiWeight < 0)
+ rssiWeight = 0;
+
+ countWeight = ROAM_AP_COUNT_WEIGHT * (count + ROAM_MIN_COUNT)
+ /(ROAM_MAX_COUNT + ROAM_MIN_COUNT);
+
+ if(countWeight > ROAM_AP_COUNT_WEIGHT)
+ countWeight = ROAM_AP_COUNT_WEIGHT;
+
+ rssicountWeight = ROAM_MAX_WEIGHT - (rssiWeight + countWeight);
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ FL("rssiWeight=%d, countWeight=%d, rssicountWeight=%d rssi=%d count=%d"),
+ rssiWeight, countWeight, rssicountWeight, rssi, count);
+
+ return rssicountWeight;
+}
+
+/* Calculate BSS score based on AP capabilty and channel condition
+ * for PER based roaming */
+static tANI_U32 calculateBssScore(tSirBssDescription *bssInfo,
+ tANI_S32 best_rssi, tANI_S32 ap_cnt, tANI_S32 cca)
+{
+ tANI_S32 score = 0;
+ tANI_S32 ap_load = 0;
+ tANI_S32 normalised_width = PER_ROAM_20MHZ;
+ tANI_S32 normalised_rssi;
+ tANI_S32 channel_weight;
+ if (bssInfo->rssi) {
+ /* Calculate % of rssi we are getting
+ * max = 100
+ * min = 0
+ * less than -40 = 100%
+ * -40 - -55 = 80%
+ * -55 - -65 = 60%
+ * below that = 100 - value
+ * TODO: a linear decrement function after PER_ROAM_GOOD_RSSI_WEIGHT
+ * since throughput decrements linearly after PER_ROAM_GOOD_RSSI_WEIGHT
+ **/
+ if (bssInfo->rssi >= PER_EXCELENT_RSSI)
+ normalised_rssi = PER_ROAM_EXCELLENT_RSSI_WEIGHT;
+ else if (bssInfo->rssi >= PER_GOOD_RSSI)
+ normalised_rssi = PER_ROAM_GOOD_RSSI_WEIGHT;
+ else if (bssInfo->rssi >= PER_POOR_RSSI)
+ normalised_rssi = PER_ROAM_BAD_RSSI_WEIGHT;
+ else
+ normalised_rssi = bssInfo->rssi - MIN_RSSI;
+
+ /* Calculate score part for rssi */
+ score += (normalised_rssi * RSSI_WEIGHTAGE);
+ }
+
+ if (bssInfo->HTCapsPresent) {
+ score += PER_ROAM_MAX_WEIGHT * HT_CAPABILITY_WEIGHTAGE;
+ }
+ /* VHT caps are available */
+ if (bssInfo->vhtCapsPresent) {
+ score += PER_ROAM_MAX_WEIGHT * VHT_CAP_WEIGHTAGE;
+ }
+
+ if (bssInfo->beacomformingCapable)
+ score += PER_ROAM_MAX_WEIGHT * BEAMFORMING_CAP_WEIGHTAGE;
+
+ /* Channel width 20Mhz=30, 40Mhz=70, 80Mhz=100 */
+ if (bssInfo->chanWidth == eHT_CHANNEL_WIDTH_80MHZ)
+ normalised_width = PER_ROAM_80MHZ;
+ else if (bssInfo->chanWidth == eHT_CHANNEL_WIDTH_40MHZ)
+ normalised_width = PER_ROAM_40MHZ;
+ else
+ normalised_width = PER_ROAM_20MHZ;
+ score += normalised_width * CHAN_WIDTH_WEIGHTAGE;
+
+ /* Channel Band, Channel Number */
+ if (GetRFBand(bssInfo->channelId) == SIR_BAND_5_GHZ)
+ score += PER_ROAM_MAX_WEIGHT * CHAN_BAND_WEIGHTAGE;
+
+ /* WMM emabled */
+ if (bssInfo->wmeInfoPresent)
+ score += PER_ROAM_MAX_WEIGHT * WMM_WEIGHTAGE;
+
+#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_ROAM_SCAN_OFFLOAD)
+ /* AP load Ie */
+ if (bssInfo->QBSSLoad_present) {
+ /* calculate value in % */
+ ap_load = (bssInfo->QBSS_ChanLoad * PER_ROAM_MAX_WEIGHT) / MAX_AP_LOAD;
+ }
+#endif
+ //TODO we don't have this info for current AP, need to check
+ /* if CCA consideration is off in configuration, FW will send 50% for
+ every channel which should be considered as it is */
+ if (ap_load)
+ score += (100 - ap_load) * CCA_WEIGHTAGE;
+ else
+ score += (100 - cca) * CCA_WEIGHTAGE;
+
+ channel_weight = GetPERRoamRssiCountWeight(best_rssi, ap_cnt);
+
+ score += channel_weight * OTHER_AP_WEIGHT;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_LOW,
+ FL("rssi=%d normalized_rssi=%d htcaps=%d vht=%d bw=%d channel=%d wmm=%d beamforming=%d ap_load=%d channel_weight=%d"),
+ bssInfo->rssi, normalised_rssi, bssInfo->HTCapsPresent,
+ bssInfo->vhtCapsPresent, bssInfo->chanWidth,
+ bssInfo->channelId, bssInfo->wmeInfoPresent,
+ bssInfo->beacomformingCapable, ap_load, channel_weight);
+ return score;
+}
+
+/* Calculate candidate AP score for PER based roaming */
+static tANI_S32 csrFindCongestionScore (tpAniSirGlobal pMac, tCsrScanResult *pBss)
+{
+ tANI_S32 score = 0;
+ tANI_S32 i;
+ tANI_S32 candidateApCnt, best_rssi, other_ap_cnt;
+ tANI_U32 current_timestamp;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo;
+
+ tSirBssDescription *bssInfo = &(pBss->Result.BssDescriptor);
+ pBss->congestionScore = 0;
+ for (i = 0; i < pMac->PERroamCandidatesCnt; i++)
+ if (pMac->candidateChannelInfo[i].channelNumber ==
+ pBss->Result.BssDescriptor.channelId)
+ break;
+
+ if (i == SIR_PER_ROAM_MAX_CANDIDATE_CNT) {
+ smsLog(pMac, LOGE,
+ FL("candidate chan info not found for channel %d bssid "
+ MAC_ADDRESS_STR), pBss->Result.BssDescriptor.channelId,
+ MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId));
+ return -1;
+ }
+
+ /* find best RSSI of other AP in this channel */
+ best_rssi = MIN_RSSI;
+ for (other_ap_cnt = 0; other_ap_cnt <
+ pMac->candidateChannelInfo[i].otherApCount; other_ap_cnt++) {
+ if (pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt] > best_rssi)
+ best_rssi = pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt];
+ }
+
+ score = calculateBssScore(bssInfo, best_rssi,
+ pMac->candidateChannelInfo[i].otherApCount,
+ pMac->candidateChannelInfo[i].channelCCA);
+ current_timestamp = jiffies_to_msecs(jiffies);
+
+ /* penalty logic */
+
+ /* In the previous list */
+ for (candidateApCnt = 0; candidateApCnt <
+ SIR_PER_ROAM_MAX_CANDIDATE_CNT; candidateApCnt++) {
+ if (sirCompareMacAddr(pMac->previousRoamApInfo[candidateApCnt].bssAddr,
+ pBss->Result.BssDescriptor.bssId) &&
+ ((current_timestamp - pMac->previousRoamApInfo[candidateApCnt].timeStamp) <
+ PENALTY_TIMEOUT)) {
+ score = (score * PENALTY_REMAINING_SCORE)/PENALTY_TOTAL_SCORE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("AP BSSID " MAC_ADDRESS_STR "adding penalty(in previous list)new score %d"),
+ MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId),
+ score);
+ break;
+ }
+ }
+ /* preauth failed last time */
+ for (candidateApCnt = 0; candidateApCnt <
+ MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS; candidateApCnt++) {
+ if (sirCompareMacAddr(pNeighborRoamInfo->FTRoamInfo.
+ preAuthFailList.macAddress[candidateApCnt],
+ pBss->Result.BssDescriptor.bssId)) {
+ score = (score * PENALTY_REMAINING_SCORE)/PENALTY_TOTAL_SCORE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("AP BSSID " MAC_ADDRESS_STR "adding penalty(previously auth failed)new score %d"),
+ MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId),
+ score);
+ break;
+ }
+ }
+ pBss->congestionScore = score;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("AP BSSID " MAC_ADDRESS_STR " score %d channel %d"),
+ MAC_ADDR_ARRAY(pBss->Result.BssDescriptor.bssId),
+ score, pBss->Result.BssDescriptor.channelId);
+ return 0;
+}
+
+/* Calculate current AP score for PER based roaming */
+static tANI_S32 csrFindSelfCongestionScore(tpAniSirGlobal pMac,
+ tSirBssDescription *bssInfo)
+{
+ tANI_S32 i, best_rssi, other_ap_cnt;
+ tANI_S32 score = 0;
+
+ for (i = 0; i <= pMac->PERroamCandidatesCnt; i++)
+ if (pMac->candidateChannelInfo[i].channelNumber == bssInfo->channelId)
+ break;
+ if (i > pMac->PERroamCandidatesCnt) {
+ /* home channel info is not present, no need to roam */
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("home channel %d congestion info not present"),
+ bssInfo->channelId);
+ pMac->currentBssScore = PER_ROAM_MAX_BSS_SCORE;
+ return -1;
+ }
+
+ /* find best RSSI of other AP in this channel */
+ best_rssi = MIN_RSSI;
+ for (other_ap_cnt = 0; other_ap_cnt <
+ pMac->candidateChannelInfo[i].otherApCount; other_ap_cnt++) {
+ if (pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt] > best_rssi)
+ best_rssi = pMac->candidateChannelInfo[i].otherApRssi[other_ap_cnt];
+ }
+
+ score = calculateBssScore(bssInfo, best_rssi,
+ pMac->candidateChannelInfo[i].otherApCount,
+ pMac->candidateChannelInfo[i].channelCCA);
+ pMac->currentBssScore = score;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("PER Roam Current AP score %d channel %d"),
+ score, bssInfo->channelId);
+ return 0;
+}
+
+
+static tANI_BOOLEAN csrIsBetterBssInCongestion(tCsrScanResult *pBss1,
+ tCsrScanResult *pBss2)
+{
+ tANI_BOOLEAN ret;
+
+ if(CSR_IS_BETTER_PREFER_VALUE(pBss1->congestionScore,
+ pBss2->congestionScore))
+ ret = eANI_BOOLEAN_TRUE;
+ else
+ ret = eANI_BOOLEAN_FALSE;
+
+ return (ret);
+}
+#endif
//To check whther pBss1 is better than pBss2
static tANI_BOOLEAN csrIsBetterBss(tCsrScanResult *pBss1, tCsrScanResult *pBss2)
@@ -2168,7 +2421,9 @@
tDot11fBeaconIEs *pIes, *pNewIes;
tANI_BOOLEAN fMatch;
tANI_U16 i = 0;
-
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac,
+ pMac->roam.roamSession->sessionId);
+
if(phResult)
{
*phResult = CSR_INVALID_SCANRESULT_HANDLE;
@@ -2285,7 +2540,13 @@
vos_mem_set(pRetList, sizeof(tScanResultList), 0);
csrLLOpen(pMac->hHdd, &pRetList->List);
pRetList->pCurEntry = NULL;
-
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if (pFilter && pFilter->isPERRoamScan)
+ if (pSession && pSession->pConnectBssDesc)
+ csrFindSelfCongestionScore(pMac,
+ pSession->pConnectBssDesc);
+#endif
+
csrLLLock(&pMac->scan.scanResultList);
pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_NOLOCK );
while( pEntry )
@@ -2377,7 +2638,22 @@
//No need to lock pRetList because it is locally allocated and no outside can access it at this time
if(csrLLIsListEmpty(&pRetList->List, LL_ACCESS_NOLOCK))
{
- csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK);
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if (pFilter && pFilter->isPERRoamScan) {
+ csrFindCongestionScore(pMac, pResult);
+ if (pResult->congestionScore > pMac->currentBssScore) {
+ csrLLInsertTail(&pRetList->List, &pResult->Link,
+ LL_ACCESS_NOLOCK);
+ smsLog(pMac, LOGW,
+ FL("added one entry in LL in PER Roam list"));
+ }
+ }
+ else
+#endif
+ {
+ csrLLInsertTail(&pRetList->List, &pResult->Link,
+ LL_ACCESS_NOLOCK);
+ }
}
else
{
@@ -2389,20 +2665,48 @@
while(pTmpEntry)
{
pTmpResult = GET_BASE_ADDR( pTmpEntry, tCsrScanResult, Link );
- if(csrIsBetterBss(pResult, pTmpResult))
- {
- csrLLInsertEntry(&pRetList->List, pTmpEntry, &pResult->Link, LL_ACCESS_NOLOCK);
- //To indicate we are done
- pResult = NULL;
- break;
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if (pFilter && pFilter->isPERRoamScan) {
+ csrFindCongestionScore(pMac, pResult);
+ if(csrIsBetterBssInCongestion(pResult, pTmpResult)&&
+ (pResult->congestionScore > pMac->currentBssScore))
+ {
+ csrLLInsertEntry(&pRetList->List, pTmpEntry,
+ &pResult->Link, LL_ACCESS_NOLOCK);
+ smsLog(pMac, LOGW,
+ FL("added another entry in LL in PER Roam list"));
+ pResult = NULL;
+ break;
+ }
+ pTmpEntry = csrLLNext(&pRetList->List,
+ pTmpEntry, LL_ACCESS_NOLOCK);
}
- pTmpEntry = csrLLNext(&pRetList->List, pTmpEntry, LL_ACCESS_NOLOCK);
+ else
+#endif
+ {
+ if(csrIsBetterBss(pResult, pTmpResult))
+ {
+ csrLLInsertEntry(&pRetList->List, pTmpEntry,
+ &pResult->Link, LL_ACCESS_NOLOCK);
+ //To indicate we are done
+ pResult = NULL;
+ break;
+ }
+ pTmpEntry = csrLLNext(&pRetList->List,
+ pTmpEntry, LL_ACCESS_NOLOCK);
+ }
}
if(pResult != NULL)
- {
- //This one is not better than any one
- csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK);
- }
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if ((pFilter && !pFilter->isPERRoamScan) ||
+ (pFilter == NULL) ||
+ (pResult->congestionScore > pMac->currentBssScore))
+#endif
+ {
+ //This one is not better than any one
+ csrLLInsertTail(&pRetList->List,
+ &pResult->Link, LL_ACCESS_NOLOCK);
+ }
}
count++;
}
@@ -2425,6 +2729,8 @@
csrLLClose(&pRetList->List);
vos_mem_free(pRetList);
status = eHAL_STATUS_E_NULL_VALUE;
+ smsLog(pMac, LOGW,
+ FL("Nil scan results or no matching AP found"));
}
else if(phResult)
{
diff --git a/CORE/SME/src/csr/csrInsideApi.h b/CORE/SME/src/csr/csrInsideApi.h
index 8ee20e7..c11d5e0 100644
--- a/CORE/SME/src/csr/csrInsideApi.h
+++ b/CORE/SME/src/csr/csrInsideApi.h
@@ -112,6 +112,43 @@
#define CSR_JOIN_RETRY_TIMEOUT_PERIOD ( 1 * PAL_TIMER_TO_SEC_UNIT ) // 1 second
#endif
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+#define ROAMING_RSSI_WEIGHT 50
+#define MIN_RSSI (-100)
+#define MAX_RSSI 0
+#define ROAM_AP_COUNT_WEIGHT 50
+#define ROAM_MAX_COUNT 30
+#define ROAM_MIN_COUNT 0
+#define ROAM_MAX_WEIGHT 100
+
+#define RSSI_WEIGHTAGE 25
+#define HT_CAPABILITY_WEIGHTAGE 10
+#define VHT_CAP_WEIGHTAGE 6
+#define BEAMFORMING_CAP_WEIGHTAGE 2
+#define CHAN_WIDTH_WEIGHTAGE 10
+#define CHAN_BAND_WEIGHTAGE 5
+#define WMM_WEIGHTAGE 2
+#define CCA_WEIGHTAGE 10
+#define OTHER_AP_WEIGHT 30
+
+#define MAX_AP_LOAD 255
+#define PENALTY_TIMEOUT (30 * 60 * 1000)
+#define PENALTY_REMAINING_SCORE (7)
+#define PENALTY_TOTAL_SCORE (10)
+#define PER_EXCELENT_RSSI -40
+#define PER_GOOD_RSSI -55
+#define PER_POOR_RSSI -65
+#define PER_ROAM_EXCELLENT_RSSI_WEIGHT 100
+#define PER_ROAM_GOOD_RSSI_WEIGHT 80
+#define PER_ROAM_BAD_RSSI_WEIGHT 60
+#define PER_ROAM_MAX_WEIGHT 100
+#define PER_ROAM_80MHZ 100
+#define PER_ROAM_40MHZ 70
+#define PER_ROAM_20MHZ 30
+#define PER_ROAM_PENALTY (3/10)
+#define PER_ROAM_MAX_BSS_SCORE 10000
+#endif
+
typedef enum
{
eCsrNextScanNothing,
@@ -170,7 +207,9 @@
eCsrEncryptionType ucEncryptionType; //Preferred Encryption type that matched with profile.
eCsrEncryptionType mcEncryptionType;
eCsrAuthType authType; //Preferred auth type that matched with the profile.
-
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ int congestionScore;
+#endif
tCsrScanResultInfo Result;
}tCsrScanResult;
diff --git a/CORE/SME/src/csr/csrNeighborRoam.c b/CORE/SME/src/csr/csrNeighborRoam.c
index b889aa6..14f6756 100644
--- a/CORE/SME/src/csr/csrNeighborRoam.c
+++ b/CORE/SME/src/csr/csrNeighborRoam.c
@@ -1381,6 +1381,10 @@
pScanFilter->ChannelInfo.numOfChannels = 0;
pScanFilter->ChannelInfo.ChannelList = NULL;
}
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if (pMac->PERroamCandidatesCnt)
+ pScanFilter->isPERRoamScan = true;
+#endif
#ifdef WLAN_FEATURE_VOWIFI_11R
if (pNeighborRoamInfo->is11rAssoc)
{
@@ -2212,10 +2216,15 @@
else
{
- /* There is no candidate or We are not roaming Now.
- * Inform the FW to restart Roam Offload Scan */
- csrRoamOffloadScan(pMac, ROAM_SCAN_OFFLOAD_RESTART,
- REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+ if (pMac->PERroamCandidatesCnt == 0)
+#endif
+ {
+ /* There is no candidate or We are not roaming Now.
+ * Inform the FW to restart Roam Offload Scan */
+ csrRoamOffloadScan(pMac, ROAM_SCAN_OFFLOAD_RESTART,
+ REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
+ }
}
}
CSR_NEIGHBOR_ROAM_STATE_TRANSITION(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED);
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 75a4c37..3dc10cd 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -6194,6 +6194,90 @@
}
#endif /* WLAN_FEATURE_RMC */
+#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
+void sme_PERRoamScanStartStop(void *hHal, tANI_U8 start)
+{
+ eHalStatus status;
+ VOS_STATUS vosStatus;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ vos_msg_t vosMessage;
+ tPERRoamScanStart *pMsg;
+
+ status = sme_AcquireGlobalLock(&pMac->sme);
+ if ( eHAL_STATUS_SUCCESS == status)
+ {
+ pMsg = (tPERRoamScanStart *)
+ vos_mem_malloc(sizeof(tPERRoamScanStart));
+ if (NULL == pMsg)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to allocate memory", __func__);
+ sme_ReleaseGlobalLock( &pMac->sme );
+ return;
+ }
+
+ pMsg->msgType = WDA_PER_ROAM_SCAN_TRIGGER_REQ;
+ pMsg->msgLen = (tANI_U16)sizeof(*pMsg);
+
+ pMsg->start = start;
+
+ vosMessage.type = WDA_PER_ROAM_SCAN_TRIGGER_REQ;
+ vosMessage.bodyptr = pMsg;
+ vosMessage.reserved = 0;
+
+ MTRACE(vos_trace(VOS_MODULE_ID_SME,
+ TRACE_CODE_SME_TX_WDA_MSG, NO_SESSION, vosMessage.type));
+ vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage );
+ if ( !VOS_IS_STATUS_SUCCESS(vosStatus) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: Post TX Fail monitor Start MSG fail", __func__);
+ vos_mem_free(pMsg);
+ status = eHAL_STATUS_FAILURE;
+ }
+ sme_ReleaseGlobalLock(&pMac->sme);
+ }
+}
+
+/* sme_set_per_roam_rxconfig : set PER config for Rx monitoring
+ * @hHal: hal pointer
+ * @staId: station id
+ * @minRate : rate at which to start monitoring
+ * @maxRate : Rate at which to stop monitoring
+ * @minPercentage: minimum % of packets required in minRate to trigger a scan
+ * @minPktRequired: minimum number of packets required to trigger a scan
+ * @waitPeriodForNextPERScan: time to wait before start monitoring again once
+ * roam scan is triggered
+ * */
+
+VOS_STATUS sme_set_per_roam_rxconfig (tHalHandle hHal, v_U8_t staId,
+ v_U16_t minRate, v_U16_t maxRate,
+ v_U8_t minPercentage, v_U16_t minPktRequired,
+ v_U64_t waitPeriodForNextPERScan)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_SME, NULL);
+ WLANTL_StartRxRateMonitor(pVosContext, staId, minRate, maxRate,
+ minPercentage, minPktRequired,
+ (void *) hHal, waitPeriodForNextPERScan,
+ sme_PERRoamScanStartStop);
+ pMac->PERroamCandidatesCnt = 0;
+ return eHAL_STATUS_SUCCESS;
+}
+
+/* sme_unset_per_roam_rxconfig : unset PER config for Rx monitoring
+ * */
+VOS_STATUS sme_unset_per_roam_rxconfig (tHalHandle hHal)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ v_VOID_t * pVosContext = vos_get_global_context(VOS_MODULE_ID_SME, NULL);
+ vos_mem_set(pMac->previousRoamApInfo,
+ sizeof(tSirRoamAPInfo) * SIR_PER_ROAM_MAX_CANDIDATE_CNT, 0);
+ WLANTL_StopRxRateMonitor(pVosContext);
+ return eHAL_STATUS_SUCCESS;
+}
+#endif
+
/* ---------------------------------------------------------------------------
\fn sme_BtcSignalBtEvent
\brief API to signal Bluetooth (BT) event to the WLAN driver. Based on the