diff options
| -rw-r--r-- | include/net/mac80211.h | 24 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 2 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 64 |
4 files changed, 82 insertions, 12 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 936bc410d061..d14226f29ffc 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -954,6 +954,11 @@ enum ieee80211_tkip_key_type { | |||
| 954 | * Hardware can provide ack status reports of Tx frames to | 954 | * Hardware can provide ack status reports of Tx frames to |
| 955 | * the stack. | 955 | * the stack. |
| 956 | * | 956 | * |
| 957 | * @IEEE80211_HW_CONNECTION_MONITOR: | ||
| 958 | * The hardware performs its own connection monitoring, including | ||
| 959 | * periodic keep-alives to the AP and probing the AP on beacon loss. | ||
| 960 | * When this flag is set, signaling beacon-loss will cause an immediate | ||
| 961 | * change to disassociated state. | ||
| 957 | */ | 962 | */ |
| 958 | enum ieee80211_hw_flags { | 963 | enum ieee80211_hw_flags { |
| 959 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 964 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
| @@ -975,6 +980,7 @@ enum ieee80211_hw_flags { | |||
| 975 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, | 980 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, |
| 976 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, | 981 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, |
| 977 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, | 982 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, |
| 983 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, | ||
| 978 | }; | 984 | }; |
| 979 | 985 | ||
| 980 | /** | 986 | /** |
| @@ -2364,12 +2370,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
| 2364 | * | 2370 | * |
| 2365 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 2371 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
| 2366 | * | 2372 | * |
| 2367 | * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and | 2373 | * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and |
| 2368 | * IEEE80211_CONF_PS is set, the driver needs to inform whenever the | 2374 | * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the |
| 2369 | * hardware is not receiving beacons with this function. | 2375 | * hardware is not receiving beacons with this function. |
| 2370 | */ | 2376 | */ |
| 2371 | void ieee80211_beacon_loss(struct ieee80211_vif *vif); | 2377 | void ieee80211_beacon_loss(struct ieee80211_vif *vif); |
| 2372 | 2378 | ||
| 2379 | /** | ||
| 2380 | * ieee80211_connection_loss - inform hardware has lost connection to the AP | ||
| 2381 | * | ||
| 2382 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
| 2383 | * | ||
| 2384 | * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and | ||
| 2385 | * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver | ||
| 2386 | * needs to inform if the connection to the AP has been lost. | ||
| 2387 | * | ||
| 2388 | * This function will cause immediate change to disassociated state, | ||
| 2389 | * without connection recovery attempts. | ||
| 2390 | */ | ||
| 2391 | void ieee80211_connection_loss(struct ieee80211_vif *vif); | ||
| 2392 | |||
| 2373 | /* Rate control API */ | 2393 | /* Rate control API */ |
| 2374 | 2394 | ||
| 2375 | /** | 2395 | /** |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b84126491ab1..ab369e2a5282 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -327,7 +327,7 @@ struct ieee80211_if_managed { | |||
| 327 | struct work_struct work; | 327 | struct work_struct work; |
| 328 | struct work_struct monitor_work; | 328 | struct work_struct monitor_work; |
| 329 | struct work_struct chswitch_work; | 329 | struct work_struct chswitch_work; |
| 330 | struct work_struct beacon_loss_work; | 330 | struct work_struct beacon_connection_loss_work; |
| 331 | 331 | ||
| 332 | unsigned long probe_timeout; | 332 | unsigned long probe_timeout; |
| 333 | int probe_send_count; | 333 | int probe_send_count; |
| @@ -1156,7 +1156,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
| 1156 | int powersave); | 1156 | int powersave); |
| 1157 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1157 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
| 1158 | struct ieee80211_hdr *hdr); | 1158 | struct ieee80211_hdr *hdr); |
| 1159 | void ieee80211_beacon_loss_work(struct work_struct *work); | 1159 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); |
| 1160 | 1160 | ||
| 1161 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1161 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
| 1162 | enum queue_stop_reason reason); | 1162 | enum queue_stop_reason reason); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d5571b9420cd..b4ec59a8dc03 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -486,7 +486,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 486 | cancel_work_sync(&sdata->u.mgd.work); | 486 | cancel_work_sync(&sdata->u.mgd.work); |
| 487 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 487 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
| 488 | cancel_work_sync(&sdata->u.mgd.monitor_work); | 488 | cancel_work_sync(&sdata->u.mgd.monitor_work); |
| 489 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | 489 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); |
| 490 | 490 | ||
| 491 | /* | 491 | /* |
| 492 | * When we get here, the interface is marked down. | 492 | * When we get here, the interface is marked down. |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0ab284c32135..865ea1cfb7bb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -851,6 +851,9 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
| 851 | if (is_multicast_ether_addr(hdr->addr1)) | 851 | if (is_multicast_ether_addr(hdr->addr1)) |
| 852 | return; | 852 | return; |
| 853 | 853 | ||
| 854 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
| 855 | return; | ||
| 856 | |||
| 854 | mod_timer(&sdata->u.mgd.conn_mon_timer, | 857 | mod_timer(&sdata->u.mgd.conn_mon_timer, |
| 855 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | 858 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); |
| 856 | } | 859 | } |
| @@ -928,23 +931,68 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
| 928 | mutex_unlock(&ifmgd->mtx); | 931 | mutex_unlock(&ifmgd->mtx); |
| 929 | } | 932 | } |
| 930 | 933 | ||
| 931 | void ieee80211_beacon_loss_work(struct work_struct *work) | 934 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) |
| 935 | { | ||
| 936 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 937 | struct ieee80211_local *local = sdata->local; | ||
| 938 | u8 bssid[ETH_ALEN]; | ||
| 939 | |||
| 940 | mutex_lock(&ifmgd->mtx); | ||
| 941 | if (!ifmgd->associated) { | ||
| 942 | mutex_unlock(&ifmgd->mtx); | ||
| 943 | return; | ||
| 944 | } | ||
| 945 | |||
| 946 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||
| 947 | |||
| 948 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | ||
| 949 | |||
| 950 | ieee80211_set_disassoc(sdata); | ||
| 951 | ieee80211_recalc_idle(local); | ||
| 952 | mutex_unlock(&ifmgd->mtx); | ||
| 953 | /* | ||
| 954 | * must be outside lock due to cfg80211, | ||
| 955 | * but that's not a problem. | ||
| 956 | */ | ||
| 957 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
| 958 | IEEE80211_STYPE_DEAUTH, | ||
| 959 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
| 960 | NULL); | ||
| 961 | } | ||
| 962 | |||
| 963 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) | ||
| 932 | { | 964 | { |
| 933 | struct ieee80211_sub_if_data *sdata = | 965 | struct ieee80211_sub_if_data *sdata = |
| 934 | container_of(work, struct ieee80211_sub_if_data, | 966 | container_of(work, struct ieee80211_sub_if_data, |
| 935 | u.mgd.beacon_loss_work); | 967 | u.mgd.beacon_connection_loss_work); |
| 936 | 968 | ||
| 937 | ieee80211_mgd_probe_ap(sdata, true); | 969 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
| 970 | __ieee80211_connection_loss(sdata); | ||
| 971 | else | ||
| 972 | ieee80211_mgd_probe_ap(sdata, true); | ||
| 938 | } | 973 | } |
| 939 | 974 | ||
| 940 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 975 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
| 941 | { | 976 | { |
| 942 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 977 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
| 978 | struct ieee80211_hw *hw = &sdata->local->hw; | ||
| 943 | 979 | ||
| 944 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); | 980 | WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); |
| 981 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | ||
| 945 | } | 982 | } |
| 946 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 983 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
| 947 | 984 | ||
| 985 | void ieee80211_connection_loss(struct ieee80211_vif *vif) | ||
| 986 | { | ||
| 987 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
| 988 | struct ieee80211_hw *hw = &sdata->local->hw; | ||
| 989 | |||
| 990 | WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR)); | ||
| 991 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | ||
| 992 | } | ||
| 993 | EXPORT_SYMBOL(ieee80211_connection_loss); | ||
| 994 | |||
| 995 | |||
| 948 | static enum rx_mgmt_action __must_check | 996 | static enum rx_mgmt_action __must_check |
| 949 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 997 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
| 950 | struct ieee80211_mgmt *mgmt, size_t len) | 998 | struct ieee80211_mgmt *mgmt, size_t len) |
| @@ -1634,7 +1682,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
| 1634 | if (local->quiescing) | 1682 | if (local->quiescing) |
| 1635 | return; | 1683 | return; |
| 1636 | 1684 | ||
| 1637 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); | 1685 | ieee80211_queue_work(&sdata->local->hw, |
| 1686 | &sdata->u.mgd.beacon_connection_loss_work); | ||
| 1638 | } | 1687 | } |
| 1639 | 1688 | ||
| 1640 | static void ieee80211_sta_conn_mon_timer(unsigned long data) | 1689 | static void ieee80211_sta_conn_mon_timer(unsigned long data) |
| @@ -1686,7 +1735,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
| 1686 | */ | 1735 | */ |
| 1687 | 1736 | ||
| 1688 | cancel_work_sync(&ifmgd->work); | 1737 | cancel_work_sync(&ifmgd->work); |
| 1689 | cancel_work_sync(&ifmgd->beacon_loss_work); | 1738 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
| 1690 | if (del_timer_sync(&ifmgd->timer)) | 1739 | if (del_timer_sync(&ifmgd->timer)) |
| 1691 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 1740 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
| 1692 | 1741 | ||
| @@ -1720,7 +1769,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 1720 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 1769 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
| 1721 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); | 1770 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); |
| 1722 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1771 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
| 1723 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | 1772 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
| 1773 | ieee80211_beacon_connection_loss_work); | ||
| 1724 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 1774 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
| 1725 | (unsigned long) sdata); | 1775 | (unsigned long) sdata); |
| 1726 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 1776 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
