qcacld-2.0: Monitor mode - Frame filtering

Use WMI Monitor mode Filter CMD to send frame type
to firmware for filtering
Add iwpriv option for user to select frame type
iwpriv wlan0 setMonFilter FrameType

Change-Id: Ib22dc782d01de83ada3b6effb277436c7e386014
CRs-Fixed: 2169766
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 49708b9..bcc7967 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -245,6 +245,13 @@
 
 #define WE_SET_MODULATED_DTIM                 88
 
+#define WE_SET_MON_FILTER                     89
+typedef enum eMonFilterType{
+        MON_MGMT_PKT,
+        MON_CTRL_PKT,
+        MON_DATA_PKT,
+        MON_ALL_PKT,
+} tMonFilterType;
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_INT    (SIOCIWFIRSTPRIV + 1)
@@ -369,33 +376,33 @@
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_VAR_INT_GET_NONE   (SIOCIWFIRSTPRIV + 7)
-#define WE_LOG_DUMP_CMD      1
+#define WE_LOG_DUMP_CMD                              1
 
-#define WE_P2P_NOA_CMD       2
+#define WE_P2P_NOA_CMD                               2
 //IOCTL to configure MCC params
-#define WE_MCC_CONFIG_CREDENTIAL 3
-#define WE_MCC_CONFIG_PARAMS  4
+#define WE_MCC_CONFIG_CREDENTIAL                     3
+#define WE_MCC_CONFIG_PARAMS                         4
 
 #ifdef FEATURE_WLAN_TDLS
-#define WE_TDLS_CONFIG_PARAMS   5
+#define WE_TDLS_CONFIG_PARAMS                        5
 #endif
-#define WE_IBSS_GET_PEER_INFO   6
-#define WE_UNIT_TEST_CMD   7
+#define WE_IBSS_GET_PEER_INFO                        6
+#define WE_UNIT_TEST_CMD                             7
 
-#define WE_MTRACE_DUMP_CMD    8
+#define WE_MTRACE_DUMP_CMD                           8
 #define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD    9
 
 #ifdef WLAN_FEATURE_GPIO_LED_FLASHING
-#define WE_LED_FLASHING_PARAM    10
+#define WE_LED_FLASHING_PARAM                       10
 #endif
 #ifdef MEMORY_DEBUG
-#define WE_MEM_TRACE_DUMP     11
+#define WE_MEM_TRACE_DUMP                           11
 #endif
 #ifdef FEATURE_WLAN_TDLS
 #undef  MAX_VAR_ARGS
-#define MAX_VAR_ARGS         11
+#define MAX_VAR_ARGS                                11
 #else
-#define MAX_VAR_ARGS         7
+#define MAX_VAR_ARGS                                 7
 #endif
 
 /* Private ioctls (with no sub-ioctls) */
@@ -5997,6 +6004,51 @@
     return VOS_STATUS_SUCCESS;
 }
 
+/**
+ * wlan_hdd_mnt_filter_type_cmd() - set filter packet type
+ * configuration to firmware
+ * @data: pointer to filter type configuration data.
+ * @data_len: the length in byte of filter type data.
+ *
+ * This is called when wlan driver needs to set
+ * filter packet type to firmware in monitor mode.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int wlan_hdd_mnt_filter_type_cmd(hdd_adapter_t *pAdapter, v_U8_t *data,
+                                        int data_len)
+{
+    hdd_context_t *pHddCtx = NULL;
+    v_CONTEXT_t pVosContext = NULL;
+    struct sme_mnt_filter_type_req  filter_type;
+    VOS_STATUS status;
+    int ret_val = -EIO;
+
+    /* Get the Global VOSS Context */
+    pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+    if (!pVosContext) {
+        hddLog(VOS_TRACE_LEVEL_FATAL,"%s: VOS context is Null", __func__);
+        return ret_val;
+    }
+
+    /* Get the HDD context */
+    pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext);
+    if (!pHddCtx) {
+        hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HDD context is Null",__func__);
+        return ret_val;
+    }
+
+    filter_type.vdev_id = pAdapter->sessionId;
+    filter_type.request_data_len = data_len;
+    filter_type.request_data = data;
+
+    status = sme_mnt_filter_type_cmd(&filter_type);
+    if (VOS_STATUS_SUCCESS == status) {
+        ret_val = 0;
+    }
+    return ret_val;
+}
+
 /* set param sub-ioctls */
 static int __iw_setint_getnone(struct net_device *dev,
                                struct iw_request_info *info,
@@ -7315,11 +7367,42 @@
             }
             break;
         }
