[WCNCR00154177] scan: Add partial scan support

[Description]
Add partial scan support (up to 32 channels, full scan otherwise)

Change-Id: I9e3f3f7b8eb49f3afd43b05377adbcbeae8e7a40
Signed-off-by: sho <sho.masuda@mediatek.com>
CR-Id: WCNCR00154177
Feature: scan
diff --git a/Makefile.ce b/Makefile.ce
index 5045546..2b37fb0 100644
--- a/Makefile.ce
+++ b/Makefile.ce
@@ -152,6 +152,8 @@
 
 #CFG_SUPPORT_DFS_MASTER=1
 
+CFG_SCAN_CHANNEL_SPECIFIED=1
+
 CFG_SUPPORT_ROAMING=0
 
 # Report all bss networks to cfg80211 when do p2p scan
@@ -235,6 +237,10 @@
 PLATFORM_FLAGS += -DCFG_P2P_SCAN_REPORT_ALL_BSS=$(CFG_P2P_SCAN_REPORT_ALL_BSS)
 endif
 
+ifneq ($(CFG_SCAN_CHANNEL_SPECIFIED),)
+PLATFORM_FLAGS += -DCFG_SCAN_CHANNEL_SPECIFIED=$(CFG_SCAN_CHANNEL_SPECIFIED)
+endif
+
 ##############################################################
 # Compile settings
 ##############################################################
diff --git a/Makefile.x86 b/Makefile.x86
index 81e3c66..c48baf1 100644
--- a/Makefile.x86
+++ b/Makefile.x86
@@ -66,6 +66,8 @@
 
 #CFG_SUPPORT_DFS_MASTER=1
 
+CFG_SCAN_CHANNEL_SPECIFIED=1
+
 #CFG_SUPPORT_SINGLE_SKU_LOCAL_DB=0
 
 # Report all bss networks to cfg80211 when do p2p scan
@@ -140,6 +142,10 @@
 PLATFORM_FLAGS += -DCFG_P2P_SCAN_REPORT_ALL_BSS=$(CFG_P2P_SCAN_REPORT_ALL_BSS)
 endif
 
+ifneq ($(CFG_SCAN_CHANNEL_SPECIFIED),)
+PLATFORM_FLAGS += -DCFG_SCAN_CHANNEL_SPECIFIED=$(CFG_SCAN_CHANNEL_SPECIFIED)
+endif
+
 all: driver
 
 driver:
diff --git a/common/wlan_oid.c b/common/wlan_oid.c
index 72696aa..e089a33 100644
--- a/common/wlan_oid.c
+++ b/common/wlan_oid.c
@@ -738,7 +738,13 @@
 	if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) {
 		if ((prAdapter->fgEnOnlineScan == TRUE) && (prAdapter->ucRddStatus)) {
 			if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED)
-				aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, pucIe, u4IeLength);
+#if CFG_SCAN_CHANNEL_SPECIFIED
+				aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid,
+					prScanRequest->ucChannelListNum, prScanRequest->arChnlInfoList,
+					pucIe, u4IeLength);
+#else
+				aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, pucIe, u4IeLength);
+#endif
 			else
 				return WLAN_STATUS_FAILURE;
 		} else
@@ -747,9 +753,21 @@
 #endif
 	{
 		if (prAdapter->fgEnOnlineScan == TRUE)
-			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, pucIe, u4IeLength);
+#if CFG_SCAN_CHANNEL_SPECIFIED
+			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid,
+				prScanRequest->ucChannelListNum, prScanRequest->arChnlInfoList,
+				pucIe, u4IeLength);
+#else
+			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, pucIe, u4IeLength);
+#endif
 		else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != PARAM_MEDIA_STATE_CONNECTED)
-			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, pucIe, u4IeLength);
+#if CFG_SCAN_CHANNEL_SPECIFIED
+			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid,
+				prScanRequest->ucChannelListNum, prScanRequest->arChnlInfoList,
+				pucIe, u4IeLength);
+#else
+			aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, pucIe, u4IeLength);
+#endif
 		else
 			return WLAN_STATUS_FAILURE;
 	}
diff --git a/include/config.h b/include/config.h
index 3c4c318..eb9d10d 100644
--- a/include/config.h
+++ b/include/config.h
@@ -959,6 +959,16 @@
 #ifndef CFG_PRE_ALLOCATION_IO_BUFFER
 #define CFG_PRE_ALLOCATION_IO_BUFFER 0
 #endif
+
+
+/*------------------------------------------------------------------------------
+ * Support scan with channels specified
+ *------------------------------------------------------------------------------
+ */
+#ifndef CFG_SCAN_CHANNEL_SPECIFIED
+#define CFG_SCAN_CHANNEL_SPECIFIED 1
+#endif
+
 /*******************************************************************************
 *                             D A T A   T Y P E S
 ********************************************************************************
diff --git a/include/mgmt/ais_fsm.h b/include/mgmt/ais_fsm.h
index f5189fe..99eadcb 100644
--- a/include/mgmt/ais_fsm.h
+++ b/include/mgmt/ais_fsm.h
@@ -216,6 +216,11 @@
 	UINT_32 u4ScanIELength;
 	UINT_8 aucScanIEBuf[MAX_IE_LENGTH];
 
+#if CFG_SCAN_CHANNEL_SPECIFIED
+	UINT_8 ucScanChannelListNum;
+	RF_CHANNEL_INFO_T arScanChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST];
+#endif
+
 	/* Pending Request List */
 	LINK_T rPendingReqList;
 
@@ -233,7 +238,6 @@
 
 	/* for roaming target */
 	PARAM_SSID_T rRoamingSSID;
-
 } AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T;
 
 /*******************************************************************************
@@ -383,7 +387,9 @@
 
 VOID
 aisFsmScanRequestAdv(IN P_ADAPTER_T prAdapter,
-		     IN UINT_8 ucSsidNum, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength);
+	IN UINT_8 ucSsidNum, IN P_PARAM_SSID_T prSsid,
+	IN UINT_8 ucChannelListNum, IN P_RF_CHANNEL_INFO_T prChnlInfoList,
+	IN PUINT_8 pucIe, IN UINT_32 u4IeLength);
 
 /*----------------------------------------------------------------------------*/
 /* Internal State Checking                                                    */
diff --git a/include/mgmt/scan.h b/include/mgmt/scan.h
index e8647c6..593a9cb 100644
--- a/include/mgmt/scan.h
+++ b/include/mgmt/scan.h
@@ -724,4 +724,10 @@
 VOID scanReportScanResultToAgps(P_ADAPTER_T prAdapter);
 #endif
 
+#if CFG_SCAN_CHANNEL_SPECIFIED
+static inline bool is_valid_scan_chnl_cnt(UINT_8 num)
+{
+	return (num && num < MAXIMUM_OPERATION_CHANNEL_LIST);
+}
+#endif
 #endif /* _SCAN_H */
diff --git a/include/wlan_oid.h b/include/wlan_oid.h
index 6e1a232..f6a0236 100644
--- a/include/wlan_oid.h
+++ b/include/wlan_oid.h
@@ -1900,6 +1900,10 @@
 	PARAM_SSID_T rSsid[CFG_SCAN_SSID_MAX_NUM];
 	UINT_32 u4IELength;
 	PUINT_8 pucIE;
+#if CFG_SCAN_CHANNEL_SPECIFIED
+	UINT_8 ucChannelListNum;
+	RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST];
+#endif
 } PARAM_SCAN_REQUEST_ADV_T, *P_PARAM_SCAN_REQUEST_ADV_T;
 
 /*--------------------------------------------------------------*/
diff --git a/mgmt/ais_fsm.c b/mgmt/ais_fsm.c
index fde306b..76ecb5f 100644
--- a/mgmt/ais_fsm.c
+++ b/mgmt/ais_fsm.c
@@ -1232,6 +1232,13 @@
 				prScanReqMsg->ucChannelListNum = 1;
 				prScanReqMsg->arChnlInfoList[0].eBand = eBand;
 				prScanReqMsg->arChnlInfoList[0].ucChannelNum = ucChannel;
+#if CFG_SCAN_CHANNEL_SPECIFIED
+			} else if (is_valid_scan_chnl_cnt(prAisFsmInfo->ucScanChannelListNum)) {
+				prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED;
+				prScanReqMsg->ucChannelListNum = prAisFsmInfo->ucScanChannelListNum;
+				kalMemCopy(prScanReqMsg->arChnlInfoList, prAisFsmInfo->arScanChnlInfoList,
+					sizeof(RF_CHANNEL_INFO_T) * prScanReqMsg->ucChannelListNum);
+#endif
 			} else if (prAdapter->aePreferBand[prAdapter->prAisBssInfo->ucBssIndex] == BAND_NULL) {
 				if (prAdapter->fgEnable5GBand == TRUE)
 					prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL;
@@ -3243,7 +3250,9 @@
 /*----------------------------------------------------------------------------*/
 VOID
 aisFsmScanRequestAdv(IN P_ADAPTER_T prAdapter,
-		     IN UINT_8 ucSsidNum, IN P_PARAM_SSID_T prSsid, IN PUINT_8 pucIe, IN UINT_32 u4IeLength)
+	IN UINT_8 ucSsidNum, IN P_PARAM_SSID_T prSsid,
+	IN UINT_8 ucChannelListNum, IN P_RF_CHANNEL_INFO_T prChnlInfoList,
+	IN PUINT_8 pucIe, IN UINT_32 u4IeLength)
 {
 	UINT_32 i;
 	P_CONNECTION_SETTINGS_T prConnSettings;
@@ -3282,6 +3291,15 @@
 			prAisFsmInfo->u4ScanIELength = 0;
 		}
 
