diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8be854e86cd9..06fac2991d40 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -747,7 +747,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
747 | unsigned long flags; | 747 | unsigned long flags; |
748 | struct sk_buff *skb, *tmp; | 748 | struct sk_buff *skb, *tmp; |
749 | u32 hw_reconf_flags = 0; | 749 | u32 hw_reconf_flags = 0; |
750 | int i; | 750 | int i, flushed; |
751 | 751 | ||
752 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 752 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
753 | 753 | ||
@@ -772,11 +772,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
772 | * (because if we remove a STA after ops->remove_interface() | 772 | * (because if we remove a STA after ops->remove_interface() |
773 | * the driver will have removed the vif info already!) | 773 | * the driver will have removed the vif info already!) |
774 | * | 774 | * |
775 | * This is relevant only in AP, WDS and mesh modes, since in | 775 | * This is relevant only in WDS mode, in all other modes we've |
776 | * all other modes we've already removed all stations when | 776 | * already removed all stations when disconnecting or similar, |
777 | * disconnecting etc. | 777 | * so warn otherwise. |
778 | * | ||
779 | * We call sta_info_flush_cleanup() later, to combine RCU waits. | ||
778 | */ | 780 | */ |
779 | sta_info_flush(local, sdata); | 781 | flushed = sta_info_flush_defer(sdata); |
782 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || | ||
783 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); | ||
780 | 784 | ||
781 | /* | 785 | /* |
782 | * Don't count this interface for promisc/allmulti while it | 786 | * Don't count this interface for promisc/allmulti while it |
@@ -859,11 +863,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
859 | cancel_work_sync(&sdata->work); | 863 | cancel_work_sync(&sdata->work); |
860 | /* | 864 | /* |
861 | * When we get here, the interface is marked down. | 865 | * When we get here, the interface is marked down. |
862 | * Call synchronize_rcu() to wait for the RX path | 866 | * |
863 | * should it be using the interface and enqueuing | 867 | * sta_info_flush_cleanup() requires rcu_barrier() |
864 | * frames at this very time on another CPU. | 868 | * first to wait for the station call_rcu() calls |
869 | * to complete, here we need at least sychronize_rcu() | ||
870 | * it to wait for the RX path in case it is using the | ||
871 | * interface and enqueuing frames at this very time on | ||
872 | * another CPU. | ||
865 | */ | 873 | */ |
866 | synchronize_rcu(); | 874 | rcu_barrier(); |
875 | sta_info_flush_cleanup(sdata); | ||
876 | |||
867 | skb_queue_purge(&sdata->skb_queue); | 877 | skb_queue_purge(&sdata->skb_queue); |
868 | 878 | ||
869 | /* | 879 | /* |
@@ -961,7 +971,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
961 | */ | 971 | */ |
962 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | 972 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) |
963 | { | 973 | { |
964 | struct ieee80211_local *local = sdata->local; | ||
965 | int flushed; | 974 | int flushed; |
966 | int i; | 975 | int i; |
967 | 976 | ||
@@ -977,7 +986,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | |||
977 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 986 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
978 | mesh_rmc_free(sdata); | 987 | mesh_rmc_free(sdata); |
979 | 988 | ||
980 | flushed = sta_info_flush(local, sdata); | 989 | flushed = sta_info_flush(sdata); |
981 | WARN_ON(flushed); | 990 | WARN_ON(flushed); |
982 | } | 991 | } |
983 | 992 | ||
@@ -1218,6 +1227,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1218 | case NL80211_IFTYPE_AP: | 1227 | case NL80211_IFTYPE_AP: |
1219 | skb_queue_head_init(&sdata->u.ap.ps.bc_buf); | 1228 | skb_queue_head_init(&sdata->u.ap.ps.bc_buf); |
1220 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 1229 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
1230 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||
1221 | break; | 1231 | break; |
1222 | case NL80211_IFTYPE_P2P_CLIENT: | 1232 | case NL80211_IFTYPE_P2P_CLIENT: |
1223 | type = NL80211_IFTYPE_STATION; | 1233 | type = NL80211_IFTYPE_STATION; |
@@ -1225,9 +1235,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1225 | sdata->vif.p2p = true; | 1235 | sdata->vif.p2p = true; |
1226 | /* fall through */ | 1236 | /* fall through */ |
1227 | case NL80211_IFTYPE_STATION: | 1237 | case NL80211_IFTYPE_STATION: |
1238 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | ||
1228 | ieee80211_sta_setup_sdata(sdata); | 1239 | ieee80211_sta_setup_sdata(sdata); |
1229 | break; | 1240 | break; |
1230 | case NL80211_IFTYPE_ADHOC: | 1241 | case NL80211_IFTYPE_ADHOC: |
1242 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | ||
1231 | ieee80211_ibss_setup_sdata(sdata); | 1243 | ieee80211_ibss_setup_sdata(sdata); |
1232 | break; | 1244 | break; |
1233 | case NL80211_IFTYPE_MESH_POINT: | 1245 | case NL80211_IFTYPE_MESH_POINT: |
@@ -1241,8 +1253,12 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1241 | MONITOR_FLAG_OTHER_BSS; | 1253 | MONITOR_FLAG_OTHER_BSS; |
1242 | break; | 1254 | break; |
1243 | case NL80211_IFTYPE_WDS: | 1255 | case NL80211_IFTYPE_WDS: |
1256 | sdata->vif.bss_conf.bssid = NULL; | ||
1257 | break; | ||
1244 | case NL80211_IFTYPE_AP_VLAN: | 1258 | case NL80211_IFTYPE_AP_VLAN: |
1259 | break; | ||
1245 | case NL80211_IFTYPE_P2P_DEVICE: | 1260 | case NL80211_IFTYPE_P2P_DEVICE: |
1261 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||
1246 | break; | 1262 | break; |
1247 | case NL80211_IFTYPE_UNSPECIFIED: | 1263 | case NL80211_IFTYPE_UNSPECIFIED: |
1248 | case NUM_NL80211_IFTYPES: | 1264 | case NUM_NL80211_IFTYPES: |