Переглянути джерело

qcacld-3.0: Port Dynamic MC/BC Filter ioctls from qcacld-2.0

Port the dynamic MC/BC filter configuration ioctls from qcacld-2.0 to
qcacld-3.0

Change-Id: Ie2fd9e519ac62ea77b149fd5dcf400d9b30621ad
CRs-Fixed: 1102502
Dustin Brown 8 роки тому
батько
коміт
0cbc7574e8
2 змінених файлів з 337 додано та 4 видалено
  1. 15 2
      core/hdd/inc/wlan_hdd_power.h
  2. 322 2
      core/hdd/src/wlan_hdd_wext.c

+ 15 - 2
core/hdd/inc/wlan_hdd_power.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -38,7 +38,8 @@
 
 #ifdef WLAN_FEATURE_PACKET_FILTERING
 
-#define HDD_MAX_CMP_PER_PACKET_FILTER     5
+#define HDD_MAX_CMP_PER_PACKET_FILTER	5
+#define HDD_MC_FILTER_MAX_MC_ADDRS	16
 
 /**
  * enum pkt_filter_protocol_layer - packet filter protocol layer
@@ -126,6 +127,18 @@ struct pkt_filter_cfg {
 
 #endif
 
+/**
+ * struct pkt_filter_mc_addr_list - dynamic mc/bc filter config from user space
+ * @mcbc_filter_setting: The type of filter being configured
+ * @mc_addr_cnt: The number of mc addresses to configure
+ * @mc_addrs: The mc mac addresses to configure
+ */
+struct pkt_filter_mc_addr_list {
+	uint8_t mcbc_filter_setting;
+	uint8_t mc_addr_cnt;
+	uint8_t mc_addrs[HDD_MC_FILTER_MAX_MC_ADDRS][QDF_MAC_ADDR_SIZE];
+};
+
 /**
  * enum suspend_resume_state - Suspend resume state
  * @HDD_WLAN_EARLY_SUSPEND: Early suspend state.

+ 322 - 2
core/hdd/src/wlan_hdd_wext.c

@@ -973,8 +973,8 @@ static const hdd_freq_chan_map_t freq_chan_map[] = {
 
 #define WLAN_SET_BAND_CONFIG  (SIOCIWFIRSTPRIV + 25)
 
-/* (SIOCIWFIRSTPRIV + 26) is currently unused */
-/* (SIOCIWFIRSTPRIV + 27) is currently unused */
+#define WLAN_PRIV_SET_MCBC_FILTER   (SIOCIWFIRSTPRIV + 26)
+#define WLAN_PRIV_CLEAR_MCBC_FILTER (SIOCIWFIRSTPRIV + 27)
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_TWO_INT_GET_NONE   (SIOCIWFIRSTPRIV + 28)
@@ -9292,6 +9292,307 @@ static int iw_set_fties(struct net_device *dev,
 	return ret;
 }
 
