diff options
-rw-r--r-- | include/net/mac80211.h | 20 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 8 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 46 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 23 | ||||
-rw-r--r-- | net/mac80211/util.c | 40 |
6 files changed, 145 insertions, 0 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b29456a945c2..8ff3d8a1377c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -194,6 +194,17 @@ enum ieee80211_bss_change { | |||
194 | #define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4 | 194 | #define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4 |
195 | 195 | ||
196 | /** | 196 | /** |
197 | * enum ieee80211_rssi_event - RSSI threshold event | ||
198 | * An indicator for when RSSI goes below/above a certain threshold. | ||
199 | * @RSSI_EVENT_HIGH: AP's rssi crossed the high threshold set by the driver. | ||
200 | * @RSSI_EVENT_LOW: AP's rssi crossed the low threshold set by the driver. | ||
201 | */ | ||
202 | enum ieee80211_rssi_event { | ||
203 | RSSI_EVENT_HIGH, | ||
204 | RSSI_EVENT_LOW, | ||
205 | }; | ||
206 | |||
207 | /** | ||
197 | * struct ieee80211_bss_conf - holds the BSS's changing parameters | 208 | * struct ieee80211_bss_conf - holds the BSS's changing parameters |
198 | * | 209 | * |
199 | * This structure keeps information about a BSS (and an association | 210 | * This structure keeps information about a BSS (and an association |
@@ -1867,6 +1878,8 @@ enum ieee80211_ampdu_mlme_action { | |||
1867 | * @set_bitrate_mask: Set a mask of rates to be used for rate control selection | 1878 | * @set_bitrate_mask: Set a mask of rates to be used for rate control selection |
1868 | * when transmitting a frame. Currently only legacy rates are handled. | 1879 | * when transmitting a frame. Currently only legacy rates are handled. |
1869 | * The callback can sleep. | 1880 | * The callback can sleep. |
1881 | * @rssi_callback: Notify driver when the average RSSI goes above/below | ||
1882 | * thresholds that were registered previously. The callback can sleep. | ||
1870 | */ | 1883 | */ |
1871 | struct ieee80211_ops { | 1884 | struct ieee80211_ops { |
1872 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 1885 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -1975,6 +1988,8 @@ struct ieee80211_ops { | |||
1975 | bool (*tx_frames_pending)(struct ieee80211_hw *hw); | 1988 | bool (*tx_frames_pending)(struct ieee80211_hw *hw); |
1976 | int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1989 | int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
1977 | const struct cfg80211_bitrate_mask *mask); | 1990 | const struct cfg80211_bitrate_mask *mask); |
1991 | void (*rssi_callback)(struct ieee80211_hw *hw, | ||
1992 | enum ieee80211_rssi_event rssi_event); | ||
1978 | }; | 1993 | }; |
1979 | 1994 | ||
1980 | /** | 1995 | /** |
@@ -3316,4 +3331,9 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) | |||
3316 | return ieee80211_iftype_p2p(vif->type, vif->p2p); | 3331 | return ieee80211_iftype_p2p(vif->type, vif->p2p); |
3317 | } | 3332 | } |
3318 | 3333 | ||
3334 | void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, | ||
3335 | int rssi_min_thold, | ||
3336 | int rssi_max_thold); | ||
3337 | |||
3338 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); | ||
3319 | #endif /* MAC80211_H */ | 3339 | #endif /* MAC80211_H */ |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index edd2dd79c9be..b2d6bba44054 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -657,4 +657,12 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, | |||
657 | trace_drv_return_void(local); | 657 | trace_drv_return_void(local); |
658 | } | 658 | } |
659 | 659 | ||
660 | static inline void drv_rssi_callback(struct ieee80211_local *local, | ||
661 | const enum ieee80211_rssi_event event) | ||
662 | { | ||
663 | trace_drv_rssi_callback(local, event); | ||
664 | if (local->ops->rssi_callback) | ||
665 | local->ops->rssi_callback(&local->hw, event); | ||
666 | trace_drv_return_void(local); | ||
667 | } | ||
660 | #endif /* __MAC80211_DRIVER_OPS */ | 668 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 31a9dfa81f65..4470f6e8b845 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -1052,6 +1052,28 @@ TRACE_EVENT(drv_set_rekey_data, | |||
1052 | LOCAL_PR_ARG, VIF_PR_ARG) | 1052 | LOCAL_PR_ARG, VIF_PR_ARG) |
1053 | ); | 1053 | ); |
1054 | 1054 | ||
1055 | TRACE_EVENT(drv_rssi_callback, | ||
1056 | TP_PROTO(struct ieee80211_local *local, | ||
1057 | enum ieee80211_rssi_event rssi_event), | ||
1058 | |||
1059 | TP_ARGS(local, rssi_event), | ||
1060 | |||
1061 | TP_STRUCT__entry( | ||
1062 | LOCAL_ENTRY | ||
1063 | __field(u32, rssi_event) | ||
1064 | ), | ||
1065 | |||
1066 | TP_fast_assign( | ||
1067 | LOCAL_ASSIGN; | ||
1068 | __entry->rssi_event = rssi_event; | ||
1069 | ), | ||
1070 | |||
1071 | TP_printk( | ||
1072 | LOCAL_PR_FMT " rssi_event:%d", | ||
1073 | LOCAL_PR_ARG, __entry->rssi_event | ||
1074 | ) | ||
1075 | ); | ||
1076 | |||
1055 | /* | 1077 | /* |
1056 | * Tracing for API calls that drivers call. | 1078 | * Tracing for API calls that drivers call. |
1057 | */ | 1079 | */ |
@@ -1342,6 +1364,30 @@ TRACE_EVENT(api_gtk_rekey_notify, | |||
1342 | TP_printk(VIF_PR_FMT, VIF_PR_ARG) | 1364 | TP_printk(VIF_PR_FMT, VIF_PR_ARG) |
1343 | ); | 1365 | ); |
1344 | 1366 | ||
1367 | TRACE_EVENT(api_enable_rssi_reports, | ||
1368 | TP_PROTO(struct ieee80211_sub_if_data *sdata, | ||
1369 | int rssi_min_thold, int rssi_max_thold), | ||
1370 | |||
1371 | TP_ARGS(sdata, rssi_min_thold, rssi_max_thold), | ||
1372 | |||
1373 | TP_STRUCT__entry( | ||
1374 | VIF_ENTRY | ||
1375 | __field(int, rssi_min_thold) | ||
1376 | __field(int, rssi_max_thold) | ||
1377 | ), | ||
1378 | |||
1379 | TP_fast_assign( | ||
1380 | VIF_ASSIGN; | ||
1381 | __entry->rssi_min_thold = rssi_min_thold; | ||
1382 | __entry->rssi_max_thold = rssi_max_thold; | ||
1383 | ), | ||
1384 | |||
1385 | TP_printk( | ||
1386 | VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d", | ||
1387 | VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold | ||
1388 | ) | ||
1389 | ); | ||
1390 | |||
1345 | /* | 1391 | /* |
1346 | * Tracing for internal functions | 1392 | * Tracing for internal functions |
1347 | * (which may also be called in response to driver calls) | 1393 | * (which may also be called in response to driver calls) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4c7a831e7d1e..96600bec44c5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -432,6 +432,14 @@ struct ieee80211_if_managed { | |||
432 | * generated for the current association. | 432 | * generated for the current association. |
433 | */ | 433 | */ |
434 | int last_cqm_event_signal; | 434 | int last_cqm_event_signal; |
435 | |||
436 | /* | ||
437 | * State variables for keeping track of RSSI of the AP currently | ||
438 | * connected to and informing driver when RSSI has gone | ||
439 | * below/above a certain threshold. | ||
440 | */ | ||
441 | int rssi_min_thold, rssi_max_thold; | ||
442 | int last_ave_beacon_signal; | ||
435 | }; | 443 | }; |
436 | 444 | ||
437 | struct ieee80211_if_ibss { | 445 | struct ieee80211_if_ibss { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b6d9bd5f4d3c..4b0460ad8c8f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1763,6 +1763,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1763 | ifmgd->ave_beacon_signal = rx_status->signal * 16; | 1763 | ifmgd->ave_beacon_signal = rx_status->signal * 16; |
1764 | ifmgd->last_cqm_event_signal = 0; | 1764 | ifmgd->last_cqm_event_signal = 0; |
1765 | ifmgd->count_beacon_signal = 1; | 1765 | ifmgd->count_beacon_signal = 1; |
1766 | ifmgd->last_ave_beacon_signal = 0; | ||
1766 | } else { | 1767 | } else { |
1767 | ifmgd->ave_beacon_signal = | 1768 | ifmgd->ave_beacon_signal = |
1768 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + | 1769 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + |
@@ -1770,6 +1771,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1770 | ifmgd->ave_beacon_signal) / 16; | 1771 | ifmgd->ave_beacon_signal) / 16; |
1771 | ifmgd->count_beacon_signal++; | 1772 | ifmgd->count_beacon_signal++; |
1772 | } | 1773 | } |
1774 | |||
1775 | if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && | ||
1776 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { | ||
1777 | int sig = ifmgd->ave_beacon_signal; | ||
1778 | int last_sig = ifmgd->last_ave_beacon_signal; | ||
1779 | |||
1780 | /* | ||
1781 | * if signal crosses either of the boundaries, invoke callback | ||
1782 | * with appropriate parameters | ||
1783 | */ | ||
1784 | if (sig > ifmgd->rssi_max_thold && | ||
1785 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { | ||
1786 | ifmgd->last_ave_beacon_signal = sig; | ||
1787 | drv_rssi_callback(local, RSSI_EVENT_HIGH); | ||
1788 | } else if (sig < ifmgd->rssi_min_thold && | ||
1789 | (last_sig >= ifmgd->rssi_max_thold || | ||
1790 | last_sig == 0)) { | ||
1791 | ifmgd->last_ave_beacon_signal = sig; | ||
1792 | drv_rssi_callback(local, RSSI_EVENT_LOW); | ||
1793 | } | ||
1794 | } | ||
1795 | |||
1773 | if (bss_conf->cqm_rssi_thold && | 1796 | if (bss_conf->cqm_rssi_thold && |
1774 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && | 1797 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && |
1775 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { | 1798 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 652e5695225a..190132063c99 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1450,3 +1450,43 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | |||
1450 | 1450 | ||
1451 | return pos; | 1451 | return pos; |
1452 | } | 1452 | } |
1453 | |||
1454 | static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata, | ||
1455 | int rssi_min_thold, | ||
1456 | int rssi_max_thold) | ||
1457 | { | ||
1458 | trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold); | ||
1459 | |||
1460 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
1461 | return; | ||
1462 | |||
1463 | /* | ||
1464 | * Scale up threshold values before storing it, as the RSSI averaging | ||
1465 | * algorithm uses a scaled up value as well. Change this scaling | ||
1466 | * factor if the RSSI averaging algorithm changes. | ||
1467 | */ | ||
1468 | sdata->u.mgd.rssi_min_thold = rssi_min_thold*16; | ||
1469 | sdata->u.mgd.rssi_max_thold = rssi_max_thold*16; | ||
1470 | } | ||
1471 | |||
1472 | void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, | ||
1473 | int rssi_min_thold, | ||
1474 | int rssi_max_thold) | ||
1475 | { | ||
1476 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1477 | |||
1478 | WARN_ON(rssi_min_thold == rssi_max_thold || | ||
1479 | rssi_min_thold > rssi_max_thold); | ||
1480 | |||
1481 | _ieee80211_enable_rssi_reports(sdata, rssi_min_thold, | ||
1482 | rssi_max_thold); | ||
1483 | } | ||
1484 | EXPORT_SYMBOL(ieee80211_enable_rssi_reports); | ||
1485 | |||
1486 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) | ||
1487 | { | ||
1488 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1489 | |||
1490 | _ieee80211_enable_rssi_reports(sdata, 0, 0); | ||
1491 | } | ||
1492 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); | ||