diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-06 15:57:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-06 15:57:18 -0400 |
commit | bfe34ebbaa125f00da309f59cc9d30febe1e3115 (patch) | |
tree | 505b43fc81be09ec5b42f82a3e64f300a5e838d5 /net | |
parent | 3d7ddd540b4c2d24c6a3e7a52c083a0c31e6151c (diff) | |
parent | 6b4f645a491ac29c7dced415d034eea7736155a6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/driver-trace.c | 3 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 9 | ||||
-rw-r--r-- | net/mac80211/iface.c | 36 | ||||
-rw-r--r-- | net/mac80211/main.c | 40 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 10 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 4 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 113 | ||||
-rw-r--r-- | net/mac80211/pm.c | 8 | ||||
-rw-r--r-- | net/mac80211/scan.c | 8 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 41 | ||||
-rw-r--r-- | net/rfkill/core.c | 4 | ||||
-rw-r--r-- | net/wireless/core.c | 24 | ||||
-rw-r--r-- | net/wireless/core.h | 8 | ||||
-rw-r--r-- | net/wireless/mlme.c | 38 | ||||
-rw-r--r-- | net/wireless/reg.c | 107 | ||||
-rw-r--r-- | net/wireless/reg.h | 15 | ||||
-rw-r--r-- | net/wireless/sme.c | 55 | ||||
-rw-r--r-- | net/wireless/wext.c | 1 |
20 files changed, 349 insertions, 183 deletions
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c index 6da6f79932fc..8ed8711b1a6d 100644 --- a/net/mac80211/driver-trace.c +++ b/net/mac80211/driver-trace.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* bug in tracepoint.h, it should include this */ | 1 | /* bug in tracepoint.h, it should include this */ |
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | 3 | ||
4 | /* sparse isn't too happy with all macros... */ | ||
5 | #ifndef __CHECKER__ | ||
4 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
5 | #define CREATE_TRACE_POINTS | 7 | #define CREATE_TRACE_POINTS |
6 | #include "driver-trace.h" | 8 | #include "driver-trace.h" |
9 | #endif | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6e3cca65c460..920ec8792f4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -781,7 +781,7 @@ static void ieee80211_ibss_timer(unsigned long data) | |||
781 | } | 781 | } |
782 | 782 | ||
783 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | 783 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); |
784 | queue_work(local->hw.workqueue, &ifibss->work); | 784 | ieee80211_queue_work(&local->hw, &ifibss->work); |
785 | } | 785 | } |
786 | 786 | ||
787 | #ifdef CONFIG_PM | 787 | #ifdef CONFIG_PM |
@@ -853,7 +853,7 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
853 | case IEEE80211_STYPE_PROBE_REQ: | 853 | case IEEE80211_STYPE_PROBE_REQ: |
854 | case IEEE80211_STYPE_AUTH: | 854 | case IEEE80211_STYPE_AUTH: |
855 | skb_queue_tail(&sdata->u.ibss.skb_queue, skb); | 855 | skb_queue_tail(&sdata->u.ibss.skb_queue, skb); |
856 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); | 856 | ieee80211_queue_work(&local->hw, &sdata->u.ibss.work); |
857 | return RX_QUEUED; | 857 | return RX_QUEUED; |
858 | } | 858 | } |
859 | 859 | ||
@@ -912,7 +912,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
912 | ieee80211_recalc_idle(sdata->local); | 912 | ieee80211_recalc_idle(sdata->local); |
913 | 913 | ||
914 | set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); | 914 | set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); |
915 | queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); | 915 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work); |
916 | 916 | ||
917 | return 0; | 917 | return 0; |
918 | } | 918 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index aec6853cb435..630a438180fd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -280,6 +280,7 @@ struct ieee80211_if_managed { | |||
280 | struct work_struct beacon_loss_work; | 280 | struct work_struct beacon_loss_work; |
281 | 281 | ||
282 | unsigned long probe_timeout; | 282 | unsigned long probe_timeout; |
283 | int probe_send_count; | ||
283 | 284 | ||
284 | struct mutex mtx; | 285 | struct mutex mtx; |
285 | struct ieee80211_bss *associated; | 286 | struct ieee80211_bss *associated; |
@@ -614,6 +615,12 @@ struct ieee80211_local { | |||
614 | 615 | ||
615 | const struct ieee80211_ops *ops; | 616 | const struct ieee80211_ops *ops; |
616 | 617 | ||
618 | /* | ||
619 | * private workqueue to mac80211. mac80211 makes this accessible | ||
620 | * via ieee80211_queue_work() | ||
621 | */ | ||
622 | struct workqueue_struct *workqueue; | ||
623 | |||
617 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 624 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; |
618 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | 625 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ |
619 | spinlock_t queue_stop_reason_lock; | 626 | spinlock_t queue_stop_reason_lock; |
@@ -621,7 +628,7 @@ struct ieee80211_local { | |||
621 | int open_count; | 628 | int open_count; |
622 | int monitors, cooked_mntrs; | 629 | int monitors, cooked_mntrs; |
623 | /* number of interfaces with corresponding FIF_ flags */ | 630 | /* number of interfaces with corresponding FIF_ flags */ |
624 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; | 631 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; |
625 | unsigned int filter_flags; /* FIF_* */ | 632 | unsigned int filter_flags; /* FIF_* */ |
626 | struct iw_statistics wstats; | 633 | struct iw_statistics wstats; |
627 | 634 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6c655b6547fb..e8fb03b91a44 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -220,8 +220,10 @@ static int ieee80211_open(struct net_device *dev) | |||
220 | local->fif_fcsfail++; | 220 | local->fif_fcsfail++; |
221 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | 221 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) |
222 | local->fif_plcpfail++; | 222 | local->fif_plcpfail++; |
223 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) | 223 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { |
224 | local->fif_control++; | 224 | local->fif_control++; |
225 | local->fif_pspoll++; | ||
226 | } | ||
225 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | 227 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) |
226 | local->fif_other_bss++; | 228 | local->fif_other_bss++; |
227 | 229 | ||
@@ -244,7 +246,14 @@ static int ieee80211_open(struct net_device *dev) | |||
244 | spin_unlock_bh(&local->filter_lock); | 246 | spin_unlock_bh(&local->filter_lock); |
245 | 247 | ||
246 | ieee80211_start_mesh(sdata); | 248 | ieee80211_start_mesh(sdata); |
249 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
250 | local->fif_pspoll++; | ||
251 | |||
252 | spin_lock_bh(&local->filter_lock); | ||
253 | ieee80211_configure_filter(local); | ||
254 | spin_unlock_bh(&local->filter_lock); | ||
247 | } | 255 | } |
256 | |||
248 | changed |= ieee80211_reset_erp_info(sdata); | 257 | changed |= ieee80211_reset_erp_info(sdata); |
249 | ieee80211_bss_info_change_notify(sdata, changed); | 258 | ieee80211_bss_info_change_notify(sdata, changed); |
250 | ieee80211_enable_keys(sdata); | 259 | ieee80211_enable_keys(sdata); |
@@ -312,7 +321,7 @@ static int ieee80211_open(struct net_device *dev) | |||
312 | * to fix this. | 321 | * to fix this. |
313 | */ | 322 | */ |
314 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 323 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
315 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); | 324 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); |
316 | 325 | ||
317 | netif_tx_start_all_queues(dev); | 326 | netif_tx_start_all_queues(dev); |
318 | 327 | ||
@@ -388,6 +397,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
388 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 397 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
389 | atomic_dec(&local->iff_promiscs); | 398 | atomic_dec(&local->iff_promiscs); |
390 | 399 | ||
400 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
401 | local->fif_pspoll--; | ||
402 | |||
391 | netif_addr_lock_bh(dev); | 403 | netif_addr_lock_bh(dev); |
392 | spin_lock_bh(&local->filter_lock); | 404 | spin_lock_bh(&local->filter_lock); |
393 | __dev_addr_unsync(&local->mc_list, &local->mc_count, | 405 | __dev_addr_unsync(&local->mc_list, &local->mc_count, |
@@ -401,7 +413,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
401 | 413 | ||
402 | /* APs need special treatment */ | 414 | /* APs need special treatment */ |
403 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 415 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
404 | struct ieee80211_sub_if_data *vlan, *tmp; | 416 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
405 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 417 | struct beacon_data *old_beacon = sdata->u.ap.beacon; |
406 | 418 | ||
407 | /* remove beacon */ | 419 | /* remove beacon */ |
@@ -410,7 +422,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
410 | kfree(old_beacon); | 422 | kfree(old_beacon); |
411 | 423 | ||
412 | /* down all dependent devices, that is VLANs */ | 424 | /* down all dependent devices, that is VLANs */ |
413 | list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, | 425 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
414 | u.vlan.list) | 426 | u.vlan.list) |
415 | dev_close(vlan->dev); | 427 | dev_close(vlan->dev); |
416 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 428 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
@@ -439,8 +451,10 @@ static int ieee80211_stop(struct net_device *dev) | |||
439 | local->fif_fcsfail--; | 451 | local->fif_fcsfail--; |
440 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | 452 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) |
441 | local->fif_plcpfail--; | 453 | local->fif_plcpfail--; |
442 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) | 454 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { |
455 | local->fif_pspoll--; | ||
443 | local->fif_control--; | 456 | local->fif_control--; |
457 | } | ||
444 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | 458 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) |
445 | local->fif_other_bss--; | 459 | local->fif_other_bss--; |
446 | 460 | ||
@@ -522,6 +536,16 @@ static int ieee80211_stop(struct net_device *dev) | |||
522 | ieee80211_scan_completed(&local->hw, true); | 536 | ieee80211_scan_completed(&local->hw, true); |
523 | } | 537 | } |
524 | 538 | ||
539 | /* | ||
540 | * Disable beaconing for AP and mesh, IBSS can't | ||
541 | * still be joined to a network at this point. | ||
542 | */ | ||
543 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
544 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { | ||
545 | ieee80211_bss_info_change_notify(sdata, | ||
546 | BSS_CHANGED_BEACON_ENABLED); | ||
547 | } | ||
548 | |||
525 | conf.vif = &sdata->vif; | 549 | conf.vif = &sdata->vif; |
526 | conf.type = sdata->vif.type; | 550 | conf.type = sdata->vif.type; |
527 | conf.mac_addr = dev->dev_addr; | 551 | conf.mac_addr = dev->dev_addr; |
@@ -541,7 +565,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
541 | 565 | ||
542 | ieee80211_led_radio(local, false); | 566 | ieee80211_led_radio(local, false); |
543 | 567 | ||
544 | flush_workqueue(local->hw.workqueue); | 568 | flush_workqueue(local->workqueue); |
545 | 569 | ||
546 | tasklet_disable(&local->tx_pending_tasklet); | 570 | tasklet_disable(&local->tx_pending_tasklet); |
547 | tasklet_disable(&local->tasklet); | 571 | tasklet_disable(&local->tasklet); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c1a799194fff..0c4f8e122ed6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -77,6 +77,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
77 | if (local->fif_other_bss) | 77 | if (local->fif_other_bss) |
78 | new_flags |= FIF_OTHER_BSS; | 78 | new_flags |= FIF_OTHER_BSS; |
79 | 79 | ||
80 | if (local->fif_pspoll) | ||
81 | new_flags |= FIF_PSPOLL; | ||
82 | |||
80 | changed_flags = local->filter_flags ^ new_flags; | 83 | changed_flags = local->filter_flags ^ new_flags; |
81 | 84 | ||
82 | /* be a bit nasty */ | 85 | /* be a bit nasty */ |
@@ -198,7 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
198 | } | 201 | } |
199 | 202 | ||
200 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 203 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
201 | if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { | 204 | if (local->quiescing || !netif_running(sdata->dev) || |
205 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | ||
202 | sdata->vif.bss_conf.enable_beacon = false; | 206 | sdata->vif.bss_conf.enable_beacon = false; |
203 | } else { | 207 | } else { |
204 | /* | 208 | /* |
@@ -310,6 +314,31 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
310 | { | 314 | { |
311 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 315 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
312 | 316 | ||
317 | /* | ||
318 | * XXX: This is temporary! | ||
319 | * | ||
320 | * The problem here is that when we get here, the driver will | ||
321 | * quite likely have pretty much overwritten info->control by | ||
322 | * using info->driver_data or info->rate_driver_data. Thus, | ||
323 | * when passing out the frame to the driver again, we would be | ||
324 | * passing completely bogus data since the driver would then | ||
325 | * expect a properly filled info->control. In mac80211 itself | ||
326 | * the same problem occurs, since we need info->control.vif | ||
327 | * internally. | ||
328 | * | ||
329 | * To fix this, we should send the frame through TX processing | ||
330 | * again. However, it's not that simple, since the frame will | ||
331 | * have been software-encrypted (if applicable) already, and | ||
332 | * encrypting it again doesn't do much good. So to properly do | ||
333 | * that, we not only have to skip the actual 'raw' encryption | ||
334 | * (key selection etc. still has to be done!) but also the | ||
335 | * sequence number assignment since that impacts the crypto | ||
336 | * encapsulation, of course. | ||
337 | * | ||
338 | * Hence, for now, fix the bug by just dropping the frame. | ||
339 | */ | ||
340 | goto drop; | ||
341 | |||
313 | sta->tx_filtered_count++; | 342 | sta->tx_filtered_count++; |
314 | 343 | ||
315 | /* | 344 | /* |
@@ -363,6 +392,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
363 | return; | 392 | return; |
364 | } | 393 | } |
365 | 394 | ||
395 | drop: | ||
366 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 396 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
367 | if (net_ratelimit()) | 397 | if (net_ratelimit()) |
368 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 398 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " |
@@ -794,9 +824,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
794 | if (hw->queues > IEEE80211_MAX_QUEUES) | 824 | if (hw->queues > IEEE80211_MAX_QUEUES) |
795 | hw->queues = IEEE80211_MAX_QUEUES; | 825 | hw->queues = IEEE80211_MAX_QUEUES; |
796 | 826 | ||
797 | local->hw.workqueue = | 827 | local->workqueue = |
798 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); | 828 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
799 | if (!local->hw.workqueue) { | 829 | if (!local->workqueue) { |
800 | result = -ENOMEM; | 830 | result = -ENOMEM; |
801 | goto fail_workqueue; | 831 | goto fail_workqueue; |
802 | } | 832 | } |
@@ -886,7 +916,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
886 | sta_info_stop(local); | 916 | sta_info_stop(local); |
887 | fail_sta_info: | 917 | fail_sta_info: |
888 | debugfs_hw_del(local); | 918 | debugfs_hw_del(local); |
889 | destroy_workqueue(local->hw.workqueue); | 919 | destroy_workqueue(local->workqueue); |
890 | fail_workqueue: | 920 | fail_workqueue: |
891 | wiphy_unregister(local->hw.wiphy); | 921 | wiphy_unregister(local->hw.wiphy); |
892 | fail_wiphy_register: | 922 | fail_wiphy_register: |
@@ -928,7 +958,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
928 | skb_queue_purge(&local->skb_queue); | 958 | skb_queue_purge(&local->skb_queue); |
929 | skb_queue_purge(&local->skb_queue_unreliable); | 959 | skb_queue_purge(&local->skb_queue_unreliable); |
930 | 960 | ||
931 | destroy_workqueue(local->hw.workqueue); | 961 | destroy_workqueue(local->workqueue); |
932 | wiphy_unregister(local->hw.wiphy); | 962 | wiphy_unregister(local->hw.wiphy); |
933 | ieee80211_wep_free(local); | 963 | ieee80211_wep_free(local); |
934 | ieee80211_led_exit(local); | 964 | ieee80211_led_exit(local); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a3826978b1c..2f4f518ab45c 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
54 | return; | 54 | return; |
55 | } | 55 | } |
56 | 56 | ||
57 | queue_work(local->hw.workqueue, &ifmsh->work); | 57 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); |
58 | } | 58 | } |
59 | 59 | ||
60 | /** | 60 | /** |
@@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
357 | return; | 357 | return; |
358 | } | 358 | } |
359 | 359 | ||
360 | queue_work(local->hw.workqueue, &ifmsh->work); | 360 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); |
361 | } | 361 | } |
362 | 362 | ||
363 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | 363 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) |
@@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
471 | struct ieee80211_local *local = sdata->local; | 471 | struct ieee80211_local *local = sdata->local; |
472 | 472 | ||
473 | ifmsh->housekeeping = true; | 473 | ifmsh->housekeeping = true; |
474 | queue_work(local->hw.workqueue, &ifmsh->work); | 474 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); |
475 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 475 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
476 | BSS_CHANGED_BEACON_ENABLED); | 476 | BSS_CHANGED_BEACON_ENABLED); |
477 | } | 477 | } |
@@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | |||
619 | rcu_read_lock(); | 619 | rcu_read_lock(); |
620 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 620 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
621 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 621 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
622 | queue_work(local->hw.workqueue, &sdata->u.mesh.work); | 622 | ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); |
623 | rcu_read_unlock(); | 623 | rcu_read_unlock(); |
624 | } | 624 | } |
625 | 625 | ||
@@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
692 | case IEEE80211_STYPE_PROBE_RESP: | 692 | case IEEE80211_STYPE_PROBE_RESP: |
693 | case IEEE80211_STYPE_BEACON: | 693 | case IEEE80211_STYPE_BEACON: |
694 | skb_queue_tail(&ifmsh->skb_queue, skb); | 694 | skb_queue_tail(&ifmsh->skb_queue, skb); |
695 | queue_work(local->hw.workqueue, &ifmsh->work); | 695 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); |
696 | return RX_QUEUED; | 696 | return RX_QUEUED; |
697 | } | 697 | } |
698 | 698 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e93c37ef6a48..11ab71a68ff9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
660 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 660 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
661 | 661 | ||
662 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) | 662 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) |
663 | queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 663 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); |
664 | 664 | ||
665 | else if (time_before(jiffies, ifmsh->last_preq)) { | 665 | else if (time_before(jiffies, ifmsh->last_preq)) { |
666 | /* avoid long wait if did not send preqs for a long time | 666 | /* avoid long wait if did not send preqs for a long time |
667 | * and jiffies wrapped around | 667 | * and jiffies wrapped around |
668 | */ | 668 | */ |
669 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; | 669 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; |
670 | queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 670 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); |
671 | } else | 671 | } else |
672 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + | 672 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + |
673 | min_preq_int_jiff(sdata)); | 673 | min_preq_int_jiff(sdata)); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ee83125ed179..6d5a1ee0445f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | 31 | #define IEEE80211_AUTH_MAX_TRIES 3 |
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 33 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
34 | #define IEEE80211_MAX_PROBE_TRIES 5 | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * beacon loss detection timeout | 37 | * beacon loss detection timeout |
@@ -41,13 +42,13 @@ | |||
41 | * Time the connection can be idle before we probe | 42 | * Time the connection can be idle before we probe |
42 | * it to see if we can still talk to the AP. | 43 | * it to see if we can still talk to the AP. |
43 | */ | 44 | */ |
44 | #define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) | 45 | #define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ) |
45 | /* | 46 | /* |
46 | * Time we wait for a probe response after sending | 47 | * Time we wait for a probe response after sending |
47 | * a probe request because of beacon loss or for | 48 | * a probe request because of beacon loss or for |
48 | * checking the connection still works. | 49 | * checking the connection still works. |
49 | */ | 50 | */ |
50 | #define IEEE80211_PROBE_WAIT (HZ / 5) | 51 | #define IEEE80211_PROBE_WAIT (HZ / 2) |
51 | 52 | ||
52 | #define TMR_RUNNING_TIMER 0 | 53 | #define TMR_RUNNING_TIMER 0 |
53 | #define TMR_RUNNING_CHANSW 1 | 54 | #define TMR_RUNNING_CHANSW 1 |
@@ -565,7 +566,7 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
565 | return; | 566 | return; |
566 | } | 567 | } |
567 | 568 | ||
568 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | 569 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
569 | } | 570 | } |
570 | 571 | ||
571 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 572 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
@@ -597,7 +598,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
597 | sdata->local->csa_channel = new_ch; | 598 | sdata->local->csa_channel = new_ch; |
598 | 599 | ||
599 | if (sw_elem->count <= 1) { | 600 | if (sw_elem->count <= 1) { |
600 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | 601 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
601 | } else { | 602 | } else { |
602 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 603 | ieee80211_stop_queues_by_reason(&sdata->local->hw, |
603 | IEEE80211_QUEUE_STOP_REASON_CSA); | 604 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -763,7 +764,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
763 | if (local->quiescing || local->suspended) | 764 | if (local->quiescing || local->suspended) |
764 | return; | 765 | return; |
765 | 766 | ||
766 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 767 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); |
767 | } | 768 | } |
768 | 769 | ||
769 | /* MLME */ | 770 | /* MLME */ |
@@ -916,12 +917,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
916 | 917 | ||
917 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 918 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
918 | 919 | ||
919 | /* will be same as sdata */ | 920 | mutex_lock(&local->iflist_mtx); |
920 | if (local->ps_sdata) { | 921 | ieee80211_recalc_ps(local, -1); |
921 | mutex_lock(&local->iflist_mtx); | 922 | mutex_unlock(&local->iflist_mtx); |
922 | ieee80211_recalc_ps(local, -1); | ||
923 | mutex_unlock(&local->iflist_mtx); | ||
924 | } | ||
925 | 923 | ||
926 | netif_tx_start_all_queues(sdata->dev); | 924 | netif_tx_start_all_queues(sdata->dev); |
927 | netif_carrier_on(sdata->dev); | 925 | netif_carrier_on(sdata->dev); |
@@ -950,7 +948,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | |||
950 | * due to work needing to be done. Hence, queue the STAs work | 948 | * due to work needing to be done. Hence, queue the STAs work |
951 | * again for that. | 949 | * again for that. |
952 | */ | 950 | */ |
953 | queue_work(local->hw.workqueue, &ifmgd->work); | 951 | ieee80211_queue_work(&local->hw, &ifmgd->work); |
954 | return RX_MGMT_CFG80211_AUTH_TO; | 952 | return RX_MGMT_CFG80211_AUTH_TO; |
955 | } | 953 | } |
956 | 954 | ||
@@ -995,7 +993,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
995 | * due to work needing to be done. Hence, queue the STAs work | 993 | * due to work needing to be done. Hence, queue the STAs work |
996 | * again for that. | 994 | * again for that. |
997 | */ | 995 | */ |
998 | queue_work(local->hw.workqueue, &ifmgd->work); | 996 | ieee80211_queue_work(&local->hw, &ifmgd->work); |
999 | return RX_MGMT_CFG80211_AUTH_TO; | 997 | return RX_MGMT_CFG80211_AUTH_TO; |
1000 | } | 998 | } |
1001 | 999 | ||
@@ -1124,7 +1122,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, | |||
1124 | * due to work needing to be done. Hence, queue the STAs work | 1122 | * due to work needing to be done. Hence, queue the STAs work |
1125 | * again for that. | 1123 | * again for that. |
1126 | */ | 1124 | */ |
1127 | queue_work(local->hw.workqueue, &ifmgd->work); | 1125 | ieee80211_queue_work(&local->hw, &ifmgd->work); |
1128 | return RX_MGMT_CFG80211_ASSOC_TO; | 1126 | return RX_MGMT_CFG80211_ASSOC_TO; |
1129 | } | 1127 | } |
1130 | 1128 | ||
@@ -1156,11 +1154,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1156 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | 1154 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); |
1157 | } | 1155 | } |
1158 | 1156 | ||
1157 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | ||
1158 | { | ||
1159 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1160 | const u8 *ssid; | ||
1161 | |||
1162 | ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); | ||
1163 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, | ||
1164 | ssid + 2, ssid[1], NULL, 0); | ||
1165 | |||
1166 | ifmgd->probe_send_count++; | ||
1167 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | ||
1168 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1169 | } | ||
1170 | |||
1159 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 1171 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
1160 | bool beacon) | 1172 | bool beacon) |
1161 | { | 1173 | { |
1162 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1174 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1163 | const u8 *ssid; | ||
1164 | bool already = false; | 1175 | bool already = false; |
1165 | 1176 | ||
1166 | if (!netif_running(sdata->dev)) | 1177 | if (!netif_running(sdata->dev)) |
@@ -1203,18 +1214,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1203 | if (already) | 1214 | if (already) |
1204 | goto out; | 1215 | goto out; |
1205 | 1216 | ||
1206 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | ||
1207 | |||
1208 | mutex_lock(&sdata->local->iflist_mtx); | 1217 | mutex_lock(&sdata->local->iflist_mtx); |
1209 | ieee80211_recalc_ps(sdata->local, -1); | 1218 | ieee80211_recalc_ps(sdata->local, -1); |
1210 | mutex_unlock(&sdata->local->iflist_mtx); | 1219 | mutex_unlock(&sdata->local->iflist_mtx); |
1211 | 1220 | ||
1212 | ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); | 1221 | ifmgd->probe_send_count = 0; |
1213 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, | 1222 | ieee80211_mgd_probe_ap_send(sdata); |
1214 | ssid + 2, ssid[1], NULL, 0); | ||
1215 | |||
1216 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1217 | |||
1218 | out: | 1223 | out: |
1219 | mutex_unlock(&ifmgd->mtx); | 1224 | mutex_unlock(&ifmgd->mtx); |
1220 | } | 1225 | } |
@@ -1232,8 +1237,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
1232 | { | 1237 | { |
1233 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1238 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1234 | 1239 | ||
1235 | queue_work(sdata->local->hw.workqueue, | 1240 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); |
1236 | &sdata->u.mgd.beacon_loss_work); | ||
1237 | } | 1241 | } |
1238 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 1242 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
1239 | 1243 | ||
@@ -1570,6 +1574,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1570 | wk->bss->cbss.bssid, | 1574 | wk->bss->cbss.bssid, |
1571 | ap_ht_cap_flags); | 1575 | ap_ht_cap_flags); |
1572 | 1576 | ||
1577 | /* delete work item -- must be before set_associated for PS */ | ||
1578 | list_del(&wk->list); | ||
1579 | |||
1573 | /* set AID and assoc capability, | 1580 | /* set AID and assoc capability, |
1574 | * ieee80211_set_associated() will tell the driver */ | 1581 | * ieee80211_set_associated() will tell the driver */ |
1575 | bss_conf->aid = aid; | 1582 | bss_conf->aid = aid; |
@@ -1583,7 +1590,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1583 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1590 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1584 | mod_beacon_timer(sdata); | 1591 | mod_beacon_timer(sdata); |
1585 | 1592 | ||
1586 | list_del(&wk->list); | ||
1587 | kfree(wk); | 1593 | kfree(wk); |
1588 | return RX_MGMT_CFG80211_ASSOC; | 1594 | return RX_MGMT_CFG80211_ASSOC; |
1589 | } | 1595 | } |
@@ -1847,12 +1853,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1847 | bssid, ap_ht_cap_flags); | 1853 | bssid, ap_ht_cap_flags); |
1848 | } | 1854 | } |
1849 | 1855 | ||
1856 | /* Note: country IE parsing is done for us by cfg80211 */ | ||
1850 | if (elems.country_elem) { | 1857 | if (elems.country_elem) { |
1851 | /* Note we are only reviewing this on beacons | ||
1852 | * for the BSSID we are associated to */ | ||
1853 | regulatory_hint_11d(local->hw.wiphy, | ||
1854 | elems.country_elem, elems.country_elem_len); | ||
1855 | |||
1856 | /* TODO: IBSS also needs this */ | 1858 | /* TODO: IBSS also needs this */ |
1857 | if (elems.pwr_constr_elem) | 1859 | if (elems.pwr_constr_elem) |
1858 | ieee80211_handle_pwr_constr(sdata, | 1860 | ieee80211_handle_pwr_constr(sdata, |
@@ -1888,7 +1890,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1888 | case IEEE80211_STYPE_DISASSOC: | 1890 | case IEEE80211_STYPE_DISASSOC: |
1889 | case IEEE80211_STYPE_ACTION: | 1891 | case IEEE80211_STYPE_ACTION: |
1890 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); | 1892 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); |
1891 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); | 1893 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); |
1892 | return RX_QUEUED; | 1894 | return RX_QUEUED; |
1893 | } | 1895 | } |
1894 | 1896 | ||
@@ -2026,7 +2028,7 @@ static void ieee80211_sta_timer(unsigned long data) | |||
2026 | return; | 2028 | return; |
2027 | } | 2029 | } |
2028 | 2030 | ||
2029 | queue_work(local->hw.workqueue, &ifmgd->work); | 2031 | ieee80211_queue_work(&local->hw, &ifmgd->work); |
2030 | } | 2032 | } |
2031 | 2033 | ||
2032 | static void ieee80211_sta_work(struct work_struct *work) | 2034 | static void ieee80211_sta_work(struct work_struct *work) |
@@ -2051,13 +2053,11 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2051 | return; | 2053 | return; |
2052 | 2054 | ||
2053 | /* | 2055 | /* |
2054 | * Nothing should have been stuffed into the workqueue during | 2056 | * ieee80211_queue_work() should have picked up most cases, |
2055 | * the suspend->resume cycle. If this WARN is seen then there | 2057 | * here we'll pick the the rest. |
2056 | * is a bug with either the driver suspend or something in | ||
2057 | * mac80211 stuffing into the workqueue which we haven't yet | ||
2058 | * cleared during mac80211's suspend cycle. | ||
2059 | */ | 2058 | */ |
2060 | if (WARN_ON(local->suspended)) | 2059 | if (WARN(local->suspended, "STA MLME work scheduled while " |
2060 | "going to suspend\n")) | ||
2061 | return; | 2061 | return; |
2062 | 2062 | ||
2063 | ifmgd = &sdata->u.mgd; | 2063 | ifmgd = &sdata->u.mgd; |
@@ -2072,17 +2072,27 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2072 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 2072 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
2073 | IEEE80211_STA_CONNECTION_POLL) && | 2073 | IEEE80211_STA_CONNECTION_POLL) && |
2074 | ifmgd->associated) { | 2074 | ifmgd->associated) { |
2075 | u8 bssid[ETH_ALEN]; | ||
2076 | |||
2077 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | ||
2075 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | 2078 | if (time_is_after_jiffies(ifmgd->probe_timeout)) |
2076 | run_again(ifmgd, ifmgd->probe_timeout); | 2079 | run_again(ifmgd, ifmgd->probe_timeout); |
2077 | else { | 2080 | |
2078 | u8 bssid[ETH_ALEN]; | 2081 | else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { |
2082 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2083 | printk(KERN_DEBUG "No probe response from AP %pM" | ||
2084 | " after %dms, try %d\n", bssid, | ||
2085 | (1000 * IEEE80211_PROBE_WAIT)/HZ, | ||
2086 | ifmgd->probe_send_count); | ||
2087 | #endif | ||
2088 | ieee80211_mgd_probe_ap_send(sdata); | ||
2089 | } else { | ||
2079 | /* | 2090 | /* |
2080 | * We actually lost the connection ... or did we? | 2091 | * We actually lost the connection ... or did we? |
2081 | * Let's make sure! | 2092 | * Let's make sure! |
2082 | */ | 2093 | */ |
2083 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 2094 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
2084 | IEEE80211_STA_BEACON_POLL); | 2095 | IEEE80211_STA_BEACON_POLL); |
2085 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | ||
2086 | printk(KERN_DEBUG "No probe response from AP %pM" | 2096 | printk(KERN_DEBUG "No probe response from AP %pM" |
2087 | " after %dms, disconnecting.\n", | 2097 | " after %dms, disconnecting.\n", |
2088 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2098 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
@@ -2113,9 +2123,9 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2113 | mutex_unlock(&ifmgd->mtx); | 2123 | mutex_unlock(&ifmgd->mtx); |
2114 | 2124 | ||
2115 | if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) | 2125 | if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) |
2116 | queue_delayed_work(local->hw.workqueue, | 2126 | ieee80211_queue_delayed_work(&local->hw, |
2117 | &local->scan_work, | 2127 | &local->scan_work, |
2118 | round_jiffies_relative(0)); | 2128 | round_jiffies_relative(0)); |
2119 | return; | 2129 | return; |
2120 | } | 2130 | } |
2121 | 2131 | ||
@@ -2196,8 +2206,7 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
2196 | if (local->quiescing) | 2206 | if (local->quiescing) |
2197 | return; | 2207 | return; |
2198 | 2208 | ||
2199 | queue_work(sdata->local->hw.workqueue, | 2209 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); |
2200 | &sdata->u.mgd.beacon_loss_work); | ||
2201 | } | 2210 | } |
2202 | 2211 | ||
2203 | static void ieee80211_sta_conn_mon_timer(unsigned long data) | 2212 | static void ieee80211_sta_conn_mon_timer(unsigned long data) |
@@ -2210,7 +2219,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
2210 | if (local->quiescing) | 2219 | if (local->quiescing) |
2211 | return; | 2220 | return; |
2212 | 2221 | ||
2213 | queue_work(local->hw.workqueue, &ifmgd->monitor_work); | 2222 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
2214 | } | 2223 | } |
2215 | 2224 | ||
2216 | static void ieee80211_sta_monitor_work(struct work_struct *work) | 2225 | static void ieee80211_sta_monitor_work(struct work_struct *work) |
@@ -2229,10 +2238,10 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2229 | IEEE80211_STA_CONNECTION_POLL); | 2238 | IEEE80211_STA_CONNECTION_POLL); |
2230 | 2239 | ||
2231 | /* let's probe the connection once */ | 2240 | /* let's probe the connection once */ |
2232 | queue_work(sdata->local->hw.workqueue, | 2241 | ieee80211_queue_work(&sdata->local->hw, |
2233 | &sdata->u.mgd.monitor_work); | 2242 | &sdata->u.mgd.monitor_work); |
2234 | /* and do all the other regular work too */ | 2243 | /* and do all the other regular work too */ |
2235 | queue_work(sdata->local->hw.workqueue, | 2244 | ieee80211_queue_work(&sdata->local->hw, |
2236 | &sdata->u.mgd.work); | 2245 | &sdata->u.mgd.work); |
2237 | } | 2246 | } |
2238 | } | 2247 | } |
@@ -2393,7 +2402,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2393 | list_add(&wk->list, &sdata->u.mgd.work_list); | 2402 | list_add(&wk->list, &sdata->u.mgd.work_list); |
2394 | mutex_unlock(&ifmgd->mtx); | 2403 | mutex_unlock(&ifmgd->mtx); |
2395 | 2404 | ||
2396 | queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); | 2405 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); |
2397 | return 0; | 2406 | return 0; |
2398 | } | 2407 | } |
2399 | 2408 | ||
@@ -2467,7 +2476,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2467 | else | 2476 | else |
2468 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | 2477 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; |
2469 | 2478 | ||
2470 | queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); | 2479 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); |
2471 | 2480 | ||
2472 | err = 0; | 2481 | err = 0; |
2473 | 2482 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5e3d476972f9..a5d2f1fb4417 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -26,7 +26,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
26 | /* make quiescing visible to timers everywhere */ | 26 | /* make quiescing visible to timers everywhere */ |
27 | mb(); | 27 | mb(); |
28 | 28 | ||
29 | flush_workqueue(local->hw.workqueue); | 29 | flush_workqueue(local->workqueue); |
30 | 30 | ||
31 | /* Don't try to run timers while suspended. */ | 31 | /* Don't try to run timers while suspended. */ |
32 | del_timer_sync(&local->sta_cleanup); | 32 | del_timer_sync(&local->sta_cleanup); |
@@ -96,6 +96,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
96 | if (!netif_running(sdata->dev)) | 96 | if (!netif_running(sdata->dev)) |
97 | continue; | 97 | continue; |
98 | 98 | ||
99 | /* disable beaconing */ | ||
100 | ieee80211_bss_info_change_notify(sdata, | ||
101 | BSS_CHANGED_BEACON_ENABLED); | ||
102 | |||
99 | conf.vif = &sdata->vif; | 103 | conf.vif = &sdata->vif; |
100 | conf.type = sdata->vif.type; | 104 | conf.type = sdata->vif.type; |
101 | conf.mac_addr = sdata->dev->dev_addr; | 105 | conf.mac_addr = sdata->dev->dev_addr; |
@@ -113,7 +117,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
113 | * shouldn't be doing (or cancel everything in the | 117 | * shouldn't be doing (or cancel everything in the |
114 | * stop callback) that but better safe than sorry. | 118 | * stop callback) that but better safe than sorry. |
115 | */ | 119 | */ |
116 | flush_workqueue(local->hw.workqueue); | 120 | flush_workqueue(local->workqueue); |
117 | 121 | ||
118 | local->suspended = true; | 122 | local->suspended = true; |
119 | /* need suspended to be visible before quiescing is false */ | 123 | /* need suspended to be visible before quiescing is false */ |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 45731000eb8d..244f53f3c8b4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -385,8 +385,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
385 | spin_unlock_bh(&local->filter_lock); | 385 | spin_unlock_bh(&local->filter_lock); |
386 | 386 | ||
387 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | 387 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ |
388 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | 388 | ieee80211_queue_delayed_work(&local->hw, |
389 | IEEE80211_CHANNEL_TIME); | 389 | &local->scan_work, |
390 | IEEE80211_CHANNEL_TIME); | ||
390 | 391 | ||
391 | return 0; | 392 | return 0; |
392 | } | 393 | } |
@@ -715,8 +716,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
715 | } | 716 | } |
716 | } while (next_delay == 0); | 717 | } while (next_delay == 0); |
717 | 718 | ||
718 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | 719 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); |
719 | next_delay); | ||
720 | } | 720 | } |
721 | 721 | ||
722 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 722 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4e1b2ba122cd..7cffaa046b33 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1400,7 +1400,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1400 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 1400 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
1401 | ieee80211_stop_queues_by_reason(&local->hw, | 1401 | ieee80211_stop_queues_by_reason(&local->hw, |
1402 | IEEE80211_QUEUE_STOP_REASON_PS); | 1402 | IEEE80211_QUEUE_STOP_REASON_PS); |
1403 | queue_work(local->hw.workqueue, | 1403 | ieee80211_queue_work(&local->hw, |
1404 | &local->dynamic_ps_disable_work); | 1404 | &local->dynamic_ps_disable_work); |
1405 | } | 1405 | } |
1406 | 1406 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8502936e5314..e55d57f559ec 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -511,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
511 | } | 511 | } |
512 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 512 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); |
513 | 513 | ||
514 | /* | ||
515 | * Nothing should have been stuffed into the workqueue during | ||
516 | * the suspend->resume cycle. If this WARN is seen then there | ||
517 | * is a bug with either the driver suspend or something in | ||
518 | * mac80211 stuffing into the workqueue which we haven't yet | ||
519 | * cleared during mac80211's suspend cycle. | ||
520 | */ | ||
521 | static bool ieee80211_can_queue_work(struct ieee80211_local *local) | ||
522 | { | ||
523 | if (WARN(local->suspended, "queueing ieee80211 work while " | ||
524 | "going to suspend\n")) | ||
525 | return false; | ||
526 | |||
527 | return true; | ||
528 | } | ||
529 | |||
530 | void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) | ||
531 | { | ||
532 | struct ieee80211_local *local = hw_to_local(hw); | ||
533 | |||
534 | if (!ieee80211_can_queue_work(local)) | ||
535 | return; | ||
536 | |||
537 | queue_work(local->workqueue, work); | ||
538 | } | ||
539 | EXPORT_SYMBOL(ieee80211_queue_work); | ||
540 | |||
541 | void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, | ||
542 | struct delayed_work *dwork, | ||
543 | unsigned long delay) | ||
544 | { | ||
545 | struct ieee80211_local *local = hw_to_local(hw); | ||
546 | |||
547 | if (!ieee80211_can_queue_work(local)) | ||
548 | return; | ||
549 | |||
550 | queue_delayed_work(local->workqueue, dwork, delay); | ||
551 | } | ||
552 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | ||
553 | |||
514 | void ieee802_11_parse_elems(u8 *start, size_t len, | 554 | void ieee802_11_parse_elems(u8 *start, size_t len, |
515 | struct ieee802_11_elems *elems) | 555 | struct ieee802_11_elems *elems) |
516 | { | 556 | { |
@@ -1114,3 +1154,4 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1114 | #endif | 1154 | #endif |
1115 | return 0; | 1155 | return 0; |
1116 | } | 1156 | } |
1157 | |||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 044de1c6af3d..dbeaf2983822 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -589,11 +589,13 @@ static const char *rfkill_get_type_str(enum rfkill_type type) | |||
589 | return "wimax"; | 589 | return "wimax"; |
590 | case RFKILL_TYPE_WWAN: | 590 | case RFKILL_TYPE_WWAN: |
591 | return "wwan"; | 591 | return "wwan"; |
592 | case RFKILL_TYPE_GPS: | ||
593 | return "gps"; | ||
592 | default: | 594 | default: |
593 | BUG(); | 595 | BUG(); |
594 | } | 596 | } |
595 | 597 | ||
596 | BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); | 598 | BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_GPS + 1); |
597 | } | 599 | } |
598 | 600 | ||
599 | static ssize_t rfkill_type_show(struct device *dev, | 601 | static ssize_t rfkill_type_show(struct device *dev, |
diff --git a/net/wireless/core.c b/net/wireless/core.c index f9fee65dc06a..1e189306560d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -34,9 +34,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain, | 37 | * This is used to protect the cfg80211_rdev_list |
38 | * country_ie_regdomain, the reg_beacon_list and the the last regulatory | ||
39 | * request receipt (last_request). | ||
40 | */ | 38 | */ |
41 | DEFINE_MUTEX(cfg80211_mutex); | 39 | DEFINE_MUTEX(cfg80211_mutex); |
42 | 40 | ||
@@ -314,7 +312,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) | |||
314 | ev->cr.req_ie, ev->cr.req_ie_len, | 312 | ev->cr.req_ie, ev->cr.req_ie_len, |
315 | ev->cr.resp_ie, ev->cr.resp_ie_len, | 313 | ev->cr.resp_ie, ev->cr.resp_ie_len, |
316 | ev->cr.status, | 314 | ev->cr.status, |
317 | ev->cr.status == WLAN_STATUS_SUCCESS); | 315 | ev->cr.status == WLAN_STATUS_SUCCESS, |
316 | NULL); | ||
318 | break; | 317 | break; |
319 | case EVENT_ROAMED: | 318 | case EVENT_ROAMED: |
320 | __cfg80211_roamed(wdev, ev->rm.bssid, | 319 | __cfg80211_roamed(wdev, ev->rm.bssid, |
@@ -672,7 +671,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
672 | wdev->wext.default_mgmt_key = -1; | 671 | wdev->wext.default_mgmt_key = -1; |
673 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 672 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
674 | wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; | 673 | wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; |
675 | wdev->wext.ps_timeout = 500; | 674 | wdev->wext.ps_timeout = 100; |
676 | if (rdev->ops->set_power_mgmt) | 675 | if (rdev->ops->set_power_mgmt) |
677 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 676 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
678 | wdev->wext.ps, | 677 | wdev->wext.ps, |
@@ -724,15 +723,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
724 | break; | 723 | break; |
725 | case NETDEV_UNREGISTER: | 724 | case NETDEV_UNREGISTER: |
726 | mutex_lock(&rdev->devlist_mtx); | 725 | mutex_lock(&rdev->devlist_mtx); |
726 | /* | ||
727 | * It is possible to get NETDEV_UNREGISTER | ||
728 | * multiple times. To detect that, check | ||
729 | * that the interface is still on the list | ||
730 | * of registered interfaces, and only then | ||
731 | * remove and clean it up. | ||
732 | */ | ||
727 | if (!list_empty(&wdev->list)) { | 733 | if (!list_empty(&wdev->list)) { |
728 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 734 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
729 | list_del_init(&wdev->list); | 735 | list_del_init(&wdev->list); |
730 | } | 736 | mutex_destroy(&wdev->mtx); |
731 | mutex_unlock(&rdev->devlist_mtx); | ||
732 | mutex_destroy(&wdev->mtx); | ||
733 | #ifdef CONFIG_WIRELESS_EXT | 737 | #ifdef CONFIG_WIRELESS_EXT |
734 | kfree(wdev->wext.keys); | 738 | kfree(wdev->wext.keys); |
735 | #endif | 739 | #endif |
740 | } | ||
741 | mutex_unlock(&rdev->devlist_mtx); | ||
736 | break; | 742 | break; |
737 | case NETDEV_PRE_UP: | 743 | case NETDEV_PRE_UP: |
738 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 744 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 6d903c1d721d..325c17e6198c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -127,6 +127,11 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu | |||
127 | return container_of(pub, struct cfg80211_internal_bss, pub); | 127 | return container_of(pub, struct cfg80211_internal_bss, pub); |
128 | } | 128 | } |
129 | 129 | ||
130 | static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) | ||
131 | { | ||
132 | kref_get(&bss->ref); | ||
133 | } | ||
134 | |||
130 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | 135 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) |
131 | { | 136 | { |
132 | atomic_inc(&bss->hold); | 137 | atomic_inc(&bss->hold); |
@@ -323,7 +328,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
323 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 328 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
324 | const u8 *req_ie, size_t req_ie_len, | 329 | const u8 *req_ie, size_t req_ie_len, |
325 | const u8 *resp_ie, size_t resp_ie_len, | 330 | const u8 *resp_ie, size_t resp_ie_len, |
326 | u16 status, bool wextev); | 331 | u16 status, bool wextev, |
332 | struct cfg80211_bss *bss); | ||
327 | 333 | ||
328 | /* SME */ | 334 | /* SME */ |
329 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 097a87d7bae1..525e8e247b30 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -61,7 +61,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
61 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 61 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
62 | u8 *ie = mgmt->u.assoc_resp.variable; | 62 | u8 *ie = mgmt->u.assoc_resp.variable; |
63 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 63 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
64 | bool done; | 64 | struct cfg80211_internal_bss *bss = NULL; |
65 | 65 | ||
66 | wdev_lock(wdev); | 66 | wdev_lock(wdev); |
67 | 67 | ||
@@ -69,22 +69,32 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
69 | 69 | ||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 71 | ||
72 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | ||
73 | status_code, | ||
74 | status_code == WLAN_STATUS_SUCCESS); | ||
75 | |||
76 | if (status_code == WLAN_STATUS_SUCCESS) { | 72 | if (status_code == WLAN_STATUS_SUCCESS) { |
77 | for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { | 73 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
78 | if (wdev->auth_bsses[i] == wdev->current_bss) { | 74 | if (!wdev->auth_bsses[i]) |
79 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | 75 | continue; |
80 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | 76 | if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid, |
77 | ETH_ALEN) == 0) { | ||
78 | bss = wdev->auth_bsses[i]; | ||
81 | wdev->auth_bsses[i] = NULL; | 79 | wdev->auth_bsses[i] = NULL; |
82 | done = true; | 80 | /* additional reference to drop hold */ |
81 | cfg80211_ref_bss(bss); | ||
83 | break; | 82 | break; |
84 | } | 83 | } |
85 | } | 84 | } |
86 | 85 | ||
87 | WARN_ON(!done); | 86 | WARN_ON(!bss); |
87 | } | ||
88 | |||
89 | /* this consumes one bss reference (unless bss is NULL) */ | ||
90 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | ||
91 | status_code, | ||
92 | status_code == WLAN_STATUS_SUCCESS, | ||
93 | bss ? &bss->pub : NULL); | ||
94 | /* drop hold now, and also reference acquired above */ | ||
95 | if (bss) { | ||
96 | cfg80211_unhold_bss(bss); | ||
97 | cfg80211_put_bss(&bss->pub); | ||
88 | } | 98 | } |
89 | 99 | ||
90 | wdev_unlock(wdev); | 100 | wdev_unlock(wdev); |
@@ -144,7 +154,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
144 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 154 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
145 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 155 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
146 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 156 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
147 | false); | 157 | false, NULL); |
148 | } | 158 | } |
149 | } | 159 | } |
150 | 160 | ||
@@ -241,7 +251,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
241 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 251 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
242 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 252 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
243 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 253 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
244 | false); | 254 | false, NULL); |
245 | 255 | ||
246 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 256 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
247 | if (wdev->authtry_bsses[i] && | 257 | if (wdev->authtry_bsses[i] && |
@@ -275,7 +285,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
275 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 285 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
276 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 286 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
277 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 287 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
278 | false); | 288 | false, NULL); |
279 | 289 | ||
280 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 290 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
281 | if (wdev->auth_bsses[i] && | 291 | if (wdev->auth_bsses[i] && |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index fb40428a5946..b3ac0aace0e5 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
62 | */ | 62 | */ |
63 | static const struct ieee80211_regdomain *country_ie_regdomain; | 63 | static const struct ieee80211_regdomain *country_ie_regdomain; |
64 | 64 | ||
65 | /* | ||
66 | * Protects static reg.c components: | ||
67 | * - cfg80211_world_regdom | ||
68 | * - cfg80211_regdom | ||
69 | * - country_ie_regdomain | ||
70 | * - last_request | ||
71 | */ | ||
72 | DEFINE_MUTEX(reg_mutex); | ||
73 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | ||
74 | |||
65 | /* Used to queue up regulatory hints */ | 75 | /* Used to queue up regulatory hints */ |
66 | static LIST_HEAD(reg_requests_list); | 76 | static LIST_HEAD(reg_requests_list); |
67 | static spinlock_t reg_requests_lock; | 77 | static spinlock_t reg_requests_lock; |
@@ -1293,7 +1303,7 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1293 | struct ieee80211_supported_band *sband; | 1303 | struct ieee80211_supported_band *sband; |
1294 | struct ieee80211_channel *chan; | 1304 | struct ieee80211_channel *chan; |
1295 | 1305 | ||
1296 | assert_cfg80211_lock(); | 1306 | assert_reg_lock(); |
1297 | 1307 | ||
1298 | sband = wiphy->bands[band]; | 1308 | sband = wiphy->bands[band]; |
1299 | BUG_ON(chan_idx >= sband->n_channels); | 1309 | BUG_ON(chan_idx >= sband->n_channels); |
@@ -1342,14 +1352,14 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1342 | enum ieee80211_band band; | 1352 | enum ieee80211_band band; |
1343 | unsigned int bands_set = 0; | 1353 | unsigned int bands_set = 0; |
1344 | 1354 | ||
1345 | mutex_lock(&cfg80211_mutex); | 1355 | mutex_lock(®_mutex); |
1346 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1356 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1347 | if (!wiphy->bands[band]) | 1357 | if (!wiphy->bands[band]) |
1348 | continue; | 1358 | continue; |
1349 | handle_band_custom(wiphy, band, regd); | 1359 | handle_band_custom(wiphy, band, regd); |
1350 | bands_set++; | 1360 | bands_set++; |
1351 | } | 1361 | } |
1352 | mutex_unlock(&cfg80211_mutex); | 1362 | mutex_unlock(®_mutex); |
1353 | 1363 | ||
1354 | /* | 1364 | /* |
1355 | * no point in calling this if it won't have any effect | 1365 | * no point in calling this if it won't have any effect |
@@ -1495,7 +1505,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1495 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | 1505 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had |
1496 | * already been set or other standard error codes. | 1506 | * already been set or other standard error codes. |
1497 | * | 1507 | * |
1498 | * Caller must hold &cfg80211_mutex | 1508 | * Caller must hold &cfg80211_mutex and ®_mutex |
1499 | */ | 1509 | */ |
1500 | static int __regulatory_hint(struct wiphy *wiphy, | 1510 | static int __regulatory_hint(struct wiphy *wiphy, |
1501 | struct regulatory_request *pending_request) | 1511 | struct regulatory_request *pending_request) |
@@ -1570,6 +1580,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1570 | BUG_ON(!reg_request->alpha2); | 1580 | BUG_ON(!reg_request->alpha2); |
1571 | 1581 | ||
1572 | mutex_lock(&cfg80211_mutex); | 1582 | mutex_lock(&cfg80211_mutex); |
1583 | mutex_lock(®_mutex); | ||
1573 | 1584 | ||
1574 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | 1585 | if (wiphy_idx_valid(reg_request->wiphy_idx)) |
1575 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1586 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
@@ -1585,6 +1596,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1585 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) | 1596 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) |
1586 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1597 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1587 | out: | 1598 | out: |
1599 | mutex_unlock(®_mutex); | ||
1588 | mutex_unlock(&cfg80211_mutex); | 1600 | mutex_unlock(&cfg80211_mutex); |
1589 | } | 1601 | } |
1590 | 1602 | ||
@@ -1613,6 +1625,10 @@ static void reg_process_pending_beacon_hints(void) | |||
1613 | struct cfg80211_registered_device *rdev; | 1625 | struct cfg80211_registered_device *rdev; |
1614 | struct reg_beacon *pending_beacon, *tmp; | 1626 | struct reg_beacon *pending_beacon, *tmp; |
1615 | 1627 | ||
1628 | /* | ||
1629 | * No need to hold the reg_mutex here as we just touch wiphys | ||
1630 | * and do not read or access regulatory variables. | ||
1631 | */ | ||
1616 | mutex_lock(&cfg80211_mutex); | 1632 | mutex_lock(&cfg80211_mutex); |
1617 | 1633 | ||
1618 | /* This goes through the _pending_ beacon list */ | 1634 | /* This goes through the _pending_ beacon list */ |
@@ -1734,12 +1750,13 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
1734 | } | 1750 | } |
1735 | EXPORT_SYMBOL(regulatory_hint); | 1751 | EXPORT_SYMBOL(regulatory_hint); |
1736 | 1752 | ||
1753 | /* Caller must hold reg_mutex */ | ||
1737 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1754 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
1738 | u32 country_ie_checksum) | 1755 | u32 country_ie_checksum) |
1739 | { | 1756 | { |
1740 | struct wiphy *request_wiphy; | 1757 | struct wiphy *request_wiphy; |
1741 | 1758 | ||
1742 | assert_cfg80211_lock(); | 1759 | assert_reg_lock(); |
1743 | 1760 | ||
1744 | if (unlikely(last_request->initiator != | 1761 | if (unlikely(last_request->initiator != |
1745 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | 1762 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) |
@@ -1762,6 +1779,10 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1762 | return false; | 1779 | return false; |
1763 | } | 1780 | } |
1764 | 1781 | ||
1782 | /* | ||
1783 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and | ||
1784 | * therefore cannot iterate over the rdev list here. | ||
1785 | */ | ||
1765 | void regulatory_hint_11d(struct wiphy *wiphy, | 1786 | void regulatory_hint_11d(struct wiphy *wiphy, |
1766 | u8 *country_ie, | 1787 | u8 *country_ie, |
1767 | u8 country_ie_len) | 1788 | u8 country_ie_len) |
@@ -1772,12 +1793,10 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1772 | enum environment_cap env = ENVIRON_ANY; | 1793 | enum environment_cap env = ENVIRON_ANY; |
1773 | struct regulatory_request *request; | 1794 | struct regulatory_request *request; |
1774 | 1795 | ||
1775 | mutex_lock(&cfg80211_mutex); | 1796 | mutex_lock(®_mutex); |
1776 | 1797 | ||
1777 | if (unlikely(!last_request)) { | 1798 | if (unlikely(!last_request)) |
1778 | mutex_unlock(&cfg80211_mutex); | 1799 | goto out; |
1779 | return; | ||
1780 | } | ||
1781 | 1800 | ||
1782 | /* IE len must be evenly divisible by 2 */ | 1801 | /* IE len must be evenly divisible by 2 */ |
1783 | if (country_ie_len & 0x01) | 1802 | if (country_ie_len & 0x01) |
@@ -1803,54 +1822,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1803 | env = ENVIRON_OUTDOOR; | 1822 | env = ENVIRON_OUTDOOR; |
1804 | 1823 | ||
1805 | /* | 1824 | /* |
1806 | * We will run this for *every* beacon processed for the BSSID, so | 1825 | * We will run this only upon a successful connection on cfg80211. |
1807 | * we optimize an early check to exit out early if we don't have to | 1826 | * We leave conflict resolution to the workqueue, where can hold |
1808 | * do anything | 1827 | * cfg80211_mutex. |
1809 | */ | 1828 | */ |
1810 | if (likely(last_request->initiator == | 1829 | if (likely(last_request->initiator == |
1811 | NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1830 | NL80211_REGDOM_SET_BY_COUNTRY_IE && |
1812 | wiphy_idx_valid(last_request->wiphy_idx))) { | 1831 | wiphy_idx_valid(last_request->wiphy_idx))) |
1813 | struct cfg80211_registered_device *rdev_last_ie; | 1832 | goto out; |
1814 | |||
1815 | rdev_last_ie = | ||
1816 | cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx); | ||
1817 | |||
1818 | /* | ||
1819 | * Lets keep this simple -- we trust the first AP | ||
1820 | * after we intersect with CRDA | ||
1821 | */ | ||
1822 | if (likely(&rdev_last_ie->wiphy == wiphy)) { | ||
1823 | /* | ||
1824 | * Ignore IEs coming in on this wiphy with | ||
1825 | * the same alpha2 and environment cap | ||
1826 | */ | ||
1827 | if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, | ||
1828 | alpha2) && | ||
1829 | env == rdev_last_ie->env)) { | ||
1830 | goto out; | ||
1831 | } | ||
1832 | /* | ||
1833 | * the wiphy moved on to another BSSID or the AP | ||
1834 | * was reconfigured. XXX: We need to deal with the | ||
1835 | * case where the user suspends and goes to goes | ||
1836 | * to another country, and then gets IEs from an | ||
1837 | * AP with different settings | ||
1838 | */ | ||
1839 | goto out; | ||
1840 | } else { | ||
1841 | /* | ||
1842 | * Ignore IEs coming in on two separate wiphys with | ||
1843 | * the same alpha2 and environment cap | ||
1844 | */ | ||
1845 | if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, | ||
1846 | alpha2) && | ||
1847 | env == rdev_last_ie->env)) { | ||
1848 | goto out; | ||
1849 | } | ||
1850 | /* We could potentially intersect though */ | ||
1851 | goto out; | ||
1852 | } | ||
1853 | } | ||
1854 | 1833 | ||
1855 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 1834 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); |
1856 | if (!rd) | 1835 | if (!rd) |
@@ -1885,7 +1864,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1885 | request->country_ie_checksum = checksum; | 1864 | request->country_ie_checksum = checksum; |
1886 | request->country_ie_env = env; | 1865 | request->country_ie_env = env; |
1887 | 1866 | ||
1888 | mutex_unlock(&cfg80211_mutex); | 1867 | mutex_unlock(®_mutex); |
1889 | 1868 | ||
1890 | queue_regulatory_request(request); | 1869 | queue_regulatory_request(request); |
1891 | 1870 | ||
@@ -1894,9 +1873,8 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1894 | free_rd_out: | 1873 | free_rd_out: |
1895 | kfree(rd); | 1874 | kfree(rd); |
1896 | out: | 1875 | out: |
1897 | mutex_unlock(&cfg80211_mutex); | 1876 | mutex_unlock(®_mutex); |
1898 | } | 1877 | } |
1899 | EXPORT_SYMBOL(regulatory_hint_11d); | ||
1900 | 1878 | ||
1901 | static bool freq_is_chan_12_13_14(u16 freq) | 1879 | static bool freq_is_chan_12_13_14(u16 freq) |
1902 | { | 1880 | { |
@@ -2227,10 +2205,13 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2227 | 2205 | ||
2228 | assert_cfg80211_lock(); | 2206 | assert_cfg80211_lock(); |
2229 | 2207 | ||
2208 | mutex_lock(®_mutex); | ||
2209 | |||
2230 | /* Note that this doesn't update the wiphys, this is done below */ | 2210 | /* Note that this doesn't update the wiphys, this is done below */ |
2231 | r = __set_regdom(rd); | 2211 | r = __set_regdom(rd); |
2232 | if (r) { | 2212 | if (r) { |
2233 | kfree(rd); | 2213 | kfree(rd); |
2214 | mutex_unlock(®_mutex); | ||
2234 | return r; | 2215 | return r; |
2235 | } | 2216 | } |
2236 | 2217 | ||
@@ -2245,6 +2226,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2245 | 2226 | ||
2246 | nl80211_send_reg_change_event(last_request); | 2227 | nl80211_send_reg_change_event(last_request); |
2247 | 2228 | ||
2229 | mutex_unlock(®_mutex); | ||
2230 | |||
2248 | return r; | 2231 | return r; |
2249 | } | 2232 | } |
2250 | 2233 | ||
@@ -2255,16 +2238,20 @@ void reg_device_remove(struct wiphy *wiphy) | |||
2255 | 2238 | ||
2256 | assert_cfg80211_lock(); | 2239 | assert_cfg80211_lock(); |
2257 | 2240 | ||
2241 | mutex_lock(®_mutex); | ||
2242 | |||
2258 | kfree(wiphy->regd); | 2243 | kfree(wiphy->regd); |
2259 | 2244 | ||
2260 | if (last_request) | 2245 | if (last_request) |
2261 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2246 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
2262 | 2247 | ||
2263 | if (!request_wiphy || request_wiphy != wiphy) | 2248 | if (!request_wiphy || request_wiphy != wiphy) |
2264 | return; | 2249 | goto out; |
2265 | 2250 | ||
2266 | last_request->wiphy_idx = WIPHY_IDX_STALE; | 2251 | last_request->wiphy_idx = WIPHY_IDX_STALE; |
2267 | last_request->country_ie_env = ENVIRON_ANY; | 2252 | last_request->country_ie_env = ENVIRON_ANY; |
2253 | out: | ||
2254 | mutex_unlock(®_mutex); | ||
2268 | } | 2255 | } |
2269 | 2256 | ||
2270 | int regulatory_init(void) | 2257 | int regulatory_init(void) |
@@ -2325,6 +2312,7 @@ void regulatory_exit(void) | |||
2325 | cancel_work_sync(®_work); | 2312 | cancel_work_sync(®_work); |
2326 | 2313 | ||
2327 | mutex_lock(&cfg80211_mutex); | 2314 | mutex_lock(&cfg80211_mutex); |
2315 | mutex_lock(®_mutex); | ||
2328 | 2316 | ||
2329 | reset_regdomains(); | 2317 | reset_regdomains(); |
2330 | 2318 | ||
@@ -2363,5 +2351,6 @@ void regulatory_exit(void) | |||
2363 | } | 2351 | } |
2364 | spin_unlock(®_requests_lock); | 2352 | spin_unlock(®_requests_lock); |
2365 | 2353 | ||
2354 | mutex_unlock(®_mutex); | ||
2366 | mutex_unlock(&cfg80211_mutex); | 2355 | mutex_unlock(&cfg80211_mutex); |
2367 | } | 2356 | } |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index e37829a49dc4..662a9dad76d5 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -36,4 +36,19 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
36 | struct ieee80211_channel *beacon_chan, | 36 | struct ieee80211_channel *beacon_chan, |
37 | gfp_t gfp); | 37 | gfp_t gfp); |
38 | 38 | ||
39 | /** | ||
40 | * regulatory_hint_11d - hints a country IE as a regulatory domain | ||
41 | * @wiphy: the wireless device giving the hint (used only for reporting | ||
42 | * conflicts) | ||
43 | * @country_ie: pointer to the country IE | ||
44 | * @country_ie_len: length of the country IE | ||
45 | * | ||
46 | * We will intersect the rd with the what CRDA tells us should apply | ||
47 | * for the alpha2 this country IE belongs to, this prevents APs from | ||
48 | * sending us incorrect or outdated information against a country. | ||
49 | */ | ||
50 | void regulatory_hint_11d(struct wiphy *wiphy, | ||
51 | u8 *country_ie, | ||
52 | u8 country_ie_len); | ||
53 | |||
39 | #endif /* __NET_WIRELESS_REG_H */ | 54 | #endif /* __NET_WIRELESS_REG_H */ |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d2b5d4ce0a00..8a7dcbf90602 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <net/cfg80211.h> | 13 | #include <net/cfg80211.h> |
14 | #include <net/rtnetlink.h> | 14 | #include <net/rtnetlink.h> |
15 | #include "nl80211.h" | 15 | #include "nl80211.h" |
16 | #include "reg.h" | ||
16 | 17 | ||
17 | struct cfg80211_conn { | 18 | struct cfg80211_conn { |
18 | struct cfg80211_connect_params params; | 19 | struct cfg80211_connect_params params; |
@@ -182,7 +183,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
182 | wdev->conn->params.bssid, | 183 | wdev->conn->params.bssid, |
183 | NULL, 0, NULL, 0, | 184 | NULL, 0, NULL, 0, |
184 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 185 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
185 | false); | 186 | false, NULL); |
186 | wdev_unlock(wdev); | 187 | wdev_unlock(wdev); |
187 | } | 188 | } |
188 | 189 | ||
@@ -247,7 +248,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) | |||
247 | wdev->conn->params.bssid, | 248 | wdev->conn->params.bssid, |
248 | NULL, 0, NULL, 0, | 249 | NULL, 0, NULL, 0, |
249 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 250 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
250 | false); | 251 | false, NULL); |
251 | } | 252 | } |
252 | } | 253 | } |
253 | 254 | ||
@@ -305,7 +306,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
305 | schedule_work(&rdev->conn_work); | 306 | schedule_work(&rdev->conn_work); |
306 | } else if (status_code != WLAN_STATUS_SUCCESS) { | 307 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
307 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 308 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
308 | status_code, false); | 309 | status_code, false, NULL); |
309 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 310 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && |
310 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | 311 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
311 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 312 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
@@ -316,10 +317,11 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
316 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 317 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
317 | const u8 *req_ie, size_t req_ie_len, | 318 | const u8 *req_ie, size_t req_ie_len, |
318 | const u8 *resp_ie, size_t resp_ie_len, | 319 | const u8 *resp_ie, size_t resp_ie_len, |
319 | u16 status, bool wextev) | 320 | u16 status, bool wextev, |
321 | struct cfg80211_bss *bss) | ||
320 | { | 322 | { |
321 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 323 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
322 | struct cfg80211_bss *bss; | 324 | u8 *country_ie; |
323 | #ifdef CONFIG_WIRELESS_EXT | 325 | #ifdef CONFIG_WIRELESS_EXT |
324 | union iwreq_data wrqu; | 326 | union iwreq_data wrqu; |
325 | #endif | 327 | #endif |
@@ -361,6 +363,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
361 | } | 363 | } |
362 | #endif | 364 | #endif |
363 | 365 | ||
366 | if (wdev->current_bss) { | ||
367 | cfg80211_unhold_bss(wdev->current_bss); | ||
368 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
369 | wdev->current_bss = NULL; | ||
370 | } | ||
371 | |||
364 | if (status == WLAN_STATUS_SUCCESS && | 372 | if (status == WLAN_STATUS_SUCCESS && |
365 | wdev->sme_state == CFG80211_SME_IDLE) | 373 | wdev->sme_state == CFG80211_SME_IDLE) |
366 | goto success; | 374 | goto success; |
@@ -368,12 +376,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
368 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 376 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
369 | return; | 377 | return; |
370 | 378 | ||
371 | if (wdev->current_bss) { | ||
372 | cfg80211_unhold_bss(wdev->current_bss); | ||
373 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
374 | wdev->current_bss = NULL; | ||
375 | } | ||
376 | |||
377 | if (wdev->conn) | 379 | if (wdev->conn) |
378 | wdev->conn->state = CFG80211_CONN_IDLE; | 380 | wdev->conn->state = CFG80211_CONN_IDLE; |
379 | 381 | ||
@@ -383,13 +385,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
383 | wdev->conn = NULL; | 385 | wdev->conn = NULL; |
384 | kfree(wdev->connect_keys); | 386 | kfree(wdev->connect_keys); |
385 | wdev->connect_keys = NULL; | 387 | wdev->connect_keys = NULL; |
388 | wdev->ssid_len = 0; | ||
386 | return; | 389 | return; |
387 | } | 390 | } |
388 | 391 | ||
389 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 392 | success: |
390 | wdev->ssid, wdev->ssid_len, | 393 | if (!bss) |
391 | WLAN_CAPABILITY_ESS, | 394 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
392 | WLAN_CAPABILITY_ESS); | 395 | wdev->ssid, wdev->ssid_len, |
396 | WLAN_CAPABILITY_ESS, | ||
397 | WLAN_CAPABILITY_ESS); | ||
393 | 398 | ||
394 | if (WARN_ON(!bss)) | 399 | if (WARN_ON(!bss)) |
395 | return; | 400 | return; |
@@ -397,9 +402,22 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
397 | cfg80211_hold_bss(bss_from_pub(bss)); | 402 | cfg80211_hold_bss(bss_from_pub(bss)); |
398 | wdev->current_bss = bss_from_pub(bss); | 403 | wdev->current_bss = bss_from_pub(bss); |
399 | 404 | ||
400 | success: | ||
401 | wdev->sme_state = CFG80211_SME_CONNECTED; | 405 | wdev->sme_state = CFG80211_SME_CONNECTED; |
402 | cfg80211_upload_connect_keys(wdev); | 406 | cfg80211_upload_connect_keys(wdev); |
407 | |||
408 | country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); | ||
409 | |||
410 | if (!country_ie) | ||
411 | return; | ||
412 | |||
413 | /* | ||
414 | * ieee80211_bss_get_ie() ensures we can access: | ||
415 | * - country_ie + 2, the start of the country ie data, and | ||
416 | * - and country_ie[1] which is the IE length | ||
417 | */ | ||
418 | regulatory_hint_11d(wdev->wiphy, | ||
419 | country_ie + 2, | ||
420 | country_ie[1]); | ||
403 | } | 421 | } |
404 | 422 | ||
405 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 423 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
@@ -549,6 +567,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
549 | 567 | ||
550 | wdev->current_bss = NULL; | 568 | wdev->current_bss = NULL; |
551 | wdev->sme_state = CFG80211_SME_IDLE; | 569 | wdev->sme_state = CFG80211_SME_IDLE; |
570 | wdev->ssid_len = 0; | ||
552 | 571 | ||
553 | if (wdev->conn) { | 572 | if (wdev->conn) { |
554 | kfree(wdev->conn->ie); | 573 | kfree(wdev->conn->ie); |
@@ -704,6 +723,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
704 | wdev->conn = NULL; | 723 | wdev->conn = NULL; |
705 | wdev->sme_state = CFG80211_SME_IDLE; | 724 | wdev->sme_state = CFG80211_SME_IDLE; |
706 | wdev->connect_keys = NULL; | 725 | wdev->connect_keys = NULL; |
726 | wdev->ssid_len = 0; | ||
707 | } | 727 | } |
708 | 728 | ||
709 | return err; | 729 | return err; |
@@ -768,6 +788,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
768 | wdev->sme_state = CFG80211_SME_IDLE; | 788 | wdev->sme_state = CFG80211_SME_IDLE; |
769 | kfree(wdev->conn); | 789 | kfree(wdev->conn); |
770 | wdev->conn = NULL; | 790 | wdev->conn = NULL; |
791 | wdev->ssid_len = 0; | ||
771 | return 0; | 792 | return 0; |
772 | } | 793 | } |
773 | 794 | ||
@@ -788,7 +809,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
788 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | 809 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) |
789 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | 810 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, |
790 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 811 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
791 | wextev); | 812 | wextev, NULL); |
792 | 813 | ||
793 | return 0; | 814 | return 0; |
794 | } | 815 | } |
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 3fe3c2c0ce11..5b4a0cee4418 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -1291,7 +1291,6 @@ static struct pernet_operations wext_pernet_ops = { | |||
1291 | static int __init wireless_nlevent_init(void) | 1291 | static int __init wireless_nlevent_init(void) |
1292 | { | 1292 | { |
1293 | return register_pernet_subsys(&wext_pernet_ops); | 1293 | return register_pernet_subsys(&wext_pernet_ops); |
1294 | return 0; | ||
1295 | } | 1294 | } |
1296 | 1295 | ||
1297 | subsys_initcall(wireless_nlevent_init); | 1296 | subsys_initcall(wireless_nlevent_init); |