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;