@@ -800,6 +800,13 @@ enum mac80211_rate_control_flags {
};
+/*
+ * How many frames need to have been used in average station's
+ * signal strength before checking against the threshold
+ */
+#define IEEE80211_STA_SIGNAL_AVE_MIN_COUNT 4
+
+
/* there are 40 bytes if you don't need the rateset to be kept */
#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
@@ -1536,6 +1536,47 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
return RX_CONTINUE;
}
+static void ieee80211_sta_rx_signal_thold_check(struct ieee80211_rx_data *rx)
+{
+ struct sta_info *sta = rx->sta;
+ struct ieee80211_bss_conf *bss_conf =
+ &rx->sdata->vif.bss_conf;
+ int sig, last_event, thold;
+
+ if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
+ NL80211_EXT_FEATURE_AP_STA_CQM_RSSI_CONFIG))
+ return;
+
+ sta->count_rx_signal++;
+ if (sta->count_rx_signal < IEEE80211_STA_SIGNAL_AVE_MIN_COUNT)
+ return;
+
+ if (!bss_conf->cqm_rssi_thold || !bss_conf->enable_beacon) {
+ sta->count_rx_signal = 0;
+ return;
+ }
+
+ sig = -ewma_signal_read(&sta->rx_stats_avg.signal);
+ last_event = sta->last_cqm_event_signal;
+ thold = bss_conf->cqm_rssi_thold;
+
+ if (sig < thold && last_event == 0) {
+ sta->last_cqm_event_signal = sig;
+ cfg80211_ap_sta_cqm_rssi_notify(
+ rx->sdata->dev, sta->addr,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ sig, GFP_ATOMIC);
+ sta->count_rx_signal = 0;
+ } else if (last_event && sig > thold) {
+ sta->last_cqm_event_signal = 0;
+ cfg80211_ap_sta_cqm_rssi_notify(
+ rx->sdata->dev, sta->addr,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ sig, GFP_ATOMIC);
+ sta->count_rx_signal = 0;
+ }
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
@@ -1591,6 +1632,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->rx_stats.last_signal = status->signal;
ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
+ ieee80211_sta_rx_signal_thold_check(rx);
}
if (status->chains) {
@@ -4000,9 +4042,11 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
stats->last_signal = status->signal;
- if (!fast_rx->uses_rss)
+ if (!fast_rx->uses_rss) {
ewma_signal_add(&sta->rx_stats_avg.signal,
-status->signal);
+ ieee80211_sta_rx_signal_thold_check(rx);
+ }
}
if (status->chains) {
@@ -481,6 +481,12 @@ struct ieee80211_sta_rx_stats {
* @pcpu_rx_stats: per-CPU RX statistics, assigned only if the driver needs
* this (by advertising the USES_RSS hw flag)
* @status_stats: TX status statistics
+ * @last_cqm_event_signal: Last data frame signal strength average that
+ * triggered a cqm event for a connected station. 0 indicates that no
+ * event has been generated for the station.
+ * @count_rx_signal: Number of data frames used in avg signal for a station.
+ * This can be used to avoid generating less reliable cqm events for
+ * the station.
*/
struct sta_info {
/* General information, mostly static */
@@ -581,6 +587,9 @@ struct sta_info {
struct cfg80211_chan_def tdls_chandef;
+ int last_cqm_event_signal;
+ unsigned int count_rx_signal;
+
/* keep last! */
struct ieee80211_sta sta;
};