qcacld-3.0: Add support for beacon filtering

qcacld-2.0 to qcacld-3.0 propagation

In case of DFS channels and EBT is disabled, beacons are
forwarded to host in every 50msecs which increase power consumption.
Add the changes to set beacon filter once DUT connect to AP.

CRs-Fixed: 973958
Change-Id: I1a9379eacbd13f8dc7fae08923cd91f087d1b2b2
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index e090491..3475a18 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -110,6 +110,19 @@
 #define HDD_PEER_AUTHORIZE_WAIT 10
 
 /**
+ * beacon_filter_table - table of IEs used for beacon filtering
+ */
+static const int beacon_filter_table[] = {
+	SIR_MAC_DS_PARAM_SET_EID,
+	SIR_MAC_ERP_INFO_EID,
+	SIR_MAC_EDCA_PARAM_SET_EID,
+	SIR_MAC_QOS_CAPABILITY_EID,
+	SIR_MAC_HT_INFO_EID,
+	SIR_MAC_VHT_OPMODE_EID,
+	SIR_MAC_VHT_OPERATION_EID,
+};
+
+/**
  * hdd_conn_set_authenticated() - set authentication state
  * @pAdapter: pointer to the adapter
  * @authState: authentication state
@@ -313,6 +326,53 @@
 }
 
 /**
+ * hdd_remove_beacon_filter() - remove beacon filter
+ * @adapter: Pointer to the hdd adapter
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int hdd_remove_beacon_filter(hdd_adapter_t *adapter)
+{
+	QDF_STATUS status;
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+	status = sme_remove_beacon_filter(hdd_ctx->hHal,
+				adapter->sessionId);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("sme_remove_beacon_filter() failed");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * hdd_add_beacon_filter() - add beacon filter
+ * @adapter: Pointer to the hdd adapter
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int hdd_add_beacon_filter(hdd_adapter_t *adapter)
+{
+	int i;
+	uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST] = {0};
+	QDF_STATUS status;
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+	for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++)
+		qdf_set_bit((beacon_filter_table[i] - 1),
+				(unsigned long int *)ie_map);
+
+	status = sme_add_beacon_filter(hdd_ctx->hHal,
+				adapter->sessionId, ie_map);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("sme_add_beacon_filter() failed");
+		return -EFAULT;
+	}
+	return 0;
+}
+
+/**
  * hdd_conn_save_connect_info() - save current connection information
  * @pAdapter: pointer to adapter
  * @pRoamInfo: pointer to roam info
@@ -1086,6 +1146,9 @@
 
 	hdd_wmm_adapter_clear(pAdapter);
 	sme_ft_reset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId);
+	if (hdd_remove_beacon_filter(pAdapter) != 0)
+		hdd_err("hdd_remove_beacon_filter() failed");
+
 	if (eCSR_ROAM_IBSS_LEAVE == roamStatus) {
 		uint8_t i;
 		sta_id = pHddStaCtx->broadcast_ibss_staid;
@@ -1775,6 +1838,9 @@
 		/* Save the connection info from CSR... */
 		hdd_conn_save_connect_info(pAdapter, pRoamInfo,
 					   eCSR_BSS_TYPE_INFRASTRUCTURE);
+
+		if (hdd_add_beacon_filter(pAdapter) != 0)
+			hdd_err("hdd_add_beacon_filter() failed");
 #ifdef FEATURE_WLAN_WAPI
 		if (pRoamInfo->u.pConnectedProfile->AuthType ==
 		    eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index f4ea4e2..e54d512 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -5541,6 +5541,18 @@
 	uint32_t   flags;
 };
 
+#define SIR_BCN_FLT_MAX_ELEMS_IE_LIST 8
+/**
+ * struct beacon_filter_param - parameters for beacon filtering
+ * @vdev_id: vdev id
+ * @ie_map: bitwise map of IEs that needs to be filtered
+ *
+ */
+struct beacon_filter_param {
+	uint32_t   vdev_id;
+	uint32_t   ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST];
+};
+
 /**
  * struct csa_offload_params - CSA offload request parameters
  * @channel: channel
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 394353d..b1e0829 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -598,6 +598,10 @@
 
 #define SIR_HAL_SET_EGAP_CONF_PARAMS        (SIR_HAL_ITC_MSG_TYPES_BEGIN + 336)
 #define SIR_HAL_HT40_OBSS_SCAN_IND          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 337)
+
+#define SIR_HAL_ADD_BCN_FILTER_CMDID        (SIR_HAL_ITC_MSG_TYPES_BEGIN + 339)
+#define SIR_HAL_REMOVE_BCN_FILTER_CMDID     (SIR_HAL_ITC_MSG_TYPES_BEGIN + 340)
+
 #define SIR_HAL_MSG_TYPES_END                (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* CFG message types */
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index c111b54..a41f85b 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1103,4 +1103,7 @@
 				      bool send_smps_action);
 
 bool sme_is_sta_smps_allowed(tHalHandle hHal, uint8_t session_id);