+#ifdef WLAN_FEATURE_PACKET_FILTERING
+static int iw_set_mc_filter_list(hdd_adapter_t *adapter,
+				 struct pkt_filter_mc_addr_list *req)
+{
+	int exit_code;
+	QDF_STATUS status;
+	tHalHandle hal;
+	tSirRcvFltMcAddrList *mc_addr_list;
+	int i;
+
+	ENTER();
+
+	mc_addr_list = qdf_mem_malloc(sizeof(*mc_addr_list));
+	if (!mc_addr_list) {
+		hdd_err("Out of memory");
+		exit_code = -ENOMEM;
+		goto exit_with_code;
+	}
+
+	mc_addr_list->action = HDD_SET_MCBC_FILTERS_TO_FW;
+	mc_addr_list->ulMulticastAddrCnt =
+		min(req->mc_addr_cnt, (uint8_t)HDD_MC_FILTER_MAX_MC_ADDRS);
+
+	hdd_info("Configuring %u MC addrs (originally %u)",
+		 mc_addr_list->ulMulticastAddrCnt, req->mc_addr_cnt);
+
+	for (i = 0; i < mc_addr_list->ulMulticastAddrCnt; i++) {
+		memcpy(&mc_addr_list->multicastAddr[i], req->mc_addrs[i],
+		       QDF_MAC_ADDR_SIZE);
+
+		hdd_info("MC addr %d: " MAC_ADDRESS_STR,
+			 i, MAC_ADDR_ARRAY(req->mc_addrs[i]));
+	}
+
+	hal = WLAN_HDD_GET_HAL_CTX(adapter);
+	status = sme_8023_multicast_list(hal, adapter->sessionId, mc_addr_list);
+	qdf_mem_free(mc_addr_list);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to configure MC address list");
+		exit_code = -EINVAL;
+		goto exit_with_code;
+	}
+
+	exit_code = 0;
+
+exit_with_code:
+	EXIT();
+	return exit_code;
+}
+
+static int iw_clear_mc_filter_list(hdd_adapter_t *adapter)
+{
+	int exit_code;
+	QDF_STATUS status;
+	tHalHandle hal;
+	tSirRcvFltMcAddrList *mc_addr_list;
+
+	ENTER();
+
+	mc_addr_list = qdf_mem_malloc(sizeof(*mc_addr_list));
+	if (!mc_addr_list) {
+		hdd_err("Out of memory");
+		exit_code = -ENOMEM;
+		goto exit_with_code;
+	}
+
+	mc_addr_list->action = HDD_DELETE_MCBC_FILTERS_FROM_FW;
+
+	hal = WLAN_HDD_GET_HAL_CTX(adapter);
+	status = sme_8023_multicast_list(hal, adapter->sessionId, mc_addr_list);
+	qdf_mem_free(mc_addr_list);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to clear MC address list");
+		exit_code = -EINVAL;
+		goto exit_with_code;
+	}
+
+	exit_code = 0;
+
+exit_with_code:
+	EXIT();
+	return exit_code;
+}
+#else
+static inline int iw_set_mc_filter_list(hdd_adapter_t *adapter,
+					struct pkt_filter_mc_addr_list *req)
+{
+	return 0;
+}
+
+static inline int iw_clear_mc_filter_list(hdd_adapter_t *adapter)
+{
+	return 0;
+}
+#endif /* WLAN_FEATURE_PACKET_FILTERING */
+
+static int iw_configure_mcbc_filter(hdd_adapter_t *adapter,
+				    struct pkt_filter_mc_addr_list *req)
+{
+	int exit_code;
+	QDF_STATUS status;
+	hdd_context_t *hdd_ctx;
+	tSirWlanSetRxpFilters *req_params;
+	tHalHandle hal;
+
+	ENTER();
+
+	hdd_info("Configuring mc/bc filter; setting:%u",
+		 req->mcbc_filter_setting);
+
+	req_params = qdf_mem_malloc(sizeof(*req_params));
+	if (!req_params) {
+		hdd_err("Out of memory");
+		exit_code = -ENOMEM;
+		goto exit_with_code;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	hdd_ctx->configuredMcastBcastFilter = req->mcbc_filter_setting;
+	hdd_conf_hostoffload(adapter, true);
+
+	req_params->configuredMcstBcstFilterSetting = req->mcbc_filter_setting;
+	req_params->setMcstBcstFilter = true;
+
+	hal = WLAN_HDD_GET_HAL_CTX(adapter);
+	status = sme_configure_rxp_filter(hal, req_params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to configure HW MC/BC filter");
+		qdf_mem_free(req_params);
+		return -EINVAL;
+	}
+
+	if (hdd_ctx->sus_res_mcastbcast_filter_valid)
+		hdd_ctx->sus_res_mcastbcast_filter = req->mcbc_filter_setting;
+
+	exit_code = 0;
+
+exit_with_code:
+	EXIT();
+	return exit_code;
+}
+
+/**
+ * __iw_set_dynamic_mcbc_filter() - Set Dynamic MCBC Filter ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
+static int __iw_set_dynamic_mcbc_filter(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu,
+					char *extra)
+{
+	int exit_code;
+	hdd_adapter_t *adapter;
+	struct pkt_filter_mc_addr_list *req;
+
+	ENTER();
+
+	req = (struct pkt_filter_mc_addr_list *)extra;
+	if (req->mcbc_filter_setting > HDD_MULTICAST_FILTER_LIST_CLEAR) {
+		hdd_err("Invalid filter setting: %u", req->mcbc_filter_setting);
+		exit_code = -EINVAL;
+		goto exit_with_code;
+	}
+
+	adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+	if (req->mcbc_filter_setting == HDD_MULTICAST_FILTER_LIST) {
+		exit_code = iw_set_mc_filter_list(adapter, req);
+		goto exit_with_code;
+	}
+
+	if (req->mcbc_filter_setting == HDD_MULTICAST_FILTER_LIST_CLEAR) {
+		exit_code = iw_clear_mc_filter_list(adapter);
+		goto exit_with_code;
+	}
+
+	exit_code = iw_configure_mcbc_filter(adapter, req);
+
+exit_with_code:
+	EXIT();
+	return exit_code;
+}
+
+/**
+ * iw_set_dynamic_mcbc_filter() - Set Dynamic MCBC Filter ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
+static int iw_set_dynamic_mcbc_filter(struct net_device *dev,
+				      struct iw_request_info *info,
+				      union iwreq_data *wrqu,
+				      char *extra)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __iw_set_dynamic_mcbc_filter(dev, info, wrqu, extra);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
+/**
+ * __iw_clear_dynamic_mcbc_filter() - Clear Dynamic MCBC Filter ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
+static int __iw_clear_dynamic_mcbc_filter(struct net_device *dev,
+					  struct iw_request_info *info,
+					  union iwreq_data *wrqu,
+					  char *extra)
+{
+	int exit_code;
+	QDF_STATUS status;
+	hdd_adapter_t *adapter;
+	hdd_context_t *hdd_ctx;
+	tHalHandle hal;
+	tSirWlanSetRxpFilters *set_params;
+	uint8_t ini_filter_setting;
+
+	ENTER();
+
+	if (!capable(CAP_NET_ADMIN)) {
+		hdd_err("Net Admin permissions required");
+		exit_code = -EPERM;
+		goto exit_with_code;
+	}
+
+	set_params = qdf_mem_malloc(sizeof(*set_params));
+	if (!set_params) {
+		hdd_err("Out of memory");
+		exit_code = -ENOMEM;
+		goto exit_with_code;
+	}
+
+	/* clear basically means: reset to ini filter settings */
+	adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ini_filter_setting = hdd_ctx->config->mcastBcastFilterSetting;
+
+	hdd_ctx->configuredMcastBcastFilter = ini_filter_setting;
+	hdd_conf_hostoffload(adapter, true);
+
+	set_params->configuredMcstBcstFilterSetting = ini_filter_setting;
+	set_params->setMcstBcstFilter = true;
+
+	hal = WLAN_HDD_GET_HAL_CTX(adapter);
+	status = sme_configure_rxp_filter(hal, set_params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to clear HW mc/bc filter");
+		qdf_mem_free(set_params);
+		exit_code = -EINVAL;
+		goto exit_with_code;
+	}
+
+	if (hdd_ctx->sus_res_mcastbcast_filter_valid)
+		hdd_ctx->sus_res_mcastbcast_filter = ini_filter_setting;
+
+	exit_code = 0;
+
+exit_with_code:
+	EXIT();
+	return exit_code;
+}
+
+/**
+ * iw_clear_dynamic_mcbc_filter() - Clear Dynamic MCBC Filter ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
+static int iw_clear_dynamic_mcbc_filter(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu,
+					char *extra)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __iw_clear_dynamic_mcbc_filter(dev, info, wrqu, extra);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
 /**
  * iw_set_host_offload - Set host offload ioctl handler
  * @dev: device upon which the ioctl was received
@@ -10576,6 +10877,10 @@ static const iw_handler we_private[] = {
 	[WLAN_SET_PNO - SIOCIWFIRSTPRIV] = iw_set_pno,
 #endif
 	[WLAN_SET_BAND_CONFIG - SIOCIWFIRSTPRIV] = iw_set_band_config,
+	[WLAN_PRIV_SET_MCBC_FILTER - SIOCIWFIRSTPRIV] =
+		iw_set_dynamic_mcbc_filter,
+	[WLAN_PRIV_CLEAR_MCBC_FILTER - SIOCIWFIRSTPRIV] =
+		iw_clear_dynamic_mcbc_filter,
 	[WLAN_GET_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_linkspeed,
 	[WLAN_PRIV_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] =
 		iw_set_two_ints_getnone,
@@ -11632,6 +11937,21 @@ static const struct iw_priv_args we_private_args[] = {
 		"SETBAND"
 	}
 	,
+	{
+		WLAN_PRIV_SET_MCBC_FILTER,
+		IW_PRIV_TYPE_BYTE | sizeof(struct pkt_filter_mc_addr_list),
+		0,
+		"setMCBCFilter"
+	}
+	,
+	{
+		WLAN_PRIV_CLEAR_MCBC_FILTER,
+		0,
+		0,
+		"clearMCBCFilter"
+	}
+	,
+
 	{
 		WLAN_GET_LINK_SPEED,
 		IW_PRIV_TYPE_CHAR | 18,