wlan: Roam if RSSI(candidate) > RSSI(curr AP) by gImmediateRoamRssiDiff.

If the potential roam candidate(s) found after the scan are much better
than the current AP, then there is no need to register for reassoc
threshold and wait until the notification is received to trigger the
roam. Since this duration is non-deterministic, the results/RSSI values
obtained from the scan (which are used to sort the candidates) might be
outdated. This could lead to roaming to a bad AP. This problem is being
fixed as follows:

Add a new configuration parameter in the INI file, namely,
gImmediateRoamRssiDiff. By default, this is set to 0. It can be
configured to a value in the range [0 .. 125] by issuing the following
command:
adb shell iwpriv wlan0 setConfig gImmediateRoamRssiDiff=<value>

Following a scan and if potential roam candidate(s) are found,
then determine whether to register for reassoc threshold or roam
immediately based on the above configuration parameter. If the RSSI of
any available candidate is better than the currently associated AP by at
least gImmediateRoamRssiDiff, then being to roam immediately (without
registering for reassoc threshold).

Fixed CRs: 427062

Change-Id: I56a86c039d680a635b38ee5d38c47f6451841a57
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index ebe9ba1..5e7a5d4 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -740,6 +740,21 @@
 #define CFG_ROAM_RSSI_DIFF_MIN                              (0)
 #define CFG_ROAM_RSSI_DIFF_MAX                              (125)
 #define CFG_ROAM_RSSI_DIFF_DEFAULT                          (0)
+
+/*
+ * Following a scan and if potential roam candidate(s) are found,
+ * then determine whether to register for reassoc threshold or roam 
+ * immediately based on this configuration parameter. If the RSSI 
+ * of any available candidate is better than the currently associated 
+ * AP by at least gImmediateRoamRssiDiff, then being to roam 
+ * immediately. 
+ * NOTE: Value of 0 means that we register for reassoc threshold and 
+ * wait for notification before triggering roam.
+ */
+#define CFG_IMMEDIATE_ROAM_RSSI_DIFF_NAME                   "gImmediateRoamRssiDiff"
+#define CFG_IMMEDIATE_ROAM_RSSI_DIFF_MIN                    (0)
+#define CFG_IMMEDIATE_ROAM_RSSI_DIFF_MAX                    (125)
+#define CFG_IMMEDIATE_ROAM_RSSI_DIFF_DEFAULT                (0)
 #endif /* (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR) */
 
 #define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME                "PktClassificationBasis" // DSCP or 802.1Q
@@ -1608,6 +1623,7 @@
    v_U8_t                       FTRssiFilterPeriod;
    v_BOOL_t                     isFastTransitionEnabled;
    v_U8_t                       RoamRssiDiff;
+   v_U8_t                       nImmediateRoamRssiDiff;
 #endif
 
    hdd_wmm_classification_t     PktClassificationBasis; // DSCP or 802.1Q
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 3090c2c..3548baa 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -54,11 +54,19 @@
 #include <pmcApi.h>
 #include <wlan_hdd_misc.h>
 
+#if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
 static void cbNotifySetRoamPrefer5GHz(hdd_context_t *pHddCtx, unsigned long NotifyId)
 {
     sme_UpdateRoamPrefer5GHz((tHalHandle)(pHddCtx->hHal), pHddCtx->cfg_ini->nRoamPrefer5GHz);
 }
 
