wlan: Preferentially scan occupied channels (learned from previous scans).

Change-Id: I62561ceec46134c5ca6ccd82d3313768d309effc
CR-Fixed: 395375
diff --git a/CORE/SME/src/csr/csrNeighborRoam.c b/CORE/SME/src/csr/csrNeighborRoam.c
index c3b3067..ca5f51d 100644
--- a/CORE/SME/src/csr/csrNeighborRoam.c
+++ b/CORE/SME/src/csr/csrNeighborRoam.c
@@ -1689,6 +1689,70 @@
 
 /* ---------------------------------------------------------------------------
 
+    \fn csrNeighborRoamMergeChannelLists
+
+    \brief  This function is used to merge two channel list.
+            NB: If called with outputNumOfChannels == 0, this routines
+                simply copies the input channel list to the output channel list.
+
+    \param  pMac - The handle returned by macOpen.
+    \param  pInputChannelList - The addtional channels to merge in to the "merged" channels list.
+    \param  inputNumOfChannels - The number of additional channels.
+    \param  pOutputChannelList - The place to put the "merged" channel list.
+    \param  outputNumOfChannels - The original number of channels in the "merged" channels list.
+    \param  pMergedOutputNumOfChannels - The final number of channels in the "merged" channel list.
+
+    \return VOS_STATUS_SUCCESS on success, corresponding error code otherwise
+
+---------------------------------------------------------------------------*/
+VOS_STATUS csrNeighborRoamMergeChannelLists(
+        tpAniSirGlobal pMac,
+        tANI_U8   *pInputChannelList,
+        int inputNumOfChannels,
+        tANI_U8   *pOutputChannelList,
+        int outputNumOfChannels,
+        int *pMergedOutputNumOfChannels
+        )
+{
+    int i = 0;
+    int j = 0;
+    int numChannels = outputNumOfChannels;
+
+    // Check for NULL pointer
+    if (!pInputChannelList) return eHAL_STATUS_E_NULL_VALUE;
+
+    // Check for NULL pointer
+    if (!pOutputChannelList) return eHAL_STATUS_E_NULL_VALUE;
+
+    // Add the "new" channels in the input list to the end of the output list.
+    for (i = 0; i < inputNumOfChannels; i++)
+    {
+        for (j = 0; j < outputNumOfChannels; j++)
+        {
+            if (pInputChannelList[i] == pOutputChannelList[j])
+                break;
+        }
+        if (j == outputNumOfChannels)
+        {
+            if (pInputChannelList[i])
+            {
+                VOS_TRACE (VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                        "%s: [INFOLOG] Adding extra %d to Neighbor channel list\n", __func__,
+                        pInputChannelList[i]);
+                pOutputChannelList[numChannels] = pInputChannelList[i];
+                numChannels++;
+            }
+        }
+    }
+
+    // Return final number of channels
+    *pMergedOutputNumOfChannels = numChannels;
+
+    return eHAL_STATUS_SUCCESS;
+}
+
+/* ---------------------------------------------------------------------------
+
     \fn csrNeighborRoamCreateChanListFromNeighborReport
 
     \brief  This function is invoked when neighbor report is received for the 
@@ -1705,8 +1769,11 @@
 {
     tpRrmNeighborReportDesc pNeighborBssDesc;
     tpCsrNeighborRoamControlInfo    pNeighborRoamInfo = &pMac->roam.neighborRoamInfo;
-    tANI_U8         numChannels = 0, i = 0, j=0;
+    tANI_U8         numChannels = 0, i = 0;
     tANI_U8         channelList[MAX_BSS_IN_NEIGHBOR_RPT];
+#if 0
+    eHalStatus  status = eHAL_STATUS_SUCCESS;
+#endif
 
     /* This should always start from 0 whenever we create a channel list out of neighbor AP list */
     pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
@@ -1753,28 +1820,18 @@
 
     if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList)
     {
+#if 0
         // Before we free the existing channel list for a safety net make sure
-        // we have a union of the IAPP and the already existing list. 
-        for (i = 0; i < pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.numOfChannels; i++)
-        {
-            for (j = 0; j < numChannels; j++)
-            {
-                if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList[i] == channelList[j])
-                    break;
-            }
-            if (j == numChannels)
-            {
-                if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList[i])
-                {
-                            VOS_TRACE (VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, 
-                                    "%s: [INFOLOG] Adding extra %d to Neighbor channel list\n", __func__,
-                            pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList[i]);
-                            channelList[numChannels] = 
-                            pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList[i];
-                            numChannels++;
-                }
-            }
-        }
+        // we have a union of the IAPP and the already existing list.
+        status = csrNeighborRoamMergeChannelLists(
+                pMac,
+                pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList,
+                pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.numOfChannels,
+                channelList,
+                numChannels,
+                &numChannels );
+#endif
+
         vos_mem_free(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList);
     }
 
