diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/Makefile | 4 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 6 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 4 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 33 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 32 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 79 | ||||
-rw-r--r-- | net/mac80211/iface.c | 7 | ||||
-rw-r--r-- | net/mac80211/key.c | 38 | ||||
-rw-r--r-- | net/mac80211/main.c | 16 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 6 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 1390 | ||||
-rw-r--r-- | net/mac80211/pm.c | 11 | ||||
-rw-r--r-- | net/mac80211/rate.c | 4 | ||||
-rw-r--r-- | net/mac80211/rate.h | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 22 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 252 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 40 | ||||
-rw-r--r-- | net/mac80211/util.c | 11 | ||||
-rw-r--r-- | net/mac80211/work.c | 815 |
21 files changed, 1298 insertions, 1483 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index d540c3b160f3..1be7a454aa77 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -9,7 +9,7 @@ mac80211-y := \ | |||
9 | scan.o offchannel.o \ | 9 | scan.o offchannel.o \ |
10 | ht.o agg-tx.o agg-rx.o \ | 10 | ht.o agg-tx.o agg-rx.o \ |
11 | ibss.o \ | 11 | ibss.o \ |
12 | mlme.o work.o \ | 12 | work.o \ |
13 | iface.o \ | 13 | iface.o \ |
14 | rate.o \ | 14 | rate.o \ |
15 | michael.o \ | 15 | michael.o \ |
@@ -25,7 +25,7 @@ mac80211-y := \ | |||
25 | wme.o \ | 25 | wme.o \ |
26 | event.o \ | 26 | event.o \ |
27 | chan.o \ | 27 | chan.o \ |
28 | driver-trace.o | 28 | driver-trace.o mlme.o |
29 | 29 | ||
30 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o | 30 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o |
31 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ | 31 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d15ba0d0de94..c3de921c8cfd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2028,7 +2028,7 @@ ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) | |||
2028 | if (wk->offchan_tx.wait && !wk->offchan_tx.status) | 2028 | if (wk->offchan_tx.wait && !wk->offchan_tx.status) |
2029 | cfg80211_mgmt_tx_status(wk->sdata->dev, | 2029 | cfg80211_mgmt_tx_status(wk->sdata->dev, |
2030 | (unsigned long) wk->offchan_tx.frame, | 2030 | (unsigned long) wk->offchan_tx.frame, |
2031 | wk->ie, wk->ie_len, false, GFP_KERNEL); | 2031 | wk->data, wk->data_len, false, GFP_KERNEL); |
2032 | 2032 | ||
2033 | return WORK_DONE_DESTROY; | 2033 | return WORK_DONE_DESTROY; |
2034 | } | 2034 | } |
@@ -2179,8 +2179,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2179 | wk->done = ieee80211_offchan_tx_done; | 2179 | wk->done = ieee80211_offchan_tx_done; |
2180 | wk->offchan_tx.frame = skb; | 2180 | wk->offchan_tx.frame = skb; |
2181 | wk->offchan_tx.wait = wait; | 2181 | wk->offchan_tx.wait = wait; |
2182 | wk->ie_len = len; | 2182 | wk->data_len = len; |
2183 | memcpy(wk->ie, buf, len); | 2183 | memcpy(wk->data, buf, len); |
2184 | 2184 | ||
2185 | ieee80211_add_work(wk); | 2185 | ieee80211_add_work(wk); |
2186 | return 0; | 2186 | return 0; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index affe64be9092..483e96ed95c1 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -263,6 +263,8 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
263 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); | 263 | sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); |
264 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) | 264 | if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) |
265 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); | 265 | sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); |
266 | if (local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE) | ||
267 | sf += snprintf(buf + sf, mxln - sf, "SCAN_WHILE_IDLE\n"); | ||
266 | 268 | ||
267 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | 269 | rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
268 | kfree(buf); | 270 | kfree(buf); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c8383712fdec..6d45804d09bc 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
64 | 64 | ||
65 | int res = scnprintf(buf, sizeof(buf), | 65 | int res = scnprintf(buf, sizeof(buf), |
66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
68 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 68 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
69 | TEST(SHORT_PREAMBLE), | 69 | TEST(SHORT_PREAMBLE), |
@@ -71,7 +71,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), |
74 | TEST(INSERTED)); | 74 | TEST(INSERTED), TEST(RATE_CONTROL)); |
75 | #undef TEST | 75 | #undef TEST |
76 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 76 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
77 | } | 77 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e8960ae39861..70dfb6415c20 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -253,6 +253,7 @@ static inline int drv_set_key(struct ieee80211_local *local, | |||
253 | 253 | ||
254 | might_sleep(); | 254 | might_sleep(); |
255 | 255 | ||
256 | sdata = get_bss_sdata(sdata); | ||
256 | check_sdata_in_driver(sdata); | 257 | check_sdata_in_driver(sdata); |
257 | 258 | ||
258 | trace_drv_set_key(local, cmd, sdata, sta, key); | 259 | trace_drv_set_key(local, cmd, sdata, sta, key); |
@@ -272,6 +273,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | |||
272 | if (sta) | 273 | if (sta) |
273 | ista = &sta->sta; | 274 | ista = &sta->sta; |
274 | 275 | ||
276 | sdata = get_bss_sdata(sdata); | ||
275 | check_sdata_in_driver(sdata); | 277 | check_sdata_in_driver(sdata); |
276 | 278 | ||
277 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); | 279 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); |
@@ -476,6 +478,37 @@ static inline void drv_sta_remove(struct ieee80211_local *local, | |||
476 | trace_drv_return_void(local); | 478 | trace_drv_return_void(local); |
477 | } | 479 | } |
478 | 480 | ||
481 | static inline __must_check | ||
482 | int drv_sta_state(struct ieee80211_local *local, | ||
483 | struct ieee80211_sub_if_data *sdata, | ||
484 | struct sta_info *sta, | ||
485 | enum ieee80211_sta_state old_state, | ||
486 | enum ieee80211_sta_state new_state) | ||
487 | { | ||
488 | int ret = 0; | ||
489 | |||
490 | might_sleep(); | ||
491 | |||
492 | sdata = get_bss_sdata(sdata); | ||
493 | check_sdata_in_driver(sdata); | ||
494 | |||
495 | trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); | ||
496 | if (local->ops->sta_state) { | ||
497 | ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, | ||
498 | old_state, new_state); | ||
499 | } else if (old_state == IEEE80211_STA_AUTH && | ||
500 | new_state == IEEE80211_STA_ASSOC) { | ||
501 | ret = drv_sta_add(local, sdata, &sta->sta); | ||
502 | if (ret == 0) | ||
503 | sta->uploaded = true; | ||
504 | } else if (old_state == IEEE80211_STA_ASSOC && | ||
505 | new_state == IEEE80211_STA_AUTH) { | ||
506 | drv_sta_remove(local, sdata, &sta->sta); | ||
507 | } | ||
508 | trace_drv_return_int(local, ret); | ||
509 | return ret; | ||
510 | } | ||
511 | |||
479 | static inline int drv_conf_tx(struct ieee80211_local *local, | 512 | static inline int drv_conf_tx(struct ieee80211_local *local, |
480 | struct ieee80211_sub_if_data *sdata, u16 queue, | 513 | struct ieee80211_sub_if_data *sdata, u16 queue, |
481 | const struct ieee80211_tx_queue_params *params) | 514 | const struct ieee80211_tx_queue_params *params) |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 6e9df8fd8fb8..384e2f08c187 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -635,6 +635,38 @@ TRACE_EVENT(drv_sta_notify, | |||
635 | ) | 635 | ) |
636 | ); | 636 | ); |
637 | 637 | ||
638 | TRACE_EVENT(drv_sta_state, | ||
639 | TP_PROTO(struct ieee80211_local *local, | ||
640 | struct ieee80211_sub_if_data *sdata, | ||
641 | struct ieee80211_sta *sta, | ||
642 | enum ieee80211_sta_state old_state, | ||
643 | enum ieee80211_sta_state new_state), | ||
644 | |||
645 | TP_ARGS(local, sdata, sta, old_state, new_state), | ||
646 | |||
647 | TP_STRUCT__entry( | ||
648 | LOCAL_ENTRY | ||
649 | VIF_ENTRY | ||
650 | STA_ENTRY | ||
651 | __field(u32, old_state) | ||
652 | __field(u32, new_state) | ||
653 | ), | ||
654 | |||
655 | TP_fast_assign( | ||
656 | LOCAL_ASSIGN; | ||
657 | VIF_ASSIGN; | ||
658 | STA_ASSIGN; | ||
659 | __entry->old_state = old_state; | ||
660 | __entry->new_state = new_state; | ||
661 | ), | ||
662 | |||
663 | TP_printk( | ||
664 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " state: %d->%d", | ||
665 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, | ||
666 | __entry->old_state, __entry->new_state | ||
667 | ) | ||
668 | ); | ||
669 | |||
638 | TRACE_EVENT(drv_sta_add, | 670 | TRACE_EVENT(drv_sta_add, |
639 | TP_PROTO(struct ieee80211_local *local, | 671 | TP_PROTO(struct ieee80211_local *local, |
640 | struct ieee80211_sub_if_data *sdata, | 672 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 7b3a0b0aa246..8361da4b36ab 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -268,7 +268,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
268 | 268 | ||
269 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 269 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
270 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 270 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); |
271 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); | 271 | /* authorize the station only if the network is not RSN protected. If |
272 | * not wait for the userspace to authorize it */ | ||
273 | if (!sta->sdata->u.ibss.control_port) | ||
274 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
272 | 275 | ||
273 | rate_control_rate_init(sta); | 276 | rate_control_rate_init(sta); |
274 | 277 | ||
@@ -1075,6 +1078,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1075 | sdata->u.ibss.fixed_bssid = false; | 1078 | sdata->u.ibss.fixed_bssid = false; |
1076 | 1079 | ||
1077 | sdata->u.ibss.privacy = params->privacy; | 1080 | sdata->u.ibss.privacy = params->privacy; |
1081 | sdata->u.ibss.control_port = params->control_port; | ||
1078 | sdata->u.ibss.basic_rates = params->basic_rates; | 1082 | sdata->u.ibss.basic_rates = params->basic_rates; |
1079 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, | 1083 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, |
1080 | sizeof(params->mcast_rate)); | 1084 | sizeof(params->mcast_rate)); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d47e8c110b16..74594f012cd3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -280,10 +280,6 @@ struct mesh_preq_queue { | |||
280 | 280 | ||
281 | enum ieee80211_work_type { | 281 | enum ieee80211_work_type { |
282 | IEEE80211_WORK_ABORT, | 282 | IEEE80211_WORK_ABORT, |
283 | IEEE80211_WORK_DIRECT_PROBE, | ||
284 | IEEE80211_WORK_AUTH, | ||
285 | IEEE80211_WORK_ASSOC_BEACON_WAIT, | ||
286 | IEEE80211_WORK_ASSOC, | ||
287 | IEEE80211_WORK_REMAIN_ON_CHANNEL, | 283 | IEEE80211_WORK_REMAIN_ON_CHANNEL, |
288 | IEEE80211_WORK_OFFCHANNEL_TX, | 284 | IEEE80211_WORK_OFFCHANNEL_TX, |
289 | }; | 285 | }; |
@@ -316,36 +312,10 @@ struct ieee80211_work { | |||
316 | unsigned long timeout; | 312 | unsigned long timeout; |
317 | enum ieee80211_work_type type; | 313 | enum ieee80211_work_type type; |
318 | 314 | ||
319 | u8 filter_ta[ETH_ALEN]; | ||
320 | |||
321 | bool started; | 315 | bool started; |
322 | 316 | ||
323 | union { | 317 | union { |
324 | struct { | 318 | struct { |
325 | int tries; | ||
326 | u16 algorithm, transaction; | ||
327 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
328 | u8 ssid_len; | ||
329 | u8 key[WLAN_KEY_LEN_WEP104]; | ||
330 | u8 key_len, key_idx; | ||
331 | bool privacy; | ||
332 | bool synced; | ||
333 | } probe_auth; | ||
334 | struct { | ||
335 | struct cfg80211_bss *bss; | ||
336 | const u8 *supp_rates; | ||
337 | const u8 *ht_information_ie; | ||
338 | enum ieee80211_smps_mode smps; | ||
339 | int tries; | ||
340 | u16 capability; | ||
341 | u8 prev_bssid[ETH_ALEN]; | ||
342 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
343 | u8 ssid_len; | ||
344 | u8 supp_rates_len; | ||
345 | bool wmm_used, use_11n, uapsd_used; | ||
346 | bool synced; | ||
347 | } assoc; | ||
348 | struct { | ||
349 | u32 duration; | 319 | u32 duration; |
350 | } remain; | 320 | } remain; |
351 | struct { | 321 | struct { |
@@ -355,9 +325,8 @@ struct ieee80211_work { | |||
355 | } offchan_tx; | 325 | } offchan_tx; |
356 | }; | 326 | }; |
357 | 327 | ||
358 | int ie_len; | 328 | size_t data_len; |
359 | /* must be last */ | 329 | u8 data[]; |
360 | u8 ie[0]; | ||
361 | }; | 330 | }; |
362 | 331 | ||
363 | /* flags used in struct ieee80211_if_managed.flags */ | 332 | /* flags used in struct ieee80211_if_managed.flags */ |
@@ -373,6 +342,43 @@ enum ieee80211_sta_flags { | |||
373 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), | 342 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), |
374 | }; | 343 | }; |
375 | 344 | ||
345 | struct ieee80211_mgd_auth_data { | ||
346 | struct cfg80211_bss *bss; | ||
347 | unsigned long timeout; | ||
348 | int tries; | ||
349 | u16 algorithm, expected_transaction; | ||
350 | |||
351 | u8 key[WLAN_KEY_LEN_WEP104]; | ||
352 | u8 key_len, key_idx; | ||
353 | bool synced; | ||
354 | bool done; | ||
355 | |||
356 | size_t ie_len; | ||
357 | u8 ie[]; | ||
358 | }; | ||
359 | |||
360 | struct ieee80211_mgd_assoc_data { | ||
361 | struct cfg80211_bss *bss; | ||
362 | const u8 *supp_rates; | ||
363 | const u8 *ht_information_ie; | ||
364 | |||
365 | unsigned long timeout; | ||
366 | int tries; | ||
367 | |||
368 | u16 capability; | ||
369 | u8 prev_bssid[ETH_ALEN]; | ||
370 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
371 | u8 ssid_len; | ||
372 | u8 supp_rates_len; | ||
373 | bool wmm_used, uapsd_used; | ||
374 | bool have_beacon; | ||
375 | bool sent_assoc; | ||
376 | bool synced; | ||
377 | |||
378 | size_t ie_len; | ||
379 | u8 ie[]; | ||
380 | }; | ||
381 | |||
376 | struct ieee80211_if_managed { | 382 | struct ieee80211_if_managed { |
377 | struct timer_list timer; | 383 | struct timer_list timer; |
378 | struct timer_list conn_mon_timer; | 384 | struct timer_list conn_mon_timer; |
@@ -389,6 +395,8 @@ struct ieee80211_if_managed { | |||
389 | 395 | ||
390 | struct mutex mtx; | 396 | struct mutex mtx; |
391 | struct cfg80211_bss *associated; | 397 | struct cfg80211_bss *associated; |
398 | struct ieee80211_mgd_auth_data *auth_data; | ||
399 | struct ieee80211_mgd_assoc_data *assoc_data; | ||
392 | 400 | ||
393 | u8 bssid[ETH_ALEN]; | 401 | u8 bssid[ETH_ALEN]; |
394 | 402 | ||
@@ -470,6 +478,8 @@ struct ieee80211_if_ibss { | |||
470 | bool fixed_channel; | 478 | bool fixed_channel; |
471 | bool privacy; | 479 | bool privacy; |
472 | 480 | ||
481 | bool control_port; | ||
482 | |||
473 | u8 bssid[ETH_ALEN]; | 483 | u8 bssid[ETH_ALEN]; |
474 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 484 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
475 | u8 ssid_len, ie_len; | 485 | u8 ssid_len, ie_len; |
@@ -770,7 +780,6 @@ struct ieee80211_local { | |||
770 | struct list_head work_list; | 780 | struct list_head work_list; |
771 | struct timer_list work_timer; | 781 | struct timer_list work_timer; |
772 | struct work_struct work_work; | 782 | struct work_struct work_work; |
773 | struct sk_buff_head work_skb_queue; | ||
774 | 783 | ||
775 | /* | 784 | /* |
776 | * private workqueue to mac80211. mac80211 makes this accessible | 785 | * private workqueue to mac80211. mac80211 makes this accessible |
@@ -1437,8 +1446,6 @@ void ieee80211_work_init(struct ieee80211_local *local); | |||
1437 | void ieee80211_add_work(struct ieee80211_work *wk); | 1446 | void ieee80211_add_work(struct ieee80211_work *wk); |
1438 | void free_work(struct ieee80211_work *wk); | 1447 | void free_work(struct ieee80211_work *wk); |
1439 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); | 1448 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); |
1440 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | ||
1441 | struct sk_buff *skb); | ||
1442 | int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | 1449 | int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, |
1443 | struct ieee80211_channel *chan, | 1450 | struct ieee80211_channel *chan, |
1444 | enum nl80211_channel_type channel_type, | 1451 | enum nl80211_channel_type channel_type, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2efd595b2f7a..6b3cd65d1e07 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1310,7 +1310,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1310 | 1310 | ||
1311 | /* do not count disabled managed interfaces */ | 1311 | /* do not count disabled managed interfaces */ |
1312 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1312 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1313 | !sdata->u.mgd.associated) { | 1313 | !sdata->u.mgd.associated && |
1314 | !sdata->u.mgd.auth_data && | ||
1315 | !sdata->u.mgd.assoc_data) { | ||
1314 | sdata->vif.bss_conf.idle = true; | 1316 | sdata->vif.bss_conf.idle = true; |
1315 | continue; | 1317 | continue; |
1316 | } | 1318 | } |
@@ -1330,7 +1332,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1330 | wk->sdata->vif.bss_conf.idle = false; | 1332 | wk->sdata->vif.bss_conf.idle = false; |
1331 | } | 1333 | } |
1332 | 1334 | ||
1333 | if (local->scan_sdata) { | 1335 | if (local->scan_sdata && |
1336 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
1334 | scanning = true; | 1337 | scanning = true; |
1335 | local->scan_sdata->vif.bss_conf.idle = false; | 1338 | local->scan_sdata->vif.bss_conf.idle = false; |
1336 | } | 1339 | } |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 87a89741432d..e8616b3ff636 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -54,14 +54,6 @@ static void assert_key_lock(struct ieee80211_local *local) | |||
54 | lockdep_assert_held(&local->key_mtx); | 54 | lockdep_assert_held(&local->key_mtx); |
55 | } | 55 | } |
56 | 56 | ||
57 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | ||
58 | { | ||
59 | if (key->sta) | ||
60 | return &key->sta->sta; | ||
61 | |||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) | 57 | static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) |
66 | { | 58 | { |
67 | /* | 59 | /* |
@@ -95,7 +87,7 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) | |||
95 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 87 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
96 | { | 88 | { |
97 | struct ieee80211_sub_if_data *sdata; | 89 | struct ieee80211_sub_if_data *sdata; |
98 | struct ieee80211_sta *sta; | 90 | struct sta_info *sta; |
99 | int ret; | 91 | int ret; |
100 | 92 | ||
101 | might_sleep(); | 93 | might_sleep(); |
@@ -105,7 +97,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
105 | 97 | ||
106 | assert_key_lock(key->local); | 98 | assert_key_lock(key->local); |
107 | 99 | ||
108 | sta = get_sta_for_key(key); | 100 | sta = key->sta; |
109 | 101 | ||
110 | /* | 102 | /* |
111 | * If this is a per-STA GTK, check if it | 103 | * If this is a per-STA GTK, check if it |
@@ -115,6 +107,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
115 | !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) | 107 | !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) |
116 | goto out_unsupported; | 108 | goto out_unsupported; |
117 | 109 | ||
110 | if (sta && !sta->uploaded) | ||
111 | goto out_unsupported; | ||
112 | |||
118 | sdata = key->sdata; | 113 | sdata = key->sdata; |
119 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | 114 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
120 | /* | 115 | /* |
@@ -123,12 +118,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
123 | */ | 118 | */ |
124 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 119 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
125 | goto out_unsupported; | 120 | goto out_unsupported; |
126 | sdata = container_of(sdata->bss, | ||
127 | struct ieee80211_sub_if_data, | ||
128 | u.ap); | ||
129 | } | 121 | } |
130 | 122 | ||
131 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); | 123 | ret = drv_set_key(key->local, SET_KEY, sdata, |
124 | sta ? &sta->sta : NULL, &key->conf); | ||
132 | 125 | ||
133 | if (!ret) { | 126 | if (!ret) { |
134 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 127 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
@@ -147,7 +140,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
147 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) | 140 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) |
148 | wiphy_err(key->local->hw.wiphy, | 141 | wiphy_err(key->local->hw.wiphy, |
149 | "failed to set key (%d, %pM) to hardware (%d)\n", | 142 | "failed to set key (%d, %pM) to hardware (%d)\n", |
150 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 143 | key->conf.keyidx, |
144 | sta ? sta->sta.addr : bcast_addr, ret); | ||
151 | 145 | ||
152 | out_unsupported: | 146 | out_unsupported: |
153 | switch (key->conf.cipher) { | 147 | switch (key->conf.cipher) { |
@@ -166,7 +160,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
166 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 160 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
167 | { | 161 | { |
168 | struct ieee80211_sub_if_data *sdata; | 162 | struct ieee80211_sub_if_data *sdata; |
169 | struct ieee80211_sta *sta; | 163 | struct sta_info *sta; |
170 | int ret; | 164 | int ret; |
171 | 165 | ||
172 | might_sleep(); | 166 | might_sleep(); |
@@ -179,7 +173,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
179 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 173 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) |
180 | return; | 174 | return; |
181 | 175 | ||
182 | sta = get_sta_for_key(key); | 176 | sta = key->sta; |
183 | sdata = key->sdata; | 177 | sdata = key->sdata; |
184 | 178 | ||
185 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | 179 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || |
@@ -187,18 +181,14 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
187 | (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) | 181 | (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))) |
188 | increment_tailroom_need_count(sdata); | 182 | increment_tailroom_need_count(sdata); |
189 | 183 | ||
190 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
191 | sdata = container_of(sdata->bss, | ||
192 | struct ieee80211_sub_if_data, | ||
193 | u.ap); | ||
194 | |||
195 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, | 184 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, |
196 | sta, &key->conf); | 185 | sta ? &sta->sta : NULL, &key->conf); |
197 | 186 | ||
198 | if (ret) | 187 | if (ret) |
199 | wiphy_err(key->local->hw.wiphy, | 188 | wiphy_err(key->local->hw.wiphy, |
200 | "failed to remove key (%d, %pM) from hardware (%d)\n", | 189 | "failed to remove key (%d, %pM) from hardware (%d)\n", |
201 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 190 | key->conf.keyidx, |
191 | sta ? sta->sta.addr : bcast_addr, ret); | ||
202 | 192 | ||
203 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 193 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
204 | } | 194 | } |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0ec18618fcfe..2306d7514fff 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -199,15 +199,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
199 | return; | 199 | return; |
200 | 200 | ||
201 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 201 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
202 | /* | 202 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; |
203 | * While not associated, claim a BSSID of all-zeroes | ||
204 | * so that drivers don't do any weird things with the | ||
205 | * BSSID at that time. | ||
206 | */ | ||
207 | if (sdata->vif.bss_conf.assoc) | ||
208 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | ||
209 | else | ||
210 | sdata->vif.bss_conf.bssid = zero; | ||
211 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 203 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
212 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 204 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
213 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 205 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
@@ -535,6 +527,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
535 | int priv_size, i; | 527 | int priv_size, i; |
536 | struct wiphy *wiphy; | 528 | struct wiphy *wiphy; |
537 | 529 | ||
530 | if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) | ||
531 | return NULL; | ||
532 | |||
538 | /* Ensure 32-byte alignment of our private data and hw private data. | 533 | /* Ensure 32-byte alignment of our private data and hw private data. |
539 | * We use the wiphy priv data for both our ieee80211_local and for | 534 | * We use the wiphy priv data for both our ieee80211_local and for |
540 | * the driver's private data | 535 | * the driver's private data |
@@ -702,6 +697,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
702 | ) | 697 | ) |
703 | return -EINVAL; | 698 | return -EINVAL; |
704 | 699 | ||
700 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | ||
701 | return -EINVAL; | ||
702 | |||
705 | if (hw->max_report_rates == 0) | 703 | if (hw->max_report_rates == 0) |
706 | hw->max_report_rates = hw->max_rates; | 704 | hw->max_report_rates = hw->max_rates; |
707 | 705 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index edf167e3b8f3..dc51669e67d8 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -336,7 +336,7 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | |||
336 | } | 336 | } |
337 | 337 | ||
338 | 338 | ||
339 | static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst, | 339 | static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst, |
340 | struct ieee80211_sub_if_data *sdata) | 340 | struct ieee80211_sub_if_data *sdata) |
341 | { | 341 | { |
342 | struct mesh_path *mpath; | 342 | struct mesh_path *mpath; |
@@ -371,12 +371,12 @@ static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst, | |||
371 | */ | 371 | */ |
372 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | 372 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) |
373 | { | 373 | { |
374 | return path_lookup(rcu_dereference(mesh_paths), dst, sdata); | 374 | return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); |
375 | } | 375 | } |
376 | 376 | ||
377 | struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | 377 | struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) |
378 | { | 378 | { |
379 | return path_lookup(rcu_dereference(mpp_paths), dst, sdata); | 379 | return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata); |
380 | } | 380 | } |
381 | 381 | ||
382 | 382 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 49fd1acd5d15..52133dab9297 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -30,6 +30,12 @@ | |||
30 | #include "rate.h" | 30 | #include "rate.h" |
31 | #include "led.h" | 31 | #include "led.h" |
32 | 32 | ||
33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
34 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
35 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) | ||
36 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
37 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
38 | |||
33 | static int max_nullfunc_tries = 2; | 39 | static int max_nullfunc_tries = 2; |
34 | module_param(max_nullfunc_tries, int, 0644); | 40 | module_param(max_nullfunc_tries, int, 0644); |
35 | MODULE_PARM_DESC(max_nullfunc_tries, | 41 | MODULE_PARM_DESC(max_nullfunc_tries, |
@@ -97,6 +103,15 @@ enum rx_mgmt_action { | |||
97 | 103 | ||
98 | /* caller must call cfg80211_send_disassoc() */ | 104 | /* caller must call cfg80211_send_disassoc() */ |
99 | RX_MGMT_CFG80211_DISASSOC, | 105 | RX_MGMT_CFG80211_DISASSOC, |
106 | |||
107 | /* caller must call cfg80211_send_rx_auth() */ | ||
108 | RX_MGMT_CFG80211_RX_AUTH, | ||
109 | |||
110 | /* caller must call cfg80211_send_rx_assoc() */ | ||
111 | RX_MGMT_CFG80211_RX_ASSOC, | ||
112 | |||
113 | /* caller must call cfg80211_send_assoc_timeout() */ | ||
114 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, | ||
100 | }; | 115 | }; |
101 | 116 | ||
102 | /* utils */ | 117 | /* utils */ |
@@ -115,8 +130,7 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | |||
115 | * has happened -- the work that runs from this timer will | 130 | * has happened -- the work that runs from this timer will |
116 | * do that. | 131 | * do that. |
117 | */ | 132 | */ |
118 | static void run_again(struct ieee80211_if_managed *ifmgd, | 133 | static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout) |
119 | unsigned long timeout) | ||
120 | { | 134 | { |
121 | ASSERT_MGD_MTX(ifmgd); | 135 | ASSERT_MGD_MTX(ifmgd); |
122 | 136 | ||
@@ -284,6 +298,319 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
284 | 298 | ||
285 | /* frame sending functions */ | 299 | /* frame sending functions */ |
286 | 300 | ||
301 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
302 | struct ieee80211_supported_band *sband, | ||
303 | u32 *rates) | ||
304 | { | ||
305 | int i, j, count; | ||
306 | *rates = 0; | ||
307 | count = 0; | ||
308 | for (i = 0; i < supp_rates_len; i++) { | ||
309 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
310 | |||
311 | for (j = 0; j < sband->n_bitrates; j++) | ||
312 | if (sband->bitrates[j].bitrate == rate) { | ||
313 | *rates |= BIT(j); | ||
314 | count++; | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return count; | ||
320 | } | ||
321 | |||
322 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | ||
323 | struct sk_buff *skb, const u8 *ht_info_ie, | ||
324 | struct ieee80211_supported_band *sband, | ||
325 | struct ieee80211_channel *channel, | ||
326 | enum ieee80211_smps_mode smps) | ||
327 | { | ||
328 | struct ieee80211_ht_info *ht_info; | ||
329 | u8 *pos; | ||
330 | u32 flags = channel->flags; | ||
331 | u16 cap; | ||
332 | struct ieee80211_sta_ht_cap ht_cap; | ||
333 | |||
334 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | ||
335 | |||
336 | if (!sband->ht_cap.ht_supported) | ||
337 | return; | ||
338 | |||
339 | if (!ht_info_ie) | ||
340 | return; | ||
341 | |||
342 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | ||
343 | return; | ||
344 | |||
345 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
346 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
347 | |||
348 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | ||
349 | |||
350 | /* determine capability flags */ | ||
351 | cap = ht_cap.cap; | ||
352 | |||
353 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
354 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
355 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
356 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
357 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
358 | } | ||
359 | break; | ||
360 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
361 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
362 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
363 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
364 | } | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | /* set SM PS mode properly */ | ||
369 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
370 | switch (smps) { | ||
371 | case IEEE80211_SMPS_AUTOMATIC: | ||
372 | case IEEE80211_SMPS_NUM_MODES: | ||
373 | WARN_ON(1); | ||
374 | case IEEE80211_SMPS_OFF: | ||
375 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
376 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
377 | break; | ||
378 | case IEEE80211_SMPS_STATIC: | ||
379 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
380 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
381 | break; | ||
382 | case IEEE80211_SMPS_DYNAMIC: | ||
383 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
384 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | /* reserve and fill IE */ | ||
389 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
390 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | ||
391 | } | ||
392 | |||
393 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | ||
394 | { | ||
395 | struct ieee80211_local *local = sdata->local; | ||
396 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
397 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
398 | struct sk_buff *skb; | ||
399 | struct ieee80211_mgmt *mgmt; | ||
400 | u8 *pos, qos_info; | ||
401 | size_t offset = 0, noffset; | ||
402 | int i, count, rates_len, supp_rates_len; | ||
403 | u16 capab; | ||
404 | struct ieee80211_supported_band *sband; | ||
405 | u32 rates = 0; | ||
406 | struct ieee80211_bss *bss = (void *)assoc_data->bss->priv; | ||
407 | |||
408 | lockdep_assert_held(&ifmgd->mtx); | ||
409 | |||
410 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||
411 | |||
412 | if (assoc_data->supp_rates_len) { | ||
413 | /* | ||
414 | * Get all rates supported by the device and the AP as | ||
415 | * some APs don't like getting a superset of their rates | ||
416 | * in the association request (e.g. D-Link DAP 1353 in | ||
417 | * b-only mode)... | ||
418 | */ | ||
419 | rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, | ||
420 | assoc_data->supp_rates_len, | ||
421 | sband, &rates); | ||
422 | } else { | ||
423 | /* | ||
424 | * In case AP not provide any supported rates information | ||
425 | * before association, we send information element(s) with | ||
426 | * all rates that we support. | ||
427 | */ | ||
428 | rates = ~0; | ||
429 | rates_len = sband->n_bitrates; | ||
430 | } | ||
431 | |||
432 | skb = alloc_skb(local->hw.extra_tx_headroom + | ||
433 | sizeof(*mgmt) + /* bit too much but doesn't matter */ | ||
434 | 2 + assoc_data->ssid_len + /* SSID */ | ||
435 | 4 + rates_len + /* (extended) rates */ | ||
436 | 4 + /* power capability */ | ||
437 | 2 + 2 * sband->n_channels + /* supported channels */ | ||
438 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||
439 | assoc_data->ie_len + /* extra IEs */ | ||
440 | 9, /* WMM */ | ||
441 | GFP_KERNEL); | ||
442 | if (!skb) | ||
443 | return; | ||
444 | |||
445 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
446 | |||
447 | capab = WLAN_CAPABILITY_ESS; | ||
448 | |||
449 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
450 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
451 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
452 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
453 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
454 | } | ||
455 | |||
456 | if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY) | ||
457 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
458 | |||
459 | if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
460 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
461 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
462 | |||
463 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
464 | memset(mgmt, 0, 24); | ||
465 | memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); | ||
466 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
467 | memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN); | ||
468 | |||
469 | if (!is_zero_ether_addr(assoc_data->prev_bssid)) { | ||
470 | skb_put(skb, 10); | ||
471 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
472 | IEEE80211_STYPE_REASSOC_REQ); | ||
473 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
474 | mgmt->u.reassoc_req.listen_interval = | ||
475 | cpu_to_le16(local->hw.conf.listen_interval); | ||
476 | memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, | ||
477 | ETH_ALEN); | ||
478 | } else { | ||
479 | skb_put(skb, 4); | ||
480 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
481 | IEEE80211_STYPE_ASSOC_REQ); | ||
482 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
483 | mgmt->u.assoc_req.listen_interval = | ||
484 | cpu_to_le16(local->hw.conf.listen_interval); | ||
485 | } | ||
486 | |||
487 | /* SSID */ | ||
488 | pos = skb_put(skb, 2 + assoc_data->ssid_len); | ||
489 | *pos++ = WLAN_EID_SSID; | ||
490 | *pos++ = assoc_data->ssid_len; | ||
491 | memcpy(pos, assoc_data->ssid, assoc_data->ssid_len); | ||
492 | |||
493 | /* add all rates which were marked to be used above */ | ||
494 | supp_rates_len = rates_len; | ||
495 | if (supp_rates_len > 8) | ||
496 | supp_rates_len = 8; | ||
497 | |||
498 | pos = skb_put(skb, supp_rates_len + 2); | ||
499 | *pos++ = WLAN_EID_SUPP_RATES; | ||
500 | *pos++ = supp_rates_len; | ||
501 | |||
502 | count = 0; | ||
503 | for (i = 0; i < sband->n_bitrates; i++) { | ||
504 | if (BIT(i) & rates) { | ||
505 | int rate = sband->bitrates[i].bitrate; | ||
506 | *pos++ = (u8) (rate / 5); | ||
507 | if (++count == 8) | ||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | if (rates_len > count) { | ||
513 | pos = skb_put(skb, rates_len - count + 2); | ||
514 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
515 | *pos++ = rates_len - count; | ||
516 | |||
517 | for (i++; i < sband->n_bitrates; i++) { | ||
518 | if (BIT(i) & rates) { | ||
519 | int rate = sband->bitrates[i].bitrate; | ||
520 | *pos++ = (u8) (rate / 5); | ||
521 | } | ||
522 | } | ||
523 | } | ||
524 | |||
525 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
526 | /* 1. power capabilities */ | ||
527 | pos = skb_put(skb, 4); | ||
528 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
529 | *pos++ = 2; | ||
530 | *pos++ = 0; /* min tx power */ | ||
531 | *pos++ = local->oper_channel->max_power; /* max tx power */ | ||
532 | |||
533 | /* 2. supported channels */ | ||
534 | /* TODO: get this in reg domain format */ | ||
535 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
536 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
537 | *pos++ = 2 * sband->n_channels; | ||
538 | for (i = 0; i < sband->n_channels; i++) { | ||
539 | *pos++ = ieee80211_frequency_to_channel( | ||
540 | sband->channels[i].center_freq); | ||
541 | *pos++ = 1; /* one channel in the subband*/ | ||
542 | } | ||
543 | } | ||
544 | |||
545 | /* if present, add any custom IEs that go before HT */ | ||
546 | if (assoc_data->ie_len && assoc_data->ie) { | ||
547 | static const u8 before_ht[] = { | ||
548 | WLAN_EID_SSID, | ||
549 | WLAN_EID_SUPP_RATES, | ||
550 | WLAN_EID_EXT_SUPP_RATES, | ||
551 | WLAN_EID_PWR_CAPABILITY, | ||
552 | WLAN_EID_SUPPORTED_CHANNELS, | ||
553 | WLAN_EID_RSN, | ||
554 | WLAN_EID_QOS_CAPA, | ||
555 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
556 | WLAN_EID_MOBILITY_DOMAIN, | ||
557 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
558 | }; | ||
559 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | ||
560 | before_ht, ARRAY_SIZE(before_ht), | ||
561 | offset); | ||
562 | pos = skb_put(skb, noffset - offset); | ||
563 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
564 | offset = noffset; | ||
565 | } | ||
566 | |||
567 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N) && | ||
568 | bss->wmm_used && local->hw.queues >= 4) | ||
569 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie, | ||
570 | sband, local->oper_channel, ifmgd->ap_smps); | ||
571 | |||
572 | /* if present, add any custom non-vendor IEs that go after HT */ | ||
573 | if (assoc_data->ie_len && assoc_data->ie) { | ||
574 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | ||
575 | assoc_data->ie_len, | ||
576 | offset); | ||
577 | pos = skb_put(skb, noffset - offset); | ||
578 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
579 | offset = noffset; | ||
580 | } | ||
581 | |||
582 | if (assoc_data->wmm_used && local->hw.queues >= 4) { | ||
583 | if (assoc_data->uapsd_used) { | ||
584 | qos_info = local->uapsd_queues; | ||
585 | qos_info |= (local->uapsd_max_sp_len << | ||
586 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
587 | } else { | ||
588 | qos_info = 0; | ||
589 | } | ||
590 | |||
591 | pos = skb_put(skb, 9); | ||
592 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
593 | *pos++ = 7; /* len */ | ||
594 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
595 | *pos++ = 0x50; | ||
596 | *pos++ = 0xf2; | ||
597 | *pos++ = 2; /* WME */ | ||
598 | *pos++ = 0; /* WME info */ | ||
599 | *pos++ = 1; /* WME ver */ | ||
600 | *pos++ = qos_info; | ||
601 | } | ||
602 | |||
603 | /* add any remaining custom (i.e. vendor specific here) IEs */ | ||
604 | if (assoc_data->ie_len && assoc_data->ie) { | ||
605 | noffset = assoc_data->ie_len; | ||
606 | pos = skb_put(skb, noffset - offset); | ||
607 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
608 | } | ||
609 | |||
610 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
611 | ieee80211_tx_skb(sdata, skb); | ||
612 | } | ||
613 | |||
287 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 614 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
288 | const u8 *bssid, u16 stype, u16 reason, | 615 | const u8 *bssid, u16 stype, u16 reason, |
289 | void *cookie, bool send_frame) | 616 | void *cookie, bool send_frame) |
@@ -1423,6 +1750,135 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) | |||
1423 | EXPORT_SYMBOL(ieee80211_connection_loss); | 1750 | EXPORT_SYMBOL(ieee80211_connection_loss); |
1424 | 1751 | ||
1425 | 1752 | ||
1753 | static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | ||
1754 | bool assoc) | ||
1755 | { | ||
1756 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | ||
1757 | |||
1758 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
1759 | |||
1760 | if (auth_data->synced) | ||
1761 | drv_finish_tx_sync(sdata->local, sdata, | ||
1762 | auth_data->bss->bssid, | ||
1763 | IEEE80211_TX_SYNC_AUTH); | ||
1764 | |||
1765 | if (!assoc) { | ||
1766 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); | ||
1767 | |||
1768 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | ||
1769 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
1770 | } | ||
1771 | |||
1772 | cfg80211_put_bss(auth_data->bss); | ||
1773 | kfree(auth_data); | ||
1774 | sdata->u.mgd.auth_data = NULL; | ||
1775 | } | ||
1776 | |||
1777 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | ||
1778 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1779 | { | ||
1780 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | ||
1781 | u8 *pos; | ||
1782 | struct ieee802_11_elems elems; | ||
1783 | |||
1784 | pos = mgmt->u.auth.variable; | ||
1785 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1786 | if (!elems.challenge) | ||
1787 | return; | ||
1788 | auth_data->expected_transaction = 4; | ||
1789 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | ||
1790 | elems.challenge - 2, elems.challenge_len + 2, | ||
1791 | auth_data->bss->bssid, auth_data->bss->bssid, | ||
1792 | auth_data->key, auth_data->key_len, | ||
1793 | auth_data->key_idx); | ||
1794 | } | ||
1795 | |||
1796 | static enum rx_mgmt_action __must_check | ||
1797 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | ||
1798 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1799 | { | ||
1800 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1801 | u8 bssid[ETH_ALEN]; | ||
1802 | u16 auth_alg, auth_transaction, status_code; | ||
1803 | struct sta_info *sta; | ||
1804 | |||
1805 | lockdep_assert_held(&ifmgd->mtx); | ||
1806 | |||
1807 | if (len < 24 + 6) | ||
1808 | return RX_MGMT_NONE; | ||
1809 | |||
1810 | if (!ifmgd->auth_data || ifmgd->auth_data->done) | ||
1811 | return RX_MGMT_NONE; | ||
1812 | |||
1813 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | ||
1814 | |||
1815 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN)) | ||
1816 | return RX_MGMT_NONE; | ||
1817 | |||
1818 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1819 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1820 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1821 | |||
1822 | if (auth_alg != ifmgd->auth_data->algorithm || | ||
1823 | auth_transaction != ifmgd->auth_data->expected_transaction) | ||
1824 | return RX_MGMT_NONE; | ||
1825 | |||
1826 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1827 | printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", | ||
1828 | sdata->name, mgmt->sa, status_code); | ||
1829 | goto out; | ||
1830 | } | ||
1831 | |||
1832 | switch (ifmgd->auth_data->algorithm) { | ||
1833 | case WLAN_AUTH_OPEN: | ||
1834 | case WLAN_AUTH_LEAP: | ||
1835 | case WLAN_AUTH_FT: | ||
1836 | break; | ||
1837 | case WLAN_AUTH_SHARED_KEY: | ||
1838 | if (ifmgd->auth_data->expected_transaction != 4) { | ||
1839 | ieee80211_auth_challenge(sdata, mgmt, len); | ||
1840 | /* need another frame */ | ||
1841 | return RX_MGMT_NONE; | ||
1842 | } | ||
1843 | break; | ||
1844 | default: | ||
1845 | WARN_ONCE(1, "invalid auth alg %d", | ||
1846 | ifmgd->auth_data->algorithm); | ||
1847 | return RX_MGMT_NONE; | ||
1848 | } | ||
1849 | |||
1850 | printk(KERN_DEBUG "%s: authenticated\n", sdata->name); | ||
1851 | out: | ||
1852 | if (ifmgd->auth_data->synced) | ||
1853 | drv_finish_tx_sync(sdata->local, sdata, bssid, | ||
1854 | IEEE80211_TX_SYNC_AUTH); | ||
1855 | ifmgd->auth_data->synced = false; | ||
1856 | ifmgd->auth_data->done = true; | ||
1857 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | ||
1858 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
1859 | |||
1860 | /* move station state to auth */ | ||
1861 | mutex_lock(&sdata->local->sta_mtx); | ||
1862 | sta = sta_info_get(sdata, bssid); | ||
1863 | if (!sta) { | ||
1864 | WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); | ||
1865 | goto out_err; | ||
1866 | } | ||
1867 | if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { | ||
1868 | printk(KERN_DEBUG "%s: failed moving %pM to auth\n", | ||
1869 | sdata->name, bssid); | ||
1870 | goto out_err; | ||
1871 | } | ||
1872 | mutex_unlock(&sdata->local->sta_mtx); | ||
1873 | |||
1874 | return RX_MGMT_CFG80211_RX_AUTH; | ||
1875 | out_err: | ||
1876 | mutex_unlock(&sdata->local->sta_mtx); | ||
1877 | /* ignore frame -- wait for timeout */ | ||
1878 | return RX_MGMT_NONE; | ||
1879 | } | ||
1880 | |||
1881 | |||
1426 | static enum rx_mgmt_action __must_check | 1882 | static enum rx_mgmt_action __must_check |
1427 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1883 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1428 | struct ieee80211_mgmt *mgmt, size_t len) | 1884 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1431,10 +1887,14 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1431 | const u8 *bssid = NULL; | 1887 | const u8 *bssid = NULL; |
1432 | u16 reason_code; | 1888 | u16 reason_code; |
1433 | 1889 | ||
1890 | lockdep_assert_held(&ifmgd->mtx); | ||
1891 | |||
1434 | if (len < 24 + 2) | 1892 | if (len < 24 + 2) |
1435 | return RX_MGMT_NONE; | 1893 | return RX_MGMT_NONE; |
1436 | 1894 | ||
1437 | ASSERT_MGD_MTX(ifmgd); | 1895 | if (!ifmgd->associated || |
1896 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) | ||
1897 | return RX_MGMT_NONE; | ||
1438 | 1898 | ||
1439 | bssid = ifmgd->associated->bssid; | 1899 | bssid = ifmgd->associated->bssid; |
1440 | 1900 | ||
@@ -1459,15 +1919,13 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1459 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1919 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1460 | u16 reason_code; | 1920 | u16 reason_code; |
1461 | 1921 | ||
1462 | if (len < 24 + 2) | 1922 | lockdep_assert_held(&ifmgd->mtx); |
1463 | return RX_MGMT_NONE; | ||
1464 | |||
1465 | ASSERT_MGD_MTX(ifmgd); | ||
1466 | 1923 | ||
1467 | if (WARN_ON(!ifmgd->associated)) | 1924 | if (len < 24 + 2) |
1468 | return RX_MGMT_NONE; | 1925 | return RX_MGMT_NONE; |
1469 | 1926 | ||
1470 | if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) | 1927 | if (!ifmgd->associated || |
1928 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) | ||
1471 | return RX_MGMT_NONE; | 1929 | return RX_MGMT_NONE; |
1472 | 1930 | ||
1473 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1931 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
@@ -1524,15 +1982,37 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | |||
1524 | } | 1982 | } |
1525 | } | 1983 | } |
1526 | 1984 | ||
1527 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, | 1985 | static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, |
1986 | bool assoc) | ||
1987 | { | ||
1988 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | ||
1989 | |||
1990 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
1991 | |||
1992 | if (assoc_data->synced) | ||
1993 | drv_finish_tx_sync(sdata->local, sdata, | ||
1994 | assoc_data->bss->bssid, | ||
1995 | IEEE80211_TX_SYNC_ASSOC); | ||
1996 | |||
1997 | if (!assoc) { | ||
1998 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); | ||
1999 | |||
2000 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | ||
2001 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
2002 | } | ||
2003 | |||
2004 | kfree(assoc_data); | ||
2005 | sdata->u.mgd.assoc_data = NULL; | ||
2006 | } | ||
2007 | |||
2008 | static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | ||
2009 | struct cfg80211_bss *cbss, | ||
1528 | struct ieee80211_mgmt *mgmt, size_t len) | 2010 | struct ieee80211_mgmt *mgmt, size_t len) |
1529 | { | 2011 | { |
1530 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
1531 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2012 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1532 | struct ieee80211_local *local = sdata->local; | 2013 | struct ieee80211_local *local = sdata->local; |
1533 | struct ieee80211_supported_band *sband; | 2014 | struct ieee80211_supported_band *sband; |
1534 | struct sta_info *sta; | 2015 | struct sta_info *sta; |
1535 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
1536 | u8 *pos; | 2016 | u8 *pos; |
1537 | u32 rates, basic_rates; | 2017 | u32 rates, basic_rates; |
1538 | u16 capab_info, aid; | 2018 | u16 capab_info, aid; |
@@ -1581,29 +2061,15 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1581 | * station info was already allocated and inserted before | 2061 | * station info was already allocated and inserted before |
1582 | * the association and should be available to us | 2062 | * the association and should be available to us |
1583 | */ | 2063 | */ |
1584 | sta = sta_info_get_rx(sdata, cbss->bssid); | 2064 | sta = sta_info_get(sdata, cbss->bssid); |
1585 | if (WARN_ON(!sta)) { | 2065 | if (WARN_ON(!sta)) { |
1586 | mutex_unlock(&sdata->local->sta_mtx); | 2066 | mutex_unlock(&sdata->local->sta_mtx); |
1587 | return false; | 2067 | return false; |
1588 | } | 2068 | } |
1589 | 2069 | ||
1590 | err = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1591 | if (!err) | ||
1592 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1593 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
1594 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1595 | if (err) { | ||
1596 | printk(KERN_DEBUG | ||
1597 | "%s: failed to move station %pM to desired state\n", | ||
1598 | sdata->name, sta->sta.addr); | ||
1599 | WARN_ON(__sta_info_destroy(sta)); | ||
1600 | mutex_unlock(&sdata->local->sta_mtx); | ||
1601 | return false; | ||
1602 | } | ||
1603 | |||
1604 | rates = 0; | 2070 | rates = 0; |
1605 | basic_rates = 0; | 2071 | basic_rates = 0; |
1606 | sband = local->hw.wiphy->bands[wk->chan->band]; | 2072 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
1607 | 2073 | ||
1608 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, | 2074 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, |
1609 | &rates, &basic_rates, &have_higher_than_11mbit, | 2075 | &rates, &basic_rates, &have_higher_than_11mbit, |
@@ -1624,11 +2090,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1624 | basic_rates = BIT(min_rate_index); | 2090 | basic_rates = BIT(min_rate_index); |
1625 | } | 2091 | } |
1626 | 2092 | ||
1627 | sta->sta.supp_rates[wk->chan->band] = rates; | 2093 | sta->sta.supp_rates[local->oper_channel->band] = rates; |
1628 | sdata->vif.bss_conf.basic_rates = basic_rates; | 2094 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1629 | 2095 | ||
1630 | /* cf. IEEE 802.11 9.2.12 */ | 2096 | /* cf. IEEE 802.11 9.2.12 */ |
1631 | if (wk->chan->band == IEEE80211_BAND_2GHZ && | 2097 | if (local->oper_channel->band == IEEE80211_BAND_2GHZ && |
1632 | have_higher_than_11mbit) | 2098 | have_higher_than_11mbit) |
1633 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 2099 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
1634 | else | 2100 | else |
@@ -1648,15 +2114,22 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1648 | if (elems.wmm_param) | 2114 | if (elems.wmm_param) |
1649 | set_sta_flag(sta, WLAN_STA_WME); | 2115 | set_sta_flag(sta, WLAN_STA_WME); |
1650 | 2116 | ||
1651 | /* sta_info_reinsert will also unlock the mutex lock */ | 2117 | err = sta_info_move_state(sta, IEEE80211_STA_AUTH); |
1652 | err = sta_info_reinsert(sta); | 2118 | if (!err) |
1653 | sta = NULL; | 2119 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
2120 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
2121 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1654 | if (err) { | 2122 | if (err) { |
1655 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 2123 | printk(KERN_DEBUG |
1656 | " the AP (error %d)\n", sdata->name, err); | 2124 | "%s: failed to move station %pM to desired state\n", |
2125 | sdata->name, sta->sta.addr); | ||
2126 | WARN_ON(__sta_info_destroy(sta)); | ||
2127 | mutex_unlock(&sdata->local->sta_mtx); | ||
1657 | return false; | 2128 | return false; |
1658 | } | 2129 | } |
1659 | 2130 | ||
2131 | mutex_unlock(&sdata->local->sta_mtx); | ||
2132 | |||
1660 | /* | 2133 | /* |
1661 | * Always handle WMM once after association regardless | 2134 | * Always handle WMM once after association regardless |
1662 | * of the first value the AP uses. Setting -1 here has | 2135 | * of the first value the AP uses. Setting -1 here has |
@@ -1671,8 +2144,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1671 | else | 2144 | else |
1672 | ieee80211_set_wmm_default(sdata); | 2145 | ieee80211_set_wmm_default(sdata); |
1673 | 2146 | ||
1674 | local->oper_channel = wk->chan; | ||
1675 | |||
1676 | if (elems.ht_info_elem && elems.wmm_param && | 2147 | if (elems.ht_info_elem && elems.wmm_param && |
1677 | (sdata->local->hw.queues >= 4) && | 2148 | (sdata->local->hw.queues >= 4) && |
1678 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2149 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
@@ -1703,7 +2174,82 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1703 | return true; | 2174 | return true; |
1704 | } | 2175 | } |
1705 | 2176 | ||
2177 | static enum rx_mgmt_action __must_check | ||
2178 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | ||
2179 | struct ieee80211_mgmt *mgmt, size_t len, | ||
2180 | struct cfg80211_bss **bss) | ||
2181 | { | ||
2182 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2183 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
2184 | u16 capab_info, status_code, aid; | ||
2185 | struct ieee802_11_elems elems; | ||
2186 | u8 *pos; | ||
2187 | bool reassoc; | ||
2188 | |||
2189 | lockdep_assert_held(&ifmgd->mtx); | ||
2190 | |||
2191 | if (!assoc_data) | ||
2192 | return RX_MGMT_NONE; | ||
2193 | if (memcmp(assoc_data->bss->bssid, mgmt->bssid, ETH_ALEN)) | ||
2194 | return RX_MGMT_NONE; | ||
1706 | 2195 | ||
2196 | /* | ||
2197 | * AssocResp and ReassocResp have identical structure, so process both | ||
2198 | * of them in this function. | ||
2199 | */ | ||
2200 | |||
2201 | if (len < 24 + 6) | ||
2202 | return RX_MGMT_NONE; | ||
2203 | |||
2204 | reassoc = ieee80211_is_reassoc_req(mgmt->frame_control); | ||
2205 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
2206 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
2207 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | ||
2208 | |||
2209 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
2210 | "status=%d aid=%d)\n", | ||
2211 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
2212 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
2213 | |||
2214 | pos = mgmt->u.assoc_resp.variable; | ||
2215 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
2216 | |||
2217 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
2218 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
2219 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
2220 | u32 tu, ms; | ||
2221 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
2222 | ms = tu * 1024 / 1000; | ||
2223 | printk(KERN_DEBUG "%s: %pM rejected association temporarily; " | ||
2224 | "comeback duration %u TU (%u ms)\n", | ||
2225 | sdata->name, mgmt->sa, tu, ms); | ||
2226 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); | ||
2227 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
2228 | run_again(ifmgd, assoc_data->timeout); | ||
2229 | return RX_MGMT_NONE; | ||
2230 | } | ||
2231 | |||
2232 | *bss = assoc_data->bss; | ||
2233 | |||
2234 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
2235 | printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", | ||
2236 | sdata->name, mgmt->sa, status_code); | ||
2237 | ieee80211_destroy_assoc_data(sdata, false); | ||
2238 | } else { | ||
2239 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
2240 | |||
2241 | ieee80211_destroy_assoc_data(sdata, true); | ||
2242 | |||
2243 | if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { | ||
2244 | /* oops -- internal error -- send timeout for now */ | ||
2245 | sta_info_destroy_addr(sdata, mgmt->bssid); | ||
2246 | cfg80211_put_bss(*bss); | ||
2247 | return RX_MGMT_CFG80211_ASSOC_TIMEOUT; | ||
2248 | } | ||
2249 | } | ||
2250 | |||
2251 | return RX_MGMT_CFG80211_RX_ASSOC; | ||
2252 | } | ||
1707 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2253 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1708 | struct ieee80211_mgmt *mgmt, | 2254 | struct ieee80211_mgmt *mgmt, |
1709 | size_t len, | 2255 | size_t len, |
@@ -1717,7 +2263,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1717 | struct ieee80211_channel *channel; | 2263 | struct ieee80211_channel *channel; |
1718 | bool need_ps = false; | 2264 | bool need_ps = false; |
1719 | 2265 | ||
1720 | if (sdata->u.mgd.associated) { | 2266 | if (sdata->u.mgd.associated && |
2267 | memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | ||
2268 | ETH_ALEN) == 0) { | ||
1721 | bss = (void *)sdata->u.mgd.associated->priv; | 2269 | bss = (void *)sdata->u.mgd.associated->priv; |
1722 | /* not previously set so we may need to recalc */ | 2270 | /* not previously set so we may need to recalc */ |
1723 | need_ps = !bss->dtim_period; | 2271 | need_ps = !bss->dtim_period; |
@@ -1787,6 +2335,15 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1787 | if (ifmgd->associated && | 2335 | if (ifmgd->associated && |
1788 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) | 2336 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
1789 | ieee80211_reset_ap_probe(sdata); | 2337 | ieee80211_reset_ap_probe(sdata); |
2338 | |||
2339 | if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && | ||
2340 | memcmp(mgmt->bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN) == 0) { | ||
2341 | /* got probe response, continue with auth */ | ||
2342 | printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); | ||
2343 | ifmgd->auth_data->tries = 0; | ||
2344 | ifmgd->auth_data->timeout = jiffies; | ||
2345 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
2346 | } | ||
1790 | } | 2347 | } |
1791 | 2348 | ||
1792 | /* | 2349 | /* |
@@ -1826,7 +2383,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1826 | u32 ncrc; | 2383 | u32 ncrc; |
1827 | u8 *bssid; | 2384 | u8 *bssid; |
1828 | 2385 | ||
1829 | ASSERT_MGD_MTX(ifmgd); | 2386 | lockdep_assert_held(&ifmgd->mtx); |
1830 | 2387 | ||
1831 | /* Process beacon from the current BSS */ | 2388 | /* Process beacon from the current BSS */ |
1832 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 2389 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
@@ -1836,21 +2393,25 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1836 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 2393 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1837 | return; | 2394 | return; |
1838 | 2395 | ||
1839 | /* | 2396 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && |
1840 | * We might have received a number of frames, among them a | 2397 | memcmp(mgmt->bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN) == 0) { |
1841 | * disassoc frame and a beacon... | 2398 | ieee802_11_parse_elems(mgmt->u.beacon.variable, |
1842 | */ | 2399 | len - baselen, &elems); |
1843 | if (!ifmgd->associated) | ||
1844 | return; | ||
1845 | 2400 | ||
1846 | bssid = ifmgd->associated->bssid; | 2401 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, |
2402 | false); | ||
2403 | ifmgd->assoc_data->have_beacon = true; | ||
2404 | ifmgd->assoc_data->sent_assoc = false; | ||
2405 | /* continue assoc process */ | ||
2406 | ifmgd->assoc_data->timeout = jiffies; | ||
2407 | run_again(ifmgd, ifmgd->assoc_data->timeout); | ||
2408 | return; | ||
2409 | } | ||
1847 | 2410 | ||
1848 | /* | 2411 | if (!ifmgd->associated || |
1849 | * And in theory even frames from a different AP we were just | 2412 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) |
1850 | * associated to a split-second ago! | ||
1851 | */ | ||
1852 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1853 | return; | 2413 | return; |
2414 | bssid = ifmgd->associated->bssid; | ||
1854 | 2415 | ||
1855 | /* Track average RSSI from the Beacon frames of the current AP */ | 2416 | /* Track average RSSI from the Beacon frames of the current AP */ |
1856 | ifmgd->last_beacon_signal = rx_status->signal; | 2417 | ifmgd->last_beacon_signal = rx_status->signal; |
@@ -2034,6 +2595,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2034 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2595 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2035 | struct ieee80211_rx_status *rx_status; | 2596 | struct ieee80211_rx_status *rx_status; |
2036 | struct ieee80211_mgmt *mgmt; | 2597 | struct ieee80211_mgmt *mgmt; |
2598 | struct cfg80211_bss *bss = NULL; | ||
2037 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 2599 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
2038 | u16 fc; | 2600 | u16 fc; |
2039 | 2601 | ||
@@ -2043,92 +2605,59 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2043 | 2605 | ||
2044 | mutex_lock(&ifmgd->mtx); | 2606 | mutex_lock(&ifmgd->mtx); |
2045 | 2607 | ||
2046 | if (ifmgd->associated && | 2608 | switch (fc & IEEE80211_FCTL_STYPE) { |
2047 | memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { | 2609 | case IEEE80211_STYPE_BEACON: |
2048 | switch (fc & IEEE80211_FCTL_STYPE) { | 2610 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); |
2049 | case IEEE80211_STYPE_BEACON: | 2611 | break; |
2050 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 2612 | case IEEE80211_STYPE_PROBE_RESP: |
2051 | rx_status); | 2613 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
2052 | break; | 2614 | break; |
2053 | case IEEE80211_STYPE_PROBE_RESP: | 2615 | case IEEE80211_STYPE_AUTH: |
2054 | ieee80211_rx_mgmt_probe_resp(sdata, skb); | 2616 | rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
2055 | break; | 2617 | break; |
2056 | case IEEE80211_STYPE_DEAUTH: | 2618 | case IEEE80211_STYPE_DEAUTH: |
2057 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); | 2619 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
2058 | break; | 2620 | break; |
2059 | case IEEE80211_STYPE_DISASSOC: | 2621 | case IEEE80211_STYPE_DISASSOC: |
2060 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 2622 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
2061 | break; | 2623 | break; |
2062 | case IEEE80211_STYPE_ACTION: | 2624 | case IEEE80211_STYPE_ASSOC_RESP: |
2063 | switch (mgmt->u.action.category) { | 2625 | case IEEE80211_STYPE_REASSOC_RESP: |
2064 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 2626 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); |
2065 | ieee80211_sta_process_chanswitch(sdata, | 2627 | break; |
2066 | &mgmt->u.action.u.chan_switch.sw_elem, | 2628 | case IEEE80211_STYPE_ACTION: |
2067 | (void *)ifmgd->associated->priv, | 2629 | switch (mgmt->u.action.category) { |
2068 | rx_status->mactime); | 2630 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
2069 | break; | 2631 | ieee80211_sta_process_chanswitch(sdata, |
2070 | } | 2632 | &mgmt->u.action.u.chan_switch.sw_elem, |
2071 | } | 2633 | (void *)ifmgd->associated->priv, |
2072 | mutex_unlock(&ifmgd->mtx); | 2634 | rx_status->mactime); |
2073 | |||
2074 | switch (rma) { | ||
2075 | case RX_MGMT_NONE: | ||
2076 | /* no action */ | ||
2077 | break; | ||
2078 | case RX_MGMT_CFG80211_DEAUTH: | ||
2079 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | ||
2080 | break; | ||
2081 | case RX_MGMT_CFG80211_DISASSOC: | ||
2082 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); | ||
2083 | break; | 2635 | break; |
2084 | default: | ||
2085 | WARN(1, "unexpected: %d", rma); | ||
2086 | } | 2636 | } |
2087 | return; | ||
2088 | } | 2637 | } |
2089 | |||
2090 | mutex_unlock(&ifmgd->mtx); | 2638 | mutex_unlock(&ifmgd->mtx); |
2091 | 2639 | ||
2092 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && | 2640 | switch (rma) { |
2093 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { | 2641 | case RX_MGMT_NONE: |
2094 | struct ieee80211_local *local = sdata->local; | 2642 | /* no action */ |
2095 | struct ieee80211_work *wk; | 2643 | break; |
2096 | 2644 | case RX_MGMT_CFG80211_DEAUTH: | |
2097 | mutex_lock(&local->mtx); | ||
2098 | list_for_each_entry(wk, &local->work_list, list) { | ||
2099 | if (wk->sdata != sdata) | ||
2100 | continue; | ||
2101 | |||
2102 | if (wk->type != IEEE80211_WORK_ASSOC && | ||
2103 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
2104 | continue; | ||
2105 | |||
2106 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) | ||
2107 | continue; | ||
2108 | if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN)) | ||
2109 | continue; | ||
2110 | |||
2111 | /* | ||
2112 | * Printing the message only here means we can't | ||
2113 | * spuriously print it, but it also means that it | ||
2114 | * won't be printed when the frame comes in before | ||
2115 | * we even tried to associate or in similar cases. | ||
2116 | * | ||
2117 | * Ultimately, I suspect cfg80211 should print the | ||
2118 | * messages instead. | ||
2119 | */ | ||
2120 | printk(KERN_DEBUG | ||
2121 | "%s: deauthenticated from %pM (Reason: %u)\n", | ||
2122 | sdata->name, mgmt->bssid, | ||
2123 | le16_to_cpu(mgmt->u.deauth.reason_code)); | ||
2124 | |||
2125 | list_del_rcu(&wk->list); | ||
2126 | free_work(wk); | ||
2127 | break; | ||
2128 | } | ||
2129 | mutex_unlock(&local->mtx); | ||
2130 | |||
2131 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 2645 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
2646 | break; | ||
2647 | case RX_MGMT_CFG80211_DISASSOC: | ||
2648 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); | ||
2649 | break; | ||
2650 | case RX_MGMT_CFG80211_RX_AUTH: | ||
2651 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len); | ||
2652 | break; | ||
2653 | case RX_MGMT_CFG80211_RX_ASSOC: | ||
2654 | cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len); | ||
2655 | break; | ||
2656 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: | ||
2657 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | ||
2658 | break; | ||
2659 | default: | ||
2660 | WARN(1, "unexpected: %d", rma); | ||
2132 | } | 2661 | } |
2133 | } | 2662 | } |
2134 | 2663 | ||
@@ -2173,14 +2702,160 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2173 | mutex_lock(&ifmgd->mtx); | 2702 | mutex_lock(&ifmgd->mtx); |
2174 | } | 2703 | } |
2175 | 2704 | ||
2705 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | ||
2706 | { | ||
2707 | struct ieee80211_local *local = sdata->local; | ||
2708 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2709 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; | ||
2710 | |||
2711 | lockdep_assert_held(&ifmgd->mtx); | ||
2712 | |||
2713 | if (WARN_ON_ONCE(!auth_data)) | ||
2714 | return -EINVAL; | ||
2715 | |||
2716 | if (!auth_data->synced) { | ||
2717 | int ret = drv_tx_sync(local, sdata, auth_data->bss->bssid, | ||
2718 | IEEE80211_TX_SYNC_AUTH); | ||
2719 | if (ret) | ||
2720 | return ret; | ||
2721 | } | ||
2722 | auth_data->synced = true; | ||
2723 | |||
2724 | auth_data->tries++; | ||
2725 | |||
2726 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
2727 | printk(KERN_DEBUG "%s: authentication with %pM timed out\n", | ||
2728 | sdata->name, auth_data->bss->bssid); | ||
2729 | |||
2730 | /* | ||
2731 | * Most likely AP is not in the range so remove the | ||
2732 | * bss struct for that AP. | ||
2733 | */ | ||
2734 | cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss); | ||
2735 | |||
2736 | return -ETIMEDOUT; | ||
2737 | } | ||
2738 | |||
2739 | if (auth_data->bss->proberesp_ies) { | ||
2740 | printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n", | ||
2741 | sdata->name, auth_data->bss->bssid, auth_data->tries, | ||
2742 | IEEE80211_AUTH_MAX_TRIES); | ||
2743 | |||
2744 | auth_data->expected_transaction = 2; | ||
2745 | ieee80211_send_auth(sdata, 1, auth_data->algorithm, | ||
2746 | auth_data->ie, auth_data->ie_len, | ||
2747 | auth_data->bss->bssid, | ||
2748 | auth_data->bss->bssid, NULL, 0, 0); | ||
2749 | } else { | ||
2750 | const u8 *ssidie; | ||
2751 | |||
2752 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", | ||
2753 | sdata->name, auth_data->bss->bssid, auth_data->tries, | ||
2754 | IEEE80211_AUTH_MAX_TRIES); | ||
2755 | |||
2756 | ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); | ||
2757 | if (!ssidie) | ||
2758 | return -EINVAL; | ||
2759 | /* | ||
2760 | * Direct probe is sent to broadcast address as some APs | ||
2761 | * will not answer to direct packet in unassociated state. | ||
2762 | */ | ||
2763 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | ||
2764 | NULL, 0, (u32) -1, true, false); | ||
2765 | } | ||
2766 | |||
2767 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
2768 | run_again(ifmgd, auth_data->timeout); | ||
2769 | |||
2770 | return 0; | ||
2771 | } | ||
2772 | |||
2773 | static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | ||
2774 | { | ||
2775 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | ||
2776 | struct ieee80211_local *local = sdata->local; | ||
2777 | |||
2778 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
2779 | |||
2780 | if (!assoc_data->synced) { | ||
2781 | int ret = drv_tx_sync(local, sdata, assoc_data->bss->bssid, | ||
2782 | IEEE80211_TX_SYNC_ASSOC); | ||
2783 | if (ret) | ||
2784 | return ret; | ||
2785 | } | ||
2786 | assoc_data->synced = true; | ||
2787 | |||
2788 | assoc_data->tries++; | ||
2789 | if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
2790 | printk(KERN_DEBUG "%s: association with %pM timed out\n", | ||
2791 | sdata->name, assoc_data->bss->bssid); | ||
2792 | |||
2793 | /* | ||
2794 | * Most likely AP is not in the range so remove the | ||
2795 | * bss struct for that AP. | ||
2796 | */ | ||
2797 | cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); | ||
2798 | |||
2799 | return -ETIMEDOUT; | ||
2800 | } | ||
2801 | |||
2802 | printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n", | ||
2803 | sdata->name, assoc_data->bss->bssid, assoc_data->tries, | ||
2804 | IEEE80211_ASSOC_MAX_TRIES); | ||
2805 | ieee80211_send_assoc(sdata); | ||
2806 | |||
2807 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
2808 | run_again(&sdata->u.mgd, assoc_data->timeout); | ||
2809 | |||
2810 | return 0; | ||
2811 | } | ||
2812 | |||
2176 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 2813 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
2177 | { | 2814 | { |
2178 | struct ieee80211_local *local = sdata->local; | 2815 | struct ieee80211_local *local = sdata->local; |
2179 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2816 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2180 | 2817 | ||
2181 | /* then process the rest of the work */ | ||
2182 | mutex_lock(&ifmgd->mtx); | 2818 | mutex_lock(&ifmgd->mtx); |
2183 | 2819 | ||
2820 | if (ifmgd->auth_data && | ||
2821 | time_after(jiffies, ifmgd->auth_data->timeout)) { | ||
2822 | if (ifmgd->auth_data->done) { | ||
2823 | /* | ||
2824 | * ok ... we waited for assoc but userspace didn't, | ||
2825 | * so let's just kill the auth data | ||
2826 | */ | ||
2827 | ieee80211_destroy_auth_data(sdata, false); | ||
2828 | } else if (ieee80211_probe_auth(sdata)) { | ||
2829 | u8 bssid[ETH_ALEN]; | ||
2830 | |||
2831 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | ||
2832 | |||
2833 | ieee80211_destroy_auth_data(sdata, false); | ||
2834 | |||
2835 | mutex_unlock(&ifmgd->mtx); | ||
2836 | cfg80211_send_auth_timeout(sdata->dev, bssid); | ||
2837 | mutex_lock(&ifmgd->mtx); | ||
2838 | } | ||
2839 | } else if (ifmgd->auth_data) | ||
2840 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
2841 | |||
2842 | if (ifmgd->assoc_data && | ||
2843 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | ||
2844 | if (!ifmgd->assoc_data->have_beacon || | ||
2845 | ieee80211_do_assoc(sdata)) { | ||
2846 | u8 bssid[ETH_ALEN]; | ||
2847 | |||
2848 | memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN); | ||
2849 | |||
2850 | ieee80211_destroy_assoc_data(sdata, false); | ||
2851 | |||
2852 | mutex_unlock(&ifmgd->mtx); | ||
2853 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | ||
2854 | mutex_lock(&ifmgd->mtx); | ||
2855 | } | ||
2856 | } else if (ifmgd->assoc_data) | ||
2857 | run_again(ifmgd, ifmgd->assoc_data->timeout); | ||
2858 | |||
2184 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 2859 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
2185 | IEEE80211_STA_CONNECTION_POLL) && | 2860 | IEEE80211_STA_CONNECTION_POLL) && |
2186 | ifmgd->associated) { | 2861 | ifmgd->associated) { |
@@ -2256,6 +2931,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2256 | } | 2931 | } |
2257 | 2932 | ||
2258 | mutex_unlock(&ifmgd->mtx); | 2933 | mutex_unlock(&ifmgd->mtx); |
2934 | |||
2935 | mutex_lock(&local->mtx); | ||
2936 | ieee80211_recalc_idle(local); | ||
2937 | mutex_unlock(&local->mtx); | ||
2259 | } | 2938 | } |
2260 | 2939 | ||
2261 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 2940 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -2428,53 +3107,24 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
2428 | } | 3107 | } |
2429 | 3108 | ||
2430 | /* config hooks */ | 3109 | /* config hooks */ |
2431 | static enum work_done_result | ||
2432 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | ||
2433 | struct sk_buff *skb) | ||
2434 | { | ||
2435 | struct ieee80211_local *local = wk->sdata->local; | ||
2436 | |||
2437 | if (!skb) { | ||
2438 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | ||
2439 | goto destroy; | ||
2440 | } | ||
2441 | |||
2442 | if (wk->type == IEEE80211_WORK_AUTH) { | ||
2443 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | ||
2444 | goto destroy; | ||
2445 | } | ||
2446 | |||
2447 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
2448 | ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); | ||
2449 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2450 | |||
2451 | wk->type = IEEE80211_WORK_AUTH; | ||
2452 | wk->probe_auth.tries = 0; | ||
2453 | return WORK_DONE_REQUEUE; | ||
2454 | destroy: | ||
2455 | if (wk->probe_auth.synced) | ||
2456 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2457 | IEEE80211_TX_SYNC_AUTH); | ||
2458 | |||
2459 | return WORK_DONE_DESTROY; | ||
2460 | } | ||
2461 | |||
2462 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 3110 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
2463 | struct cfg80211_auth_request *req) | 3111 | struct cfg80211_auth_request *req) |
2464 | { | 3112 | { |
2465 | const u8 *ssid; | 3113 | struct ieee80211_local *local = sdata->local; |
2466 | struct ieee80211_work *wk; | 3114 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3115 | struct ieee80211_mgd_auth_data *auth_data; | ||
3116 | struct sta_info *sta; | ||
2467 | u16 auth_alg; | 3117 | u16 auth_alg; |
3118 | int err; | ||
2468 | 3119 | ||
2469 | if (req->local_state_change) | 3120 | /* prepare auth data structure */ |
2470 | return 0; /* no need to update mac80211 state */ | ||
2471 | 3121 | ||
2472 | switch (req->auth_type) { | 3122 | switch (req->auth_type) { |
2473 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | 3123 | case NL80211_AUTHTYPE_OPEN_SYSTEM: |
2474 | auth_alg = WLAN_AUTH_OPEN; | 3124 | auth_alg = WLAN_AUTH_OPEN; |
2475 | break; | 3125 | break; |
2476 | case NL80211_AUTHTYPE_SHARED_KEY: | 3126 | case NL80211_AUTHTYPE_SHARED_KEY: |
2477 | if (IS_ERR(sdata->local->wep_tx_tfm)) | 3127 | if (IS_ERR(local->wep_tx_tfm)) |
2478 | return -EOPNOTSUPP; | 3128 | return -EOPNOTSUPP; |
2479 | auth_alg = WLAN_AUTH_SHARED_KEY; | 3129 | auth_alg = WLAN_AUTH_SHARED_KEY; |
2480 | break; | 3130 | break; |
@@ -2488,171 +3138,142 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2488 | return -EOPNOTSUPP; | 3138 | return -EOPNOTSUPP; |
2489 | } | 3139 | } |
2490 | 3140 | ||
2491 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); | 3141 | auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL); |
2492 | if (!wk) | 3142 | if (!auth_data) |
2493 | return -ENOMEM; | 3143 | return -ENOMEM; |
2494 | 3144 | ||
2495 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | 3145 | auth_data->bss = req->bss; |
2496 | 3146 | ||
2497 | if (req->ie && req->ie_len) { | 3147 | if (req->ie && req->ie_len) { |
2498 | memcpy(wk->ie, req->ie, req->ie_len); | 3148 | memcpy(auth_data->ie, req->ie, req->ie_len); |
2499 | wk->ie_len = req->ie_len; | 3149 | auth_data->ie_len = req->ie_len; |
2500 | } | 3150 | } |
2501 | 3151 | ||
2502 | if (req->key && req->key_len) { | 3152 | if (req->key && req->key_len) { |
2503 | wk->probe_auth.key_len = req->key_len; | 3153 | auth_data->key_len = req->key_len; |
2504 | wk->probe_auth.key_idx = req->key_idx; | 3154 | auth_data->key_idx = req->key_idx; |
2505 | memcpy(wk->probe_auth.key, req->key, req->key_len); | 3155 | memcpy(auth_data->key, req->key, req->key_len); |
2506 | } | 3156 | } |
2507 | 3157 | ||
2508 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 3158 | auth_data->algorithm = auth_alg; |
2509 | memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); | ||
2510 | wk->probe_auth.ssid_len = ssid[1]; | ||
2511 | |||
2512 | wk->probe_auth.algorithm = auth_alg; | ||
2513 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | ||
2514 | |||
2515 | /* if we already have a probe, don't probe again */ | ||
2516 | if (req->bss->proberesp_ies) | ||
2517 | wk->type = IEEE80211_WORK_AUTH; | ||
2518 | else | ||
2519 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | ||
2520 | wk->chan = req->bss->channel; | ||
2521 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2522 | wk->sdata = sdata; | ||
2523 | wk->done = ieee80211_probe_auth_done; | ||
2524 | |||
2525 | ieee80211_add_work(wk); | ||
2526 | return 0; | ||
2527 | } | ||
2528 | |||
2529 | /* create and insert a dummy station entry */ | ||
2530 | static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata, | ||
2531 | u8 *bssid) { | ||
2532 | struct sta_info *sta; | ||
2533 | int err; | ||
2534 | 3159 | ||
2535 | sta = sta_info_alloc(sdata, bssid, GFP_KERNEL); | 3160 | /* try to authenticate/probe */ |
2536 | if (!sta) | ||
2537 | return -ENOMEM; | ||
2538 | 3161 | ||
2539 | sta->dummy = true; | 3162 | mutex_lock(&ifmgd->mtx); |
2540 | 3163 | ||
2541 | err = sta_info_insert(sta); | 3164 | if ((ifmgd->auth_data && !ifmgd->auth_data->done) || |
2542 | sta = NULL; | 3165 | ifmgd->assoc_data) { |
2543 | if (err) { | 3166 | err = -EBUSY; |
2544 | printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for" | 3167 | goto err_free; |
2545 | " the AP (error %d)\n", sdata->name, err); | ||
2546 | return err; | ||
2547 | } | 3168 | } |
2548 | 3169 | ||
2549 | return 0; | 3170 | if (ifmgd->auth_data) |
2550 | } | 3171 | ieee80211_destroy_auth_data(sdata, false); |
2551 | 3172 | ||
2552 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | 3173 | /* prep auth_data so we don't go into idle on disassoc */ |
2553 | struct sk_buff *skb) | 3174 | ifmgd->auth_data = auth_data; |
2554 | { | ||
2555 | struct ieee80211_local *local = wk->sdata->local; | ||
2556 | struct ieee80211_mgmt *mgmt; | ||
2557 | struct ieee80211_rx_status *rx_status; | ||
2558 | struct ieee802_11_elems elems; | ||
2559 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
2560 | u16 status; | ||
2561 | 3175 | ||
2562 | if (!skb) { | 3176 | if (ifmgd->associated) |
2563 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3177 | ieee80211_set_disassoc(sdata, true, false); |
2564 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | ||
2565 | goto destroy; | ||
2566 | } | ||
2567 | 3178 | ||
2568 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | 3179 | printk(KERN_DEBUG "%s: authenticate with %pM\n", |
2569 | mutex_lock(&wk->sdata->u.mgd.mtx); | 3180 | sdata->name, req->bss->bssid); |
2570 | rx_status = (void *) skb->cb; | ||
2571 | ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems); | ||
2572 | ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status, | ||
2573 | &elems, true); | ||
2574 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2575 | 3181 | ||
2576 | wk->type = IEEE80211_WORK_ASSOC; | 3182 | mutex_lock(&local->mtx); |
2577 | /* not really done yet */ | 3183 | ieee80211_recalc_idle(sdata->local); |
2578 | return WORK_DONE_REQUEUE; | 3184 | mutex_unlock(&local->mtx); |
2579 | } | ||
2580 | 3185 | ||
2581 | mgmt = (void *)skb->data; | 3186 | /* switch to the right channel */ |
2582 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 3187 | local->oper_channel = req->bss->channel; |
3188 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
2583 | 3189 | ||
2584 | if (status == WLAN_STATUS_SUCCESS) { | 3190 | /* set BSSID */ |
2585 | if (wk->assoc.synced) | 3191 | memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); |
2586 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | 3192 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
2587 | IEEE80211_TX_SYNC_ASSOC); | ||
2588 | 3193 | ||
2589 | mutex_lock(&wk->sdata->u.mgd.mtx); | 3194 | /* add station entry */ |
2590 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | 3195 | sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); |
2591 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 3196 | if (!sta) { |
2592 | /* oops -- internal error -- send timeout for now */ | 3197 | err = -ENOMEM; |
2593 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3198 | goto err_clear; |
2594 | cfg80211_send_assoc_timeout(wk->sdata->dev, | 3199 | } |
2595 | wk->filter_ta); | ||
2596 | return WORK_DONE_DESTROY; | ||
2597 | } | ||
2598 | 3200 | ||
2599 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 3201 | err = sta_info_insert(sta); |
2600 | } else { | 3202 | if (err) { |
2601 | /* assoc failed - destroy the dummy station entry */ | 3203 | printk(KERN_DEBUG |
2602 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3204 | "%s: failed to insert STA entry for the AP %pM (error %d)\n", |
3205 | sdata->name, req->bss->bssid, err); | ||
3206 | goto err_clear; | ||
2603 | } | 3207 | } |
2604 | 3208 | ||
2605 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | 3209 | err = ieee80211_probe_auth(sdata); |
2606 | destroy: | 3210 | if (err) { |
2607 | if (wk->assoc.synced) | 3211 | if (auth_data->synced) |
2608 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | 3212 | drv_finish_tx_sync(local, sdata, req->bss->bssid, |
2609 | IEEE80211_TX_SYNC_ASSOC); | 3213 | IEEE80211_TX_SYNC_AUTH); |
3214 | sta_info_destroy_addr(sdata, req->bss->bssid); | ||
3215 | goto err_clear; | ||
3216 | } | ||
3217 | |||
3218 | /* hold our own reference */ | ||
3219 | cfg80211_ref_bss(auth_data->bss); | ||
3220 | err = 0; | ||
3221 | goto out_unlock; | ||
3222 | |||
3223 | err_clear: | ||
3224 | ifmgd->auth_data = NULL; | ||
3225 | err_free: | ||
3226 | kfree(auth_data); | ||
3227 | out_unlock: | ||
3228 | mutex_unlock(&ifmgd->mtx); | ||
2610 | 3229 | ||
2611 | return WORK_DONE_DESTROY; | 3230 | return err; |
2612 | } | 3231 | } |
2613 | 3232 | ||
2614 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 3233 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
2615 | struct cfg80211_assoc_request *req) | 3234 | struct cfg80211_assoc_request *req) |
2616 | { | 3235 | { |
3236 | struct ieee80211_local *local = sdata->local; | ||
2617 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3237 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2618 | struct ieee80211_bss *bss = (void *)req->bss->priv; | 3238 | struct ieee80211_bss *bss = (void *)req->bss->priv; |
2619 | struct ieee80211_work *wk; | 3239 | struct ieee80211_mgd_assoc_data *assoc_data; |
2620 | const u8 *ssid; | 3240 | struct sta_info *sta; |
3241 | const u8 *ssidie; | ||
2621 | int i, err; | 3242 | int i, err; |
2622 | 3243 | ||
3244 | ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
3245 | if (!ssidie) | ||
3246 | return -EINVAL; | ||
3247 | |||
3248 | assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); | ||
3249 | if (!assoc_data) | ||
3250 | return -ENOMEM; | ||
3251 | |||
2623 | mutex_lock(&ifmgd->mtx); | 3252 | mutex_lock(&ifmgd->mtx); |
2624 | if (ifmgd->associated) { | ||
2625 | if (!req->prev_bssid || | ||
2626 | memcmp(req->prev_bssid, ifmgd->associated->bssid, | ||
2627 | ETH_ALEN)) { | ||
2628 | /* | ||
2629 | * We are already associated and the request was not a | ||
2630 | * reassociation request from the current BSS, so | ||
2631 | * reject it. | ||
2632 | */ | ||
2633 | mutex_unlock(&ifmgd->mtx); | ||
2634 | return -EALREADY; | ||
2635 | } | ||
2636 | 3253 | ||
2637 | /* Trying to reassociate - clear previous association state */ | 3254 | if (ifmgd->associated) |
2638 | ieee80211_set_disassoc(sdata, true, false); | 3255 | ieee80211_set_disassoc(sdata, true, false); |
3256 | |||
3257 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | ||
3258 | err = -EBUSY; | ||
3259 | goto err_free; | ||
2639 | } | 3260 | } |
2640 | mutex_unlock(&ifmgd->mtx); | ||
2641 | 3261 | ||
2642 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); | 3262 | if (ifmgd->assoc_data) { |
2643 | if (!wk) | 3263 | err = -EBUSY; |
2644 | return -ENOMEM; | 3264 | goto err_free; |
3265 | } | ||
2645 | 3266 | ||
2646 | /* | 3267 | if (ifmgd->auth_data) { |
2647 | * create a dummy station info entry in order | 3268 | bool match; |
2648 | * to start accepting incoming EAPOL packets from the station | 3269 | |
2649 | */ | 3270 | /* keep sta info, bssid if matching */ |
2650 | err = ieee80211_pre_assoc(sdata, req->bss->bssid); | 3271 | match = memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN) == 0; |
2651 | if (err) { | 3272 | ieee80211_destroy_auth_data(sdata, match); |
2652 | kfree(wk); | ||
2653 | return err; | ||
2654 | } | 3273 | } |
2655 | 3274 | ||
3275 | /* prepare assoc data */ | ||
3276 | |||
2656 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 3277 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2657 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 3278 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
2658 | 3279 | ||
@@ -2664,7 +3285,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2664 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | 3285 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) |
2665 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3286 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2666 | 3287 | ||
2667 | |||
2668 | if (req->flags & ASSOC_REQ_DISABLE_HT) | 3288 | if (req->flags & ASSOC_REQ_DISABLE_HT) |
2669 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3289 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2670 | 3290 | ||
@@ -2673,16 +3293,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2673 | sizeof(ifmgd->ht_capa_mask)); | 3293 | sizeof(ifmgd->ht_capa_mask)); |
2674 | 3294 | ||
2675 | if (req->ie && req->ie_len) { | 3295 | if (req->ie && req->ie_len) { |
2676 | memcpy(wk->ie, req->ie, req->ie_len); | 3296 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
2677 | wk->ie_len = req->ie_len; | 3297 | assoc_data->ie_len = req->ie_len; |
2678 | } else | 3298 | } |
2679 | wk->ie_len = 0; | ||
2680 | |||
2681 | wk->assoc.bss = req->bss; | ||
2682 | 3299 | ||
2683 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | 3300 | assoc_data->bss = req->bss; |
2684 | 3301 | ||
2685 | /* new association always uses requested smps mode */ | ||
2686 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | 3302 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { |
2687 | if (ifmgd->powersave) | 3303 | if (ifmgd->powersave) |
2688 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | 3304 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; |
@@ -2691,7 +3307,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2691 | } else | 3307 | } else |
2692 | ifmgd->ap_smps = ifmgd->req_smps; | 3308 | ifmgd->ap_smps = ifmgd->req_smps; |
2693 | 3309 | ||
2694 | wk->assoc.smps = ifmgd->ap_smps; | ||
2695 | /* | 3310 | /* |
2696 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | 3311 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. |
2697 | * We still associate in non-HT mode (11a/b/g) if any one of these | 3312 | * We still associate in non-HT mode (11a/b/g) if any one of these |
@@ -2699,39 +3314,27 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2699 | * We can set this to true for non-11n hardware, that'll be checked | 3314 | * We can set this to true for non-11n hardware, that'll be checked |
2700 | * separately along with the peer capabilities. | 3315 | * separately along with the peer capabilities. |
2701 | */ | 3316 | */ |
2702 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | 3317 | assoc_data->capability = req->bss->capability; |
2703 | wk->assoc.capability = req->bss->capability; | 3318 | assoc_data->wmm_used = bss->wmm_used; |
2704 | wk->assoc.wmm_used = bss->wmm_used; | 3319 | assoc_data->supp_rates = bss->supp_rates; |
2705 | wk->assoc.supp_rates = bss->supp_rates; | 3320 | assoc_data->supp_rates_len = bss->supp_rates_len; |
2706 | wk->assoc.supp_rates_len = bss->supp_rates_len; | 3321 | assoc_data->ht_information_ie = |
2707 | wk->assoc.ht_information_ie = | ||
2708 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 3322 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); |
2709 | 3323 | ||
2710 | if (bss->wmm_used && bss->uapsd_supported && | 3324 | if (bss->wmm_used && bss->uapsd_supported && |
2711 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 3325 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
2712 | wk->assoc.uapsd_used = true; | 3326 | assoc_data->uapsd_used = true; |
2713 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | 3327 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; |
2714 | } else { | 3328 | } else { |
2715 | wk->assoc.uapsd_used = false; | 3329 | assoc_data->uapsd_used = false; |
2716 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | 3330 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; |
2717 | } | 3331 | } |
2718 | 3332 | ||
2719 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 3333 | memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); |
2720 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | 3334 | assoc_data->ssid_len = ssidie[1]; |
2721 | wk->assoc.ssid_len = ssid[1]; | ||
2722 | 3335 | ||
2723 | if (req->prev_bssid) | 3336 | if (req->prev_bssid) |
2724 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 3337 | memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); |
2725 | |||
2726 | wk->chan = req->bss->channel; | ||
2727 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2728 | wk->sdata = sdata; | ||
2729 | wk->done = ieee80211_assoc_done; | ||
2730 | if (!bss->dtim_period && | ||
2731 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
2732 | wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT; | ||
2733 | else | ||
2734 | wk->type = IEEE80211_WORK_ASSOC; | ||
2735 | 3338 | ||
2736 | if (req->use_mfp) { | 3339 | if (req->use_mfp) { |
2737 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 3340 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
@@ -2749,89 +3352,100 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2749 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 3352 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
2750 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 3353 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
2751 | 3354 | ||
2752 | ieee80211_add_work(wk); | 3355 | /* kick off associate process */ |
2753 | return 0; | 3356 | |
3357 | ifmgd->assoc_data = assoc_data; | ||
3358 | |||
3359 | mutex_lock(&local->mtx); | ||
3360 | ieee80211_recalc_idle(sdata->local); | ||
3361 | mutex_unlock(&local->mtx); | ||
3362 | |||
3363 | /* switch to the right channel */ | ||
3364 | local->oper_channel = req->bss->channel; | ||
3365 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
3366 | |||
3367 | rcu_read_lock(); | ||
3368 | sta = sta_info_get(sdata, req->bss->bssid); | ||
3369 | rcu_read_unlock(); | ||
3370 | |||
3371 | if (!sta) { | ||
3372 | /* set BSSID */ | ||
3373 | memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); | ||
3374 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
3375 | |||
3376 | sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); | ||
3377 | if (!sta) { | ||
3378 | err = -ENOMEM; | ||
3379 | goto err_clear; | ||
3380 | } | ||
3381 | |||
3382 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | ||
3383 | |||
3384 | err = sta_info_insert(sta); | ||
3385 | sta = NULL; | ||
3386 | if (err) { | ||
3387 | printk(KERN_DEBUG | ||
3388 | "%s: failed to insert STA entry for the AP (error %d)\n", | ||
3389 | sdata->name, err); | ||
3390 | goto err_clear; | ||
3391 | } | ||
3392 | } else | ||
3393 | WARN_ON_ONCE(memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN)); | ||
3394 | |||
3395 | if (!bss->dtim_period && | ||
3396 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { | ||
3397 | /* | ||
3398 | * Wait up to one beacon interval ... | ||
3399 | * should this be more if we miss one? | ||
3400 | */ | ||
3401 | printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", | ||
3402 | sdata->name, ifmgd->bssid); | ||
3403 | assoc_data->timeout = jiffies + | ||
3404 | TU_TO_EXP_TIME(req->bss->beacon_interval); | ||
3405 | } else { | ||
3406 | assoc_data->have_beacon = true; | ||
3407 | assoc_data->sent_assoc = false; | ||
3408 | assoc_data->timeout = jiffies; | ||
3409 | } | ||
3410 | run_again(ifmgd, assoc_data->timeout); | ||
3411 | |||
3412 | err = 0; | ||
3413 | goto out; | ||
3414 | err_clear: | ||
3415 | ifmgd->assoc_data = NULL; | ||
3416 | err_free: | ||
3417 | kfree(assoc_data); | ||
3418 | out: | ||
3419 | mutex_unlock(&ifmgd->mtx); | ||
3420 | |||
3421 | return err; | ||
2754 | } | 3422 | } |
2755 | 3423 | ||
2756 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | 3424 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
2757 | struct cfg80211_deauth_request *req, | 3425 | struct cfg80211_deauth_request *req, |
2758 | void *cookie) | 3426 | void *cookie) |
2759 | { | 3427 | { |
2760 | struct ieee80211_local *local = sdata->local; | ||
2761 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3428 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2762 | u8 bssid[ETH_ALEN]; | ||
2763 | bool assoc_bss = false; | 3429 | bool assoc_bss = false; |
2764 | 3430 | ||
2765 | mutex_lock(&ifmgd->mtx); | 3431 | mutex_lock(&ifmgd->mtx); |
2766 | 3432 | ||
2767 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | 3433 | if (ifmgd->associated && |
2768 | if (ifmgd->associated == req->bss) { | 3434 | memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { |
2769 | ieee80211_set_disassoc(sdata, false, true); | 3435 | ieee80211_set_disassoc(sdata, false, true); |
2770 | mutex_unlock(&ifmgd->mtx); | ||
2771 | assoc_bss = true; | 3436 | assoc_bss = true; |
2772 | } else { | 3437 | } else if (ifmgd->auth_data) { |
2773 | bool not_auth_yet = false; | 3438 | ieee80211_destroy_auth_data(sdata, false); |
2774 | struct ieee80211_work *tmp, *wk = NULL; | ||
2775 | |||
2776 | mutex_unlock(&ifmgd->mtx); | 3439 | mutex_unlock(&ifmgd->mtx); |
2777 | 3440 | return 0; | |
2778 | mutex_lock(&local->mtx); | ||
2779 | list_for_each_entry(tmp, &local->work_list, list) { | ||
2780 | if (tmp->sdata != sdata) | ||
2781 | continue; | ||
2782 | |||
2783 | if (tmp->type != IEEE80211_WORK_DIRECT_PROBE && | ||
2784 | tmp->type != IEEE80211_WORK_AUTH && | ||
2785 | tmp->type != IEEE80211_WORK_ASSOC && | ||
2786 | tmp->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
2787 | continue; | ||
2788 | |||
2789 | if (memcmp(req->bss->bssid, tmp->filter_ta, ETH_ALEN)) | ||
2790 | continue; | ||
2791 | |||
2792 | not_auth_yet = tmp->type == IEEE80211_WORK_DIRECT_PROBE; | ||
2793 | list_del_rcu(&tmp->list); | ||
2794 | synchronize_rcu(); | ||
2795 | wk = tmp; | ||
2796 | break; | ||
2797 | } | ||
2798 | mutex_unlock(&local->mtx); | ||
2799 | |||
2800 | if (wk && wk->type == IEEE80211_WORK_ASSOC) { | ||
2801 | /* clean up dummy sta & TX sync */ | ||
2802 | sta_info_destroy_addr(wk->sdata, wk->filter_ta); | ||
2803 | if (wk->assoc.synced) | ||
2804 | drv_finish_tx_sync(local, wk->sdata, | ||
2805 | wk->filter_ta, | ||
2806 | IEEE80211_TX_SYNC_ASSOC); | ||
2807 | } else if (wk && wk->type == IEEE80211_WORK_AUTH) { | ||
2808 | if (wk->probe_auth.synced) | ||
2809 | drv_finish_tx_sync(local, wk->sdata, | ||
2810 | wk->filter_ta, | ||
2811 | IEEE80211_TX_SYNC_AUTH); | ||
2812 | } | ||
2813 | kfree(wk); | ||
2814 | |||
2815 | /* | ||
2816 | * If somebody requests authentication and we haven't | ||
2817 | * sent out an auth frame yet there's no need to send | ||
2818 | * out a deauth frame either. If the state was PROBE, | ||
2819 | * then this is the case. If it's AUTH we have sent a | ||
2820 | * frame, and if it's IDLE we have completed the auth | ||
2821 | * process already. | ||
2822 | */ | ||
2823 | if (not_auth_yet) { | ||
2824 | __cfg80211_auth_canceled(sdata->dev, bssid); | ||
2825 | return 0; | ||
2826 | } | ||
2827 | } | 3441 | } |
3442 | mutex_unlock(&ifmgd->mtx); | ||
2828 | 3443 | ||
2829 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", | 3444 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", |
2830 | sdata->name, bssid, req->reason_code); | 3445 | sdata->name, req->bssid, req->reason_code); |
2831 | 3446 | ||
2832 | ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, | 3447 | ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, |
2833 | req->reason_code, cookie, | 3448 | req->reason_code, cookie, true); |
2834 | !req->local_state_change); | ||
2835 | if (assoc_bss) | 3449 | if (assoc_bss) |
2836 | sta_info_flush(sdata->local, sdata); | 3450 | sta_info_flush(sdata->local, sdata); |
2837 | 3451 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 596efaf50e09..2b53a5348ace 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -98,13 +98,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
98 | mutex_lock(&local->sta_mtx); | 98 | mutex_lock(&local->sta_mtx); |
99 | list_for_each_entry(sta, &local->sta_list, list) { | 99 | list_for_each_entry(sta, &local->sta_list, list) { |
100 | if (sta->uploaded) { | 100 | if (sta->uploaded) { |
101 | sdata = sta->sdata; | 101 | enum ieee80211_sta_state state; |
102 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
103 | sdata = container_of(sdata->bss, | ||
104 | struct ieee80211_sub_if_data, | ||
105 | u.ap); | ||
106 | 102 | ||
107 | drv_sta_remove(local, sdata, &sta->sta); | 103 | state = sta->sta_state; |
104 | for (; state > IEEE80211_STA_NOTEXIST; state--) | ||
105 | WARN_ON(drv_sta_state(local, sdata, sta, | ||
106 | state, state - 1)); | ||
108 | } | 107 | } |
109 | 108 | ||
110 | mesh_plink_quiesce(sta); | 109 | mesh_plink_quiesce(sta); |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3fef26d8898a..111fba38be82 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -324,7 +324,7 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate, | |||
324 | rbit = rate->idx % 8; | 324 | rbit = rate->idx % 8; |
325 | 325 | ||
326 | /* sanity check */ | 326 | /* sanity check */ |
327 | if (ridx < 0 || ridx > IEEE80211_HT_MCS_MASK_LEN) | 327 | if (ridx < 0 || ridx >= IEEE80211_HT_MCS_MASK_LEN) |
328 | return false; | 328 | return false; |
329 | 329 | ||
330 | /* See whether the selected rate or anything below it is allowed. */ | 330 | /* See whether the selected rate or anything below it is allowed. */ |
@@ -439,7 +439,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
439 | u32 mask; | 439 | u32 mask; |
440 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | 440 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; |
441 | 441 | ||
442 | if (sta) { | 442 | if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) { |
443 | ista = &sta->sta; | 443 | ista = &sta->sta; |
444 | priv_sta = sta->rate_ctrl_priv; | 444 | priv_sta = sta->rate_ctrl_priv; |
445 | } | 445 | } |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 8268457bd143..fbb1efdc4d04 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -37,7 +37,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
37 | struct ieee80211_sta *ista = &sta->sta; | 37 | struct ieee80211_sta *ista = &sta->sta; |
38 | void *priv_sta = sta->rate_ctrl_priv; | 38 | void *priv_sta = sta->rate_ctrl_priv; |
39 | 39 | ||
40 | if (!ref) | 40 | if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) |
41 | return; | 41 | return; |
42 | 42 | ||
43 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | 43 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); |
@@ -58,6 +58,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
58 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 58 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
59 | 59 | ||
60 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 60 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
61 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | ||
61 | } | 62 | } |
62 | 63 | ||
63 | static inline void rate_control_rate_update(struct ieee80211_local *local, | 64 | static inline void rate_control_rate_update(struct ieee80211_local *local, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5ee0847a7e1..3ab85c02ef04 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -859,7 +859,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
859 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 859 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
860 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 860 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
861 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { | 861 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
862 | if (rx->sta && rx->sta->dummy && | 862 | /* |
863 | * accept port control frames from the AP even when it's not | ||
864 | * yet marked ASSOC to prevent a race where we don't set the | ||
865 | * assoc bit quickly enough before it sends the first frame | ||
866 | */ | ||
867 | if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && | ||
863 | ieee80211_is_data_present(hdr->frame_control)) { | 868 | ieee80211_is_data_present(hdr->frame_control)) { |
864 | u16 ethertype; | 869 | u16 ethertype; |
865 | u8 *payload; | 870 | u8 *payload; |
@@ -2479,14 +2484,9 @@ static ieee80211_rx_result debug_noinline | |||
2479 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | 2484 | ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) |
2480 | { | 2485 | { |
2481 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2486 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
2482 | ieee80211_rx_result rxs; | ||
2483 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; | 2487 | struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; |
2484 | __le16 stype; | 2488 | __le16 stype; |
2485 | 2489 | ||
2486 | rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); | ||
2487 | if (rxs != RX_CONTINUE) | ||
2488 | return rxs; | ||
2489 | |||
2490 | stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); | 2490 | stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); |
2491 | 2491 | ||
2492 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 2492 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
@@ -2495,10 +2495,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2495 | return RX_DROP_MONITOR; | 2495 | return RX_DROP_MONITOR; |
2496 | 2496 | ||
2497 | switch (stype) { | 2497 | switch (stype) { |
2498 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | ||
2498 | case cpu_to_le16(IEEE80211_STYPE_BEACON): | 2499 | case cpu_to_le16(IEEE80211_STYPE_BEACON): |
2499 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): | 2500 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): |
2500 | /* process for all: mesh, mlme, ibss */ | 2501 | /* process for all: mesh, mlme, ibss */ |
2501 | break; | 2502 | break; |
2503 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): | ||
2504 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): | ||
2502 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | 2505 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): |
2503 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): | 2506 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): |
2504 | if (is_multicast_ether_addr(mgmt->da) && | 2507 | if (is_multicast_ether_addr(mgmt->da) && |
@@ -2510,7 +2513,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2510 | return RX_DROP_MONITOR; | 2513 | return RX_DROP_MONITOR; |
2511 | break; | 2514 | break; |
2512 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | 2515 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): |
2513 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | ||
2514 | /* process only for ibss */ | 2516 | /* process only for ibss */ |
2515 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | 2517 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
2516 | return RX_DROP_MONITOR; | 2518 | return RX_DROP_MONITOR; |
@@ -2949,7 +2951,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2949 | if (ieee80211_is_data(fc)) { | 2951 | if (ieee80211_is_data(fc)) { |
2950 | prev_sta = NULL; | 2952 | prev_sta = NULL; |
2951 | 2953 | ||
2952 | for_each_sta_info_rx(local, hdr->addr2, sta, tmp) { | 2954 | for_each_sta_info(local, hdr->addr2, sta, tmp) { |
2953 | if (!prev_sta) { | 2955 | if (!prev_sta) { |
2954 | prev_sta = sta; | 2956 | prev_sta = sta; |
2955 | continue; | 2957 | continue; |
@@ -2993,7 +2995,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2993 | continue; | 2995 | continue; |
2994 | } | 2996 | } |
2995 | 2997 | ||
2996 | rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); | 2998 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
2997 | rx.sdata = prev; | 2999 | rx.sdata = prev; |
2998 | ieee80211_prepare_and_rx_handle(&rx, skb, false); | 3000 | ieee80211_prepare_and_rx_handle(&rx, skb, false); |
2999 | 3001 | ||
@@ -3001,7 +3003,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
3001 | } | 3003 | } |
3002 | 3004 | ||
3003 | if (prev) { | 3005 | if (prev) { |
3004 | rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); | 3006 | rx.sta = sta_info_get_bss(prev, hdr->addr2); |
3005 | rx.sdata = prev; | 3007 | rx.sdata = prev; |
3006 | 3008 | ||
3007 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) | 3009 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fa0823892b2d..4034ee616022 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,25 +100,6 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
101 | lockdep_is_held(&local->sta_mtx)); | 101 | lockdep_is_held(&local->sta_mtx)); |
102 | while (sta) { | 102 | while (sta) { |
103 | if (sta->sdata == sdata && !sta->dummy && | ||
104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
105 | break; | ||
106 | sta = rcu_dereference_check(sta->hnext, | ||
107 | lockdep_is_held(&local->sta_mtx)); | ||
108 | } | ||
109 | return sta; | ||
110 | } | ||
111 | |||
112 | /* get a station info entry even if it is a dummy station*/ | ||
113 | struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | ||
114 | const u8 *addr) | ||
115 | { | ||
116 | struct ieee80211_local *local = sdata->local; | ||
117 | struct sta_info *sta; | ||
118 | |||
119 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
120 | lockdep_is_held(&local->sta_mtx)); | ||
121 | while (sta) { | ||
122 | if (sta->sdata == sdata && | 103 | if (sta->sdata == sdata && |
123 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
124 | break; | 105 | break; |
@@ -143,30 +124,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
143 | while (sta) { | 124 | while (sta) { |
144 | if ((sta->sdata == sdata || | 125 | if ((sta->sdata == sdata || |
145 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | 126 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && |
146 | !sta->dummy && | ||
147 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
148 | break; | ||
149 | sta = rcu_dereference_check(sta->hnext, | ||
150 | lockdep_is_held(&local->sta_mtx)); | ||
151 | } | ||
152 | return sta; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Get sta info either from the specified interface | ||
157 | * or from one of its vlans (including dummy stations) | ||
158 | */ | ||
159 | struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | ||
160 | const u8 *addr) | ||
161 | { | ||
162 | struct ieee80211_local *local = sdata->local; | ||
163 | struct sta_info *sta; | ||
164 | |||
165 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
166 | lockdep_is_held(&local->sta_mtx)); | ||
167 | while (sta) { | ||
168 | if ((sta->sdata == sdata || | ||
169 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | ||
170 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 127 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
171 | break; | 128 | break; |
172 | sta = rcu_dereference_check(sta->hnext, | 129 | sta = rcu_dereference_check(sta->hnext, |
@@ -293,6 +250,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
293 | sta->sdata = sdata; | 250 | sta->sdata = sdata; |
294 | sta->last_rx = jiffies; | 251 | sta->last_rx = jiffies; |
295 | 252 | ||
253 | sta->sta_state = IEEE80211_STA_NONE; | ||
254 | |||
296 | do_posix_clock_monotonic_gettime(&uptime); | 255 | do_posix_clock_monotonic_gettime(&uptime); |
297 | sta->last_connected = uptime.tv_sec; | 256 | sta->last_connected = uptime.tv_sec; |
298 | ewma_init(&sta->avg_signal, 1024, 8); | 257 | ewma_init(&sta->avg_signal, 1024, 8); |
@@ -349,6 +308,43 @@ static int sta_info_insert_check(struct sta_info *sta) | |||
349 | return 0; | 308 | return 0; |
350 | } | 309 | } |
351 | 310 | ||
311 | static int sta_info_insert_drv_state(struct ieee80211_local *local, | ||
312 | struct ieee80211_sub_if_data *sdata, | ||
313 | struct sta_info *sta) | ||
314 | { | ||
315 | enum ieee80211_sta_state state; | ||
316 | int err = 0; | ||
317 | |||
318 | for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) { | ||
319 | err = drv_sta_state(local, sdata, sta, state, state + 1); | ||
320 | if (err) | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | if (!err) { | ||
325 | /* | ||
326 | * Drivers using legacy sta_add/sta_remove callbacks only | ||
327 | * get uploaded set to true after sta_add is called. | ||
328 | */ | ||
329 | if (!local->ops->sta_add) | ||
330 | sta->uploaded = true; | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
335 | printk(KERN_DEBUG | ||
336 | "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n", | ||
337 | sdata->name, sta->sta.addr, state + 1, err); | ||
338 | err = 0; | ||
339 | } | ||
340 | |||
341 | /* unwind on error */ | ||
342 | for (; state > IEEE80211_STA_NOTEXIST; state--) | ||
343 | WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1)); | ||
344 | |||
345 | return err; | ||
346 | } | ||
347 | |||
352 | /* | 348 | /* |
353 | * should be called with sta_mtx locked | 349 | * should be called with sta_mtx locked |
354 | * this function replaces the mutex lock | 350 | * this function replaces the mutex lock |
@@ -358,72 +354,43 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
358 | { | 354 | { |
359 | struct ieee80211_local *local = sta->local; | 355 | struct ieee80211_local *local = sta->local; |
360 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 356 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
361 | struct sta_info *exist_sta; | 357 | struct station_info sinfo; |
362 | bool dummy_reinsert = false; | ||
363 | int err = 0; | 358 | int err = 0; |
364 | 359 | ||
365 | lockdep_assert_held(&local->sta_mtx); | 360 | lockdep_assert_held(&local->sta_mtx); |
366 | 361 | ||
367 | /* | 362 | /* check if STA exists already */ |
368 | * check if STA exists already. | 363 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
369 | * only accept a scenario of a second call to sta_info_insert_finish | 364 | err = -EEXIST; |
370 | * with a dummy station entry that was inserted earlier | 365 | goto out_err; |
371 | * in that case - assume that the dummy station flag should | ||
372 | * be removed. | ||
373 | */ | ||
374 | exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr); | ||
375 | if (exist_sta) { | ||
376 | if (exist_sta == sta && sta->dummy) { | ||
377 | dummy_reinsert = true; | ||
378 | } else { | ||
379 | err = -EEXIST; | ||
380 | goto out_err; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | if (!sta->dummy || dummy_reinsert) { | ||
385 | /* notify driver */ | ||
386 | err = drv_sta_add(local, sdata, &sta->sta); | ||
387 | if (err) { | ||
388 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
389 | goto out_err; | ||
390 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " | ||
391 | "driver (%d) - keeping it anyway.\n", | ||
392 | sdata->name, sta->sta.addr, err); | ||
393 | } else | ||
394 | sta->uploaded = true; | ||
395 | } | 366 | } |
396 | 367 | ||
397 | if (!dummy_reinsert) { | 368 | /* notify driver */ |
398 | local->num_sta++; | 369 | err = sta_info_insert_drv_state(local, sdata, sta); |
399 | local->sta_generation++; | 370 | if (err) |
400 | smp_mb(); | 371 | goto out_err; |
401 | 372 | ||
402 | /* make the station visible */ | 373 | local->num_sta++; |
403 | sta_info_hash_add(local, sta); | 374 | local->sta_generation++; |
375 | smp_mb(); | ||
404 | 376 | ||
405 | list_add(&sta->list, &local->sta_list); | 377 | /* make the station visible */ |
378 | sta_info_hash_add(local, sta); | ||
406 | 379 | ||
407 | set_sta_flag(sta, WLAN_STA_INSERTED); | 380 | list_add(&sta->list, &local->sta_list); |
408 | } else { | ||
409 | sta->dummy = false; | ||
410 | } | ||
411 | 381 | ||
412 | if (!sta->dummy) { | 382 | set_sta_flag(sta, WLAN_STA_INSERTED); |
413 | struct station_info sinfo; | ||
414 | 383 | ||
415 | ieee80211_sta_debugfs_add(sta); | 384 | ieee80211_sta_debugfs_add(sta); |
416 | rate_control_add_sta_debugfs(sta); | 385 | rate_control_add_sta_debugfs(sta); |
417 | 386 | ||
418 | memset(&sinfo, 0, sizeof(sinfo)); | 387 | memset(&sinfo, 0, sizeof(sinfo)); |
419 | sinfo.filled = 0; | 388 | sinfo.filled = 0; |
420 | sinfo.generation = local->sta_generation; | 389 | sinfo.generation = local->sta_generation; |
421 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | 390 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); |
422 | } | ||
423 | 391 | ||
424 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 392 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
425 | wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n", | 393 | wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); |
426 | sta->dummy ? "dummy " : "", sta->sta.addr); | ||
427 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 394 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
428 | 395 | ||
429 | /* move reference to rcu-protected */ | 396 | /* move reference to rcu-protected */ |
@@ -475,25 +442,6 @@ int sta_info_insert(struct sta_info *sta) | |||
475 | return err; | 442 | return err; |
476 | } | 443 | } |
477 | 444 | ||
478 | /* Caller must hold sta->local->sta_mtx */ | ||
479 | int sta_info_reinsert(struct sta_info *sta) | ||
480 | { | ||
481 | struct ieee80211_local *local = sta->local; | ||
482 | int err = 0; | ||
483 | |||
484 | err = sta_info_insert_check(sta); | ||
485 | if (err) { | ||
486 | mutex_unlock(&local->sta_mtx); | ||
487 | return err; | ||
488 | } | ||
489 | |||
490 | might_sleep(); | ||
491 | |||
492 | err = sta_info_insert_finish(sta); | ||
493 | rcu_read_unlock(); | ||
494 | return err; | ||
495 | } | ||
496 | |||
497 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 445 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
498 | { | 446 | { |
499 | /* | 447 | /* |
@@ -757,20 +705,17 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
757 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | 705 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); |
758 | 706 | ||
759 | while (sta->sta_state > IEEE80211_STA_NONE) { | 707 | while (sta->sta_state > IEEE80211_STA_NONE) { |
760 | int err = sta_info_move_state(sta, sta->sta_state - 1); | 708 | ret = sta_info_move_state(sta, sta->sta_state - 1); |
761 | if (err) { | 709 | if (ret) { |
762 | WARN_ON_ONCE(1); | 710 | WARN_ON_ONCE(1); |
763 | break; | 711 | break; |
764 | } | 712 | } |
765 | } | 713 | } |
766 | 714 | ||
767 | if (sta->uploaded) { | 715 | if (sta->uploaded) { |
768 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 716 | ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE, |
769 | sdata = container_of(sdata->bss, | 717 | IEEE80211_STA_NOTEXIST); |
770 | struct ieee80211_sub_if_data, | 718 | WARN_ON_ONCE(ret != 0); |
771 | u.ap); | ||
772 | drv_sta_remove(local, sdata, &sta->sta); | ||
773 | sdata = sta->sdata; | ||
774 | } | 719 | } |
775 | 720 | ||
776 | /* | 721 | /* |
@@ -843,7 +788,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) | |||
843 | int ret; | 788 | int ret; |
844 | 789 | ||
845 | mutex_lock(&sdata->local->sta_mtx); | 790 | mutex_lock(&sdata->local->sta_mtx); |
846 | sta = sta_info_get_rx(sdata, addr); | 791 | sta = sta_info_get(sdata, addr); |
847 | ret = __sta_info_destroy(sta); | 792 | ret = __sta_info_destroy(sta); |
848 | mutex_unlock(&sdata->local->sta_mtx); | 793 | mutex_unlock(&sdata->local->sta_mtx); |
849 | 794 | ||
@@ -857,7 +802,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, | |||
857 | int ret; | 802 | int ret; |
858 | 803 | ||
859 | mutex_lock(&sdata->local->sta_mtx); | 804 | mutex_lock(&sdata->local->sta_mtx); |
860 | sta = sta_info_get_bss_rx(sdata, addr); | 805 | sta = sta_info_get_bss(sdata, addr); |
861 | ret = __sta_info_destroy(sta); | 806 | ret = __sta_info_destroy(sta); |
862 | mutex_unlock(&sdata->local->sta_mtx); | 807 | mutex_unlock(&sdata->local->sta_mtx); |
863 | 808 | ||
@@ -1408,20 +1353,60 @@ int sta_info_move_state(struct sta_info *sta, | |||
1408 | if (sta->sta_state == new_state) | 1353 | if (sta->sta_state == new_state) |
1409 | return 0; | 1354 | return 0; |
1410 | 1355 | ||
1356 | /* check allowed transitions first */ | ||
1357 | |||
1358 | switch (new_state) { | ||
1359 | case IEEE80211_STA_NONE: | ||
1360 | if (sta->sta_state != IEEE80211_STA_AUTH) | ||
1361 | return -EINVAL; | ||
1362 | break; | ||
1363 | case IEEE80211_STA_AUTH: | ||
1364 | if (sta->sta_state != IEEE80211_STA_NONE && | ||
1365 | sta->sta_state != IEEE80211_STA_ASSOC) | ||
1366 | return -EINVAL; | ||
1367 | break; | ||
1368 | case IEEE80211_STA_ASSOC: | ||
1369 | if (sta->sta_state != IEEE80211_STA_AUTH && | ||
1370 | sta->sta_state != IEEE80211_STA_AUTHORIZED) | ||
1371 | return -EINVAL; | ||
1372 | break; | ||
1373 | case IEEE80211_STA_AUTHORIZED: | ||
1374 | if (sta->sta_state != IEEE80211_STA_ASSOC) | ||
1375 | return -EINVAL; | ||
1376 | break; | ||
1377 | default: | ||
1378 | WARN(1, "invalid state %d", new_state); | ||
1379 | return -EINVAL; | ||
1380 | } | ||
1381 | |||
1382 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1383 | printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", | ||
1384 | sta->sdata->name, sta->sta.addr, new_state); | ||
1385 | #endif | ||
1386 | |||
1387 | /* | ||
1388 | * notify the driver before the actual changes so it can | ||
1389 | * fail the transition | ||
1390 | */ | ||
1391 | if (test_sta_flag(sta, WLAN_STA_INSERTED)) { | ||
1392 | int err = drv_sta_state(sta->local, sta->sdata, sta, | ||
1393 | sta->sta_state, new_state); | ||
1394 | if (err) | ||
1395 | return err; | ||
1396 | } | ||
1397 | |||
1398 | /* reflect the change in all state variables */ | ||
1399 | |||
1411 | switch (new_state) { | 1400 | switch (new_state) { |
1412 | case IEEE80211_STA_NONE: | 1401 | case IEEE80211_STA_NONE: |
1413 | if (sta->sta_state == IEEE80211_STA_AUTH) | 1402 | if (sta->sta_state == IEEE80211_STA_AUTH) |
1414 | clear_bit(WLAN_STA_AUTH, &sta->_flags); | 1403 | clear_bit(WLAN_STA_AUTH, &sta->_flags); |
1415 | else | ||
1416 | return -EINVAL; | ||
1417 | break; | 1404 | break; |
1418 | case IEEE80211_STA_AUTH: | 1405 | case IEEE80211_STA_AUTH: |
1419 | if (sta->sta_state == IEEE80211_STA_NONE) | 1406 | if (sta->sta_state == IEEE80211_STA_NONE) |
1420 | set_bit(WLAN_STA_AUTH, &sta->_flags); | 1407 | set_bit(WLAN_STA_AUTH, &sta->_flags); |
1421 | else if (sta->sta_state == IEEE80211_STA_ASSOC) | 1408 | else if (sta->sta_state == IEEE80211_STA_ASSOC) |
1422 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); | 1409 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); |
1423 | else | ||
1424 | return -EINVAL; | ||
1425 | break; | 1410 | break; |
1426 | case IEEE80211_STA_ASSOC: | 1411 | case IEEE80211_STA_ASSOC: |
1427 | if (sta->sta_state == IEEE80211_STA_AUTH) { | 1412 | if (sta->sta_state == IEEE80211_STA_AUTH) { |
@@ -1430,24 +1415,19 @@ int sta_info_move_state(struct sta_info *sta, | |||
1430 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) | 1415 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) |
1431 | atomic_dec(&sta->sdata->u.ap.num_sta_authorized); | 1416 | atomic_dec(&sta->sdata->u.ap.num_sta_authorized); |
1432 | clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); | 1417 | clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); |
1433 | } else | 1418 | } |
1434 | return -EINVAL; | ||
1435 | break; | 1419 | break; |
1436 | case IEEE80211_STA_AUTHORIZED: | 1420 | case IEEE80211_STA_AUTHORIZED: |
1437 | if (sta->sta_state == IEEE80211_STA_ASSOC) { | 1421 | if (sta->sta_state == IEEE80211_STA_ASSOC) { |
1438 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) | 1422 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) |
1439 | atomic_inc(&sta->sdata->u.ap.num_sta_authorized); | 1423 | atomic_inc(&sta->sdata->u.ap.num_sta_authorized); |
1440 | set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); | 1424 | set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); |
1441 | } else | 1425 | } |
1442 | return -EINVAL; | ||
1443 | break; | 1426 | break; |
1444 | default: | 1427 | default: |
1445 | WARN(1, "invalid state %d", new_state); | 1428 | break; |
1446 | return -EINVAL; | ||
1447 | } | 1429 | } |
1448 | 1430 | ||
1449 | printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", | ||
1450 | sta->sdata->name, sta->sta.addr, new_state); | ||
1451 | sta->sta_state = new_state; | 1431 | sta->sta_state = new_state; |
1452 | 1432 | ||
1453 | return 0; | 1433 | return 0; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 381de37d2478..23a97c9dc042 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -53,6 +53,7 @@ | |||
53 | * reply to other uAPSD trigger frames or PS-Poll. | 53 | * reply to other uAPSD trigger frames or PS-Poll. |
54 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. | 54 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. |
55 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. | 55 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. |
56 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. | ||
56 | */ | 57 | */ |
57 | enum ieee80211_sta_info_flags { | 58 | enum ieee80211_sta_info_flags { |
58 | WLAN_STA_AUTH, | 59 | WLAN_STA_AUTH, |
@@ -73,14 +74,7 @@ enum ieee80211_sta_info_flags { | |||
73 | WLAN_STA_SP, | 74 | WLAN_STA_SP, |
74 | WLAN_STA_4ADDR_EVENT, | 75 | WLAN_STA_4ADDR_EVENT, |
75 | WLAN_STA_INSERTED, | 76 | WLAN_STA_INSERTED, |
76 | }; | 77 | WLAN_STA_RATE_CONTROL, |
77 | |||
78 | enum ieee80211_sta_state { | ||
79 | /* NOTE: These need to be ordered correctly! */ | ||
80 | IEEE80211_STA_NONE, | ||
81 | IEEE80211_STA_AUTH, | ||
82 | IEEE80211_STA_ASSOC, | ||
83 | IEEE80211_STA_AUTHORIZED, | ||
84 | }; | 78 | }; |
85 | 79 | ||
86 | #define STA_TID_NUM 16 | 80 | #define STA_TID_NUM 16 |
@@ -273,8 +267,6 @@ struct sta_ampdu_mlme { | |||
273 | * @dead: set to true when sta is unlinked | 267 | * @dead: set to true when sta is unlinked |
274 | * @uploaded: set to true when sta is uploaded to the driver | 268 | * @uploaded: set to true when sta is uploaded to the driver |
275 | * @lost_packets: number of consecutive lost packets | 269 | * @lost_packets: number of consecutive lost packets |
276 | * @dummy: indicate a dummy station created for receiving | ||
277 | * EAP frames before association | ||
278 | * @sta: station information we share with the driver | 270 | * @sta: station information we share with the driver |
279 | * @sta_state: duplicates information about station state (for debug) | 271 | * @sta_state: duplicates information about station state (for debug) |
280 | * @beacon_loss_count: number of times beacon loss has triggered | 272 | * @beacon_loss_count: number of times beacon loss has triggered |
@@ -372,9 +364,6 @@ struct sta_info { | |||
372 | unsigned int lost_packets; | 364 | unsigned int lost_packets; |
373 | unsigned int beacon_loss_count; | 365 | unsigned int beacon_loss_count; |
374 | 366 | ||
375 | /* should be right in front of sta to be in the same cache line */ | ||
376 | bool dummy; | ||
377 | |||
378 | /* keep last! */ | 367 | /* keep last! */ |
379 | struct ieee80211_sta sta; | 368 | struct ieee80211_sta sta; |
380 | }; | 369 | }; |
@@ -476,15 +465,9 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) | |||
476 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 465 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
477 | const u8 *addr); | 466 | const u8 *addr); |
478 | 467 | ||
479 | struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | ||
480 | const u8 *addr); | ||
481 | |||
482 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | 468 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, |
483 | const u8 *addr); | 469 | const u8 *addr); |
484 | 470 | ||
485 | struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | ||
486 | const u8 *addr); | ||
487 | |||
488 | static inline | 471 | static inline |
489 | void for_each_sta_info_type_check(struct ieee80211_local *local, | 472 | void for_each_sta_info_type_check(struct ieee80211_local *local, |
490 | const u8 *addr, | 473 | const u8 *addr, |
@@ -493,23 +476,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local, | |||
493 | { | 476 | { |
494 | } | 477 | } |
495 | 478 | ||
496 | #define for_each_sta_info(local, _addr, _sta, nxt) \ | 479 | #define for_each_sta_info(local, _addr, _sta, nxt) \ |
497 | for ( /* initialise loop */ \ | ||
498 | _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ | ||
499 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ | ||
500 | /* typecheck */ \ | ||
501 | for_each_sta_info_type_check(local, (_addr), _sta, nxt),\ | ||
502 | /* continue condition */ \ | ||
503 | _sta; \ | ||
504 | /* advance loop */ \ | ||
505 | _sta = nxt, \ | ||
506 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ | ||
507 | ) \ | ||
508 | /* run code only if address matches and it's not a dummy sta */ \ | ||
509 | if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \ | ||
510 | !_sta->dummy) | ||
511 | |||
512 | #define for_each_sta_info_rx(local, _addr, _sta, nxt) \ | ||
513 | for ( /* initialise loop */ \ | 480 | for ( /* initialise loop */ \ |
514 | _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ | 481 | _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ |
515 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ | 482 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ |
@@ -548,7 +515,6 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); | |||
548 | */ | 515 | */ |
549 | int sta_info_insert(struct sta_info *sta); | 516 | int sta_info_insert(struct sta_info *sta); |
550 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); | 517 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
551 | int sta_info_reinsert(struct sta_info *sta); | ||
552 | 518 | ||
553 | int __must_check __sta_info_destroy(struct sta_info *sta); | 519 | int __must_check __sta_info_destroy(struct sta_info *sta); |
554 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, | 520 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d82d886d0867..264397aee811 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1185,13 +1185,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1185 | mutex_lock(&local->sta_mtx); | 1185 | mutex_lock(&local->sta_mtx); |
1186 | list_for_each_entry(sta, &local->sta_list, list) { | 1186 | list_for_each_entry(sta, &local->sta_list, list) { |
1187 | if (sta->uploaded) { | 1187 | if (sta->uploaded) { |
1188 | sdata = sta->sdata; | 1188 | enum ieee80211_sta_state state; |
1189 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1190 | sdata = container_of(sdata->bss, | ||
1191 | struct ieee80211_sub_if_data, | ||
1192 | u.ap); | ||
1193 | 1189 | ||
1194 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); | 1190 | for (state = IEEE80211_STA_NOTEXIST; |
1191 | state < sta->sta_state - 1; state++) | ||
1192 | WARN_ON(drv_sta_state(local, sta->sdata, sta, | ||
1193 | state, state + 1)); | ||
1195 | } | 1194 | } |
1196 | } | 1195 | } |
1197 | mutex_unlock(&local->sta_mtx); | 1196 | mutex_unlock(&local->sta_mtx); |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0a1a176fbe91..c6e230efa049 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -27,16 +27,9 @@ | |||
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "driver-ops.h" | 28 | #include "driver-ops.h" |
29 | 29 | ||
30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
34 | |||
35 | enum work_action { | 30 | enum work_action { |
36 | WORK_ACT_MISMATCH, | ||
37 | WORK_ACT_NONE, | 31 | WORK_ACT_NONE, |
38 | WORK_ACT_TIMEOUT, | 32 | WORK_ACT_TIMEOUT, |
39 | WORK_ACT_DONE, | ||
40 | }; | 33 | }; |
41 | 34 | ||
42 | 35 | ||
@@ -71,465 +64,6 @@ void free_work(struct ieee80211_work *wk) | |||
71 | kfree_rcu(wk, rcu_head); | 64 | kfree_rcu(wk, rcu_head); |
72 | } | 65 | } |
73 | 66 | ||
74 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
75 | struct ieee80211_supported_band *sband, | ||
76 | u32 *rates) | ||
77 | { | ||
78 | int i, j, count; | ||
79 | *rates = 0; | ||
80 | count = 0; | ||
81 | for (i = 0; i < supp_rates_len; i++) { | ||
82 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
83 | |||
84 | for (j = 0; j < sband->n_bitrates; j++) | ||
85 | if (sband->bitrates[j].bitrate == rate) { | ||
86 | *rates |= BIT(j); | ||
87 | count++; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return count; | ||
93 | } | ||
94 | |||
95 | /* frame sending functions */ | ||
96 | |||
97 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | ||
98 | struct sk_buff *skb, const u8 *ht_info_ie, | ||
99 | struct ieee80211_supported_band *sband, | ||
100 | struct ieee80211_channel *channel, | ||
101 | enum ieee80211_smps_mode smps) | ||
102 | { | ||
103 | struct ieee80211_ht_info *ht_info; | ||
104 | u8 *pos; | ||
105 | u32 flags = channel->flags; | ||
106 | u16 cap; | ||
107 | struct ieee80211_sta_ht_cap ht_cap; | ||
108 | |||
109 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | ||
110 | |||
111 | if (!sband->ht_cap.ht_supported) | ||
112 | return; | ||
113 | |||
114 | if (!ht_info_ie) | ||
115 | return; | ||
116 | |||
117 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | ||
118 | return; | ||
119 | |||
120 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
121 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
122 | |||
123 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | ||
124 | |||
125 | /* determine capability flags */ | ||
126 | cap = ht_cap.cap; | ||
127 | |||
128 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
129 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
130 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
131 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
132 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
133 | } | ||
134 | break; | ||
135 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
136 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
137 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
138 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
139 | } | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | /* set SM PS mode properly */ | ||
144 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
145 | switch (smps) { | ||
146 | case IEEE80211_SMPS_AUTOMATIC: | ||
147 | case IEEE80211_SMPS_NUM_MODES: | ||
148 | WARN_ON(1); | ||
149 | case IEEE80211_SMPS_OFF: | ||
150 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
151 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
152 | break; | ||
153 | case IEEE80211_SMPS_STATIC: | ||
154 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
155 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
156 | break; | ||
157 | case IEEE80211_SMPS_DYNAMIC: | ||
158 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
159 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | /* reserve and fill IE */ | ||
164 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
165 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | ||
166 | } | ||
167 | |||
168 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
169 | struct ieee80211_work *wk) | ||
170 | { | ||
171 | struct ieee80211_local *local = sdata->local; | ||
172 | struct sk_buff *skb; | ||
173 | struct ieee80211_mgmt *mgmt; | ||
174 | u8 *pos, qos_info; | ||
175 | size_t offset = 0, noffset; | ||
176 | int i, count, rates_len, supp_rates_len; | ||
177 | u16 capab; | ||
178 | struct ieee80211_supported_band *sband; | ||
179 | u32 rates = 0; | ||
180 | |||
181 | sband = local->hw.wiphy->bands[wk->chan->band]; | ||
182 | |||
183 | if (wk->assoc.supp_rates_len) { | ||
184 | /* | ||
185 | * Get all rates supported by the device and the AP as | ||
186 | * some APs don't like getting a superset of their rates | ||
187 | * in the association request (e.g. D-Link DAP 1353 in | ||
188 | * b-only mode)... | ||
189 | */ | ||
190 | rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, | ||
191 | wk->assoc.supp_rates_len, | ||
192 | sband, &rates); | ||
193 | } else { | ||
194 | /* | ||
195 | * In case AP not provide any supported rates information | ||
196 | * before association, we send information element(s) with | ||
197 | * all rates that we support. | ||
198 | */ | ||
199 | rates = ~0; | ||
200 | rates_len = sband->n_bitrates; | ||
201 | } | ||
202 | |||
203 | skb = alloc_skb(local->hw.extra_tx_headroom + | ||
204 | sizeof(*mgmt) + /* bit too much but doesn't matter */ | ||
205 | 2 + wk->assoc.ssid_len + /* SSID */ | ||
206 | 4 + rates_len + /* (extended) rates */ | ||
207 | 4 + /* power capability */ | ||
208 | 2 + 2 * sband->n_channels + /* supported channels */ | ||
209 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||
210 | wk->ie_len + /* extra IEs */ | ||
211 | 9, /* WMM */ | ||
212 | GFP_KERNEL); | ||
213 | if (!skb) | ||
214 | return; | ||
215 | |||
216 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
217 | |||
218 | capab = WLAN_CAPABILITY_ESS; | ||
219 | |||
220 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
221 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
222 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
223 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
224 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
225 | } | ||
226 | |||
227 | if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) | ||
228 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
229 | |||
230 | if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
231 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
232 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
233 | |||
234 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
235 | memset(mgmt, 0, 24); | ||
236 | memcpy(mgmt->da, wk->filter_ta, ETH_ALEN); | ||
237 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
238 | memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN); | ||
239 | |||
240 | if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { | ||
241 | skb_put(skb, 10); | ||
242 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
243 | IEEE80211_STYPE_REASSOC_REQ); | ||
244 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
245 | mgmt->u.reassoc_req.listen_interval = | ||
246 | cpu_to_le16(local->hw.conf.listen_interval); | ||
247 | memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, | ||
248 | ETH_ALEN); | ||
249 | } else { | ||
250 | skb_put(skb, 4); | ||
251 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
252 | IEEE80211_STYPE_ASSOC_REQ); | ||
253 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
254 | mgmt->u.assoc_req.listen_interval = | ||
255 | cpu_to_le16(local->hw.conf.listen_interval); | ||
256 | } | ||
257 | |||
258 | /* SSID */ | ||
259 | pos = skb_put(skb, 2 + wk->assoc.ssid_len); | ||
260 | *pos++ = WLAN_EID_SSID; | ||
261 | *pos++ = wk->assoc.ssid_len; | ||
262 | memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); | ||
263 | |||
264 | /* add all rates which were marked to be used above */ | ||
265 | supp_rates_len = rates_len; | ||
266 | if (supp_rates_len > 8) | ||
267 | supp_rates_len = 8; | ||
268 | |||
269 | pos = skb_put(skb, supp_rates_len + 2); | ||
270 | *pos++ = WLAN_EID_SUPP_RATES; | ||
271 | *pos++ = supp_rates_len; | ||
272 | |||
273 | count = 0; | ||
274 | for (i = 0; i < sband->n_bitrates; i++) { | ||
275 | if (BIT(i) & rates) { | ||
276 | int rate = sband->bitrates[i].bitrate; | ||
277 | *pos++ = (u8) (rate / 5); | ||
278 | if (++count == 8) | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | if (rates_len > count) { | ||
284 | pos = skb_put(skb, rates_len - count + 2); | ||
285 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
286 | *pos++ = rates_len - count; | ||
287 | |||
288 | for (i++; i < sband->n_bitrates; i++) { | ||
289 | if (BIT(i) & rates) { | ||
290 | int rate = sband->bitrates[i].bitrate; | ||
291 | *pos++ = (u8) (rate / 5); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
297 | /* 1. power capabilities */ | ||
298 | pos = skb_put(skb, 4); | ||
299 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
300 | *pos++ = 2; | ||
301 | *pos++ = 0; /* min tx power */ | ||
302 | *pos++ = wk->chan->max_power; /* max tx power */ | ||
303 | |||
304 | /* 2. supported channels */ | ||
305 | /* TODO: get this in reg domain format */ | ||
306 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
307 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
308 | *pos++ = 2 * sband->n_channels; | ||
309 | for (i = 0; i < sband->n_channels; i++) { | ||
310 | *pos++ = ieee80211_frequency_to_channel( | ||
311 | sband->channels[i].center_freq); | ||
312 | *pos++ = 1; /* one channel in the subband*/ | ||
313 | } | ||
314 | } | ||
315 | |||
316 | /* if present, add any custom IEs that go before HT */ | ||
317 | if (wk->ie_len && wk->ie) { | ||
318 | static const u8 before_ht[] = { | ||
319 | WLAN_EID_SSID, | ||
320 | WLAN_EID_SUPP_RATES, | ||
321 | WLAN_EID_EXT_SUPP_RATES, | ||
322 | WLAN_EID_PWR_CAPABILITY, | ||
323 | WLAN_EID_SUPPORTED_CHANNELS, | ||
324 | WLAN_EID_RSN, | ||
325 | WLAN_EID_QOS_CAPA, | ||
326 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
327 | WLAN_EID_MOBILITY_DOMAIN, | ||
328 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
329 | }; | ||
330 | noffset = ieee80211_ie_split(wk->ie, wk->ie_len, | ||
331 | before_ht, ARRAY_SIZE(before_ht), | ||
332 | offset); | ||
333 | pos = skb_put(skb, noffset - offset); | ||
334 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
335 | offset = noffset; | ||
336 | } | ||
337 | |||
338 | if (wk->assoc.use_11n && wk->assoc.wmm_used && | ||
339 | local->hw.queues >= 4) | ||
340 | ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie, | ||
341 | sband, wk->chan, wk->assoc.smps); | ||
342 | |||
343 | /* if present, add any custom non-vendor IEs that go after HT */ | ||
344 | if (wk->ie_len && wk->ie) { | ||
345 | noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len, | ||
346 | offset); | ||
347 | pos = skb_put(skb, noffset - offset); | ||
348 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
349 | offset = noffset; | ||
350 | } | ||
351 | |||
352 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { | ||
353 | if (wk->assoc.uapsd_used) { | ||
354 | qos_info = local->uapsd_queues; | ||
355 | qos_info |= (local->uapsd_max_sp_len << | ||
356 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
357 | } else { | ||
358 | qos_info = 0; | ||
359 | } | ||
360 | |||
361 | pos = skb_put(skb, 9); | ||
362 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
363 | *pos++ = 7; /* len */ | ||
364 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
365 | *pos++ = 0x50; | ||
366 | *pos++ = 0xf2; | ||
367 | *pos++ = 2; /* WME */ | ||
368 | *pos++ = 0; /* WME info */ | ||
369 | *pos++ = 1; /* WME ver */ | ||
370 | *pos++ = qos_info; | ||
371 | } | ||
372 | |||
373 | /* add any remaining custom (i.e. vendor specific here) IEs */ | ||
374 | if (wk->ie_len && wk->ie) { | ||
375 | noffset = wk->ie_len; | ||
376 | pos = skb_put(skb, noffset - offset); | ||
377 | memcpy(pos, wk->ie + offset, noffset - offset); | ||
378 | } | ||
379 | |||
380 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
381 | ieee80211_tx_skb(sdata, skb); | ||
382 | } | ||
383 | |||
384 | static void ieee80211_remove_auth_bss(struct ieee80211_local *local, | ||
385 | struct ieee80211_work *wk) | ||
386 | { | ||
387 | struct cfg80211_bss *cbss; | ||
388 | u16 capa_val = WLAN_CAPABILITY_ESS; | ||
389 | |||
390 | if (wk->probe_auth.privacy) | ||
391 | capa_val |= WLAN_CAPABILITY_PRIVACY; | ||
392 | |||
393 | cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta, | ||
394 | wk->probe_auth.ssid, wk->probe_auth.ssid_len, | ||
395 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | ||
396 | capa_val); | ||
397 | if (!cbss) | ||
398 | return; | ||
399 | |||
400 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
401 | cfg80211_put_bss(cbss); | ||
402 | } | ||
403 | |||
404 | static enum work_action __must_check | ||
405 | ieee80211_direct_probe(struct ieee80211_work *wk) | ||
406 | { | ||
407 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
408 | struct ieee80211_local *local = sdata->local; | ||
409 | |||
410 | if (!wk->probe_auth.synced) { | ||
411 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
412 | IEEE80211_TX_SYNC_AUTH); | ||
413 | if (ret) | ||
414 | return WORK_ACT_TIMEOUT; | ||
415 | } | ||
416 | wk->probe_auth.synced = true; | ||
417 | |||
418 | wk->probe_auth.tries++; | ||
419 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
420 | printk(KERN_DEBUG "%s: direct probe to %pM timed out\n", | ||
421 | sdata->name, wk->filter_ta); | ||
422 | |||
423 | /* | ||
424 | * Most likely AP is not in the range so remove the | ||
425 | * bss struct for that AP. | ||
426 | */ | ||
427 | ieee80211_remove_auth_bss(local, wk); | ||
428 | |||
429 | return WORK_ACT_TIMEOUT; | ||
430 | } | ||
431 | |||
432 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", | ||
433 | sdata->name, wk->filter_ta, wk->probe_auth.tries, | ||
434 | IEEE80211_AUTH_MAX_TRIES); | ||
435 | |||
436 | /* | ||
437 | * Direct probe is sent to broadcast address as some APs | ||
438 | * will not answer to direct packet in unassociated state. | ||
439 | */ | ||
440 | ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, | ||
441 | wk->probe_auth.ssid_len, NULL, 0, | ||
442 | (u32) -1, true, false); | ||
443 | |||
444 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
445 | run_again(local, wk->timeout); | ||
446 | |||
447 | return WORK_ACT_NONE; | ||
448 | } | ||
449 | |||
450 | |||
451 | static enum work_action __must_check | ||
452 | ieee80211_authenticate(struct ieee80211_work *wk) | ||
453 | { | ||
454 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
455 | struct ieee80211_local *local = sdata->local; | ||
456 | |||
457 | if (!wk->probe_auth.synced) { | ||
458 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
459 | IEEE80211_TX_SYNC_AUTH); | ||
460 | if (ret) | ||
461 | return WORK_ACT_TIMEOUT; | ||
462 | } | ||
463 | wk->probe_auth.synced = true; | ||
464 | |||
465 | wk->probe_auth.tries++; | ||
466 | if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
467 | printk(KERN_DEBUG "%s: authentication with %pM" | ||
468 | " timed out\n", sdata->name, wk->filter_ta); | ||
469 | |||
470 | /* | ||
471 | * Most likely AP is not in the range so remove the | ||
472 | * bss struct for that AP. | ||
473 | */ | ||
474 | ieee80211_remove_auth_bss(local, wk); | ||
475 | |||
476 | return WORK_ACT_TIMEOUT; | ||
477 | } | ||
478 | |||
479 | printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n", | ||
480 | sdata->name, wk->filter_ta, wk->probe_auth.tries); | ||
481 | |||
482 | ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie, | ||
483 | wk->ie_len, wk->filter_ta, wk->filter_ta, NULL, 0, | ||
484 | 0); | ||
485 | wk->probe_auth.transaction = 2; | ||
486 | |||
487 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
488 | run_again(local, wk->timeout); | ||
489 | |||
490 | return WORK_ACT_NONE; | ||
491 | } | ||
492 | |||
493 | static enum work_action __must_check | ||
494 | ieee80211_associate(struct ieee80211_work *wk) | ||
495 | { | ||
496 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
497 | struct ieee80211_local *local = sdata->local; | ||
498 | |||
499 | if (!wk->assoc.synced) { | ||
500 | int ret = drv_tx_sync(local, sdata, wk->filter_ta, | ||
501 | IEEE80211_TX_SYNC_ASSOC); | ||
502 | if (ret) | ||
503 | return WORK_ACT_TIMEOUT; | ||
504 | } | ||
505 | wk->assoc.synced = true; | ||
506 | |||
507 | wk->assoc.tries++; | ||
508 | if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
509 | printk(KERN_DEBUG "%s: association with %pM" | ||
510 | " timed out\n", | ||
511 | sdata->name, wk->filter_ta); | ||
512 | |||
513 | /* | ||
514 | * Most likely AP is not in the range so remove the | ||
515 | * bss struct for that AP. | ||
516 | */ | ||
517 | if (wk->assoc.bss) | ||
518 | cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss); | ||
519 | |||
520 | return WORK_ACT_TIMEOUT; | ||
521 | } | ||
522 | |||
523 | printk(KERN_DEBUG "%s: associate with %pM (try %d)\n", | ||
524 | sdata->name, wk->filter_ta, wk->assoc.tries); | ||
525 | ieee80211_send_assoc(sdata, wk); | ||
526 | |||
527 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
528 | run_again(local, wk->timeout); | ||
529 | |||
530 | return WORK_ACT_NONE; | ||
531 | } | ||
532 | |||
533 | static enum work_action __must_check | 67 | static enum work_action __must_check |
534 | ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | 68 | ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) |
535 | { | 69 | { |
@@ -569,300 +103,6 @@ ieee80211_offchannel_tx(struct ieee80211_work *wk) | |||
569 | return WORK_ACT_TIMEOUT; | 103 | return WORK_ACT_TIMEOUT; |
570 | } | 104 | } |
571 | 105 | ||
572 | static enum work_action __must_check | ||
573 | ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) | ||
574 | { | ||
575 | if (wk->started) | ||
576 | return WORK_ACT_TIMEOUT; | ||
577 | |||
578 | /* | ||
579 | * Wait up to one beacon interval ... | ||
580 | * should this be more if we miss one? | ||
581 | */ | ||
582 | printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", | ||
583 | wk->sdata->name, wk->filter_ta); | ||
584 | wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval); | ||
585 | return WORK_ACT_NONE; | ||
586 | } | ||
587 | |||
588 | static void ieee80211_auth_challenge(struct ieee80211_work *wk, | ||
589 | struct ieee80211_mgmt *mgmt, | ||
590 | size_t len) | ||
591 | { | ||
592 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
593 | u8 *pos; | ||
594 | struct ieee802_11_elems elems; | ||
595 | |||
596 | pos = mgmt->u.auth.variable; | ||
597 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
598 | if (!elems.challenge) | ||
599 | return; | ||
600 | ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm, | ||
601 | elems.challenge - 2, elems.challenge_len + 2, | ||
602 | wk->filter_ta, wk->filter_ta, wk->probe_auth.key, | ||
603 | wk->probe_auth.key_len, wk->probe_auth.key_idx); | ||
604 | wk->probe_auth.transaction = 4; | ||
605 | } | ||
606 | |||
607 | static enum work_action __must_check | ||
608 | ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, | ||
609 | struct ieee80211_mgmt *mgmt, size_t len) | ||
610 | { | ||
611 | u16 auth_alg, auth_transaction, status_code; | ||
612 | |||
613 | if (wk->type != IEEE80211_WORK_AUTH) | ||
614 | return WORK_ACT_MISMATCH; | ||
615 | |||
616 | if (len < 24 + 6) | ||
617 | return WORK_ACT_NONE; | ||
618 | |||
619 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
620 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
621 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
622 | |||
623 | if (auth_alg != wk->probe_auth.algorithm || | ||
624 | auth_transaction != wk->probe_auth.transaction) | ||
625 | return WORK_ACT_NONE; | ||
626 | |||
627 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
628 | printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", | ||
629 | wk->sdata->name, mgmt->sa, status_code); | ||
630 | return WORK_ACT_DONE; | ||
631 | } | ||
632 | |||
633 | switch (wk->probe_auth.algorithm) { | ||
634 | case WLAN_AUTH_OPEN: | ||
635 | case WLAN_AUTH_LEAP: | ||
636 | case WLAN_AUTH_FT: | ||
637 | break; | ||
638 | case WLAN_AUTH_SHARED_KEY: | ||
639 | if (wk->probe_auth.transaction != 4) { | ||
640 | ieee80211_auth_challenge(wk, mgmt, len); | ||
641 | /* need another frame */ | ||
642 | return WORK_ACT_NONE; | ||
643 | } | ||
644 | break; | ||
645 | default: | ||
646 | WARN_ON(1); | ||
647 | return WORK_ACT_NONE; | ||
648 | } | ||
649 | |||
650 | printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name); | ||
651 | return WORK_ACT_DONE; | ||
652 | } | ||
653 | |||
654 | static enum work_action __must_check | ||
655 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, | ||
656 | struct ieee80211_mgmt *mgmt, size_t len, | ||
657 | bool reassoc) | ||
658 | { | ||
659 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
660 | struct ieee80211_local *local = sdata->local; | ||
661 | u16 capab_info, status_code, aid; | ||
662 | struct ieee802_11_elems elems; | ||
663 | u8 *pos; | ||
664 | |||
665 | if (wk->type != IEEE80211_WORK_ASSOC) | ||
666 | return WORK_ACT_MISMATCH; | ||
667 | |||
668 | /* | ||
669 | * AssocResp and ReassocResp have identical structure, so process both | ||
670 | * of them in this function. | ||
671 | */ | ||
672 | |||
673 | if (len < 24 + 6) | ||
674 | return WORK_ACT_NONE; | ||
675 | |||
676 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
677 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
678 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | ||
679 | |||
680 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
681 | "status=%d aid=%d)\n", | ||
682 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
683 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
684 | |||
685 | pos = mgmt->u.assoc_resp.variable; | ||
686 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
687 | |||
688 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
689 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
690 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
691 | u32 tu, ms; | ||
692 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
693 | ms = tu * 1024 / 1000; | ||
694 | printk(KERN_DEBUG "%s: %pM rejected association temporarily; " | ||
695 | "comeback duration %u TU (%u ms)\n", | ||
696 | sdata->name, mgmt->sa, tu, ms); | ||
697 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
698 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
699 | run_again(local, wk->timeout); | ||
700 | return WORK_ACT_NONE; | ||
701 | } | ||
702 | |||
703 | if (status_code != WLAN_STATUS_SUCCESS) | ||
704 | printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", | ||
705 | sdata->name, mgmt->sa, status_code); | ||
706 | else | ||
707 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
708 | |||
709 | return WORK_ACT_DONE; | ||
710 | } | ||
711 | |||
712 | static enum work_action __must_check | ||
713 | ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, | ||
714 | struct ieee80211_mgmt *mgmt, size_t len, | ||
715 | struct ieee80211_rx_status *rx_status) | ||
716 | { | ||
717 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
718 | struct ieee80211_local *local = sdata->local; | ||
719 | size_t baselen; | ||
720 | |||
721 | ASSERT_WORK_MTX(local); | ||
722 | |||
723 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | ||
724 | return WORK_ACT_MISMATCH; | ||
725 | |||
726 | if (len < 24 + 12) | ||
727 | return WORK_ACT_NONE; | ||
728 | |||
729 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | ||
730 | if (baselen > len) | ||
731 | return WORK_ACT_NONE; | ||
732 | |||
733 | printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); | ||
734 | return WORK_ACT_DONE; | ||
735 | } | ||
736 | |||
737 | static enum work_action __must_check | ||
738 | ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk, | ||
739 | struct ieee80211_mgmt *mgmt, size_t len) | ||
740 | { | ||
741 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
742 | struct ieee80211_local *local = sdata->local; | ||
743 | |||
744 | ASSERT_WORK_MTX(local); | ||
745 | |||
746 | if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
747 | return WORK_ACT_MISMATCH; | ||
748 | |||
749 | if (len < 24 + 12) | ||
750 | return WORK_ACT_NONE; | ||
751 | |||
752 | printk(KERN_DEBUG "%s: beacon received\n", sdata->name); | ||
753 | return WORK_ACT_DONE; | ||
754 | } | ||
755 | |||
756 | static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | ||
757 | struct sk_buff *skb) | ||
758 | { | ||
759 | struct ieee80211_rx_status *rx_status; | ||
760 | struct ieee80211_mgmt *mgmt; | ||
761 | struct ieee80211_work *wk; | ||
762 | enum work_action rma = WORK_ACT_NONE; | ||
763 | u16 fc; | ||
764 | |||
765 | rx_status = (struct ieee80211_rx_status *) skb->cb; | ||
766 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
767 | fc = le16_to_cpu(mgmt->frame_control); | ||
768 | |||
769 | mutex_lock(&local->mtx); | ||
770 | |||
771 | list_for_each_entry(wk, &local->work_list, list) { | ||
772 | const u8 *bssid = NULL; | ||
773 | |||
774 | switch (wk->type) { | ||
775 | case IEEE80211_WORK_DIRECT_PROBE: | ||
776 | case IEEE80211_WORK_AUTH: | ||
777 | case IEEE80211_WORK_ASSOC: | ||
778 | case IEEE80211_WORK_ASSOC_BEACON_WAIT: | ||
779 | bssid = wk->filter_ta; | ||
780 | break; | ||
781 | default: | ||
782 | continue; | ||
783 | } | ||
784 | |||
785 | /* | ||
786 | * Before queuing, we already verified mgmt->sa, | ||
787 | * so this is needed just for matching. | ||
788 | */ | ||
789 | if (compare_ether_addr(bssid, mgmt->bssid)) | ||
790 | continue; | ||
791 | |||
792 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
793 | case IEEE80211_STYPE_BEACON: | ||
794 | rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len); | ||
795 | break; | ||
796 | case IEEE80211_STYPE_PROBE_RESP: | ||
797 | rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, | ||
798 | rx_status); | ||
799 | break; | ||
800 | case IEEE80211_STYPE_AUTH: | ||
801 | rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len); | ||
802 | break; | ||
803 | case IEEE80211_STYPE_ASSOC_RESP: | ||
804 | rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, | ||
805 | skb->len, false); | ||
806 | break; | ||
807 | case IEEE80211_STYPE_REASSOC_RESP: | ||
808 | rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt, | ||
809 | skb->len, true); | ||
810 | break; | ||
811 | default: | ||
812 | WARN_ON(1); | ||
813 | rma = WORK_ACT_NONE; | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * We've either received an unexpected frame, or we have | ||
818 | * multiple work items and need to match the frame to the | ||
819 | * right one. | ||
820 | */ | ||
821 | if (rma == WORK_ACT_MISMATCH) | ||
822 | continue; | ||
823 | |||
824 | /* | ||
825 | * We've processed this frame for that work, so it can't | ||
826 | * belong to another work struct. | ||
827 | * NB: this is also required for correctness for 'rma'! | ||
828 | */ | ||
829 | break; | ||
830 | } | ||
831 | |||
832 | switch (rma) { | ||
833 | case WORK_ACT_MISMATCH: | ||
834 | /* ignore this unmatched frame */ | ||
835 | break; | ||
836 | case WORK_ACT_NONE: | ||
837 | break; | ||
838 | case WORK_ACT_DONE: | ||
839 | list_del_rcu(&wk->list); | ||
840 | break; | ||
841 | default: | ||
842 | WARN(1, "unexpected: %d", rma); | ||
843 | } | ||
844 | |||
845 | mutex_unlock(&local->mtx); | ||
846 | |||
847 | if (rma != WORK_ACT_DONE) | ||
848 | goto out; | ||
849 | |||
850 | switch (wk->done(wk, skb)) { | ||
851 | case WORK_DONE_DESTROY: | ||
852 | free_work(wk); | ||
853 | break; | ||
854 | case WORK_DONE_REQUEUE: | ||
855 | synchronize_rcu(); | ||
856 | wk->started = false; /* restart */ | ||
857 | mutex_lock(&local->mtx); | ||
858 | list_add_tail(&wk->list, &local->work_list); | ||
859 | mutex_unlock(&local->mtx); | ||
860 | } | ||
861 | |||
862 | out: | ||
863 | kfree_skb(skb); | ||
864 | } | ||
865 | |||
866 | static void ieee80211_work_timer(unsigned long data) | 106 | static void ieee80211_work_timer(unsigned long data) |
867 | { | 107 | { |
868 | struct ieee80211_local *local = (void *) data; | 108 | struct ieee80211_local *local = (void *) data; |
@@ -877,7 +117,6 @@ static void ieee80211_work_work(struct work_struct *work) | |||
877 | { | 117 | { |
878 | struct ieee80211_local *local = | 118 | struct ieee80211_local *local = |
879 | container_of(work, struct ieee80211_local, work_work); | 119 | container_of(work, struct ieee80211_local, work_work); |
880 | struct sk_buff *skb; | ||
881 | struct ieee80211_work *wk, *tmp; | 120 | struct ieee80211_work *wk, *tmp; |
882 | LIST_HEAD(free_work); | 121 | LIST_HEAD(free_work); |
883 | enum work_action rma; | 122 | enum work_action rma; |
@@ -893,10 +132,6 @@ static void ieee80211_work_work(struct work_struct *work) | |||
893 | if (WARN(local->suspended, "work scheduled while going to suspend\n")) | 132 | if (WARN(local->suspended, "work scheduled while going to suspend\n")) |
894 | return; | 133 | return; |
895 | 134 | ||
896 | /* first process frames to avoid timing out while a frame is pending */ | ||
897 | while ((skb = skb_dequeue(&local->work_skb_queue))) | ||
898 | ieee80211_work_rx_queued_mgmt(local, skb); | ||
899 | |||
900 | mutex_lock(&local->mtx); | 135 | mutex_lock(&local->mtx); |
901 | 136 | ||
902 | ieee80211_recalc_idle(local); | 137 | ieee80211_recalc_idle(local); |
@@ -947,24 +182,12 @@ static void ieee80211_work_work(struct work_struct *work) | |||
947 | case IEEE80211_WORK_ABORT: | 182 | case IEEE80211_WORK_ABORT: |
948 | rma = WORK_ACT_TIMEOUT; | 183 | rma = WORK_ACT_TIMEOUT; |
949 | break; | 184 | break; |
950 | case IEEE80211_WORK_DIRECT_PROBE: | ||
951 | rma = ieee80211_direct_probe(wk); | ||
952 | break; | ||
953 | case IEEE80211_WORK_AUTH: | ||
954 | rma = ieee80211_authenticate(wk); | ||
955 | break; | ||
956 | case IEEE80211_WORK_ASSOC: | ||
957 | rma = ieee80211_associate(wk); | ||
958 | break; | ||
959 | case IEEE80211_WORK_REMAIN_ON_CHANNEL: | 185 | case IEEE80211_WORK_REMAIN_ON_CHANNEL: |
960 | rma = ieee80211_remain_on_channel_timeout(wk); | 186 | rma = ieee80211_remain_on_channel_timeout(wk); |
961 | break; | 187 | break; |
962 | case IEEE80211_WORK_OFFCHANNEL_TX: | 188 | case IEEE80211_WORK_OFFCHANNEL_TX: |
963 | rma = ieee80211_offchannel_tx(wk); | 189 | rma = ieee80211_offchannel_tx(wk); |
964 | break; | 190 | break; |
965 | case IEEE80211_WORK_ASSOC_BEACON_WAIT: | ||
966 | rma = ieee80211_assoc_beacon_wait(wk); | ||
967 | break; | ||
968 | } | 191 | } |
969 | 192 | ||
970 | wk->started = started; | 193 | wk->started = started; |
@@ -1052,7 +275,6 @@ void ieee80211_work_init(struct ieee80211_local *local) | |||
1052 | setup_timer(&local->work_timer, ieee80211_work_timer, | 275 | setup_timer(&local->work_timer, ieee80211_work_timer, |
1053 | (unsigned long)local); | 276 | (unsigned long)local); |
1054 | INIT_WORK(&local->work_work, ieee80211_work_work); | 277 | INIT_WORK(&local->work_work, ieee80211_work_work); |
1055 | skb_queue_head_init(&local->work_skb_queue); | ||
1056 | } | 278 | } |
1057 | 279 | ||
1058 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) | 280 | void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) |
@@ -1086,43 +308,6 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) | |||
1086 | mutex_unlock(&local->mtx); | 308 | mutex_unlock(&local->mtx); |
1087 | } | 309 | } |
1088 | 310 | ||
1089 | ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | ||
1090 | struct sk_buff *skb) | ||
1091 | { | ||
1092 | struct ieee80211_local *local = sdata->local; | ||
1093 | struct ieee80211_mgmt *mgmt; | ||
1094 | struct ieee80211_work *wk; | ||
1095 | u16 fc; | ||
1096 | |||
1097 | if (skb->len < 24) | ||
1098 | return RX_DROP_MONITOR; | ||
1099 | |||
1100 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
1101 | fc = le16_to_cpu(mgmt->frame_control); | ||
1102 | |||
1103 | list_for_each_entry_rcu(wk, &local->work_list, list) { | ||
1104 | if (sdata != wk->sdata) | ||
1105 | continue; | ||
1106 | if (compare_ether_addr(wk->filter_ta, mgmt->sa)) | ||
1107 | continue; | ||
1108 | if (compare_ether_addr(wk->filter_ta, mgmt->bssid)) | ||
1109 | continue; | ||
1110 | |||
1111 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1112 | case IEEE80211_STYPE_AUTH: | ||
1113 | case IEEE80211_STYPE_PROBE_RESP: | ||
1114 | case IEEE80211_STYPE_ASSOC_RESP: | ||
1115 | case IEEE80211_STYPE_REASSOC_RESP: | ||
1116 | case IEEE80211_STYPE_BEACON: | ||
1117 | skb_queue_tail(&local->work_skb_queue, skb); | ||
1118 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
1119 | return RX_QUEUED; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | return RX_CONTINUE; | ||
1124 | } | ||
1125 | |||
1126 | static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, | 311 | static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, |
1127 | struct sk_buff *skb) | 312 | struct sk_buff *skb) |
1128 | { | 313 | { |