qcacld-3.0: Adds API to send avoid_freq list for DNBS

Adds API to send "list of frequencies to be avoided"
to the application, when Do_Not_Break_Stream is active.
When DNBS is active, all frequencies other than the
AP/P2P-GO operating frequency, in the current band are to be avoided.

Change-Id: Ia27b5911715a216f0ab49aa0d984243e9ea49b64
CRs-Fixed: 2045120
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 3b252d6..d414051 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -802,6 +802,137 @@
 	return 0;
 }
 
+/**
+ * wlan_hdd_get_adjacent_chan(): Gets next/previous channel
+ * with respect to the channel passed.
+ * @chan: Channel
+ * @upper: If "true" then next channel is returned or else
+ * previous channel is returned.
+ *
+ * This function returns the next/previous adjacent-channel to
+ * the channel passed. If "upper = true" then next channel is
+ * returned else previous is returned.
+ */
+int wlan_hdd_get_adjacent_chan(uint8_t chan, bool upper)
+{
+	enum channel_enum ch_idx = reg_get_chan_enum(chan);
+
+	if (ch_idx == INVALID_CHANNEL)
+		return -EINVAL;
+
+	if (upper && (ch_idx < (NUM_CHANNELS - 1)))
+		ch_idx++;
+	else if (!upper && (ch_idx > CHAN_ENUM_1))
+		ch_idx--;
+	else
+		return -EINVAL;
+
+	return WLAN_REG_CH_NUM(ch_idx);
+}
+
+/**
+ * wlan_hdd_send_avoid_freq_for_dnbs(): Sends list of frequencies to be
+ * avoided when Do_Not_Break_Stream is active.
+ * @pHddCtx:  HDD Context
+ * @op_chan:  AP/P2P-GO operating channel
+ *
+ * This function sends list of frequencies to be avoided when
+ * Do_Not_Break_Stream is active.
+ * To clear the avoid_frequency_list in the application,
+ * op_chan = 0 can be passed.
+ *
+ * Return: 0 on success and errno on failure
+ */
+int wlan_hdd_send_avoid_freq_for_dnbs(hdd_context_t *pHddCtx, uint8_t op_chan)
+{
+	tHddAvoidFreqList p2p_avoid_freq_list;
+	uint8_t min_chan, max_chan;
+	int ret;
+	int chan;
+
+	ENTER();
+
+	if (!pHddCtx) {
+		hdd_err("invalid param");
+		return -EINVAL;
+	}
+
+	qdf_mem_zero(&p2p_avoid_freq_list, sizeof(tHddAvoidFreqList));
+	/*
+	 * If channel passed is zero, clear the avoid_freq list in application.
+	 */
+	if (!op_chan) {
+		ret = wlan_hdd_send_avoid_freq_event(pHddCtx,
+						     &p2p_avoid_freq_list);
+		if (ret)
+			hdd_err("wlan_hdd_send_avoid_freq_event error:%d",
+				ret);
+
+		return ret;
+	}
+
+	if (WLAN_REG_IS_24GHZ_CH(op_chan)) {
+		min_chan = REG_MIN_24GHZ_CH_NUM;
+		max_chan = REG_MAX_24GHZ_CH_NUM;
+	} else if WLAN_REG_IS_5GHZ_CH(op_chan) {
+		min_chan = REG_MIN_5GHZ_CH_NUM;
+		max_chan = REG_MAX_5GHZ_CH_NUM;
+	} else {
+		hdd_err("invalid channel:%d", op_chan);
+		return -EINVAL;
+	}
+
+	if ((op_chan > min_chan) && (op_chan < max_chan)) {
+		p2p_avoid_freq_list.avoidFreqRangeCount = 2;
+		p2p_avoid_freq_list.avoidFreqRange[0].startFreq =
+			wlan_chan_to_freq(min_chan);
+
+		/* Get channel before the op_chan */
+		chan = wlan_hdd_get_adjacent_chan(op_chan, false);
+		if (chan < 0)
+			return -EINVAL;
+		p2p_avoid_freq_list.avoidFreqRange[0].endFreq =
+			wlan_chan_to_freq(chan);
+
+		/* Get channel next to the op_chan */
+		chan = wlan_hdd_get_adjacent_chan(op_chan, true);
+		if (chan < 0)
+			return -EINVAL;
+		p2p_avoid_freq_list.avoidFreqRange[1].startFreq =
+			wlan_chan_to_freq(chan);
+
+		p2p_avoid_freq_list.avoidFreqRange[1].endFreq =
+			wlan_chan_to_freq(max_chan);
+	} else if (op_chan == min_chan) {
+		p2p_avoid_freq_list.avoidFreqRangeCount = 1;
+
+		chan = wlan_hdd_get_adjacent_chan(op_chan, true);
+		if (chan < 0)
+			return -EINVAL;
+		p2p_avoid_freq_list.avoidFreqRange[0].startFreq =
+			wlan_chan_to_freq(chan);
+
+		p2p_avoid_freq_list.avoidFreqRange[0].endFreq =
+			wlan_chan_to_freq(max_chan);
+	} else {
+		p2p_avoid_freq_list.avoidFreqRangeCount = 1;
+		p2p_avoid_freq_list.avoidFreqRange[0].startFreq =
+			wlan_chan_to_freq(min_chan);
+
+		chan = wlan_hdd_get_adjacent_chan(op_chan, false);
+		if (chan < 0)
+			return -EINVAL;
+		p2p_avoid_freq_list.avoidFreqRange[0].endFreq =
+			wlan_chan_to_freq(chan);
+	}
+
+	ret = wlan_hdd_send_avoid_freq_event(pHddCtx, &p2p_avoid_freq_list);
+	if (ret)
+		hdd_err("wlan_hdd_send_avoid_freq_event error:%d", ret);
+
+	return ret;
+}
+
 /* vendor specific events */
 static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = {
 	[QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX] = {