@@ -1903,6 +1960,109 @@
 #endif /* WLAN_FEATURE_VOWIFI_11R */
 
 
+#ifdef FEATURE_WLAN_LFR
+tANI_BOOLEAN csrNeighborRoamIsSsidCandidateMatch(
+        tpAniSirGlobal pMac,
+        tDot11fBeaconIEs *pIes)
+{
+    tpCsrNeighborRoamControlInfo    pNeighborRoamInfo = &pMac->roam.neighborRoamInfo;
+    tANI_U8 sessionId   = (tANI_U8)pNeighborRoamInfo->csrSessionId;
+    tCsrRoamConnectedProfile *pCurProfile;
+    tANI_BOOLEAN fMatch = FALSE;
+
+    if( !(pMac->roam.roamSession
+            && CSR_IS_SESSION_VALID(pMac, sessionId)))
+        return TRUE;  // Treat missing information as a match for everything.
+
+    pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile;
+
+    if( !pCurProfile)
+        return TRUE;  // Treat missing information as a match for everything.
+
+    if( pIes )
+    {
+        if(pIes->SSID.present)
+        {
+            fMatch = csrIsSsidMatch( pMac, (void *)pCurProfile->SSID.ssId, pCurProfile->SSID.length,
+                    pIes->SSID.ssid, pIes->SSID.num_ssid,
+                    eANI_BOOLEAN_TRUE ); // Treat a missing SSID as a non-match.
+            // Return the result of the match operation
+            return fMatch;
+        } else
+            return FALSE;  // Treat a missing SSID as a non-match.
+    } else
+        return FALSE;  // Again, treat missing SSID information as a non-match.
+}
+
+/* ---------------------------------------------------------------------------
+
+    \fn csrNeighborRoamReorderChannelList
+
+    \brief  This function is used to reorder the channel list used for the background
+            scan. It uses the information learned from previous scans to re-order the
+            scan channel list to "favor" the "occupied channels".  The actual algorithm
+            is to scan the current set of "occupied channels" first, for every BG scan,
+            followed by a "chunk" of the remaining list of "valid channels".
+
+    \param  pMac - The handle returned by macOpen.
+    \param  pInputChannelList - The default channels list.
+    \param  numOfChannels - The number of channels in the default channels list.
+    \param  pOutputChannelList - The place to put the "re-ordered" channel list.
+    \param  pOutputNumOfChannels - The number of channels in the "re-ordered" channel list.
+
+    \return VOS_STATUS_SUCCESS on success, corresponding error code otherwise
+
+---------------------------------------------------------------------------*/
+VOS_STATUS csrNeighborRoamReorderChannelList(
+        tpAniSirGlobal pMac,
+        tANI_U8   *pInputChannelList,
+        int numOfChannels,
+        tANI_U8   *pOutputChannelList,
+        int *pOutputNumOfChannels
+        )
+{
+    int i = 0;
+    int j = 0;
+    static int index = 0;
+    int outputNumOfChannels  = 0; // Clear the output number of channels
+    tANI_U8 numOccupiedChannels = pMac->scan.occupiedChannels.numChannels;
+    tANI_U8 *pOccupiedChannelList = pMac->scan.occupiedChannels.channelList;
+
+
+    // Copy over the "occupied channels" at the FRONT of pOutputChannelList.
+    for (i = 0; i < numOccupiedChannels; i++)
+    {
+        if (pOccupiedChannelList[i] != 0)
+        {
+            pOutputChannelList[i] = pOccupiedChannelList[i];
+            outputNumOfChannels++;
+        }
+    }
+
+    // Copy over one "chunk" of channels from the "rest of the channels"...append them to the END of pOutputChannelList.
+    for (j = 0; j < CSR_BG_SCAN_VALID_CHANNEL_LIST_CHUNK_SIZE; j++)
+    {
+        if (!csrIsChannelPresentInList(pOccupiedChannelList, numOccupiedChannels, pInputChannelList[j+index % numOfChannels]))
+        {
+            pOutputChannelList[i] = pInputChannelList[j+index % numOfChannels];
+            i++;
+            outputNumOfChannels++;
+        }
+    }
+
+    //Let's update the index...at which we start retrieving the next chunk
+    index = (index + CSR_BG_SCAN_VALID_CHANNEL_LIST_CHUNK_SIZE) % numOfChannels;
+
+    //VOS_ASSERT(numOfChannels == i);
+    smsLog(pMac, LOGE, FL("numOfChannels in the default channels list=%d. Number in the final list=%d."), numOfChannels, i);
+
+    // Return the number of channels
+    *pOutputNumOfChannels = outputNumOfChannels;
+
+    return eHAL_STATUS_SUCCESS;
+}
+#endif /* FEATURE_WLAN_LFR */
+
 /* ---------------------------------------------------------------------------
 
     \fn csrNeighborRoamTransitToCFGChanScan
@@ -1923,7 +2083,7 @@
     eHalStatus  status  = eHAL_STATUS_SUCCESS;
     int i = 0;
     int numOfChannels = 0;
-    tANI_U8   channelList[MAX_BSS_IN_NEIGHBOR_RPT];
+    tANI_U8   channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN];
 
     if ( 
 #ifdef FEATURE_WLAN_CCX
@@ -1945,37 +2105,88 @@
             vos_mem_free(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList);
             pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = NULL;
         }
-        // Find the right subset of the cfg list based on the current band we are on.
-        for (i = 0; i < pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels; i++)
+        VOS_ASSERT( pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList == NULL);
+
+        // Now obtain the contents for "channelList" (the "default valid channel list") from EITHER
+        // the gNeighborScanChannelList in "cfg.ini", OR the actual "valid channel list" information formed by CSR.
+        if (0 != pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels)
         {
-            if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i])
+            // Copy the "default valid channel list" (channelList) from the gNeighborScanChannelList in "cfg.ini".
+            NEIGHBOR_ROAM_DEBUG(pMac, LOGE, "Using the channel list from cfg.ini");
+            status = csrNeighborRoamMergeChannelLists(
+                    pMac,
+                    pNeighborRoamInfo->cfgParams.channelInfo.ChannelList,
+                    pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels,
+                    channelList,
+                    0, //NB: If 0, simply copy the input channel list to the output list.
+                    &numOfChannels );
+        }
+        else
+        {
+            /* Get current list of valid channels. */
+            NEIGHBOR_ROAM_DEBUG(pMac, LOGE, "Switching to master list of valid channels");
+            numOfChannels = sizeof(pMac->roam.validChannelList);
+            if(HAL_STATUS_SUCCESS(csrGetCfgValidChannels(pMac, (tANI_U8 *)pMac->roam.validChannelList, (tANI_U32 *) &numOfChannels)))
             {
-                        VOS_TRACE (VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, 
-                                "%s: [INFOLOG] Adding %d to Neighbor channel list\n", __func__,
-                                pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i]);
-                        channelList[numOfChannels] = pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i];
-                        numOfChannels++;
+                // Copy the "default valid channel list" (channelList) from the actual "valid channel list" information formed by CSR
+                status = csrNeighborRoamMergeChannelLists(
+                        pMac,
+                        (tANI_U8 *)pMac->roam.validChannelList,
+                        numOfChannels,   // The number of channels in the validChannelList
+                        channelList,
+                        0, //NB: If 0, simply copy the input channel list to the output list.
+                        &numOfChannels );  // The final number of channels in the output list. Will be numOfChannels
+            }
+            else
+            {
+                smsLog(pMac, LOGE, FL("Could not get valid channel list, TL event ignored"));
+                return VOS_STATUS_E_FAILURE;
             }
         }
 