+QDF_STATUS sme_add_beacon_filter(tHalHandle hal,
+				uint32_t session_id, uint32_t *ie_map);
+QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id);
 #endif /* #if !defined( __SME_API_H ) */
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index e1b88e8..689dede 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -15464,3 +15464,97 @@
 
 	return (csr_session->supported_nss_1x1 == true) ? false : true;
 }
+
+/**
+ * sme_add_beacon_filter() - set the beacon filter configuration
+ * @hal: The handle returned by macOpen
+ * @session_id: session id
+ * @ie_map: bitwise array of IEs
+ *
+ * Return: Return QDF_STATUS, otherwise appropriate failure code
+ */
+QDF_STATUS sme_add_beacon_filter(tHalHandle hal,
+				 uint32_t session_id,
+				 uint32_t *ie_map)
+{
+	cds_msg_t message;
+	QDF_STATUS qdf_status;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+	struct beacon_filter_param *filter_param;
+
+	if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) {
+		sms_log(mac_ctx, LOGE,
+			"CSR session not valid: %d",
+			session_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	filter_param = qdf_mem_malloc(sizeof(*filter_param));
+	if (NULL == filter_param) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				"%s: fail to alloc filter_param", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	filter_param->vdev_id = session_id;
+
+	qdf_mem_copy(filter_param->ie_map, ie_map,
+			BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(uint32_t));
+
+	message.type = WMA_ADD_BCN_FILTER_CMDID;
+	message.bodyptr = filter_param;
+	qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA,
+					&message);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			"%s: Not able to post msg to WDA!",
+			__func__);
+
+		qdf_mem_free(filter_param);
+	}
+	return qdf_status;
+}
+
+/**
+ * sme_remove_beacon_filter() - set the beacon filter configuration
+ * @hal: The handle returned by macOpen
+ * @session_id: session id
+ *
+ * Return: Return QDF_STATUS, otherwise appropriate failure code
+ */
+QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id)
+{
+	cds_msg_t message;
+	QDF_STATUS qdf_status;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+	struct beacon_filter_param *filter_param;
+
+	if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) {
+		sms_log(mac_ctx, LOGE,
+			"CSR session not valid: %d",
+			session_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	filter_param = qdf_mem_malloc(sizeof(*filter_param));
+	if (NULL == filter_param) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				"%s: fail to alloc filter_param", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	filter_param->vdev_id = session_id;
+
+	message.type = WMA_REMOVE_BCN_FILTER_CMDID;
+	message.bodyptr = filter_param;
+	qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA,
+					&message);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			"%s: Not able to post msg to WDA!",
+			__func__);
+
+		qdf_mem_free(filter_param);
+	}
+	return qdf_status;
+}
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index f97eb1b..cec1e1e 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -223,6 +223,11 @@
 #endif
 bool wma_is_scan_simultaneous_capable(void);
 
+QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma,
+				struct beacon_filter_param *filter_params);
+
+QDF_STATUS wma_add_beacon_filter(WMA_HANDLE wma,
+				struct beacon_filter_param *filter_params);
 #ifdef FEATURE_GREEN_AP
 void wma_setup_egap_support(struct wma_tgt_cfg *tgt_cfg, WMA_HANDLE handle);
 void wma_register_egap_event_handle(WMA_HANDLE handle);
diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h
index d581679..dfd8f8a 100644
--- a/core/wma/inc/wma_types.h
+++ b/core/wma/inc/wma_types.h
@@ -464,6 +464,8 @@
 #define WMA_LRO_CONFIG_CMD                   SIR_HAL_LRO_CONFIG_CMD
 #define WMA_GW_PARAM_UPDATE_REQ              SIR_HAL_GATEWAY_PARAM_UPDATE_REQ
 #define WMA_SET_EGAP_CONF_PARAMS             SIR_HAL_SET_EGAP_CONF_PARAMS
