From 3def8945b0d4a9f5d3b117c760549efa1021de7f Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Thu, 5 Oct 2017 16:19:36 +0530 Subject: [PATCH] qcacld-3.0: Configure and clear default packet filters over suspend and resume In suspend mode multicast, broadcast packets wakes up host, this leads to higher power consumption. Add support to configure the IPv6/IPv4 multicast, IPv4 broadcast, XID, STP, DTP/LLC/CDP packet filters based on ini bit map param, before the device goes to suspend mode and clear the same filters in resume. CRs-Fixed: 2011442 Change-Id: Ib355459132086902ba008f2abd17415a8f569b41 --- core/hdd/inc/wlan_hdd_cfg.h | 39 +++++ core/hdd/inc/wlan_hdd_main.h | 1 + core/hdd/inc/wlan_hdd_packet_filter_api.h | 58 +++++++ core/hdd/inc/wlan_hdd_packet_filter_rules.h | 180 ++++++++++++++++++++ core/hdd/src/wlan_hdd_cfg.c | 8 +- core/hdd/src/wlan_hdd_packet_filter.c | 100 +++++++++++ core/hdd/src/wlan_hdd_power.c | 7 + core/hdd/src/wlan_hdd_wext.c | 10 +- 8 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 core/hdd/inc/wlan_hdd_packet_filter_api.h create mode 100644 core/hdd/inc/wlan_hdd_packet_filter_rules.h create mode 100644 core/hdd/src/wlan_hdd_packet_filter.c diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 30e38f6aaa96..796fbf254cbc 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -13105,6 +13105,44 @@ enum hdd_external_acs_freq_band { #define CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MAX (0) +/* + * + * g_enable_packet_filter_bitmap - Enable Packet filters before going into + * suspend mode + * @Min: 0 + * @Max: 63 + * @Default: 0 + * Below is the Detailed bit map of the Filters + * bit-0 : IPv6 multicast + * bit-1 : IPv4 multicast + * bit-2 : IPv4 broadcast + * bit-3 : XID - Exchange station Identification packet, solicits the + * identification of the receiving station + * bit-4 : STP - Spanning Tree Protocol, builds logical loop free topology + * bit-5 : DTP/LLC/CDP + * DTP - Dynamic Trunking Protocol is used by Ciscoswitches to negotiate + * whether an interconnection between two switches should be put into access or + * trunk mode + * LLC - Logical link control, used for multiplexing, flow & error control + * CDP - Cisco Discovery Protocol packet contains information about the cisco + * devices in the network + * + * This ini support to enable above mentioned packet filters + * when target goes to suspend mode, clear those when resume + * + * Related: None + * + * Supported Feature: PACKET FILTERING + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_PACKET_FILTERS_NAME "g_enable_packet_filter_bitmap" +#define CFG_ENABLE_PACKET_FILTERS_DEFAULT (0) +#define CFG_ENABLE_PACKET_FILTERS_MIN (0) +#define CFG_ENABLE_PACKET_FILTERS_MAX (63) + /* * Type declarations */ @@ -13961,6 +13999,7 @@ struct hdd_config { int8_t mbo_current_rssi_thres; int8_t mbo_current_rssi_mcc_thres; int8_t mbo_candidate_rssi_btc_thres; + uint8_t packet_filters_bitmap; }; #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 65950c9ca6b3..d1291489e49a 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1781,6 +1781,7 @@ struct hdd_context { eCsrBand curr_band; bool fw_mem_dump_enabled; bool imps_enabled; + int user_configured_pkt_filter_rules; }; /** diff --git a/core/hdd/inc/wlan_hdd_packet_filter_api.h b/core/hdd/inc/wlan_hdd_packet_filter_api.h new file mode 100644 index 000000000000..67c2c8fa8367 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_packet_filter_api.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_API_H__) +#define WLAN_HDD_PACKET_FILTER_API_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ + +/** + * hdd_enable_default_pkt_filters() - Enable default packet filters based + * on, filters bit map provided in INI, when target goes to suspend mode + * @adapter: Adapter context for which default filters to be configure + * + * Return: zero if success, non-zero otherwise + */ +int hdd_enable_default_pkt_filters(struct hdd_adapter *pAadapter); + +/** + * hdd_disable_default_pkt_filters() - Disable default packet filters based + * on, filters bit map provided in INI, when target resumes + * @adapter: Adapter context for which default filters to be cleared + * + * Return: zero if success, non-zero otherwise + */ +int hdd_disable_default_pkt_filters(struct hdd_adapter *adapter); + +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @sessionId: Target session for the request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_set_filter(struct hdd_context *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t sessionId); +#endif diff --git a/core/hdd/inc/wlan_hdd_packet_filter_rules.h b/core/hdd/inc/wlan_hdd_packet_filter_rules.h new file mode 100644 index 000000000000..64739aeeeef5 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_packet_filter_rules.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_RULES_H__) +#define WLAN_HDD_PACKET_FILTER_RULES_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ + +#define MAX_NUM_PACKET_FILTERS 6 + +/** + * @filter_action: Filter action, set/clear the filter + * Ex: filter_action = 1 set the filter + * filter_action = 2 clear the filter + * @filter_id: Filter id Ex: 1/2/3/4/5 .... MAX_NUM_FILTERS + * @num_params: Number of parameters Ex: 1/2/3/4/5 + * @params_data: Packet filter parameters details + * + * @protocol_layer: the type of protocol layer header to which the data + * being configured correspond + * Ex: protocol_layer = 1 - MAC Header + * protocol_layer = 2 - ARP Header + * protocol_layer = 3 - IP Header + * @compare_flag: comparison type + * EX: compare_flag = 0 - comparison is invalid + * compare_flag = 1 - compare for equality of the data present in received + * packet to the corresponding configured data + * compare_flag = 2 - compare for equality of the data present in received + * packet to the corresponding configured data after + * applying the mask + * compare_flag = 3 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * compare_flag = 4 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * after applying the mask + * @data_fffset: Offset of the data to compare from the respective protocol + * layer header start (as per the respective protocol + * specification) in terms of bytes + * @data_length: length of data to compare + * @compare_data: Array of 8 bytes + * @data_mask: Mask to be applied on the received packet data (Array of 8 bytes) + */ +static const struct pkt_filter_cfg + packet_filter_default_rules[MAX_NUM_PACKET_FILTERS] = { + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {134, 221, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 24, + .data_length = 2, + .compare_data = {255, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {255, 0, 0, 0, 0, 0, 0, 0} } } }, + + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 16, + .data_length = 1, + .compare_data = {224, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {240, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 18, + .data_length = 2, + .compare_data = {0, 255, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 255, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 8, + .data_length = 4, + .compare_data = {0, 1, 175, 129, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {0, 39, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 4, + .data_length = 2, + .compare_data = {0, 12, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } } }; +#endif diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index fd6f2a0ce77c..95a71981dfe6 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -5156,13 +5156,19 @@ struct reg_table_entry g_registry_table[] = { CFG_MBO_CAND_RSSI_BTC_THRESHOLD_DEFAULT, CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MIN, CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MAX), - REG_VARIABLE(CFG_IS_FILS_ENABLED_NAME, WLAN_PARAM_Integer, struct hdd_config, is_fils_enabled, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, CFG_IS_FILS_ENABLED_DEFAULT, CFG_IS_FILS_ENABLED_MIN, CFG_IS_FILS_ENABLED_MAX), + + REG_VARIABLE(CFG_ENABLE_PACKET_FILTERS_NAME, WLAN_PARAM_Integer, + struct hdd_config, packet_filters_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_MIN, + CFG_ENABLE_PACKET_FILTERS_MAX), }; diff --git a/core/hdd/src/wlan_hdd_packet_filter.c b/core/hdd/src/wlan_hdd_packet_filter.c new file mode 100644 index 000000000000..525a45591b58 --- /dev/null +++ b/core/hdd/src/wlan_hdd_packet_filter.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_packet_filter.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include "wlan_hdd_packet_filter_api.h" + +int hdd_enable_default_pkt_filters(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + uint8_t filters = 0, i = 0, filter_id = 1; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + if (!hdd_ctx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = hdd_ctx->config->packet_filters_bitmap; + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("setting filter[%d], of id = %d", + i+1, filter_id); + packet_filter_default_rules[i].filter_id = filter_id; + wlan_hdd_set_filter(hdd_ctx, + &packet_filter_default_rules[i], + adapter->sessionId); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} + +int hdd_disable_default_pkt_filters(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + uint8_t filters = 0, i = 0, filter_id = 1; + + struct pkt_filter_cfg packet_filter_default_rules; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + + if (!hdd_ctx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = hdd_ctx->config->packet_filters_bitmap; + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("Clearing filter[%d], of id = %d", + i+1, filter_id); + packet_filter_default_rules.filter_action = + HDD_RCV_FILTER_CLEAR; + packet_filter_default_rules.filter_id = i; + wlan_hdd_set_filter(hdd_ctx, + &packet_filter_default_rules, + adapter->sessionId); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 6366faa2ce0e..0a3c8ed0d8cf 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -81,6 +81,7 @@ #include #include "scheduler_api.h" #include "cds_utils.h" +#include "wlan_hdd_packet_filter_api.h" /* Preprocessor definitions and constants */ #ifdef QCA_WIFI_NAPIER_EMULATION @@ -1098,6 +1099,9 @@ hdd_suspend_wlan(void) WLAN_STOP_ALL_NETIF_QUEUE, WLAN_CONTROL_PATH); + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_enable_default_pkt_filters(adapter); + /* Configure supported OffLoads */ hdd_enable_host_offloads(adapter, pmo_apps_suspend); hdd_update_conn_state_mask(adapter, &conn_state_mask); @@ -1164,6 +1168,9 @@ static int hdd_resume_wlan(void) WLAN_WAKE_ALL_NETIF_QUEUE, WLAN_CONTROL_PATH); + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_disable_default_pkt_filters(adapter); + next_adapter: status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, &pNext); pAdapterNode = pNext; diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index bf4cdbc0c796..726b2cca9cd5 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -103,6 +103,7 @@ #include #include "wlan_hdd_regulatory.h" #include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_packet_filter_api.h" #define HDD_FINISH_ULA_TIME_OUT 800 #define HDD_SET_MCBC_FILTERS_TO_FW 1 @@ -12049,7 +12050,7 @@ static int iw_set_keepalive_params(struct net_device *dev, * * Return: 0 on success, non-zero on error */ -static int wlan_hdd_set_filter(struct hdd_context *hdd_ctx, +int wlan_hdd_set_filter(struct hdd_context *hdd_ctx, struct pkt_filter_cfg *request, uint8_t sessionId) { @@ -12274,6 +12275,13 @@ static int __iw_set_packet_filter_params(struct net_device *dev, return -ENOMEM; } + if (request->filter_action == HDD_RCV_FILTER_SET) + hdd_ctx->user_configured_pkt_filter_rules |= + 1 << request->filter_id; + else if (request->filter_action == HDD_RCV_FILTER_CLEAR) + hdd_ctx->user_configured_pkt_filter_rules &= + ~(1 << request->filter_id); + ret = wlan_hdd_set_filter(hdd_ctx, request, adapter->sessionId); qdf_mem_free(request);