+        /* At this point, channelList contains our best inputs on the "valid channel list" */
+
+        /* Allocate for the maximum number that might be used */
+        smsLog(pMac, LOGE, FL("%d channels in the default list. Add %d occupied channels. %d is the MAX scan channel list."),
+                numOfChannels,
+                CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN,
+                numOfChannels+CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN );
         pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.numOfChannels = numOfChannels;
-        pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = NULL; 
+        VOS_ASSERT( pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList == NULL);
         if (numOfChannels)
-            pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = vos_mem_malloc(numOfChannels);
-    
+        {
+            pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
+                vos_mem_malloc(numOfChannels+CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN );
+        }
+
         if (NULL == pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList)
         {
             smsLog(pMac, LOGE, FL("Memory allocation for Channel list failed.. TL event ignored"));
             return VOS_STATUS_E_RESOURCES;
         }
     
+#ifdef FEATURE_WLAN_LFR
         /* Since this is a legacy case, copy the channel list from CFG here */
-        vos_mem_copy(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList, 
-                                channelList, numOfChannels * sizeof(tANI_U8));
 
+        status = csrNeighborRoamReorderChannelList( pMac,
+                channelList,
+                numOfChannels,
+                pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList,
+                &numOfChannels );
+        if (eHAL_STATUS_SUCCESS != status)
+#endif
+        {
+            /* Re-ordering failed. */
+            smsLog(pMac, LOGE, FL("Cannot re-order scan channel list. (status = %d) Going to use default scan channel list."), status);
+            vos_mem_copy(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList,
+                    channelList, numOfChannels * sizeof(tANI_U8));
+        }
+
+        /* Adjust for the actual number that are used */
+        pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.numOfChannels = numOfChannels;
         for (i = 0; i < pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.numOfChannels; i++)
         {
-            NEIGHBOR_ROAM_DEBUG(pMac, LOGE, "Channel List from CFG = %d\n", 
+            NEIGHBOR_ROAM_DEBUG(pMac, LOGE, "Channel List from CFG (or scan caching) = %d\n",
                 pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList[i]);
         }
     }