Commit 04de83815993714a7ba2618f637fa1092a5f664b
Committed by
John W. Linville
1 parent
a08c1c1ac0
Exists in
master
and in
7 other branches
mac80211: add beacon filtering support
Add IEEE80211_HW_BEACON_FILTERING flag so that driver inform that it supports beacon filtering. Drivers need to call the new function ieee80211_beacon_loss() to notify about beacon loss. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 5 changed files with 92 additions and 1 deletions Side-by-side Diff
Documentation/DocBook/mac80211.tmpl
... | ... | @@ -227,6 +227,12 @@ |
227 | 227 | !Pinclude/net/mac80211.h Powersave support |
228 | 228 | </chapter> |
229 | 229 | |
230 | + <chapter id="beacon-filter"> | |
231 | + <title>Beacon filter support</title> | |
232 | +!Pinclude/net/mac80211.h Beacon filter support | |
233 | +!Finclude/net/mac80211.h ieee80211_beacon_loss | |
234 | + </chapter> | |
235 | + | |
230 | 236 | <chapter id="qos"> |
231 | 237 | <title>Multiple queues and QoS support</title> |
232 | 238 | <para>TBD</para> |
include/net/mac80211.h
... | ... | @@ -882,6 +882,10 @@ |
882 | 882 | * |
883 | 883 | * @IEEE80211_HW_MFP_CAPABLE: |
884 | 884 | * Hardware supports management frame protection (MFP, IEEE 802.11w). |
885 | + * | |
886 | + * @IEEE80211_HW_BEACON_FILTER: | |
887 | + * Hardware supports dropping of irrelevant beacon frames to | |
888 | + * avoid waking up cpu. | |
885 | 889 | */ |
886 | 890 | enum ieee80211_hw_flags { |
887 | 891 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, |
... | ... | @@ -897,6 +901,7 @@ |
897 | 901 | IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, |
898 | 902 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, |
899 | 903 | IEEE80211_HW_MFP_CAPABLE = 1<<13, |
904 | + IEEE80211_HW_BEACON_FILTER = 1<<14, | |
900 | 905 | }; |
901 | 906 | |
902 | 907 | /** |
... | ... | @@ -1121,6 +1126,24 @@ |
1121 | 1126 | */ |
1122 | 1127 | |
1123 | 1128 | /** |
1129 | + * DOC: Beacon filter support | |
1130 | + * | |
1131 | + * Some hardware have beacon filter support to reduce host cpu wakeups | |
1132 | + * which will reduce system power consumption. It usuallly works so that | |
1133 | + * the firmware creates a checksum of the beacon but omits all constantly | |
1134 | + * changing elements (TSF, TIM etc). Whenever the checksum changes the | |
1135 | + * beacon is forwarded to the host, otherwise it will be just dropped. That | |
1136 | + * way the host will only receive beacons where some relevant information | |
1137 | + * (for example ERP protection or WMM settings) have changed. | |
1138 | + * | |
1139 | + * Beacon filter support is informed with %IEEE80211_HW_BEACON_FILTER flag. | |
1140 | + * The driver needs to enable beacon filter support whenever power save is | |
1141 | + * enabled, that is %IEEE80211_CONF_PS is set. When power save is enabled, | |
1142 | + * the stack will not check for beacon miss at all and the driver needs to | |
1143 | + * notify about complete loss of beacons with ieee80211_beacon_loss(). | |
1144 | + */ | |
1145 | + | |
1146 | +/** | |
1124 | 1147 | * DOC: Frame filtering |
1125 | 1148 | * |
1126 | 1149 | * mac80211 requires to see many management frames for proper |
... | ... | @@ -1970,6 +1993,16 @@ |
1970 | 1993 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, |
1971 | 1994 | const u8 *addr); |
1972 | 1995 | |
1996 | +/** | |
1997 | + * ieee80211_beacon_loss - inform hardware does not receive beacons | |
1998 | + * | |
1999 | + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | |
2000 | + * | |
2001 | + * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and | |
2002 | + * IEEE80211_CONF_PS is set, the driver needs to inform whenever the | |
2003 | + * hardware is not receiving beacons with this function. | |
2004 | + */ | |
2005 | +void ieee80211_beacon_loss(struct ieee80211_vif *vif); | |
1973 | 2006 | |
1974 | 2007 | /* Rate control API */ |
1975 | 2008 |
net/mac80211/ieee80211_i.h
... | ... | @@ -275,6 +275,7 @@ |
275 | 275 | struct timer_list chswitch_timer; |
276 | 276 | struct work_struct work; |
277 | 277 | struct work_struct chswitch_work; |
278 | + struct work_struct beacon_loss_work; | |
278 | 279 | |
279 | 280 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
280 | 281 | |
... | ... | @@ -1086,6 +1087,7 @@ |
1086 | 1087 | int powersave); |
1087 | 1088 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1088 | 1089 | struct ieee80211_hdr *hdr); |
1090 | +void ieee80211_beacon_loss_work(struct work_struct *work); | |
1089 | 1091 | |
1090 | 1092 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1091 | 1093 | enum queue_stop_reason reason); |
net/mac80211/iface.c
... | ... | @@ -477,6 +477,9 @@ |
477 | 477 | */ |
478 | 478 | cancel_work_sync(&sdata->u.mgd.work); |
479 | 479 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
480 | + | |
481 | + cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | |
482 | + | |
480 | 483 | /* |
481 | 484 | * When we get here, the interface is marked down. |
482 | 485 | * Call synchronize_rcu() to wait for the RX path |
net/mac80211/mlme.c
... | ... | @@ -610,6 +610,8 @@ |
610 | 610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
611 | 611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
612 | 612 | |
613 | + cfg80211_hold_bss(&bss->cbss); | |
614 | + | |
613 | 615 | ieee80211_rx_bss_put(local, bss); |
614 | 616 | } |
615 | 617 | |
... | ... | @@ -751,6 +753,8 @@ |
751 | 753 | { |
752 | 754 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
753 | 755 | struct ieee80211_local *local = sdata->local; |
756 | + struct ieee80211_conf *conf = &local_to_hw(local)->conf; | |
757 | + struct ieee80211_bss *bss; | |
754 | 758 | struct sta_info *sta; |
755 | 759 | u32 changed = 0, config_changed = 0; |
756 | 760 | |
... | ... | @@ -774,6 +778,15 @@ |
774 | 778 | |
775 | 779 | ieee80211_sta_tear_down_BA_sessions(sta); |
776 | 780 | |
781 | + bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | |
782 | + conf->channel->center_freq, | |
783 | + ifmgd->ssid, ifmgd->ssid_len); | |
784 | + | |
785 | + if (bss) { | |
786 | + cfg80211_unhold_bss(&bss->cbss); | |
787 | + ieee80211_rx_bss_put(local, bss); | |
788 | + } | |
789 | + | |
777 | 790 | if (self_disconnected) { |
778 | 791 | if (deauth) |
779 | 792 | ieee80211_send_deauth_disassoc(sdata, |
... | ... | @@ -925,6 +938,33 @@ |
925 | 938 | jiffies + IEEE80211_MONITORING_INTERVAL); |
926 | 939 | } |
927 | 940 | |
941 | +void ieee80211_beacon_loss_work(struct work_struct *work) | |
942 | +{ | |
943 | + struct ieee80211_sub_if_data *sdata = | |
944 | + container_of(work, struct ieee80211_sub_if_data, | |
945 | + u.mgd.beacon_loss_work); | |
946 | + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | |
947 | + | |
948 | + printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | |
949 | + "- sending probe request\n", sdata->dev->name, | |
950 | + sdata->u.mgd.bssid); | |
951 | + | |
952 | + ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | |
953 | + ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | |
954 | + ifmgd->ssid_len, NULL, 0); | |
955 | + | |
956 | + mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); | |
957 | +} | |
958 | + | |
959 | +void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |
960 | +{ | |
961 | + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | |
962 | + | |
963 | + queue_work(sdata->local->hw.workqueue, | |
964 | + &sdata->u.mgd.beacon_loss_work); | |
965 | +} | |
966 | +EXPORT_SYMBOL(ieee80211_beacon_loss); | |
967 | + | |
928 | 968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
929 | 969 | { |
930 | 970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
... | ... | @@ -959,7 +999,13 @@ |
959 | 999 | goto unlock; |
960 | 1000 | } |
961 | 1001 | |
962 | - if (time_after(jiffies, | |
1002 | + /* | |
1003 | + * Beacon filtering is only enabled with power save and then the | |
1004 | + * stack should not check for beacon loss. | |
1005 | + */ | |
1006 | + if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && | |
1007 | + (local->hw.conf.flags & IEEE80211_CONF_PS)) && | |
1008 | + time_after(jiffies, | |
963 | 1009 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { |
964 | 1010 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " |
965 | 1011 | "- sending probe request\n", |
... | ... | @@ -1869,6 +1915,7 @@ |
1869 | 1915 | ifmgd = &sdata->u.mgd; |
1870 | 1916 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
1871 | 1917 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1918 | + INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | |
1872 | 1919 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1873 | 1920 | (unsigned long) sdata); |
1874 | 1921 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |