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, |