+        case WE_SET_MON_FILTER:
+        {
+            v_U8_t filter_type = 0;
+
+            if (VOS_MONITOR_MODE != hdd_get_conparam()) {
+                hddLog(LOGE, "Unable to set Monitor Mode Filters");
+                hddLog(LOGE, "WLAN Device is not in Monitor mode!!");
+                return -EINVAL;
+            }
+
+            if (set_value < MON_MGMT_PKT || set_value > MON_ALL_PKT) {
+                hddLog(LOGE, "Invalid Filter value recieved...");
+                hddLog(LOGE, "Valid Values to set monitor mode filter:");
+                hddLog(LOGE, "0: Filter management packets");
+                hddLog(LOGE, "1: Filter control packets");
+                hddLog(LOGE, "2: Filter data packets");
+                hddLog(LOGE, "3: Filter All packets");
+                return -EINVAL;
+            }
+            filter_type = (v_U8_t) (set_value & 0xFF);
+
+            /* filter packetin monitor mode. */
+            if (filter_type < MON_MGMT_PKT || filter_type > MON_ALL_PKT) {
+                hddLog(LOGE, "Invalid monitor mode filter type received");
+                return -EINVAL;
+            }
+
+            hddLog(LOG1, "Monitor Mode Filter type  = %d", filter_type);
+            wlan_hdd_mnt_filter_type_cmd(pAdapter, &filter_type,sizeof(v_U8_t));
+            break;
+        }
         default:
         {
-           hddLog(LOGE, "%s: Invalid sub command %d", __func__, sub_cmd);
-           ret = -EINVAL;
-           break;
+            hddLog(LOGE, "%s: Invalid sub command %d", __func__, sub_cmd);
+            ret = -EINVAL;
+            break;
         }
     }
     EXIT();
@@ -12020,6 +12103,11 @@
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
         0, "setModDTIM" },
 
+    {
+        WE_SET_MON_FILTER,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        0, "setMonFilter" },
+
     /* handlers for sub-ioctl */
     {   WE_GET_11D_STATE,
         0,
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index 826ae6c..4bf2841 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -798,7 +798,8 @@
 #define SIR_HAL_PEER_FLUSH_PENDING          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 375)
 #define SIR_HAL_SET_AC_TXQ_OPTIMIZE         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 376)
 
-#define SIR_HAL_MSG_TYPES_END              (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
+#define SIR_HAL_MNT_FILTER_TYPE_CMD         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 377)
+#define SIR_HAL_MSG_TYPES_END               (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 // CFG message types
 #define SIR_CFG_MSG_TYPES_BEGIN        (SIR_CFG_MODULE_ID << 8)
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index ef97c56..f99ad45 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -33734,6 +33734,59 @@
 					 peer_tid_bitmap, vdev_id);
 }
 
+/**
+ * wma_mnt_filter_type_cmd() - set filter packet type to firmware
+ * in monitor mode.
+ * @wda_handle: pointer to wma handle.
+ * @enable_monitor_req: pointer to filter type request.
+ *
+ * This is called to filter type to firmware via WMI command.
+ *
+ * Return: VOS_STATUS.
+ */
+VOS_STATUS wma_mnt_filter_type_cmd(tp_wma_handle wma_handle,
+                           struct hal_mnt_filter_type_request *filter_type_req)
+{
+    wmi_mnt_filter_cmd_fixed_param *cmd;
+    int status = 0;
+    wmi_buf_t buf;
+    u_int8_t *buf_ptr;
+    int32_t len = sizeof(wmi_mnt_filter_cmd_fixed_param);
+
+    if (!wma_handle || !wma_handle->wmi_handle) {
+        WMA_LOGE(FL("WMA is closed, can not issue cmd"));
+        return VOS_STATUS_E_INVAL;
+    }
+
+    buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+    if (!buf) {
+        WMA_LOGP(FL("wmi_buf_alloc failed"));
+        return -ENOMEM;
+    }
+    buf_ptr = (u_int8_t *) wmi_buf_data(buf);
+    cmd = (wmi_mnt_filter_cmd_fixed_param *) buf_ptr;
+    WMITLV_SET_HDR(&cmd->tlv_header,
+                    WMITLV_TAG_STRUC_wmi_mnt_filter_cmd_fixed_param,
+                    WMITLV_GET_STRUCT_TLVLEN(
+                    wmi_mnt_filter_cmd_fixed_param));
+    cmd->vdev_id = filter_type_req->vdev_id;
+    if (filter_type_req->request_data_len) {
+        vos_mem_copy(&(cmd->configure_type),
+        filter_type_req->request_data, filter_type_req->request_data_len);
+    }
+    WMA_LOGI("%s: Filter type=0x%x",__func__,cmd->configure_type);
+    status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
+                                    WMI_MNT_FILTER_CMDID);
+    if (status != EOK) {
+        WMA_LOGE("%s: wmi_unified_cmd_send WMI_MNT_FILTER_CMDID"
+                 " returned Error %d",
+                 __func__, status);
+        wmi_buf_free(buf);
+        return VOS_STATUS_E_FAILURE;
+    }
+    return VOS_STATUS_SUCCESS;
+}
+
 /*
  * function   : wma_mc_process_msg
  * Description :
@@ -34664,9 +34717,9 @@
 			     (struct action_frame_random_filter *)msg->bodyptr);
 			vos_mem_free(msg->bodyptr);
 			break;
-        case WDA_GET_ISOLATION:
-            wma_get_isolation(wma_handle);
-            break;
+		case WDA_GET_ISOLATION:
+			wma_get_isolation(wma_handle);
+			break;
 		case WDA_PEER_FLUSH_PENDING:
 			wma_peer_flush_pending(wma_handle, msg->bodyptr);
 			vos_mem_free(msg->bodyptr);
@@ -34675,6 +34728,11 @@
 			wma_set_ac_txq_optimize(wma_handle, msg->bodyptr);
 			vos_mem_free(msg->bodyptr);
 			break;
+		case WDA_MNT_FILTER_TYPE_CMD:
+			wma_mnt_filter_type_cmd(wma_handle,
+				(struct hal_mnt_filter_type_request*)msg->bodyptr);
+			vos_mem_free(msg->bodyptr);
+			break;
 		default:
 			WMA_LOGD("unknow msg type %x", msg->type);
 			/* Do Nothing? MSG Body should be freed at here */
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 7ed05ff..777f7eb 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -297,6 +297,12 @@
 	uint8_t     max_rssi_penalize_5g;
 };
 