+#if CFG_SCAN_CHANNEL_SPECIFIED
+		if (ucChannelListNum) {
+			prAisFsmInfo->ucScanChannelListNum = ucChannelListNum;
+			kalMemCopy(prAisFsmInfo->arScanChnlInfoList, prChnlInfoList,
+				sizeof(RF_CHANNEL_INFO_T) * prAisFsmInfo->ucScanChannelListNum);
+		} else
+			prAisFsmInfo->ucScanChannelListNum = 0;
+#endif
+
 		if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) {
 			if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE
 			    && prAisFsmInfo->fgIsInfraChannelFinished == FALSE) {
diff --git a/os/linux/gl_cfg80211.c b/os/linux/gl_cfg80211.c
index 7125aad..81cfeec 100644
--- a/os/linux/gl_cfg80211.c
+++ b/os/linux/gl_cfg80211.c
@@ -793,6 +793,32 @@
 	if (request->ie_len > 0)
 		rScanRequest.pucIE = (PUINT_8) (request->ie);
 
+#if CFG_SCAN_CHANNEL_SPECIFIED
+	DBGLOG(REQ, INFO, "scan channel num = %d\n", request->n_channels);
+
+	if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) {
+		DBGLOG(REQ, WARN, "scan channel num (%d) exceeds %d, do a full scan instead\n",
+			   request->n_channels, MAXIMUM_OPERATION_CHANNEL_LIST);
+		rScanRequest.ucChannelListNum = 0;
+	} else {
+		rScanRequest.ucChannelListNum = request->n_channels;
+		for (i = 0; i < request->n_channels; i++) {
+			rScanRequest.arChnlInfoList[i].eBand =
+				kalCfg80211ToMtkBand(request->channels[i]->band);
+			rScanRequest.arChnlInfoList[i].u4CenterFreq1 = request->channels[i]->center_freq;
+			rScanRequest.arChnlInfoList[i].u4CenterFreq2 = 0;
+			rScanRequest.arChnlInfoList[i].u2PriChnlFreq = request->channels[i]->center_freq;
+#if KERNEL_VERSION(3, 11, 0) <= CFG80211_VERSION_CODE
+			rScanRequest.arChnlInfoList[i].ucChnlBw = request->scan_width;
+#else
+			rScanRequest.arChnlInfoList[i].ucChnlBw = 0;
+#endif
+			rScanRequest.arChnlInfoList[i].ucChannelNum =
+				ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+		}
+	}
+#endif
+
 	rStatus = kalIoctl(prGlueInfo,
 			   wlanoidSetBssidListScanAdv,
 			   &rScanRequest, sizeof(PARAM_SCAN_REQUEST_ADV_T), FALSE, FALSE, FALSE, &u4BufLen);
diff --git a/os/linux/include/gl_kal.h b/os/linux/include/gl_kal.h
index 0b6a575..ad27f5f 100644
--- a/os/linux/include/gl_kal.h
+++ b/os/linux/include/gl_kal.h
@@ -460,6 +460,19 @@
 #endif
 
 /**
+ * kalCfg80211ToMtkBand - Band translation helper
+ *
+ * @band: cfg80211_band
+ *
+ * Translates cfg80211 band into internal band definition
+ */
+#if CFG_SCAN_CHANNEL_SPECIFIED
+#define kalCfg80211ToMtkBand(cfg80211_band) \
+	(cfg80211_band == KAL_BAND_2GHZ ? BAND_2G4 : \
+	 cfg80211_band == KAL_BAND_5GHZ ? BAND_5G : BAND_NULL)
+#endif
+
+/**
  * kalCfg80211ScanDone - abstraction of cfg80211_scan_done
  *
  * @request: the corresponding scan request (sanity checked by callers!)