qcacld-2.0: Validate avoid frequency channel list

Validate the avoid frequency channel list of
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY command and update the
driver's unsafe channel list with the channels received in the command.

Change-Id: I1a10e668bf6fe6dbb22f7f2f8aef929fc6e7fc65
CRs-Fixed: 1100216
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 73dbedf..f805735 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -13049,6 +13049,53 @@
 }
 
 #ifdef FEATURE_WLAN_CH_AVOID
+
+static int hdd_validate_avoid_freq_chanlist(hdd_context_t *hdd_ctx,
+					    tHddAvoidFreqList *channel_list)
+{
+	unsigned int range_idx, ch_idx;
+	unsigned int unsafe_channel_index, unsafe_channel_count = 0;
+	bool ch_found = false;
+
+	unsafe_channel_count = VOS_MIN((uint16_t)hdd_ctx->unsafe_channel_count,
+			(uint16_t)NUM_20MHZ_RF_CHANNELS);
+
+	for (range_idx = 0; range_idx < channel_list->avoidFreqRangeCount;
+					range_idx++) {
+		if ((channel_list->avoidFreqRange[range_idx].startFreq <
+		     VOS_24_GHZ_CHANNEL_1) ||
+		    (channel_list->avoidFreqRange[range_idx].endFreq >
+		     VOS_5_GHZ_CHANNEL_165) ||
+		    (channel_list->avoidFreqRange[range_idx].startFreq >
+		     channel_list->avoidFreqRange[range_idx].endFreq))
+				continue;
+
+		for (ch_idx = channel_list->avoidFreqRange[range_idx].startFreq;
+		     ch_idx <= channel_list->avoidFreqRange[range_idx].endFreq;
+		     ch_idx++) {
+			for (unsafe_channel_index = 0;
+			     unsafe_channel_index < unsafe_channel_count;
+			     unsafe_channel_index++) {
+				if (ch_idx ==
+					hdd_ctx->unsafe_channel_list[
+					unsafe_channel_index]) {
+					hddLog(VOS_TRACE_LEVEL_INFO,
+					       FL("Duplicate channel %d"),
+					       ch_idx);
+					ch_found = true;
+					break;
+				}
+			}
+			if (!ch_found) {
+				hdd_ctx->unsafe_channel_list[
+				unsafe_channel_count++] = ch_idx;
+			}
+			ch_found = false;
+		}
+	}
+	return unsafe_channel_count;
+}
+
 /**
  * __wlan_hdd_cfg80211_avoid_freq() - ask driver to restart SAP if SAP
  * is on unsafe channel.
@@ -13071,28 +13118,43 @@
 {
 	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
 	int ret;
-	uint16_t unsafe_channel_count;
 	int unsafe_channel_index;
+	tHddAvoidFreqList *channel_list;
+	tVOS_CON_MODE curr_mode;
 
 	ENTER();
 
-	if (VOS_FTM_MODE == hdd_get_conparam()) {
-		hddLog(LOGE, FL("Command not allowed in FTM mode"));
+        curr_mode = hdd_get_conparam();
+	if (VOS_FTM_MODE == curr_mode ||
+	    VOS_MONITOR_MODE == curr_mode) {
+		hddLog(LOGE, FL("Command not allowed in FTM/MONITOR mode"));
 		return -EINVAL;
 	}
 
 	ret = wlan_hdd_validate_context(hdd_ctx);
 	if (0 != ret)
 		return -EINVAL;
+
+	channel_list = (tHddAvoidFreqList *)data;
+	if (!channel_list) {
+		hddLog(LOGE, FL("Avoid frequency channel list empty"));
+		return -EINVAL;
+	}
+
 	vos_get_wlan_unsafe_channel(hdd_ctx->unsafe_channel_list,
 			&(hdd_ctx->unsafe_channel_count),
 			sizeof(hdd_ctx->unsafe_channel_list));
 
-	unsafe_channel_count = VOS_MIN((uint16_t)hdd_ctx->unsafe_channel_count,
-			(uint16_t)NUM_20MHZ_RF_CHANNELS);
+	hdd_ctx->unsafe_channel_count =
+		hdd_validate_avoid_freq_chanlist(hdd_ctx,
+						 channel_list);
+
+	vos_set_wlan_unsafe_channel(hdd_ctx->unsafe_channel_list,
+			hdd_ctx->unsafe_channel_count);
+
 	for (unsafe_channel_index = 0;
-			unsafe_channel_index < unsafe_channel_count;
-			unsafe_channel_index++) {
+		unsafe_channel_index < hdd_ctx->unsafe_channel_count;
+		unsafe_channel_index++) {
 		hddLog(LOGE, FL("Channel %d is not safe. "),
 			hdd_ctx->unsafe_channel_list[unsafe_channel_index]);
 	}
diff --git a/CORE/VOSS/inc/vos_utils.h b/CORE/VOSS/inc/vos_utils.h
index e4af65b..f86e796 100644
--- a/CORE/VOSS/inc/vos_utils.h
+++ b/CORE/VOSS/inc/vos_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2012, 2014-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -61,9 +61,11 @@
 
 #define VOS_24_GHZ_BASE_FREQ   2407
 #define VOS_5_GHZ_BASE_FREQ    5000
+#define VOS_24_GHZ_CHANNEL_1   1
 #define VOS_24_GHZ_CHANNEL_14  14
 #define VOS_24_GHZ_CHANNEL_15  15
 #define VOS_24_GHZ_CHANNEL_27  27
+#define VOS_5_GHZ_CHANNEL_165  165
 #define VOS_5_GHZ_CHANNEL_170  170
 #define VOS_CHAN_SPACING_5MHZ  5
 #define VOS_CHAN_SPACING_20MHZ 20