diff --git a/core/hdd/inc/hdd_config.h b/core/hdd/inc/hdd_config.h index c399d689703f..9c9fb5a2915f 100644 --- a/core/hdd/inc/hdd_config.h +++ b/core/hdd/inc/hdd_config.h @@ -1395,6 +1395,31 @@ struct dhcp_server { CFG_VALUE_OR_DEFAULT, \ "Disable wow feature") +/* + * + * nb_commands_interval - Used to rate limit nb commands from userspace + * + * @Min: 0 + * @Max: 10 + * Default: 3 + * + * This ini is used to specify the duration in which any supp. nb command from + * userspace will not be processed completely in driver. For ex, the default + * value of 3 seconds signifies that consecutive commands within that + * time will not be processed fully. + * + * Usage: Internal + * + * + */ +#define CFG_NB_COMMANDS_RATE_LIMIT CFG_INI_UINT( \ + "nb_commands_interval", \ + 0, \ + 10, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Rate limiting for nb commands") + #ifdef WLAN_FEATURE_PERIODIC_STA_STATS /* * @@ -1606,6 +1631,7 @@ enum host_log_level { CFG(CFG_PRIVATE_WEXT_CONTROL) \ CFG(CFG_PROVISION_INTERFACE_POOL) \ CFG(CFG_TIMER_MULTIPLIER) \ + CFG(CFG_NB_COMMANDS_RATE_LIMIT) \ CFG(CFG_HDD_DOT11_MODE) \ CFG(CFG_ENABLE_DISABLE_CHANNEL) \ CFG(CFG_SAR_CONVERSION) \ diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index e66ea6dfbcb5..64327536efb9 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -253,6 +253,7 @@ struct hdd_config { /* Duration for which periodic logging should be done */ uint32_t periodic_stats_timer_duration; #endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ + uint8_t nb_commands_interval; }; /** diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 1b55f399a74d..6f2248f623bd 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -156,6 +156,29 @@ struct hdd_apf_context { #define NUM_TX_QUEUES 4 #endif +/* HDD_IS_RATE_LIMIT_REQ: Macro helper to implement rate limiting + * @flag: The flag to determine if limiting is required or not + * @rate: The number of seconds within which if multiple commands come, the + * flag will be set to true + * + * If the function in which this macro is used is called multiple times within + * "rate" number of seconds, the "flag" will be set to true which can be used + * to reject/take appropriate action. + */ +#define HDD_IS_RATE_LIMIT_REQ(flag, rate)\ + do {\ + static ulong __last_ticks;\ + ulong __ticks = jiffies;\ + flag = false; \ + if (!time_after(__ticks,\ + __last_ticks + rate * HZ)) {\ + flag = true; \ + } \ + else { \ + __last_ticks = __ticks;\ + } \ + } while (0) + /* * API in_compat_syscall() is introduced in 4.6 kernel to check whether we're * in a compat syscall or not. It is a new way to query the syscall type, which diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index f4ed4224a2ce..08e48cfaeca2 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -11315,6 +11315,8 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx) config->disable_channel = cfg_get(psoc, CFG_ENABLE_DISABLE_CHANNEL); config->enable_sar_conversion = cfg_get(psoc, CFG_SAR_CONVERSION); config->is_wow_disabled = cfg_get(psoc, CFG_WOW_DISABLE); + config->nb_commands_interval = + cfg_get(psoc, CFG_NB_COMMANDS_RATE_LIMIT); hdd_periodic_sta_stats_config(config, psoc); hdd_init_vc_mode_cfg_bitmap(config, psoc); diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 2065adc0c92d..3359ac32ff46 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -2441,6 +2441,7 @@ static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); int status; struct hdd_station_ctx *sta_ctx; + static bool is_rate_limited; hdd_enter_dev(ndev); @@ -2485,8 +2486,11 @@ static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, return 0; } - if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { - hdd_debug("Driver Module not enabled return success"); + HDD_IS_RATE_LIMIT_REQ(is_rate_limited, + hdd_ctx->config->nb_commands_interval); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED || + is_rate_limited) { + hdd_debug("Modules not enabled/rate limited, use cached stats"); /* Send cached data to upperlayer*/ *dbm = adapter->hdd_stats.class_a_stat.max_pwr; return 0;