summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/hdd/inc/wlan_hdd_power.h15
-rw-r--r--core/hdd/src/wlan_hdd_wext.c324
2 files changed, 336 insertions, 3 deletions
diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h
index 749559551336..815a9f90c28c 100644
--- a/core/hdd/inc/wlan_hdd_power.h
+++ b/core/hdd/inc/wlan_hdd_power.h
@@ -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
@@ -127,6 +128,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.
* @HDD_WLAN_SUSPEND: Suspend state.
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index c362daa7df08..1184fa10d9a7 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -970,8 +970,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)
@@ -9238,6 +9238,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
@@ -10519,6 +10820,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,
@@ -11569,6 +11874,21 @@ static const struct iw_priv_args we_private_args[] = {
}
,
{
+ 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,
IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed"