aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-03-19 01:14:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-03-23 16:51:42 -0400
commit1e4dcd012423b6a28f968a55886d2b27896a1586 (patch)
treec2eadaf6a33175840b2f5d8fb7dd6af1d5be76ed
parent43ead78ac48b75aaf47de96fcf10cbf5962f32a6 (diff)
mac80211: Add support for connection monitor in hardware
This patch is based on a RFC patch by Kalle Valo. The wl1271 has a feature which handles the connection monitor logic in hardware, basically sending periodically nullfunc frames and reporting to the host if AP is lost, after attempting to recover by sending probe-requests to the AP. Add support to mac80211 by adding a new flag IEEE80211_HW_CONNECTION_MONITOR which prevents conn_mon_timer from triggering during idle periods, and prevents sending probe-requests to the AP if beacon-loss is indicated by the hardware. Cc: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/mac80211.h24
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/mlme.c64
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 */
958enum ieee80211_hw_flags { 963enum 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 */
2371void ieee80211_beacon_loss(struct ieee80211_vif *vif); 2377void 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 */
2391void 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);
1157void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, 1157void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
1158 struct ieee80211_hdr *hdr); 1158 struct ieee80211_hdr *hdr);
1159void ieee80211_beacon_loss_work(struct work_struct *work); 1159void ieee80211_beacon_connection_loss_work(struct work_struct *work);
1160 1160
1161void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 1161void 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
931void ieee80211_beacon_loss_work(struct work_struct *work) 934static 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
963void 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
940void ieee80211_beacon_loss(struct ieee80211_vif *vif) 975void 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}
946EXPORT_SYMBOL(ieee80211_beacon_loss); 983EXPORT_SYMBOL(ieee80211_beacon_loss);
947 984
985void 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}
993EXPORT_SYMBOL(ieee80211_connection_loss);
994
995
948static enum rx_mgmt_action __must_check 996static enum rx_mgmt_action __must_check
949ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, 997ieee80211_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
1640static void ieee80211_sta_conn_mon_timer(unsigned long data) 1689static 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,