diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 20 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 257 | ||||
-rw-r--r-- | net/mac80211/rx.c | 22 |
3 files changed, 227 insertions, 72 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 06b3411530f2..a34bca2dc52f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -256,12 +256,13 @@ struct ieee80211_mgd_work { | |||
256 | 256 | ||
257 | /* flags used in struct ieee80211_if_managed.flags */ | 257 | /* flags used in struct ieee80211_if_managed.flags */ |
258 | enum ieee80211_sta_flags { | 258 | enum ieee80211_sta_flags { |
259 | IEEE80211_STA_PROBEREQ_POLL = BIT(3), | 259 | IEEE80211_STA_BEACON_POLL = BIT(0), |
260 | IEEE80211_STA_CONTROL_PORT = BIT(4), | 260 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
261 | IEEE80211_STA_WMM_ENABLED = BIT(5), | 261 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
262 | IEEE80211_STA_DISABLE_11N = BIT(6), | 262 | IEEE80211_STA_WMM_ENABLED = BIT(3), |
263 | IEEE80211_STA_CSA_RECEIVED = BIT(7), | 263 | IEEE80211_STA_DISABLE_11N = BIT(4), |
264 | IEEE80211_STA_MFP_ENABLED = BIT(8), | 264 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
265 | IEEE80211_STA_MFP_ENABLED = BIT(6), | ||
265 | }; | 266 | }; |
266 | 267 | ||
267 | /* flags for MLME request */ | 268 | /* flags for MLME request */ |
@@ -271,11 +272,16 @@ enum ieee80211_sta_request { | |||
271 | 272 | ||
272 | struct ieee80211_if_managed { | 273 | struct ieee80211_if_managed { |
273 | struct timer_list timer; | 274 | struct timer_list timer; |
275 | struct timer_list conn_mon_timer; | ||
276 | struct timer_list bcn_mon_timer; | ||
274 | struct timer_list chswitch_timer; | 277 | struct timer_list chswitch_timer; |
275 | struct work_struct work; | 278 | struct work_struct work; |
279 | struct work_struct monitor_work; | ||
276 | struct work_struct chswitch_work; | 280 | struct work_struct chswitch_work; |
277 | struct work_struct beacon_loss_work; | 281 | struct work_struct beacon_loss_work; |
278 | 282 | ||
283 | unsigned long probe_timeout; | ||
284 | |||
279 | struct mutex mtx; | 285 | struct mutex mtx; |
280 | struct ieee80211_bss *associated; | 286 | struct ieee80211_bss *associated; |
281 | struct list_head work_list; | 287 | struct list_head work_list; |
@@ -292,8 +298,6 @@ struct ieee80211_if_managed { | |||
292 | 298 | ||
293 | unsigned long request; | 299 | unsigned long request; |
294 | 300 | ||
295 | unsigned long last_beacon; | ||
296 | |||
297 | unsigned int flags; | 301 | unsigned int flags; |
298 | 302 | ||
299 | u32 beacon_crc; | 303 | u32 beacon_crc; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c1114bb8095b..18dad229344c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -31,8 +31,23 @@ | |||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | 31 | #define IEEE80211_AUTH_MAX_TRIES 3 |
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 33 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
34 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 34 | |
35 | #define IEEE80211_PROBE_WAIT (HZ / 5) | 35 | /* |
36 | * beacon loss detection timeout | ||
37 | * XXX: should depend on beacon interval | ||
38 | */ | ||
39 | #define IEEE80211_BEACON_LOSS_TIME (2 * HZ) | ||
40 | /* | ||
41 | * Time the connection can be idle before we probe | ||
42 | * it to see if we can still talk to the AP. | ||
43 | */ | ||
44 | #define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) | ||
45 | /* | ||
46 | * Time we wait for a probe response after sending | ||
47 | * a probe request because of beacon loss or for | ||
48 | * checking the connection still works. | ||
49 | */ | ||
50 | #define IEEE80211_PROBE_WAIT (HZ / 5) | ||
36 | 51 | ||
37 | #define TMR_RUNNING_TIMER 0 | 52 | #define TMR_RUNNING_TIMER 0 |
38 | #define TMR_RUNNING_CHANSW 1 | 53 | #define TMR_RUNNING_CHANSW 1 |
@@ -92,6 +107,15 @@ static void run_again(struct ieee80211_if_managed *ifmgd, | |||
92 | mod_timer(&ifmgd->timer, timeout); | 107 | mod_timer(&ifmgd->timer, timeout); |
93 | } | 108 | } |
94 | 109 | ||
110 | static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) | ||
111 | { | ||
112 | if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) | ||
113 | return; | ||
114 | |||
115 | mod_timer(&sdata->u.mgd.bcn_mon_timer, | ||
116 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); | ||
117 | } | ||
118 | |||
95 | static int ecw2cw(int ecw) | 119 | static int ecw2cw(int ecw) |
96 | { | 120 | { |
97 | return (1 << ecw) - 1; | 121 | return (1 << ecw) - 1; |
@@ -666,7 +690,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
666 | 690 | ||
667 | if (count == 1 && found->u.mgd.powersave && | 691 | if (count == 1 && found->u.mgd.powersave && |
668 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && | 692 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && |
669 | !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { | 693 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
694 | IEEE80211_STA_CONNECTION_POLL))) { | ||
670 | s32 beaconint_us; | 695 | s32 beaconint_us; |
671 | 696 | ||
672 | if (latency < 0) | 697 | if (latency < 0) |
@@ -872,6 +897,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
872 | sdata->u.mgd.associated = bss; | 897 | sdata->u.mgd.associated = bss; |
873 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); | 898 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); |
874 | 899 | ||
900 | /* just to be sure */ | ||
901 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
902 | IEEE80211_STA_BEACON_POLL); | ||
903 | |||
875 | ieee80211_led_assoc(local, 1); | 904 | ieee80211_led_assoc(local, 1); |
876 | 905 | ||
877 | sdata->vif.bss_conf.assoc = 1; | 906 | sdata->vif.bss_conf.assoc = 1; |
@@ -983,16 +1012,21 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
983 | return RX_MGMT_NONE; | 1012 | return RX_MGMT_NONE; |
984 | } | 1013 | } |
985 | 1014 | ||
986 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 1015 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) |
987 | const u8 *bssid, bool deauth) | ||
988 | { | 1016 | { |
989 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1017 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
990 | struct ieee80211_local *local = sdata->local; | 1018 | struct ieee80211_local *local = sdata->local; |
991 | struct sta_info *sta; | 1019 | struct sta_info *sta; |
992 | u32 changed = 0, config_changed = 0; | 1020 | u32 changed = 0, config_changed = 0; |
1021 | u8 bssid[ETH_ALEN]; | ||
993 | 1022 | ||
994 | ASSERT_MGD_MTX(ifmgd); | 1023 | ASSERT_MGD_MTX(ifmgd); |
995 | 1024 | ||
1025 | if (WARN_ON(!ifmgd->associated)) | ||
1026 | return; | ||
1027 | |||
1028 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | ||
1029 | |||
996 | ifmgd->associated = NULL; | 1030 | ifmgd->associated = NULL; |
997 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1031 | memset(ifmgd->bssid, 0, ETH_ALEN); |
998 | 1032 | ||
@@ -1112,32 +1146,22 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1112 | * from AP because we know that the connection is working both ways | 1146 | * from AP because we know that the connection is working both ways |
1113 | * at that time. But multicast frames (and hence also beacons) must | 1147 | * at that time. But multicast frames (and hence also beacons) must |
1114 | * be ignored here, because we need to trigger the timer during | 1148 | * be ignored here, because we need to trigger the timer during |
1115 | * data idle periods for sending the periodical probe request to | 1149 | * data idle periods for sending the periodic probe request to the |
1116 | * the AP. | 1150 | * AP we're connected to. |
1117 | */ | 1151 | */ |
1118 | if (!is_multicast_ether_addr(hdr->addr1)) | 1152 | if (is_multicast_ether_addr(hdr->addr1)) |
1119 | mod_timer(&sdata->u.mgd.timer, | 1153 | return; |
1120 | jiffies + IEEE80211_MONITORING_INTERVAL); | 1154 | |
1155 | mod_timer(&sdata->u.mgd.conn_mon_timer, | ||
1156 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | ||
1121 | } | 1157 | } |
1122 | 1158 | ||
1123 | void ieee80211_beacon_loss_work(struct work_struct *work) | 1159 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
1160 | bool beacon) | ||
1124 | { | 1161 | { |
1125 | struct ieee80211_sub_if_data *sdata = | ||
1126 | container_of(work, struct ieee80211_sub_if_data, | ||
1127 | u.mgd.beacon_loss_work); | ||
1128 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1162 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1129 | const u8 *ssid; | 1163 | const u8 *ssid; |
1130 | 1164 | bool already = false; | |
1131 | /* | ||
1132 | * The driver has already reported this event and we have | ||
1133 | * already sent a probe request. Maybe the AP died and the | ||
1134 | * driver keeps reporting until we disassociate... We have | ||
1135 | * to ignore that because otherwise we would continually | ||
1136 | * reset the timer and never check whether we received a | ||
1137 | * probe response! | ||
1138 | */ | ||
1139 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | ||
1140 | return; | ||
1141 | 1165 | ||
1142 | mutex_lock(&ifmgd->mtx); | 1166 | mutex_lock(&ifmgd->mtx); |
1143 | 1167 | ||
@@ -1145,12 +1169,35 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
1145 | goto out; | 1169 | goto out; |
1146 | 1170 | ||
1147 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1171 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1148 | if (net_ratelimit()) | 1172 | if (beacon && net_ratelimit()) |
1149 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP " | 1173 | printk(KERN_DEBUG "%s: detected beacon loss from AP " |
1150 | "- sending probe request\n", sdata->dev->name); | 1174 | "- sending probe request\n", sdata->dev->name); |
1151 | #endif | 1175 | #endif |
1152 | 1176 | ||
1153 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1177 | /* |
1178 | * The driver/our work has already reported this event or the | ||
1179 | * connection monitoring has kicked in and we have already sent | ||
1180 | * a probe request. Or maybe the AP died and the driver keeps | ||
1181 | * reporting until we disassociate... | ||
1182 | * | ||
1183 | * In either case we have to ignore the current call to this | ||
1184 | * function (except for setting the correct probe reason bit) | ||
1185 | * because otherwise we would reset the timer every time and | ||
1186 | * never check whether we received a probe response! | ||
1187 | */ | ||
1188 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
1189 | IEEE80211_STA_CONNECTION_POLL)) | ||
1190 | already = true; | ||
1191 | |||
1192 | if (beacon) | ||
1193 | ifmgd->flags |= IEEE80211_STA_BEACON_POLL; | ||
1194 | else | ||
1195 | ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL; | ||
1196 | |||
1197 | if (already) | ||
1198 | goto out; | ||
1199 | |||
1200 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | ||
1154 | 1201 | ||
1155 | mutex_lock(&sdata->local->iflist_mtx); | 1202 | mutex_lock(&sdata->local->iflist_mtx); |
1156 | ieee80211_recalc_ps(sdata->local, -1); | 1203 | ieee80211_recalc_ps(sdata->local, -1); |
@@ -1160,11 +1207,21 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
1160 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, | 1207 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, |
1161 | ssid + 2, ssid[1], NULL, 0); | 1208 | ssid + 2, ssid[1], NULL, 0); |
1162 | 1209 | ||
1163 | run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); | 1210 | run_again(ifmgd, ifmgd->probe_timeout); |
1211 | |||
1164 | out: | 1212 | out: |
1165 | mutex_unlock(&ifmgd->mtx); | 1213 | mutex_unlock(&ifmgd->mtx); |
1166 | } | 1214 | } |
1167 | 1215 | ||
1216 | void ieee80211_beacon_loss_work(struct work_struct *work) | ||
1217 | { | ||
1218 | struct ieee80211_sub_if_data *sdata = | ||
1219 | container_of(work, struct ieee80211_sub_if_data, | ||
1220 | u.mgd.beacon_loss_work); | ||
1221 | |||
1222 | ieee80211_mgd_probe_ap(sdata, true); | ||
1223 | } | ||
1224 | |||
1168 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1225 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
1169 | { | 1226 | { |
1170 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1227 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
@@ -1278,7 +1335,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1278 | sdata->dev->name, bssid, reason_code); | 1335 | sdata->dev->name, bssid, reason_code); |
1279 | 1336 | ||
1280 | if (!wk) { | 1337 | if (!wk) { |
1281 | ieee80211_set_disassoc(sdata, bssid, true); | 1338 | ieee80211_set_disassoc(sdata); |
1282 | } else { | 1339 | } else { |
1283 | list_del(&wk->list); | 1340 | list_del(&wk->list); |
1284 | kfree(wk); | 1341 | kfree(wk); |
@@ -1311,7 +1368,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1311 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1368 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1312 | sdata->dev->name, reason_code); | 1369 | sdata->dev->name, reason_code); |
1313 | 1370 | ||
1314 | ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); | 1371 | ieee80211_set_disassoc(sdata); |
1315 | return RX_MGMT_CFG80211_DISASSOC; | 1372 | return RX_MGMT_CFG80211_DISASSOC; |
1316 | } | 1373 | } |
1317 | 1374 | ||
@@ -1412,9 +1469,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1412 | return RX_MGMT_NONE; | 1469 | return RX_MGMT_NONE; |
1413 | } | 1470 | } |
1414 | 1471 | ||
1415 | /* update new sta with its last rx activity */ | ||
1416 | sta->last_rx = jiffies; | ||
1417 | |||
1418 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | 1472 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | |
1419 | WLAN_STA_ASSOC_AP); | 1473 | WLAN_STA_ASSOC_AP); |
1420 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 1474 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
@@ -1517,10 +1571,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1517 | ieee80211_set_associated(sdata, wk->bss, changed); | 1571 | ieee80211_set_associated(sdata, wk->bss, changed); |
1518 | 1572 | ||
1519 | /* | 1573 | /* |
1520 | * initialise the time of last beacon to be the association time, | 1574 | * Start timer to probe the connection to the AP now. |
1521 | * otherwise beacon loss check will trigger immediately | 1575 | * Also start the timer that will detect beacon loss. |
1522 | */ | 1576 | */ |
1523 | ifmgd->last_beacon = jiffies; | 1577 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1578 | mod_beacon_timer(sdata); | ||
1524 | 1579 | ||
1525 | list_del(&wk->list); | 1580 | list_del(&wk->list); |
1526 | kfree(wk); | 1581 | kfree(wk); |
@@ -1604,11 +1659,22 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1604 | 1659 | ||
1605 | if (ifmgd->associated && | 1660 | if (ifmgd->associated && |
1606 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && | 1661 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && |
1607 | ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | 1662 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
1608 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 1663 | IEEE80211_STA_CONNECTION_POLL)) { |
1664 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1665 | IEEE80211_STA_BEACON_POLL); | ||
1609 | mutex_lock(&sdata->local->iflist_mtx); | 1666 | mutex_lock(&sdata->local->iflist_mtx); |
1610 | ieee80211_recalc_ps(sdata->local, -1); | 1667 | ieee80211_recalc_ps(sdata->local, -1); |
1611 | mutex_unlock(&sdata->local->iflist_mtx); | 1668 | mutex_unlock(&sdata->local->iflist_mtx); |
1669 | /* | ||
1670 | * We've received a probe response, but are not sure whether | ||
1671 | * we have or will be receiving any beacons or data, so let's | ||
1672 | * schedule the timers again, just in case. | ||
1673 | */ | ||
1674 | mod_beacon_timer(sdata); | ||
1675 | mod_timer(&ifmgd->conn_mon_timer, | ||
1676 | round_jiffies_up(jiffies + | ||
1677 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1612 | } | 1678 | } |
1613 | } | 1679 | } |
1614 | 1680 | ||
@@ -1658,27 +1724,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1658 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 1724 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1659 | return; | 1725 | return; |
1660 | 1726 | ||
1661 | if (WARN_ON(!ifmgd->associated)) | 1727 | /* |
1728 | * We might have received a number of frames, among them a | ||
1729 | * disassoc frame and a beacon... | ||
1730 | */ | ||
1731 | if (!ifmgd->associated) | ||
1662 | return; | 1732 | return; |
1663 | 1733 | ||
1664 | bssid = ifmgd->associated->cbss.bssid; | 1734 | bssid = ifmgd->associated->cbss.bssid; |
1665 | 1735 | ||
1666 | if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) | 1736 | /* |
1737 | * And in theory even frames from a different AP we were just | ||
1738 | * associated to a split-second ago! | ||
1739 | */ | ||
1740 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1667 | return; | 1741 | return; |
1668 | 1742 | ||
1669 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | 1743 | if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { |
1670 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1744 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1671 | if (net_ratelimit()) { | 1745 | if (net_ratelimit()) { |
1672 | printk(KERN_DEBUG "%s: cancelling probereq poll due " | 1746 | printk(KERN_DEBUG "%s: cancelling probereq poll due " |
1673 | "to a received beacon\n", sdata->dev->name); | 1747 | "to a received beacon\n", sdata->dev->name); |
1674 | } | 1748 | } |
1675 | #endif | 1749 | #endif |
1676 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 1750 | ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; |
1677 | mutex_lock(&local->iflist_mtx); | 1751 | mutex_lock(&local->iflist_mtx); |
1678 | ieee80211_recalc_ps(local, -1); | 1752 | ieee80211_recalc_ps(local, -1); |
1679 | mutex_unlock(&local->iflist_mtx); | 1753 | mutex_unlock(&local->iflist_mtx); |
1680 | } | 1754 | } |
1681 | 1755 | ||
1756 | /* | ||
1757 | * Push the beacon loss detection into the future since | ||
1758 | * we are processing a beacon from the AP just now. | ||
1759 | */ | ||
1760 | mod_beacon_timer(sdata); | ||
1761 | |||
1682 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | 1762 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
1683 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, | 1763 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
1684 | len - baselen, &elems, | 1764 | len - baselen, &elems, |
@@ -1980,6 +2060,37 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
1980 | /* then process the rest of the work */ | 2060 | /* then process the rest of the work */ |
1981 | mutex_lock(&ifmgd->mtx); | 2061 | mutex_lock(&ifmgd->mtx); |
1982 | 2062 | ||
2063 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
2064 | IEEE80211_STA_CONNECTION_POLL) && | ||
2065 | ifmgd->associated) { | ||
2066 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
2067 | run_again(ifmgd, ifmgd->probe_timeout); | ||
2068 | else { | ||
2069 | u8 bssid[ETH_ALEN]; | ||
2070 | /* | ||
2071 | * We actually lost the connection ... or did we? | ||
2072 | * Let's make sure! | ||
2073 | */ | ||
2074 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
2075 | IEEE80211_STA_BEACON_POLL); | ||
2076 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | ||
2077 | printk(KERN_DEBUG "No probe response from AP %pM" | ||
2078 | " after %dms, disconnecting.\n", | ||
2079 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | ||
2080 | ieee80211_set_disassoc(sdata); | ||
2081 | mutex_unlock(&ifmgd->mtx); | ||
2082 | /* | ||
2083 | * must be outside lock due to cfg80211, | ||
2084 | * but that's not a problem. | ||
2085 | */ | ||
2086 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
2087 | IEEE80211_STYPE_DEAUTH, | ||
2088 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
2089 | NULL); | ||
2090 | mutex_lock(&ifmgd->mtx); | ||
2091 | } | ||
2092 | } | ||
2093 | |||
1983 | list_for_each_entry(wk, &ifmgd->work_list, list) { | 2094 | list_for_each_entry(wk, &ifmgd->work_list, list) { |
1984 | if (wk->state != IEEE80211_MGD_STATE_IDLE) { | 2095 | if (wk->state != IEEE80211_MGD_STATE_IDLE) { |
1985 | anybusy = true; | 2096 | anybusy = true; |
@@ -2067,15 +2178,51 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2067 | ieee80211_recalc_idle(local); | 2178 | ieee80211_recalc_idle(local); |
2068 | } | 2179 | } |
2069 | 2180 | ||
2181 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | ||
2182 | { | ||
2183 | struct ieee80211_sub_if_data *sdata = | ||
2184 | (struct ieee80211_sub_if_data *) data; | ||
2185 | struct ieee80211_local *local = sdata->local; | ||
2186 | |||
2187 | if (local->quiescing) | ||
2188 | return; | ||
2189 | |||
2190 | queue_work(sdata->local->hw.workqueue, | ||
2191 | &sdata->u.mgd.beacon_loss_work); | ||
2192 | } | ||
2193 | |||
2194 | static void ieee80211_sta_conn_mon_timer(unsigned long data) | ||
2195 | { | ||
2196 | struct ieee80211_sub_if_data *sdata = | ||
2197 | (struct ieee80211_sub_if_data *) data; | ||
2198 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2199 | struct ieee80211_local *local = sdata->local; | ||
2200 | |||
2201 | if (local->quiescing) | ||
2202 | return; | ||
2203 | |||
2204 | queue_work(local->hw.workqueue, &ifmgd->monitor_work); | ||
2205 | } | ||
2206 | |||
2207 | static void ieee80211_sta_monitor_work(struct work_struct *work) | ||
2208 | { | ||
2209 | struct ieee80211_sub_if_data *sdata = | ||
2210 | container_of(work, struct ieee80211_sub_if_data, | ||
2211 | u.mgd.monitor_work); | ||
2212 | |||
2213 | ieee80211_mgd_probe_ap(sdata, false); | ||
2214 | } | ||
2215 | |||
2070 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | 2216 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) |
2071 | { | 2217 | { |
2072 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 2218 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
2073 | /* | 2219 | sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | |
2074 | * Need to update last_beacon to avoid beacon loss | 2220 | IEEE80211_STA_CONNECTION_POLL); |
2075 | * test to trigger. | ||
2076 | */ | ||
2077 | sdata->u.mgd.last_beacon = jiffies; | ||
2078 | 2221 | ||
2222 | /* let's probe the connection once */ | ||
2223 | queue_work(sdata->local->hw.workqueue, | ||
2224 | &sdata->u.mgd.monitor_work); | ||
2225 | /* and do all the other regular work too */ | ||
2079 | queue_work(sdata->local->hw.workqueue, | 2226 | queue_work(sdata->local->hw.workqueue, |
2080 | &sdata->u.mgd.work); | 2227 | &sdata->u.mgd.work); |
2081 | } | 2228 | } |
@@ -2100,6 +2247,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2100 | cancel_work_sync(&ifmgd->chswitch_work); | 2247 | cancel_work_sync(&ifmgd->chswitch_work); |
2101 | if (del_timer_sync(&ifmgd->chswitch_timer)) | 2248 | if (del_timer_sync(&ifmgd->chswitch_timer)) |
2102 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | 2249 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); |
2250 | |||
2251 | cancel_work_sync(&ifmgd->monitor_work); | ||
2252 | /* these will just be re-established on connection */ | ||
2253 | del_timer_sync(&ifmgd->conn_mon_timer); | ||
2254 | del_timer_sync(&ifmgd->bcn_mon_timer); | ||
2103 | } | 2255 | } |
2104 | 2256 | ||
2105 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | 2257 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) |
@@ -2120,10 +2272,15 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2120 | 2272 | ||
2121 | ifmgd = &sdata->u.mgd; | 2273 | ifmgd = &sdata->u.mgd; |
2122 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 2274 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
2275 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); | ||
2123 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 2276 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2124 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | 2277 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); |
2125 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 2278 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2126 | (unsigned long) sdata); | 2279 | (unsigned long) sdata); |
2280 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | ||
2281 | (unsigned long) sdata); | ||
2282 | setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, | ||
2283 | (unsigned long) sdata); | ||
2127 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 2284 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
2128 | (unsigned long) sdata); | 2285 | (unsigned long) sdata); |
2129 | skb_queue_head_init(&ifmgd->skb_queue); | 2286 | skb_queue_head_init(&ifmgd->skb_queue); |
@@ -2323,7 +2480,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2323 | 2480 | ||
2324 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 2481 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { |
2325 | bssid = req->bss->bssid; | 2482 | bssid = req->bss->bssid; |
2326 | ieee80211_set_disassoc(sdata, bssid, true); | 2483 | ieee80211_set_disassoc(sdata); |
2327 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | 2484 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { |
2328 | if (&wk->bss->cbss == req->bss) { | 2485 | if (&wk->bss->cbss == req->bss) { |
2329 | bssid = req->bss->bssid; | 2486 | bssid = req->bss->bssid; |
@@ -2365,7 +2522,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2365 | return -ENOLINK; | 2522 | return -ENOLINK; |
2366 | } | 2523 | } |
2367 | 2524 | ||
2368 | ieee80211_set_disassoc(sdata, req->bss->bssid, false); | 2525 | ieee80211_set_disassoc(sdata); |
2369 | 2526 | ||
2370 | mutex_unlock(&ifmgd->mtx); | 2527 | mutex_unlock(&ifmgd->mtx); |
2371 | 2528 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe6b99059531..b513fb791153 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -833,28 +833,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
833 | if (!sta) | 833 | if (!sta) |
834 | return RX_CONTINUE; | 834 | return RX_CONTINUE; |
835 | 835 | ||
836 | /* Update last_rx only for IBSS packets which are for the current | 836 | /* |
837 | * BSSID to avoid keeping the current IBSS network alive in cases where | 837 | * Update last_rx only for IBSS packets which are for the current |
838 | * other STAs are using different BSSID. */ | 838 | * BSSID to avoid keeping the current IBSS network alive in cases |
839 | * where other STAs start using different BSSID. | ||
840 | */ | ||
839 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 841 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
840 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 842 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
841 | NL80211_IFTYPE_ADHOC); | 843 | NL80211_IFTYPE_ADHOC); |
842 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) | 844 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) |
843 | sta->last_rx = jiffies; | 845 | sta->last_rx = jiffies; |
844 | } else | 846 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
845 | if (!is_multicast_ether_addr(hdr->addr1) || | 847 | /* |
846 | rx->sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
847 | /* Update last_rx only for unicast frames in order to prevent | ||
848 | * the Probe Request frames (the only broadcast frames from a | ||
849 | * STA in infrastructure mode) from keeping a connection alive. | ||
850 | * Mesh beacons will update last_rx when if they are found to | 848 | * Mesh beacons will update last_rx when if they are found to |
851 | * match the current local configuration when processed. | 849 | * match the current local configuration when processed. |
852 | */ | 850 | */ |
853 | if (rx->sdata->vif.type == NL80211_IFTYPE_STATION && | 851 | sta->last_rx = jiffies; |
854 | ieee80211_is_beacon(hdr->frame_control)) { | ||
855 | rx->sdata->u.mgd.last_beacon = jiffies; | ||
856 | } else | ||
857 | sta->last_rx = jiffies; | ||
858 | } | 852 | } |
859 | 853 | ||
860 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 854 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |