aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-03-30 02:28:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-03-31 14:46:42 -0400
commit17e4ec147f4939ca8c81b41b4261ec7974531381 (patch)
tree8066952a1dbef6656ac1f6d6a869326576b5006e /net/mac80211
parent32fbccafed7e935432b601f0453c2b702a385a25 (diff)
mac80211: Track Beacon signal strength and implement cqm events
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>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c9
-rw-r--r--net/mac80211/debugfs_netdev.c12
-rw-r--r--net/mac80211/ieee80211_i.h19
-rw-r--r--net/mac80211/mlme.c45
4 files changed, 82 insertions, 3 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a4ca425e4f3f..4edd73cbf052 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1415,9 +1415,6 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
1415 struct ieee80211_vif *vif = &sdata->vif; 1415 struct ieee80211_vif *vif = &sdata->vif;
1416 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 1416 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
1417 1417
1418 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI))
1419 return -EOPNOTSUPP;
1420
1421 if (rssi_thold == bss_conf->cqm_rssi_thold && 1418 if (rssi_thold == bss_conf->cqm_rssi_thold &&
1422 rssi_hyst == bss_conf->cqm_rssi_hyst) 1419 rssi_hyst == bss_conf->cqm_rssi_hyst)
1423 return 0; 1420 return 0;
@@ -1425,6 +1422,12 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
1425 bss_conf->cqm_rssi_thold = rssi_thold; 1422 bss_conf->cqm_rssi_thold = rssi_thold;
1426 bss_conf->cqm_rssi_hyst = rssi_hyst; 1423 bss_conf->cqm_rssi_hyst = rssi_hyst;
1427 1424
1425 if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
1426 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1427 return -EOPNOTSUPP;
1428 return 0;
1429 }
1430
1428 /* tell the driver upon association, unless already associated */ 1431 /* tell the driver upon association, unless already associated */
1429 if (sdata->u.mgd.associated) 1432 if (sdata->u.mgd.associated)
1430 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); 1433 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9affe2cd185f..ee61a9f6fabc 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -95,6 +95,14 @@ static ssize_t ieee80211_if_fmt_##name( \
95 return scnprintf(buf, buflen, "%pM\n", sdata->field); \ 95 return scnprintf(buf, buflen, "%pM\n", sdata->field); \
96} 96}
97 97
98#define IEEE80211_IF_FMT_DEC_DIV_16(name, field) \
99static ssize_t ieee80211_if_fmt_##name( \
100 const struct ieee80211_sub_if_data *sdata, \
101 char *buf, int buflen) \
102{ \
103 return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
104}
105
98#define __IEEE80211_IF_FILE(name, _write) \ 106#define __IEEE80211_IF_FILE(name, _write) \
99static ssize_t ieee80211_if_read_##name(struct file *file, \ 107static ssize_t ieee80211_if_read_##name(struct file *file, \
100 char __user *userbuf, \ 108 char __user *userbuf, \
@@ -135,6 +143,8 @@ IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
135/* STA attributes */ 143/* STA attributes */
136IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); 144IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
137IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); 145IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
146IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
147IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
138 148
139static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, 149static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
140 enum ieee80211_smps_mode smps_mode) 150 enum ieee80211_smps_mode smps_mode)
@@ -271,6 +281,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
271 281
272 DEBUGFS_ADD(bssid); 282 DEBUGFS_ADD(bssid);
273 DEBUGFS_ADD(aid); 283 DEBUGFS_ADD(aid);
284 DEBUGFS_ADD(last_beacon);
285 DEBUGFS_ADD(ave_beacon);
274 DEBUGFS_ADD_MODE(smps, 0600); 286 DEBUGFS_ADD_MODE(smps, 0600);
275} 287}
276 288
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ab369e2a5282..741fb8bbc4a0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -317,6 +317,7 @@ enum ieee80211_sta_flags {
317 IEEE80211_STA_MFP_ENABLED = BIT(6), 317 IEEE80211_STA_MFP_ENABLED = BIT(6),
318 IEEE80211_STA_UAPSD_ENABLED = BIT(7), 318 IEEE80211_STA_UAPSD_ENABLED = BIT(7),
319 IEEE80211_STA_NULLFUNC_ACKED = BIT(8), 319 IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
320 IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9),
320}; 321};
321 322
322struct ieee80211_if_managed { 323struct ieee80211_if_managed {
@@ -359,6 +360,24 @@ struct ieee80211_if_managed {
359 int wmm_last_param_set; 360 int wmm_last_param_set;
360 361
361 u8 use_4addr; 362 u8 use_4addr;
363
364 /* Signal strength from the last Beacon frame in the current BSS. */
365 int last_beacon_signal;
366
367 /*
368 * Weighted average of the signal strength from Beacon frames in the
369 * current BSS. This is in units of 1/16 of the signal unit to maintain
370 * accuracy and to speed up calculations, i.e., the value need to be
371 * divided by 16 to get the actual value.
372 */
373 int ave_beacon_signal;
374
375 /*
376 * Last Beacon frame signal strength average (ave_beacon_signal / 16)
377 * that triggered a cqm event. 0 indicates that no event has been
378 * generated for the current association.
379 */
380 int last_cqm_event_signal;
362}; 381};
363 382
364enum ieee80211_ibss_request { 383enum ieee80211_ibss_request {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c686d1b90f9f..de7519eb2b5d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -46,6 +46,13 @@
46 */ 46 */
47#define IEEE80211_PROBE_WAIT (HZ / 2) 47#define IEEE80211_PROBE_WAIT (HZ / 2)
48 48
49/*
50 * Weight given to the latest Beacon frame when calculating average signal
51 * strength for Beacon frames received in the current BSS. This must be
52 * between 1 and 15.
53 */
54#define IEEE80211_SIGNAL_AVE_WEIGHT 3
55
49#define TMR_RUNNING_TIMER 0 56#define TMR_RUNNING_TIMER 0
50#define TMR_RUNNING_CHANSW 1 57#define TMR_RUNNING_CHANSW 1
51 58
@@ -732,6 +739,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
732 sdata->u.mgd.associated = cbss; 739 sdata->u.mgd.associated = cbss;
733 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); 740 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
734 741
742 sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
743
735 /* just to be sure */ 744 /* just to be sure */
736 sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | 745 sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
737 IEEE80211_STA_BEACON_POLL); 746 IEEE80211_STA_BEACON_POLL);
@@ -1347,6 +1356,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1347 struct ieee80211_rx_status *rx_status) 1356 struct ieee80211_rx_status *rx_status)
1348{ 1357{
1349 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1358 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1359 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
1350 size_t baselen; 1360 size_t baselen;
1351 struct ieee802_11_elems elems; 1361 struct ieee802_11_elems elems;
1352 struct ieee80211_local *local = sdata->local; 1362 struct ieee80211_local *local = sdata->local;
@@ -1382,6 +1392,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1382 if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) 1392 if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
1383 return; 1393 return;
1384 1394
1395 /* Track average RSSI from the Beacon frames of the current AP */
1396 ifmgd->last_beacon_signal = rx_status->signal;
1397 if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
1398 ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
1399 ifmgd->ave_beacon_signal = rx_status->signal;
1400 ifmgd->last_cqm_event_signal = 0;
1401 } else {
1402 ifmgd->ave_beacon_signal =
1403 (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
1404 (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
1405 ifmgd->ave_beacon_signal) / 16;
1406 }
1407 if (bss_conf->cqm_rssi_thold &&
1408 !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
1409 int sig = ifmgd->ave_beacon_signal / 16;
1410 int last_event = ifmgd->last_cqm_event_signal;
1411 int thold = bss_conf->cqm_rssi_thold;
1412 int hyst = bss_conf->cqm_rssi_hyst;
1413 if (sig < thold &&
1414 (last_event == 0 || sig < last_event - hyst)) {
1415 ifmgd->last_cqm_event_signal = sig;
1416 ieee80211_cqm_rssi_notify(
1417 &sdata->vif,
1418 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
1419 GFP_KERNEL);
1420 } else if (sig > thold &&
1421 (last_event == 0 || sig > last_event + hyst)) {
1422 ifmgd->last_cqm_event_signal = sig;
1423 ieee80211_cqm_rssi_notify(
1424 &sdata->vif,
1425 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
1426 GFP_KERNEL);
1427 }
1428 }
1429
1385 if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { 1430 if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
1386#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 1431#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
1387 if (net_ratelimit()) { 1432 if (net_ratelimit()) {