+#define WMA_ADD_BCN_FILTER_CMDID             SIR_HAL_ADD_BCN_FILTER_CMDID
+#define WMA_REMOVE_BCN_FILTER_CMDID          SIR_HAL_REMOVE_BCN_FILTER_CMDID
 
 /* Bit 6 will be used to control BD rate for Management frames */
 #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index ff31da2..fe9d40f 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -802,6 +802,123 @@
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+* wma_add_beacon_filter() - Issue WMI command to set beacon filter
+* @wma: wma handler
+* @filter_params: beacon_filter_param to set
+*
+* Return: Return QDF_STATUS
+*/
+QDF_STATUS wma_add_beacon_filter(WMA_HANDLE handle,
+				struct beacon_filter_param *filter_params)
+{
+	int i;
+	wmi_buf_t wmi_buf;
+	u_int8_t *buf;
+	A_UINT32 *ie_map;
+	int ret;
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	wmi_add_bcn_filter_cmd_fixed_param *cmd;
+	int len = sizeof(wmi_add_bcn_filter_cmd_fixed_param);
+
+	len += WMI_TLV_HDR_SIZE;
+	len += BCN_FLT_MAX_ELEMS_IE_LIST*sizeof(A_UINT32);
+
+	if (!wma || !wma->wmi_handle) {
+		WMA_LOGE("%s: WMA is closed, can not issue set beacon filter",
+			__func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
+	if (!wmi_buf) {
+		WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf = (u_int8_t *) wmi_buf_data(wmi_buf);
+
+	cmd = (wmi_add_bcn_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf);
+	cmd->vdev_id = filter_params->vdev_id;
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+			WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param,
+			WMITLV_GET_STRUCT_TLVLEN(
+				wmi_add_bcn_filter_cmd_fixed_param));
+
+	buf += sizeof(wmi_add_bcn_filter_cmd_fixed_param);
+
+	WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_UINT32,
+			(BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t)));
+
+	ie_map = (A_UINT32 *)(buf + WMI_TLV_HDR_SIZE);
+	for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) {
+		ie_map[i] = filter_params->ie_map[i];
+		WMA_LOGD("beacon filter ie map = %u", ie_map[i]);
+	}
+
+	ret = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
+			WMI_ADD_BCN_FILTER_CMDID);
+	if (ret) {
+		WMA_LOGE("Failed to send wmi add beacon filter = %d",
+				ret);
+		wmi_buf_free(wmi_buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+	WMA_LOGD("added beacon filter = %d", ret);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+* wma_remove_beacon_filter() - Issue WMI command to remove beacon filter
+* @wma: wma handler
+* @filter_params: beacon_filter_params
+*
+* Return: Return QDF_STATUS
+*/
+QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE handle,
+				struct beacon_filter_param *filter_params)
+{
+	wmi_buf_t buf;
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	wmi_rmv_bcn_filter_cmd_fixed_param *cmd;
+	int len = sizeof(wmi_rmv_bcn_filter_cmd_fixed_param);
+	int ret;
+
+	if (!wma || !wma->wmi_handle) {
+		WMA_LOGE("%s: WMA is closed, cannot issue remove beacon filter",
+			__func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	buf = wmi_buf_alloc(wma->wmi_handle, len);
+	if (!buf) {
+		WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+	cmd = (wmi_rmv_bcn_filter_cmd_fixed_param *)wmi_buf_data(buf);
+	cmd->vdev_id = filter_params->vdev_id;
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+			WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param,
+			WMITLV_GET_STRUCT_TLVLEN(
+				wmi_rmv_bcn_filter_cmd_fixed_param));
+
+	ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
+			WMI_RMV_BCN_FILTER_CMDID);
+	if (ret) {
+		WMA_LOGE("Failed to send wmi remove beacon filter = %d",
+				ret);
+		wmi_buf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+	WMA_LOGD("removed beacon filter = %d", ret);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+
 #ifdef FEATURE_GREEN_AP
 
 /**
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index cafc91b..06e5da0 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -5250,6 +5250,15 @@
 			(struct obss_ht40_scanind *)msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case WMA_ADD_BCN_FILTER_CMDID:
+		wma_add_beacon_filter(wma_handle, msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case WMA_REMOVE_BCN_FILTER_CMDID:
+		wma_remove_beacon_filter(wma_handle, msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+
 	default:
 		WMA_LOGD("unknow msg type %x", msg->type);
 		/* Do Nothing? MSG Body should be freed at here */