aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-07-29 14:47:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-29 14:47:07 -0400
commitae3568adf42d5d3bb3cfa505b94351c5d1ce4924 (patch)
tree112865a6e6b1e4ddf70362f3efb295c495ec85b9 /net/mac80211
parent7f3e01fee41a322747db2d7574516d9fbd3785c0 (diff)
parentb7753c8cd51dce67a0b152efb456a21ff1cc241b (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c13
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/key.c13
-rw-r--r--net/mac80211/key.h3
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/mlme.c32
-rw-r--r--net/mac80211/rc80211_minstrel.c1
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c4
-rw-r--r--net/mac80211/scan.c8
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/tx.c19
-rw-r--r--net/mac80211/util.c8
-rw-r--r--net/mac80211/work.c43
13 files changed, 110 insertions, 40 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index db4d9340c846..29ac8e1a509e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -158,7 +158,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
158 if (mac_addr) { 158 if (mac_addr) {
159 sta = sta_info_get_bss(sdata, mac_addr); 159 sta = sta_info_get_bss(sdata, mac_addr);
160 if (!sta) { 160 if (!sta) {
161 ieee80211_key_free(key); 161 ieee80211_key_free(sdata->local, key);
162 err = -ENOENT; 162 err = -ENOENT;
163 goto out_unlock; 163 goto out_unlock;
164 } 164 }
@@ -192,7 +192,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
192 goto out_unlock; 192 goto out_unlock;
193 193
194 if (sta->key) { 194 if (sta->key) {
195 ieee80211_key_free(sta->key); 195 ieee80211_key_free(sdata->local, sta->key);
196 WARN_ON(sta->key); 196 WARN_ON(sta->key);
197 ret = 0; 197 ret = 0;
198 } 198 }
@@ -205,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
205 goto out_unlock; 205 goto out_unlock;
206 } 206 }
207 207
208 ieee80211_key_free(sdata->keys[key_idx]); 208 ieee80211_key_free(sdata->local, sdata->keys[key_idx]);
209 WARN_ON(sdata->keys[key_idx]); 209 WARN_ON(sdata->keys[key_idx]);
210 210
211 ret = 0; 211 ret = 0;
@@ -324,15 +324,10 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
324 struct net_device *dev, 324 struct net_device *dev,
325 u8 key_idx) 325 u8 key_idx)
326{ 326{
327 struct ieee80211_sub_if_data *sdata; 327 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
328
329 rcu_read_lock();
330 328
331 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
332 ieee80211_set_default_mgmt_key(sdata, key_idx); 329 ieee80211_set_default_mgmt_key(sdata, key_idx);
333 330
334 rcu_read_unlock();
335
336 return 0; 331 return 0;
337} 332}
338 333
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef470064b154..65e0ed6c2975 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -238,6 +238,7 @@ enum ieee80211_work_type {
238 IEEE80211_WORK_ABORT, 238 IEEE80211_WORK_ABORT,
239 IEEE80211_WORK_DIRECT_PROBE, 239 IEEE80211_WORK_DIRECT_PROBE,
240 IEEE80211_WORK_AUTH, 240 IEEE80211_WORK_AUTH,
241 IEEE80211_WORK_ASSOC_BEACON_WAIT,
241 IEEE80211_WORK_ASSOC, 242 IEEE80211_WORK_ASSOC,
242 IEEE80211_WORK_REMAIN_ON_CHANNEL, 243 IEEE80211_WORK_REMAIN_ON_CHANNEL,
243}; 244};
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 50d1cff23d8e..1b9d87ed143a 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -323,13 +323,15 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
323 if (!key) 323 if (!key)
324 return; 324 return;
325 325
326 ieee80211_key_disable_hw_accel(key); 326 if (key->local)
327 ieee80211_key_disable_hw_accel(key);
327 328
328 if (key->conf.alg == ALG_CCMP) 329 if (key->conf.alg == ALG_CCMP)
329 ieee80211_aes_key_free(key->u.ccmp.tfm); 330 ieee80211_aes_key_free(key->u.ccmp.tfm);
330 if (key->conf.alg == ALG_AES_CMAC) 331 if (key->conf.alg == ALG_AES_CMAC)
331 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); 332 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
332 ieee80211_debugfs_key_remove(key); 333 if (key->local)
334 ieee80211_debugfs_key_remove(key);
333 335
334 kfree(key); 336 kfree(key);
335} 337}
@@ -410,15 +412,12 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
410 __ieee80211_key_destroy(key); 412 __ieee80211_key_destroy(key);
411} 413}
412 414
413void ieee80211_key_free(struct ieee80211_key *key) 415void ieee80211_key_free(struct ieee80211_local *local,
416 struct ieee80211_key *key)
414{ 417{
415 struct ieee80211_local *local;
416
417 if (!key) 418 if (!key)
418 return; 419 return;
419 420
420 local = key->sdata->local;
421
422 mutex_lock(&local->key_mtx); 421 mutex_lock(&local->key_mtx);
423 __ieee80211_key_free(key); 422 __ieee80211_key_free(key);
424 mutex_unlock(&local->key_mtx); 423 mutex_unlock(&local->key_mtx);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index a3849fa3fce8..b665bbb7a471 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -135,7 +135,8 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
135void ieee80211_key_link(struct ieee80211_key *key, 135void ieee80211_key_link(struct ieee80211_key *key,
136 struct ieee80211_sub_if_data *sdata, 136 struct ieee80211_sub_if_data *sdata,
137 struct sta_info *sta); 137 struct sta_info *sta);
138void ieee80211_key_free(struct ieee80211_key *key); 138void ieee80211_key_free(struct ieee80211_local *local,
139 struct ieee80211_key *key);
139void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); 140void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
140void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, 141void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
141 int idx); 142 int idx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0e95c750ded9..7cc4f913a431 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -107,12 +107,15 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
107 if (scan_chan) { 107 if (scan_chan) {
108 chan = scan_chan; 108 chan = scan_chan;
109 channel_type = NL80211_CHAN_NO_HT; 109 channel_type = NL80211_CHAN_NO_HT;
110 local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
110 } else if (local->tmp_channel) { 111 } else if (local->tmp_channel) {
111 chan = scan_chan = local->tmp_channel; 112 chan = scan_chan = local->tmp_channel;
112 channel_type = local->tmp_channel_type; 113 channel_type = local->tmp_channel_type;
114 local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
113 } else { 115 } else {
114 chan = local->oper_channel; 116 chan = local->oper_channel;
115 channel_type = local->_oper_channel_type; 117 channel_type = local->_oper_channel_type;
118 local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
116 } 119 }
117 120
118 if (chan != local->hw.conf.channel || 121 if (chan != local->hw.conf.channel ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cf8d72196c65..b6c163ac22da 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -870,6 +870,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
870 870
871 ieee80211_led_assoc(local, 1); 871 ieee80211_led_assoc(local, 1);
872 872
873 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
874 bss_conf->dtim_period = bss->dtim_period;
875 else
876 bss_conf->dtim_period = 0;
877
873 bss_conf->assoc = 1; 878 bss_conf->assoc = 1;
874 /* 879 /*
875 * For now just always ask the driver to update the basic rateset 880 * For now just always ask the driver to update the basic rateset
@@ -1751,7 +1756,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1751 if (wk->sdata != sdata) 1756 if (wk->sdata != sdata)
1752 continue; 1757 continue;
1753 1758
1754 if (wk->type != IEEE80211_WORK_ASSOC) 1759 if (wk->type != IEEE80211_WORK_ASSOC &&
1760 wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
1755 continue; 1761 continue;
1756 1762
1757 if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) 1763 if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN))
@@ -2086,6 +2092,8 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2086 struct sk_buff *skb) 2092 struct sk_buff *skb)
2087{ 2093{
2088 struct ieee80211_mgmt *mgmt; 2094 struct ieee80211_mgmt *mgmt;
2095 struct ieee80211_rx_status *rx_status;
2096 struct ieee802_11_elems elems;
2089 u16 status; 2097 u16 status;
2090 2098
2091 if (!skb) { 2099 if (!skb) {
@@ -2093,6 +2101,19 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
2093 return WORK_DONE_DESTROY; 2101 return WORK_DONE_DESTROY;
2094 } 2102 }
2095 2103
2104 if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) {
2105 mutex_lock(&wk->sdata->u.mgd.mtx);
2106 rx_status = (void *) skb->cb;
2107 ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems);
2108 ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status,
2109 &elems, true);
2110 mutex_unlock(&wk->sdata->u.mgd.mtx);
2111
2112 wk->type = IEEE80211_WORK_ASSOC;
2113 /* not really done yet */
2114 return WORK_DONE_REQUEUE;
2115 }
2116
2096 mgmt = (void *)skb->data; 2117 mgmt = (void *)skb->data;
2097 status = le16_to_cpu(mgmt->u.assoc_resp.status_code); 2118 status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
2098 2119
@@ -2206,10 +2227,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2206 if (req->prev_bssid) 2227 if (req->prev_bssid)
2207 memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); 2228 memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN);
2208 2229
2209 wk->type = IEEE80211_WORK_ASSOC;
2210 wk->chan = req->bss->channel; 2230 wk->chan = req->bss->channel;
2211 wk->sdata = sdata; 2231 wk->sdata = sdata;
2212 wk->done = ieee80211_assoc_done; 2232 wk->done = ieee80211_assoc_done;
2233 if (!bss->dtim_period &&
2234 sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
2235 wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT;
2236 else
2237 wk->type = IEEE80211_WORK_ASSOC;
2213 2238
2214 if (req->use_mfp) { 2239 if (req->use_mfp) {
2215 ifmgd->mfp = IEEE80211_MFP_REQUIRED; 2240 ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@@ -2257,7 +2282,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2257 2282
2258 if (wk->type != IEEE80211_WORK_DIRECT_PROBE && 2283 if (wk->type != IEEE80211_WORK_DIRECT_PROBE &&
2259 wk->type != IEEE80211_WORK_AUTH && 2284 wk->type != IEEE80211_WORK_AUTH &&
2260 wk->type != IEEE80211_WORK_ASSOC) 2285 wk->type != IEEE80211_WORK_ASSOC &&
2286 wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
2261 continue; 2287 continue;
2262 2288
2263 if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) 2289 if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index f65ce6dcc8e2..778c604d7939 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -67,7 +67,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
67 for (i = rix; i >= 0; i--) 67 for (i = rix; i >= 0; i--)
68 if (mi->r[i].rix == rix) 68 if (mi->r[i].rix == rix)
69 break; 69 break;
70 WARN_ON(i < 0);
71 return i; 70 return i;
72} 71}
73 72
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index b5ace243546c..c5b465904e3b 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -636,7 +636,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
636 int i; 636 int i;
637 637
638 /* fall back to the old minstrel for legacy stations */ 638 /* fall back to the old minstrel for legacy stations */
639 if (sta && !sta->ht_cap.ht_supported) { 639 if (!sta->ht_cap.ht_supported) {
640 msp->is_ht = false; 640 msp->is_ht = false;
641 memset(&msp->legacy, 0, sizeof(msp->legacy)); 641 memset(&msp->legacy, 0, sizeof(msp->legacy));
642 msp->legacy.r = msp->ratelist; 642 msp->legacy.r = msp->ratelist;
@@ -748,7 +748,7 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
748 return msp; 748 return msp;
749 749
750error1: 750error1:
751 kfree(msp->sample_table); 751 kfree(msp->ratelist);
752error: 752error:
753 kfree(msp); 753 kfree(msp);
754 return NULL; 754 return NULL;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 439c98d93a79..41f20fb7e670 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -114,6 +114,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
114 bss->dtim_period = tim_ie->dtim_period; 114 bss->dtim_period = tim_ie->dtim_period;
115 } 115 }
116 116
117 /* If the beacon had no TIM IE, or it was invalid, use 1 */
118 if (beacon && !bss->dtim_period)
119 bss->dtim_period = 1;
120
117 /* replace old supported rates if we get new values */ 121 /* replace old supported rates if we get new values */
118 srlen = 0; 122 srlen = 0;
119 if (elems->supp_rates) { 123 if (elems->supp_rates) {
@@ -286,8 +290,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
286 local->scanning = 0; 290 local->scanning = 0;
287 local->scan_channel = NULL; 291 local->scan_channel = NULL;
288 292
289 drv_sw_scan_complete(local);
290
291 /* we only have to protect scan_req and hw/sw scan */ 293 /* we only have to protect scan_req and hw/sw scan */
292 mutex_unlock(&local->scan_mtx); 294 mutex_unlock(&local->scan_mtx);
293 295
@@ -297,6 +299,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
297 299
298 ieee80211_configure_filter(local); 300 ieee80211_configure_filter(local);
299 301
302 drv_sw_scan_complete(local);
303
300 ieee80211_offchannel_return(local, true); 304 ieee80211_offchannel_return(local, true);
301 305
302 done: 306 done:
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 67656cbf2b15..6d86f0c1ad04 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -647,7 +647,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
647 return ret; 647 return ret;
648 648
649 if (sta->key) { 649 if (sta->key) {
650 ieee80211_key_free(sta->key); 650 ieee80211_key_free(local, sta->key);
651 WARN_ON(sta->key); 651 WARN_ON(sta->key);
652 } 652 }
653 653
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 698d4718b1a4..c54db966926b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -576,17 +576,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
576} 576}
577 577
578static ieee80211_tx_result debug_noinline 578static ieee80211_tx_result debug_noinline
579ieee80211_tx_h_sta(struct ieee80211_tx_data *tx)
580{
581 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
582
583 if (tx->sta && tx->sta->uploaded)
584 info->control.sta = &tx->sta->sta;
585
586 return TX_CONTINUE;
587}
588
589static ieee80211_tx_result debug_noinline
590ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) 579ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
591{ 580{
592 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); 581 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
@@ -1307,6 +1296,11 @@ static int __ieee80211_tx(struct ieee80211_local *local,
1307 break; 1296 break;
1308 } 1297 }
1309 1298
1299 if (sta && sta->uploaded)
1300 info->control.sta = &sta->sta;
1301 else
1302 info->control.sta = NULL;
1303
1310 ret = drv_tx(local, skb); 1304 ret = drv_tx(local, skb);
1311 if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { 1305 if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
1312 dev_kfree_skb(skb); 1306 dev_kfree_skb(skb);
@@ -1346,7 +1340,6 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
1346 CALL_TXH(ieee80211_tx_h_check_assoc); 1340 CALL_TXH(ieee80211_tx_h_check_assoc);
1347 CALL_TXH(ieee80211_tx_h_ps_buf); 1341 CALL_TXH(ieee80211_tx_h_ps_buf);
1348 CALL_TXH(ieee80211_tx_h_select_key); 1342 CALL_TXH(ieee80211_tx_h_select_key);
1349 CALL_TXH(ieee80211_tx_h_sta);
1350 if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) 1343 if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
1351 CALL_TXH(ieee80211_tx_h_rate_ctrl); 1344 CALL_TXH(ieee80211_tx_h_rate_ctrl);
1352 1345
@@ -1942,11 +1935,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1942 h_pos += encaps_len; 1935 h_pos += encaps_len;
1943 } 1936 }
1944 1937
1938#ifdef CONFIG_MAC80211_MESH
1945 if (meshhdrlen > 0) { 1939 if (meshhdrlen > 0) {
1946 memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen); 1940 memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
1947 nh_pos += meshhdrlen; 1941 nh_pos += meshhdrlen;
1948 h_pos += meshhdrlen; 1942 h_pos += meshhdrlen;
1949 } 1943 }
1944#endif
1950 1945
1951 if (ieee80211_is_data_qos(fc)) { 1946 if (ieee80211_is_data_qos(fc)) {
1952 __le16 *qos_control; 1947 __le16 *qos_control;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 794792177376..748387d45bc0 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -803,8 +803,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
803 803
804 /* after reinitialize QoS TX queues setting to default, 804 /* after reinitialize QoS TX queues setting to default,
805 * disable QoS at all */ 805 * disable QoS at all */
806 sdata->vif.bss_conf.qos = sdata->vif.type != NL80211_IFTYPE_STATION; 806
807 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); 807 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
808 sdata->vif.bss_conf.qos =
809 sdata->vif.type != NL80211_IFTYPE_STATION;
810 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
811 }
808} 812}
809 813
810void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 814void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index c22a71c5cb45..81d4ad64184a 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -560,6 +560,22 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
560 return WORK_ACT_TIMEOUT; 560 return WORK_ACT_TIMEOUT;
561} 561}
562 562
563static enum work_action __must_check
564ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
565{
566 if (wk->started)
567 return WORK_ACT_TIMEOUT;
568
569 /*
570 * Wait up to one beacon interval ...
571 * should this be more if we miss one?
572 */
573 printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
574 wk->sdata->name, wk->filter_ta);
575 wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
576 return WORK_ACT_NONE;
577}
578
563static void ieee80211_auth_challenge(struct ieee80211_work *wk, 579static void ieee80211_auth_challenge(struct ieee80211_work *wk,
564 struct ieee80211_mgmt *mgmt, 580 struct ieee80211_mgmt *mgmt,
565 size_t len) 581 size_t len)
@@ -709,6 +725,25 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
709 return WORK_ACT_DONE; 725 return WORK_ACT_DONE;
710} 726}
711 727
728static enum work_action __must_check
729ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
730 struct ieee80211_mgmt *mgmt, size_t len)
731{
732 struct ieee80211_sub_if_data *sdata = wk->sdata;
733 struct ieee80211_local *local = sdata->local;
734
735 ASSERT_WORK_MTX(local);
736
737 if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
738 return WORK_ACT_MISMATCH;
739
740 if (len < 24 + 12)
741 return WORK_ACT_NONE;
742
743 printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
744 return WORK_ACT_DONE;
745}
746
712static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, 747static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
713 struct sk_buff *skb) 748 struct sk_buff *skb)
714{ 749{
@@ -731,6 +766,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
731 case IEEE80211_WORK_DIRECT_PROBE: 766 case IEEE80211_WORK_DIRECT_PROBE:
732 case IEEE80211_WORK_AUTH: 767 case IEEE80211_WORK_AUTH:
733 case IEEE80211_WORK_ASSOC: 768 case IEEE80211_WORK_ASSOC:
769 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
734 bssid = wk->filter_ta; 770 bssid = wk->filter_ta;
735 break; 771 break;
736 default: 772 default:
@@ -745,6 +781,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
745 continue; 781 continue;
746 782
747 switch (fc & IEEE80211_FCTL_STYPE) { 783 switch (fc & IEEE80211_FCTL_STYPE) {
784 case IEEE80211_STYPE_BEACON:
785 rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
786 break;
748 case IEEE80211_STYPE_PROBE_RESP: 787 case IEEE80211_STYPE_PROBE_RESP:
749 rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, 788 rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
750 rx_status); 789 rx_status);
@@ -916,6 +955,9 @@ static void ieee80211_work_work(struct work_struct *work)
916 case IEEE80211_WORK_REMAIN_ON_CHANNEL: 955 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
917 rma = ieee80211_remain_on_channel_timeout(wk); 956 rma = ieee80211_remain_on_channel_timeout(wk);
918 break; 957 break;
958 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
959 rma = ieee80211_assoc_beacon_wait(wk);
960 break;
919 } 961 }
920 962
921 wk->started = started; 963 wk->started = started;
@@ -1065,6 +1107,7 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
1065 case IEEE80211_STYPE_PROBE_RESP: 1107 case IEEE80211_STYPE_PROBE_RESP:
1066 case IEEE80211_STYPE_ASSOC_RESP: 1108 case IEEE80211_STYPE_ASSOC_RESP:
1067 case IEEE80211_STYPE_REASSOC_RESP: 1109 case IEEE80211_STYPE_REASSOC_RESP:
1110 case IEEE80211_STYPE_BEACON:
1068 skb_queue_tail(&local->work_skb_queue, skb); 1111 skb_queue_tail(&local->work_skb_queue, skb);
1069 ieee80211_queue_work(&local->hw, &local->work_work); 1112 ieee80211_queue_work(&local->hw, &local->work_work);
1070 return RX_QUEUED; 1113 return RX_QUEUED;