+static void cbNotifySetImmediateRoamRssiDiff(hdd_context_t *pHddCtx, unsigned long NotifyId)
+{
+    sme_UpdateImmediateRoamRssiDiff((tHalHandle)(pHddCtx->hHal), 
+                                    pHddCtx->cfg_ini->nImmediateRoamRssiDiff);
+}
+#endif
+
 REG_TABLE_ENTRY g_registry_table[] =
 {
    REG_VARIABLE( CFG_RTS_THRESHOLD_NAME, WLAN_PARAM_Integer,
@@ -884,6 +892,14 @@
                  CFG_ROAM_RSSI_DIFF_DEFAULT, 
                  CFG_ROAM_RSSI_DIFF_MIN, 
                  CFG_ROAM_RSSI_DIFF_MAX),
+
+   REG_DYNAMIC_VARIABLE( CFG_IMMEDIATE_ROAM_RSSI_DIFF_NAME, WLAN_PARAM_Integer,
+                         hdd_config_t, nImmediateRoamRssiDiff, 
+                         VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, 
+                         CFG_IMMEDIATE_ROAM_RSSI_DIFF_DEFAULT, 
+                         CFG_IMMEDIATE_ROAM_RSSI_DIFF_MIN, 
+                         CFG_IMMEDIATE_ROAM_RSSI_DIFF_MAX,
+                         cbNotifySetImmediateRoamRssiDiff, 0),
 #endif
 
    REG_VARIABLE( CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME , WLAN_PARAM_Integer,
@@ -2009,6 +2025,7 @@
 #endif 
 #if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
   VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [RoamRssiDiff] Value = [%lu] ",pHddCtx->cfg_ini->RoamRssiDiff);
+  VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [ImmediateRoamRssiDiff] Value = [%lu] ",pHddCtx->cfg_ini->nImmediateRoamRssiDiff);
 #endif
   VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [InfraDirAcVo] Value = [%u] ",pHddCtx->cfg_ini->InfraDirAcVo);
   VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_HIGH, "Name = [InfraNomMsduSizeAcVo] Value = [0x%x] ",pHddCtx->cfg_ini->InfraNomMsduSizeAcVo);
@@ -3279,6 +3296,7 @@
 #if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
    smeConfig.csrConfig.isFastTransitionEnabled = pConfig->isFastTransitionEnabled;
    smeConfig.csrConfig.RoamRssiDiff = pConfig->RoamRssiDiff;
+   smeConfig.csrConfig.nImmediateRoamRssiDiff = pConfig->nImmediateRoamRssiDiff;
 #endif
 
 #ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
diff --git a/CORE/SME/inc/csrApi.h b/CORE/SME/inc/csrApi.h
index 0656a29..f0f793d 100644
--- a/CORE/SME/inc/csrApi.h
+++ b/CORE/SME/inc/csrApi.h
@@ -992,6 +992,7 @@
 #if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
     tANI_U8   isFastTransitionEnabled;
     tANI_U8   RoamRssiDiff;
+    tANI_U8   nImmediateRoamRssiDiff;
 #endif
 
 #ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
diff --git a/CORE/SME/inc/csrInternal.h b/CORE/SME/inc/csrInternal.h
index f17c7de..27ca2f2 100644
--- a/CORE/SME/inc/csrInternal.h
+++ b/CORE/SME/inc/csrInternal.h
@@ -576,6 +576,7 @@
 #if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
     tANI_U8   isFastTransitionEnabled;
     tANI_U8   RoamRssiDiff;
+    tANI_U8   nImmediateRoamRssiDiff;
     tANI_BOOLEAN nRoamPrefer5GHz;
 #endif
 
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index aa37c14..5dd61ff 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -2197,6 +2197,20 @@
     -------------------------------------------------------------------------*/
 
 eHalStatus sme_UpdateRoamPrefer5GHz(tHalHandle hHal, v_BOOL_t nRoamPrefer5GHz);
+
+/* ---------------------------------------------------------------------------
+    \fn sme_UpdateImmediateRoamRssiDiff
+    \brief  Update nImmediateRoamRssiDiff
+            This function is called through dynamic setConfig callback function
+            to configure nImmediateRoamRssiDiff
+            Usage: adb shell iwpriv wlan0 setConfig gImmediateRoamRssiDiff=[0 .. 125]
+    \param  hHal - HAL handle for device
+    \param  nImmediateRoamRssiDiff - minimum rssi difference between potential 
+            candidate and current AP.
+    \- return Success or failure
+    -------------------------------------------------------------------------*/
+
+eHalStatus sme_UpdateImmediateRoamRssiDiff(tHalHandle hHal, v_U8_t nImmediateRoamRssiDiff);
 #endif
 
 /* ---------------------------------------------------------------------------
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index e2e17d5..c5e93d8 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -1273,6 +1273,9 @@
 #if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
         pMac->roam.configParam.isFastTransitionEnabled = pParam->isFastTransitionEnabled;
         pMac->roam.configParam.RoamRssiDiff = pParam->RoamRssiDiff;
+        pMac->roam.configParam.nImmediateRoamRssiDiff = pParam->nImmediateRoamRssiDiff;
+        smsLog( pMac, LOG1, "nImmediateRoamRssiDiff = %d\n", 
+                pMac->roam.configParam.nImmediateRoamRssiDiff );
         pMac->roam.configParam.nRoamPrefer5GHz = pParam->nRoamPrefer5GHz;
 #endif
 #ifdef FEATURE_WLAN_LFR 
diff --git a/CORE/SME/src/csr/csrNeighborRoam.c b/CORE/SME/src/csr/csrNeighborRoam.c
index 6b0b239..40c1da6 100644
--- a/CORE/SME/src/csr/csrNeighborRoam.c
+++ b/CORE/SME/src/csr/csrNeighborRoam.c
@@ -220,6 +220,68 @@
     return;
 }
 
+static void csrNeighborRoamTriggerHandoff(tpAniSirGlobal pMac, 
+                                          tpCsrNeighborRoamControlInfo pNeighborRoamInfo)
+{
+#ifdef WLAN_FEATURE_VOWIFI_11R
+    if (pNeighborRoamInfo->is11rAssoc)
+    {
+        if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
+        {
+            csrNeighborRoamIssuePreauthReq(pMac);
+        }
+        else
+        {
+            smsLog(pMac, LOGE, FL("11R Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
+            VOS_ASSERT(0);
+        }
+    }
+    else
+#endif
+
+#ifdef FEATURE_WLAN_CCX
+        if (pNeighborRoamInfo->isCCXAssoc)
+        {
+            if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
+            {
+                csrNeighborRoamIssuePreauthReq(pMac);
+            }
+            else
+            {
+                smsLog(pMac, LOGE, FL("CCX Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
+                VOS_ASSERT(0);
+            }
+        }
+        else
+#endif
+#ifdef FEATURE_WLAN_LFR
+            if (csrRoamIsFastRoamEnabled(pMac, CSR_SESSION_ID_INVALID))
+            {
+                if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
+                {
+                    csrNeighborRoamIssuePreauthReq(pMac);
+                }
+                else
+                {
+                    smsLog(pMac, LOGE, FL("LFR Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
+                    VOS_ASSERT(0);
+                }
+            }
+            else
+#endif
+            {
+                if (eCSR_NEIGHBOR_ROAM_STATE_CFG_CHAN_LIST_SCAN == pNeighborRoamInfo->neighborRoamState)
+                {
+                    csrNeighborRoamRequestHandoff(pMac);
+                }
+                else
+                {
+                    smsLog(pMac, LOGE, FL("Non-11R Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
+                    VOS_ASSERT(0);
+                }
+            }
+}
+
 /* ---------------------------------------------------------------------------
 
     \fn csrNeighborRoamReassocIndCallback
@@ -274,63 +336,8 @@
     /* We dont need to run this timer any more. */
     palTimerStop(pMac->hHdd, pNeighborRoamInfo->neighborResultsRefreshTimer);
 
-#ifdef WLAN_FEATURE_VOWIFI_11R
-    if (pNeighborRoamInfo->is11rAssoc)
-    {
-        if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
-        {
-            csrNeighborRoamIssuePreauthReq(pMac);
-        }
-        else
-        {
-            smsLog(pMac, LOGE, FL("11R Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
-            VOS_ASSERT(0);
-        }
-    }
-    else
-#endif
+    csrNeighborRoamTriggerHandoff(pMac, pNeighborRoamInfo);
 
-#ifdef FEATURE_WLAN_CCX
-    if (pNeighborRoamInfo->isCCXAssoc)
-    {
-        if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
-        {
-            csrNeighborRoamIssuePreauthReq(pMac);
-        }
-        else
-        {
-            smsLog(pMac, LOGE, FL("CCX Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
-            VOS_ASSERT(0);
-        }
-    }
-    else
-#endif
-#ifdef FEATURE_WLAN_LFR
-    if (csrRoamIsFastRoamEnabled(pMac, CSR_SESSION_ID_INVALID))
-    {
-        if (eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN == pNeighborRoamInfo->neighborRoamState)
-        {
-            csrNeighborRoamIssuePreauthReq(pMac);
-        }
-        else
-        {
-            smsLog(pMac, LOGE, FL("LFR Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
-            VOS_ASSERT(0);
-        }
-    }
-    else
-#endif
-    {
-        if (eCSR_NEIGHBOR_ROAM_STATE_CFG_CHAN_LIST_SCAN == pNeighborRoamInfo->neighborRoamState)
-        {
-            csrNeighborRoamRequestHandoff(pMac);
-        }
-        else
-        {
-            smsLog(pMac, LOGE, FL("Non-11R Reassoc indication received in unexpected state %d"), pNeighborRoamInfo->neighborRoamState);
-            VOS_ASSERT(0);
-        }
-    }
     return VOS_STATUS_SUCCESS;
 }
 
@@ -1032,17 +1039,23 @@
     \param  pMac - The handle returned by macOpen.
             pScanResultList - Scan result result obtained from csrScanGetResult()
 
-    \return VOID
+    \return tANI_BOOLEAN - return TRUE if we have a candidate we can immediately
+            roam to. Otherwise, return FALSE.
 
 ---------------------------------------------------------------------------*/
 
-static void csrNeighborRoamProcessScanResults(tpAniSirGlobal pMac, tScanResultHandle *pScanResultList)
+static tANI_BOOLEAN csrNeighborRoamProcessScanResults(tpAniSirGlobal pMac, 
+                                                      tScanResultHandle *pScanResultList)
 {
     tCsrScanResultInfo *pScanResult;
     tpCsrNeighborRoamControlInfo    pNeighborRoamInfo = &pMac->roam.neighborRoamInfo;
     tpCsrNeighborRoamBSSInfo    pBssInfo;
     tANI_U32 CurrAPRssi;
     tANI_U8 RoamRssiDiff = pMac->roam.configParam.RoamRssiDiff;
+#if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
+    tANI_U8 immediateRoamRssiDiff = pMac->roam.configParam.nImmediateRoamRssiDiff;
+#endif
+    tANI_BOOLEAN roamNow = eANI_BOOLEAN_FALSE;
 
     /***************************************************************
      * Find out the Current AP RSSI and keep it handy to check if
@@ -1230,12 +1243,24 @@
 
         /* Just add to the end of the list as it is already sorted by RSSI */
         csrLLInsertTail(&pNeighborRoamInfo->roamableAPList, &pBssInfo->List, LL_ACCESS_LOCK);
+
+#if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
+        if (immediateRoamRssiDiff &&
+            (abs(abs(CurrAPRssi) - abs(pScanResult->BssDescriptor.rssi)) >= immediateRoamRssiDiff))
+        {
+            VOS_TRACE (VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+                       "%s: [INFOLOG] potential candidate to roam immediately (diff=%d, expected=%d)", 
+                       __func__, abs(abs(CurrAPRssi) - abs(pScanResult->BssDescriptor.rssi)),
+                       immediateRoamRssiDiff);
+            roamNow = eANI_BOOLEAN_TRUE;
+        }
+#endif
     }
 
     /* Now we have all the scan results in our local list. Good time to free up the the list we got as a part of csrGetScanResult */
     csrScanResultPurge(pMac, *pScanResultList);
 
-    return;
+    return roamNow;
 }
 
 /* ---------------------------------------------------------------------------
@@ -1442,6 +1467,7 @@
     tScanResultHandle       scanResult;
     tANI_U32                tempVal = 0;
     eHalStatus              hstatus;
+    tANI_BOOLEAN            roamNow = eANI_BOOLEAN_FALSE;
 
     pMac->roam.neighborRoamInfo.scanRspPending = eANI_BOOLEAN_FALSE;
     
@@ -1501,7 +1527,7 @@
             NEIGHBOR_ROAM_DEBUG(pMac, LOGE, FL("Get Scan Result status code %d"), hstatus);
         }
         /* Process the scan results and update roamable AP list */
-        csrNeighborRoamProcessScanResults(pMac, &scanResult);
+        roamNow = csrNeighborRoamProcessScanResults(pMac, &scanResult);
 
         /* Free the scan filter */
         csrFreeScanFilter(pMac, &scanFilter);
@@ -1593,6 +1619,28 @@
         {
             VOS_STATUS  vosStatus = VOS_STATUS_SUCCESS;
 
+            if (roamNow)
+            {
+                NEIGHBOR_ROAM_DEBUG(pMac, LOG2, 
+                    FL("Immediate roam-deregister UP indication. RSSI = %d"),
+                    NEIGHBOR_ROAM_LOOKUP_UP_THRESHOLD * (-1));
+
+                vosStatus = WLANTL_DeregRSSIIndicationCB(pMac->roam.gVosContext,
+                        (v_S7_t)NEIGHBOR_ROAM_LOOKUP_UP_THRESHOLD * (-1),
+                        WLANTL_HO_THRESHOLD_UP,
+                        csrNeighborRoamNeighborLookupUPCallback,
+                        VOS_MODULE_ID_SME);
+                
+                if(!VOS_IS_STATUS_SUCCESS(vosStatus))
+                {
+                    smsLog(pMac, LOGW, 
+                        FL("Couldn't deregister lookup UP callback with TL: Status = %d\n"), vosStatus);
+                }
+
+                csrNeighborRoamTriggerHandoff(pMac, pNeighborRoamInfo);
+                return eHAL_STATUS_SUCCESS;
+            }
+
            /* This timer should be started before registering the Reassoc callback with TL. This is because, it is very likely 
             * that the callback getting called immediately and the timer would never be stopped when pre-auth is in progress */
            if (eHAL_STATUS_SUCCESS != palTimerStart(pMac->hHdd, pNeighborRoamInfo->neighborResultsRefreshTimer, 
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 54c37e4..3b7a227 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -6816,6 +6816,25 @@
     pMac->roam.configParam.nRoamPrefer5GHz = nRoamPrefer5GHz;
     return(eHAL_STATUS_SUCCESS);
 }
+
+/* ---------------------------------------------------------------------------
+    \fn sme_UpdateImmediateRoamRssiDiff
+    \brief  Update nImmediateRoamRssiDiff
+            This function is called through dynamic setConfig callback function
+            to configure nImmediateRoamRssiDiff
+            Usage: adb shell iwpriv wlan0 setConfig gImmediateRoamRssiDiff=[0 .. 125]
+    \param  hHal - HAL handle for device
+    \param  nImmediateRoamRssiDiff - minimum rssi difference between potential 
+            candidate and current AP.
+    \- return Success or failure
+    -------------------------------------------------------------------------*/
+
+eHalStatus sme_UpdateImmediateRoamRssiDiff(tHalHandle hHal, v_U8_t nImmediateRoamRssiDiff)
+{
+    tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+    pMac->roam.configParam.nImmediateRoamRssiDiff = nImmediateRoamRssiDiff;
+    return(eHAL_STATUS_SUCCESS);
+}
 #endif
 
 
diff --git a/firmware_bin/WCNSS_qcom_cfg.ini b/firmware_bin/WCNSS_qcom_cfg.ini
index 731afb3..2fd3ef3 100644
--- a/firmware_bin/WCNSS_qcom_cfg.ini
+++ b/firmware_bin/WCNSS_qcom_cfg.ini
@@ -184,6 +184,12 @@
 #Prefer 5GHz APs while roaming (default is gRoamPrefer5GHz=1)
 gRoamPrefer5GHz=1
 
+# If the RSSI of any available candidate is better than currently associated 
+# AP by at least gImmediateRoamRssiDiff, then being to roam immediately (without
+# registering for reassoc threshold). 
+# NOTE: Value of 0 means that we would register for reassoc threshold.
+gImmediateRoamRssiDiff=10
+
 # SAP Country code
 
 # Default Country Code is 2 bytes, 3rd byte is optional indoor or out door.