Skip to content

Commit

Permalink
mac80211: Track Beacon signal strength and implement cqm events
Browse files Browse the repository at this point in the history
Calculate a running average of the signal strength reported for Beacon
frames and indicate cqm events if the average value moves below or
above the configured threshold value (and filter out repetitive events
with by using the configured hysteresis).

Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Jouni Malinen authored and John W. Linville committed Mar 31, 2010
1 parent 32fbcca commit 17e4ec1
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 3 deletions.
9 changes: 6 additions & 3 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1415,16 +1415,19 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
struct ieee80211_vif *vif = &sdata->vif;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;

if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI))
return -EOPNOTSUPP;

if (rssi_thold == bss_conf->cqm_rssi_thold &&
rssi_hyst == bss_conf->cqm_rssi_hyst)
return 0;

bss_conf->cqm_rssi_thold = rssi_thold;
bss_conf->cqm_rssi_hyst = rssi_hyst;

if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
return 0;
}

/* tell the driver upon association, unless already associated */
if (sdata->u.mgd.associated)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
Expand Down
12 changes: 12 additions & 0 deletions net/mac80211/debugfs_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ static ssize_t ieee80211_if_fmt_##name( \
return scnprintf(buf, buflen, "%pM\n", sdata->field); \
}

#define IEEE80211_IF_FMT_DEC_DIV_16(name, field) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, \
char *buf, int buflen) \
{ \
return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
}

#define __IEEE80211_IF_FILE(name, _write) \
static ssize_t ieee80211_if_read_##name(struct file *file, \
char __user *userbuf, \
Expand Down Expand Up @@ -135,6 +143,8 @@ IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
/* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);

static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
Expand Down Expand Up @@ -271,6 +281,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)

DEBUGFS_ADD(bssid);
DEBUGFS_ADD(aid);
DEBUGFS_ADD(last_beacon);
DEBUGFS_ADD(ave_beacon);
DEBUGFS_ADD_MODE(smps, 0600);
}

Expand Down
19 changes: 19 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ enum ieee80211_sta_flags {
IEEE80211_STA_MFP_ENABLED = BIT(6),
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
};

struct ieee80211_if_managed {
Expand Down Expand Up @@ -359,6 +360,24 @@ struct ieee80211_if_managed {
int wmm_last_param_set;

u8 use_4addr;

/* Signal strength from the last Beacon frame in the current BSS. */
int last_beacon_signal;

/*
* Weighted average of the signal strength from Beacon frames in the
* current BSS. This is in units of 1/16 of the signal unit to maintain
* accuracy and to speed up calculations, i.e., the value need to be
* divided by 16 to get the actual value.
*/
int ave_beacon_signal;

/*
* Last Beacon frame signal strength average (ave_beacon_signal / 16)
* that triggered a cqm event. 0 indicates that no event has been
* generated for the current association.
*/
int last_cqm_event_signal;
};

enum ieee80211_ibss_request {
Expand Down
45 changes: 45 additions & 0 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
*/
#define IEEE80211_PROBE_WAIT (HZ / 2)

/*
* Weight given to the latest Beacon frame when calculating average signal
* strength for Beacon frames received in the current BSS. This must be
* between 1 and 15.
*/
#define IEEE80211_SIGNAL_AVE_WEIGHT 3

#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1

Expand Down Expand Up @@ -732,6 +739,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.associated = cbss;
memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);

sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;

/* just to be sure */
sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
Expand Down Expand Up @@ -1347,6 +1356,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
size_t baselen;
struct ieee802_11_elems elems;
struct ieee80211_local *local = sdata->local;
Expand Down Expand Up @@ -1382,6 +1392,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
return;

/* Track average RSSI from the Beacon frames of the current AP */
ifmgd->last_beacon_signal = rx_status->signal;
if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
ifmgd->ave_beacon_signal = rx_status->signal;
ifmgd->last_cqm_event_signal = 0;
} else {
ifmgd->ave_beacon_signal =
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
(16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
ifmgd->ave_beacon_signal) / 16;
}
if (bss_conf->cqm_rssi_thold &&
!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
int sig = ifmgd->ave_beacon_signal / 16;
int last_event = ifmgd->last_cqm_event_signal;
int thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst;
if (sig < thold &&
(last_event == 0 || sig < last_event - hyst)) {
ifmgd->last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
GFP_KERNEL);
} else if (sig > thold &&
(last_event == 0 || sig > last_event + hyst)) {
ifmgd->last_cqm_event_signal = sig;
ieee80211_cqm_rssi_notify(
&sdata->vif,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
GFP_KERNEL);
}
}

if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
Expand Down

0 comments on commit 17e4ec1

Please sign in to comment.