diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 121 |
1 files changed, 81 insertions, 40 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e8a260f53c16..60f1ce5e5e52 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Interface handling (except master interface) | 2 | * Interface handling |
3 | * | 3 | * |
4 | * Copyright 2002-2005, Instant802 Networks, Inc. | 4 | * Copyright 2002-2005, Instant802 Networks, Inc. |
5 | * Copyright 2005-2006, Devicescape Software, Inc. | 5 | * Copyright 2005-2006, Devicescape Software, Inc. |
@@ -357,7 +357,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | |||
357 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 357 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
358 | } | 358 | } |
359 | 359 | ||
360 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 360 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local) |
361 | { | 361 | { |
362 | struct ieee80211_sub_if_data *sdata; | 362 | struct ieee80211_sub_if_data *sdata; |
363 | int ret; | 363 | int ret; |
@@ -410,7 +410,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
410 | return 0; | 410 | return 0; |
411 | } | 411 | } |
412 | 412 | ||
413 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 413 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local) |
414 | { | 414 | { |
415 | struct ieee80211_sub_if_data *sdata; | 415 | struct ieee80211_sub_if_data *sdata; |
416 | 416 | ||
@@ -595,7 +595,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
595 | case NL80211_IFTYPE_P2P_DEVICE: | 595 | case NL80211_IFTYPE_P2P_DEVICE: |
596 | break; | 596 | break; |
597 | default: | 597 | default: |
598 | netif_carrier_on(dev); | 598 | /* not reached */ |
599 | WARN_ON(1); | ||
599 | } | 600 | } |
600 | 601 | ||
601 | /* | 602 | /* |
@@ -652,8 +653,28 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
652 | 653 | ||
653 | ieee80211_recalc_ps(local, -1); | 654 | ieee80211_recalc_ps(local, -1); |
654 | 655 | ||
655 | if (dev) | 656 | if (dev) { |
656 | netif_tx_start_all_queues(dev); | 657 | unsigned long flags; |
658 | int n_acs = IEEE80211_NUM_ACS; | ||
659 | int ac; | ||
660 | |||
661 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
662 | n_acs = 1; | ||
663 | |||
664 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
665 | if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE || | ||
666 | (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 && | ||
667 | skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) { | ||
668 | for (ac = 0; ac < n_acs; ac++) { | ||
669 | int ac_queue = sdata->vif.hw_queue[ac]; | ||
670 | |||
671 | if (local->queue_stop_reasons[ac_queue] == 0 && | ||
672 | skb_queue_empty(&local->pending[ac_queue])) | ||
673 | netif_start_subqueue(dev, ac); | ||
674 | } | ||
675 | } | ||
676 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
677 | } | ||
657 | 678 | ||
658 | return 0; | 679 | return 0; |
659 | err_del_interface: | 680 | err_del_interface: |
@@ -707,7 +728,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
707 | if (sdata->dev) | 728 | if (sdata->dev) |
708 | netif_tx_stop_all_queues(sdata->dev); | 729 | netif_tx_stop_all_queues(sdata->dev); |
709 | 730 | ||
710 | ieee80211_roc_purge(sdata); | 731 | ieee80211_roc_purge(local, sdata); |
711 | 732 | ||
712 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 733 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
713 | ieee80211_mgd_stop(sdata); | 734 | ieee80211_mgd_stop(sdata); |
@@ -732,12 +753,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
732 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || | 753 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || |
733 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); | 754 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); |
734 | 755 | ||
735 | /* | 756 | /* don't count this interface for promisc/allmulti while it is down */ |
736 | * Don't count this interface for promisc/allmulti while it | ||
737 | * is down. dev_mc_unsync() will invoke set_multicast_list | ||
738 | * on the master interface which will sync these down to the | ||
739 | * hardware as filter flags. | ||
740 | */ | ||
741 | if (sdata->flags & IEEE80211_SDATA_ALLMULTI) | 757 | if (sdata->flags & IEEE80211_SDATA_ALLMULTI) |
742 | atomic_dec(&local->iff_allmultis); | 758 | atomic_dec(&local->iff_allmultis); |
743 | 759 | ||
@@ -758,8 +774,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
758 | sdata->dev->addr_len); | 774 | sdata->dev->addr_len); |
759 | spin_unlock_bh(&local->filter_lock); | 775 | spin_unlock_bh(&local->filter_lock); |
760 | netif_addr_unlock_bh(sdata->dev); | 776 | netif_addr_unlock_bh(sdata->dev); |
761 | |||
762 | ieee80211_configure_filter(local); | ||
763 | } | 777 | } |
764 | 778 | ||
765 | del_timer_sync(&local->dynamic_ps_timer); | 779 | del_timer_sync(&local->dynamic_ps_timer); |
@@ -770,6 +784,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
770 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 784 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
771 | 785 | ||
772 | if (sdata->wdev.cac_started) { | 786 | if (sdata->wdev.cac_started) { |
787 | WARN_ON(local->suspended); | ||
773 | mutex_lock(&local->iflist_mtx); | 788 | mutex_lock(&local->iflist_mtx); |
774 | ieee80211_vif_release_channel(sdata); | 789 | ieee80211_vif_release_channel(sdata); |
775 | mutex_unlock(&local->iflist_mtx); | 790 | mutex_unlock(&local->iflist_mtx); |
@@ -820,14 +835,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
820 | if (local->monitors == 0) { | 835 | if (local->monitors == 0) { |
821 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 836 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
822 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 837 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
823 | ieee80211_del_virtual_monitor(local); | ||
824 | } | 838 | } |
825 | 839 | ||
826 | ieee80211_adjust_monitor_flags(sdata, -1); | 840 | ieee80211_adjust_monitor_flags(sdata, -1); |
827 | ieee80211_configure_filter(local); | ||
828 | mutex_lock(&local->mtx); | ||
829 | ieee80211_recalc_idle(local); | ||
830 | mutex_unlock(&local->mtx); | ||
831 | break; | 841 | break; |
832 | case NL80211_IFTYPE_P2P_DEVICE: | 842 | case NL80211_IFTYPE_P2P_DEVICE: |
833 | /* relies on synchronize_rcu() below */ | 843 | /* relies on synchronize_rcu() below */ |
@@ -840,11 +850,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
840 | * | 850 | * |
841 | * sta_info_flush_cleanup() requires rcu_barrier() | 851 | * sta_info_flush_cleanup() requires rcu_barrier() |
842 | * first to wait for the station call_rcu() calls | 852 | * first to wait for the station call_rcu() calls |
843 | * to complete, here we need at least sychronize_rcu() | 853 | * to complete, and we also need synchronize_rcu() |
844 | * it to wait for the RX path in case it is using the | 854 | * to wait for the RX path in case it is using the |
845 | * interface and enqueuing frames at this very time on | 855 | * interface and enqueuing frames at this very time on |
846 | * another CPU. | 856 | * another CPU. |
847 | */ | 857 | */ |
858 | synchronize_rcu(); | ||
848 | rcu_barrier(); | 859 | rcu_barrier(); |
849 | sta_info_flush_cleanup(sdata); | 860 | sta_info_flush_cleanup(sdata); |
850 | 861 | ||
@@ -857,27 +868,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
857 | /* fall through */ | 868 | /* fall through */ |
858 | case NL80211_IFTYPE_AP: | 869 | case NL80211_IFTYPE_AP: |
859 | skb_queue_purge(&sdata->skb_queue); | 870 | skb_queue_purge(&sdata->skb_queue); |
860 | |||
861 | if (going_down) | ||
862 | drv_remove_interface(local, sdata); | ||
863 | } | 871 | } |
864 | 872 | ||
865 | sdata->bss = NULL; | 873 | sdata->bss = NULL; |
866 | 874 | ||
867 | ieee80211_recalc_ps(local, -1); | ||
868 | |||
869 | if (local->open_count == 0) { | ||
870 | ieee80211_clear_tx_pending(local); | ||
871 | ieee80211_stop_device(local); | ||
872 | |||
873 | /* no reconfiguring after stop! */ | ||
874 | hw_reconf_flags = 0; | ||
875 | } | ||
876 | |||
877 | /* do after stop to avoid reconfiguring when we stop anyway */ | ||
878 | if (hw_reconf_flags) | ||
879 | ieee80211_hw_config(local, hw_reconf_flags); | ||
880 | |||
881 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 875 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
882 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { | 876 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
883 | skb_queue_walk_safe(&local->pending[i], skb, tmp) { | 877 | skb_queue_walk_safe(&local->pending[i], skb, tmp) { |
@@ -890,7 +884,54 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
890 | } | 884 | } |
891 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 885 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
892 | 886 | ||
893 | if (local->monitors == local->open_count && local->monitors > 0) | 887 | if (local->open_count == 0) |
888 | ieee80211_clear_tx_pending(local); | ||
889 | |||
890 | /* | ||
891 | * If the interface goes down while suspended, presumably because | ||
892 | * the device was unplugged and that happens before our resume, | ||
893 | * then the driver is already unconfigured and the remainder of | ||
894 | * this function isn't needed. | ||
895 | * XXX: what about WoWLAN? If the device has software state, e.g. | ||
896 | * memory allocated, it might expect teardown commands from | ||
897 | * mac80211 here? | ||
898 | */ | ||
899 | if (local->suspended) { | ||
900 | WARN_ON(local->wowlan); | ||
901 | WARN_ON(rtnl_dereference(local->monitor_sdata)); | ||
902 | return; | ||
903 | } | ||
904 | |||
905 | switch (sdata->vif.type) { | ||
906 | case NL80211_IFTYPE_AP_VLAN: | ||
907 | break; | ||
908 | case NL80211_IFTYPE_MONITOR: | ||
909 | if (local->monitors == 0) | ||
910 | ieee80211_del_virtual_monitor(local); | ||
911 | |||
912 | mutex_lock(&local->mtx); | ||
913 | ieee80211_recalc_idle(local); | ||
914 | mutex_unlock(&local->mtx); | ||
915 | break; | ||
916 | default: | ||
917 | if (going_down) | ||
918 | drv_remove_interface(local, sdata); | ||
919 | } | ||
920 | |||
921 | ieee80211_recalc_ps(local, -1); | ||
922 | |||
923 | if (local->open_count == 0) { | ||
924 | ieee80211_stop_device(local); | ||
925 | |||
926 | /* no reconfiguring after stop! */ | ||
927 | return; | ||
928 | } | ||
929 | |||
930 | /* do after stop to avoid reconfiguring when we stop anyway */ | ||
931 | ieee80211_configure_filter(local); | ||
932 | ieee80211_hw_config(local, hw_reconf_flags); | ||
933 | |||
934 | if (local->monitors == local->open_count) | ||
894 | ieee80211_add_virtual_monitor(local); | 935 | ieee80211_add_virtual_monitor(local); |
895 | } | 936 | } |
896 | 937 | ||