diff options
-rw-r--r-- | Documentation/DocBook/mac80211.tmpl | 6 | ||||
-rw-r--r-- | include/net/mac80211.h | 33 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 49 |
5 files changed, 92 insertions, 1 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index 8af6d9626878..fbeaffc1dcc3 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -227,6 +227,12 @@ usage should require reading the full document. | |||
227 | !Pinclude/net/mac80211.h Powersave support | 227 | !Pinclude/net/mac80211.h Powersave support |
228 | </chapter> | 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 | <chapter id="qos"> | 236 | <chapter id="qos"> |
231 | <title>Multiple queues and QoS support</title> | 237 | <title>Multiple queues and QoS support</title> |
232 | <para>TBD</para> | 238 | <para>TBD</para> |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 174dc1d7526b..d881ed8ad2c1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -882,6 +882,10 @@ enum ieee80211_tkip_key_type { | |||
882 | * | 882 | * |
883 | * @IEEE80211_HW_MFP_CAPABLE: | 883 | * @IEEE80211_HW_MFP_CAPABLE: |
884 | * Hardware supports management frame protection (MFP, IEEE 802.11w). | 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 | enum ieee80211_hw_flags { | 890 | enum ieee80211_hw_flags { |
887 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, | 891 | IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, |
@@ -897,6 +901,7 @@ enum ieee80211_hw_flags { | |||
897 | IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, | 901 | IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11, |
898 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, | 902 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, |
899 | IEEE80211_HW_MFP_CAPABLE = 1<<13, | 903 | IEEE80211_HW_MFP_CAPABLE = 1<<13, |
904 | IEEE80211_HW_BEACON_FILTER = 1<<14, | ||
900 | }; | 905 | }; |
901 | 906 | ||
902 | /** | 907 | /** |
@@ -1121,6 +1126,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
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 | * DOC: Frame filtering | 1147 | * DOC: Frame filtering |
1125 | * | 1148 | * |
1126 | * mac80211 requires to see many management frames for proper | 1149 | * mac80211 requires to see many management frames for proper |
@@ -1970,6 +1993,16 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, | |||
1970 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, | 1993 | struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, |
1971 | const u8 *addr); | 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 | /* Rate control API */ | 2007 | /* Rate control API */ |
1975 | 2008 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8a617a7fc090..acba78e1a5ca 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -275,6 +275,7 @@ struct ieee80211_if_managed { | |||
275 | struct timer_list chswitch_timer; | 275 | struct timer_list chswitch_timer; |
276 | struct work_struct work; | 276 | struct work_struct work; |
277 | struct work_struct chswitch_work; | 277 | struct work_struct chswitch_work; |
278 | struct work_struct beacon_loss_work; | ||
278 | 279 | ||
279 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 280 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
280 | 281 | ||
@@ -1086,6 +1087,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1086 | int powersave); | 1087 | int powersave); |
1087 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1088 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1088 | struct ieee80211_hdr *hdr); | 1089 | struct ieee80211_hdr *hdr); |
1090 | void ieee80211_beacon_loss_work(struct work_struct *work); | ||
1089 | 1091 | ||
1090 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1092 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1091 | enum queue_stop_reason reason); | 1093 | enum queue_stop_reason reason); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index dd2a276fa8ca..91e8e1bacaaa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -477,6 +477,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
477 | */ | 477 | */ |
478 | cancel_work_sync(&sdata->u.mgd.work); | 478 | cancel_work_sync(&sdata->u.mgd.work); |
479 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 479 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
480 | |||
481 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | ||
482 | |||
480 | /* | 483 | /* |
481 | * When we get here, the interface is marked down. | 484 | * When we get here, the interface is marked down. |
482 | * Call synchronize_rcu() to wait for the RX path | 485 | * Call synchronize_rcu() to wait for the RX path |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8f30f4d19da0..7ecda9d59d8a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -610,6 +610,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
612 | 612 | ||
613 | cfg80211_hold_bss(&bss->cbss); | ||
614 | |||
613 | ieee80211_rx_bss_put(local, bss); | 615 | ieee80211_rx_bss_put(local, bss); |
614 | } | 616 | } |
615 | 617 | ||
@@ -751,6 +753,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
751 | { | 753 | { |
752 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 754 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
753 | struct ieee80211_local *local = sdata->local; | 755 | struct ieee80211_local *local = sdata->local; |
756 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
757 | struct ieee80211_bss *bss; | ||
754 | struct sta_info *sta; | 758 | struct sta_info *sta; |
755 | u32 changed = 0, config_changed = 0; | 759 | u32 changed = 0, config_changed = 0; |
756 | 760 | ||
@@ -774,6 +778,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
774 | 778 | ||
775 | ieee80211_sta_tear_down_BA_sessions(sta); | 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 | if (self_disconnected) { | 790 | if (self_disconnected) { |
778 | if (deauth) | 791 | if (deauth) |
779 | ieee80211_send_deauth_disassoc(sdata, | 792 | ieee80211_send_deauth_disassoc(sdata, |
@@ -925,6 +938,33 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
925 | jiffies + IEEE80211_MONITORING_INTERVAL); | 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 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | 968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
929 | { | 969 | { |
930 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -959,7 +999,13 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
959 | goto unlock; | 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 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { | 1009 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { |
964 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " | 1010 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " |
965 | "- sending probe request\n", | 1011 | "- sending probe request\n", |
@@ -1869,6 +1915,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1869 | ifmgd = &sdata->u.mgd; | 1915 | ifmgd = &sdata->u.mgd; |
1870 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 1916 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
1871 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1917 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1918 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | ||
1872 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 1919 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1873 | (unsigned long) sdata); | 1920 | (unsigned long) sdata); |
1874 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 1921 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |