qcacld-3.0: Add monitor mode support

Add monitor mode support. Configure target to deliver 802.11 packets
in raw mode. Below is the procedure to start the monitor mode.
insmod /system/lib/modules/wlan.ko con_mode=4
ifconfig wlan0 up
"iwpriv wlan0 setMonChan 36 2"
or
"iw dev mon0 set channel 36 HT40+"
tcpdump -i wlan0 -w <tcpdump.pcap>

In this mode concurrency is not supported and module doesnot support Tx.

Change-Id: I211ece0a66e2d43bc111e523714942e1557e36f4
CRs-Fixed: 963060
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index e741530..28a9522 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -367,6 +367,7 @@
 
 #define WE_SET_DUAL_MAC_SCAN_CONFIG    21
 #define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22
+#define WE_SET_MON_MODE_CHAN 23
 
 #ifdef FEATURE_WLAN_TDLS
 #undef  MAX_VAR_ARGS
@@ -9728,6 +9729,53 @@
 	return ret;
 }
 
+/**
+ * wlan_hdd_set_mon_chan() - Set capture channel on the monitor mode interface.
+ * @adapter: Handle to adapter
+ * @chan: Monitor mode channel
+ * @bandwidth: Capture channel bandwidth
+ *
+ * Return: 0 on success else error code.
+ */
+static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan,
+				 uint32_t bandwidth)
+{
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	struct hdd_mon_set_ch_info *ch_info = &sta_ctx->ch_info;
+	QDF_STATUS status;
+	tHalHandle hal_hdl = hdd_ctx->hHal;
+	struct qdf_mac_addr bssid;
+	tCsrRoamProfile roam_profile;
+	struct ch_params_s ch_params;
+
+	if (QDF_GLOBAL_MONITOR_MODE != hdd_get_conparam()) {
+		hdd_err("Not supported, device is not in monitor mode");
+		return -EINVAL;
+	}
+
+	hdd_info("Set monitor mode Channel %d", chan);
+	hdd_select_cbmode(adapter, chan);
+	roam_profile.ChannelInfo.ChannelList = &ch_info->channel;
+	roam_profile.ChannelInfo.numOfChannels = 1;
+	roam_profile.phyMode = ch_info->phy_mode;
+	roam_profile.ch_params.ch_width = bandwidth;
+
+	qdf_mem_copy(bssid.bytes, adapter->macAddressCurrent.bytes,
+		     QDF_MAC_ADDR_SIZE);
+
+	ch_params.ch_width = bandwidth;
+	sme_set_ch_params(hal_hdl, ch_info->phy_mode, chan, 0, &ch_params);
+	status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params,
+					     &roam_profile);
+	if (status) {
+		hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode",
+			status);
+	}
+
+	return qdf_status_to_os_return(status);
+}
+
 static int __iw_set_two_ints_getnone(struct net_device *dev,
 				     struct iw_request_info *info,
 				     union iwreq_data *wrqu, char *extra)
@@ -9793,6 +9841,9 @@
 		if (value[1] == DUMP_DP_TRACE)
 			qdf_dp_trace_dump_all(value[2]);
 		break;
+	case WE_SET_MON_MODE_CHAN:
+		ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]);
+		break;
 	default:
 		hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd);
 		break;
@@ -11014,6 +11065,10 @@
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
 	 0, "dump_dp_trace"}
 	,
+	{WE_SET_MON_MODE_CHAN,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+	 0, "setMonChan"}
+	,
 };
 
 const struct iw_handler_def we_handler_def = {