+struct sme_mnt_filter_type_req{
+    u_int32_t vdev_id;
+    u_int16_t request_data_len;
+    u_int8_t* request_data;
+};
+
 /*-------------------------------------------------------------------------
   Function declarations and documentation
   ------------------------------------------------------------------------*/
@@ -4847,4 +4853,5 @@
 
 eHalStatus sme_set_ac_txq_optimize(tHalHandle hal_handle, uint8_t *value);
 
+VOS_STATUS sme_mnt_filter_type_cmd(struct sme_mnt_filter_type_req *input);
 #endif //#if !defined( __SME_API_H )
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 1206f1b..e6c6ae4 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -17943,6 +17943,49 @@
 }
 
 /**
+ * sme_mnt_filter_type_cmd() - set filter packet type to firmware
+ * @input: pointer to filter type request data.
+ *
+ * Return: VOS_STATUS.
+ */
+VOS_STATUS sme_mnt_filter_type_cmd(struct sme_mnt_filter_type_req *input)
+{
+    vos_msg_t msg;
+    struct hal_mnt_filter_type_request *data;
+    size_t data_len;
+
+    data_len = sizeof(struct hal_mnt_filter_type_request) + input->request_data_len;
+    data = vos_mem_malloc(data_len);
+
+    if (data == NULL) {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                  FL("Memory allocation failure"));
+        return VOS_STATUS_E_FAULT;
+    }
+
+    vos_mem_zero(data, data_len);
+    data->request_data_len = input->request_data_len;
+    data->vdev_id = input->vdev_id;
+    if (input->request_data_len) {
+        vos_mem_copy(data->request_data,
+                input->request_data, input->request_data_len);
+    }
+
+    msg.type = WDA_MNT_FILTER_TYPE_CMD;
+    msg.reserved = 0;
+    msg.bodyptr = data;
+
+    if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg)) {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+        FL("Not able to post WDA_MNT_FILTER_TYPE_CMD message to WDA"));
+        vos_mem_free(data);
+        return VOS_STATUS_SUCCESS;
+    }
+
+    return VOS_STATUS_SUCCESS;
+}
+
+/**
  * sme_set_tsfcb() - set callback which to handle WMI_VDEV_TSF_REPORT_EVENTID
  *
  * @hHal: Handler return by macOpen.
diff --git a/CORE/WDA/inc/legacy/halMsgApi.h b/CORE/WDA/inc/legacy/halMsgApi.h
index e5f1861..0c3a8c7 100644
--- a/CORE/WDA/inc/legacy/halMsgApi.h
+++ b/CORE/WDA/inc/legacy/halMsgApi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1514,4 +1514,11 @@
 };
 #endif
 
+struct hal_mnt_filter_type_request
+{
+    u_int32_t vdev_id;
+    u_int16_t request_data_len;
+    u_int8_t  request_data[];
+};
+
 #endif /* _HALMSGAPI_H_ */
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index de561c9..8f016c5 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1105,6 +1105,7 @@
 #define WDA_ACTION_FRAME_RANDOM_MAC           SIR_HAL_ACTION_FRAME_RANDOM_MAC
 
 #define WDA_SET_AC_TXQ_OPTIMIZE               SIR_HAL_SET_AC_TXQ_OPTIMIZE
+#define WDA_MNT_FILTER_TYPE_CMD               SIR_HAL_MNT_FILTER_TYPE_CMD
 
 tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg);