diff options
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r-- | net/mac80211/ieee80211.c | 99 |
1 files changed, 42 insertions, 57 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 22cba82a0c6f..484b063a3538 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -183,6 +183,7 @@ static int ieee80211_open(struct net_device *dev) | |||
183 | struct ieee80211_if_init_conf conf; | 183 | struct ieee80211_if_init_conf conf; |
184 | int res; | 184 | int res; |
185 | bool need_hw_reconfig = 0; | 185 | bool need_hw_reconfig = 0; |
186 | struct sta_info *sta; | ||
186 | 187 | ||
187 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 188 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
188 | 189 | ||
@@ -256,6 +257,20 @@ static int ieee80211_open(struct net_device *dev) | |||
256 | case IEEE80211_IF_TYPE_WDS: | 257 | case IEEE80211_IF_TYPE_WDS: |
257 | if (is_zero_ether_addr(sdata->u.wds.remote_addr)) | 258 | if (is_zero_ether_addr(sdata->u.wds.remote_addr)) |
258 | return -ENOLINK; | 259 | return -ENOLINK; |
260 | |||
261 | /* Create STA entry for the WDS peer */ | ||
262 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, | ||
263 | GFP_KERNEL); | ||
264 | if (!sta) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | sta->flags |= WLAN_STA_AUTHORIZED; | ||
268 | |||
269 | res = sta_info_insert(sta); | ||
270 | if (res) { | ||
271 | sta_info_destroy(sta); | ||
272 | return res; | ||
273 | } | ||
259 | break; | 274 | break; |
260 | case IEEE80211_IF_TYPE_VLAN: | 275 | case IEEE80211_IF_TYPE_VLAN: |
261 | if (!sdata->u.vlan.ap) | 276 | if (!sdata->u.vlan.ap) |
@@ -367,14 +382,20 @@ static int ieee80211_open(struct net_device *dev) | |||
367 | 382 | ||
368 | static int ieee80211_stop(struct net_device *dev) | 383 | static int ieee80211_stop(struct net_device *dev) |
369 | { | 384 | { |
370 | struct ieee80211_sub_if_data *sdata; | 385 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
371 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 386 | struct ieee80211_local *local = sdata->local; |
372 | struct ieee80211_if_init_conf conf; | 387 | struct ieee80211_if_init_conf conf; |
373 | struct sta_info *sta; | 388 | struct sta_info *sta; |
374 | int i; | 389 | int i; |
375 | 390 | ||
376 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 391 | /* |
392 | * Stop TX on this interface first. | ||
393 | */ | ||
394 | netif_stop_queue(dev); | ||
377 | 395 | ||
396 | /* | ||
397 | * Now delete all active aggregation sessions. | ||
398 | */ | ||
378 | rcu_read_lock(); | 399 | rcu_read_lock(); |
379 | 400 | ||
380 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 401 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
@@ -388,7 +409,24 @@ static int ieee80211_stop(struct net_device *dev) | |||
388 | 409 | ||
389 | rcu_read_unlock(); | 410 | rcu_read_unlock(); |
390 | 411 | ||
391 | netif_stop_queue(dev); | 412 | /* |
413 | * Remove all stations associated with this interface. | ||
414 | * | ||
415 | * This must be done before calling ops->remove_interface() | ||
416 | * because otherwise we can later invoke ops->sta_notify() | ||
417 | * whenever the STAs are removed, and that invalidates driver | ||
418 | * assumptions about always getting a vif pointer that is valid | ||
419 | * (because if we remove a STA after ops->remove_interface() | ||
420 | * the driver will have removed the vif info already!) | ||
421 | * | ||
422 | * We could relax this and only unlink the stations from the | ||
423 | * hash table and list but keep them on a per-sdata list that | ||
424 | * will be inserted back again when the interface is brought | ||
425 | * up again, but I don't currently see a use case for that, | ||
426 | * except with WDS which gets a STA entry created when it is | ||
427 | * brought up. | ||
428 | */ | ||
429 | sta_info_flush(local, sdata); | ||
392 | 430 | ||
393 | /* | 431 | /* |
394 | * Don't count this interface for promisc/allmulti while it | 432 | * Don't count this interface for promisc/allmulti while it |
@@ -453,8 +491,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
453 | netif_tx_unlock_bh(local->mdev); | 491 | netif_tx_unlock_bh(local->mdev); |
454 | break; | 492 | break; |
455 | case IEEE80211_IF_TYPE_MESH_POINT: | 493 | case IEEE80211_IF_TYPE_MESH_POINT: |
456 | sta_info_flush(local, sdata); | ||
457 | /* fall through */ | ||
458 | case IEEE80211_IF_TYPE_STA: | 494 | case IEEE80211_IF_TYPE_STA: |
459 | case IEEE80211_IF_TYPE_IBSS: | 495 | case IEEE80211_IF_TYPE_IBSS: |
460 | sdata->u.sta.state = IEEE80211_DISABLED; | 496 | sdata->u.sta.state = IEEE80211_DISABLED; |
@@ -892,57 +928,6 @@ void ieee80211_if_setup(struct net_device *dev) | |||
892 | dev->destructor = ieee80211_if_free; | 928 | dev->destructor = ieee80211_if_free; |
893 | } | 929 | } |
894 | 930 | ||
895 | /* WDS specialties */ | ||
896 | |||
897 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | ||
898 | { | ||
899 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
900 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
901 | struct sta_info *sta; | ||
902 | int err; | ||
903 | DECLARE_MAC_BUF(mac); | ||
904 | |||
905 | might_sleep(); | ||
906 | |||
907 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) | ||
908 | return 0; | ||
909 | |||
910 | /* Create STA entry for the new peer */ | ||
911 | sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL); | ||
912 | if (!sta) | ||
913 | return -ENOMEM; | ||
914 | |||
915 | sta->flags |= WLAN_STA_AUTHORIZED; | ||
916 | err = sta_info_insert(sta); | ||
917 | if (err) { | ||
918 | sta_info_destroy(sta); | ||
919 | return err; | ||
920 | } | ||
921 | |||
922 | rcu_read_lock(); | ||
923 | |||
924 | /* Remove STA entry for the old peer */ | ||
925 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | ||
926 | if (sta) | ||
927 | sta_info_unlink(&sta); | ||
928 | else | ||
929 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | ||
930 | "peer %s\n", | ||
931 | dev->name, print_mac(mac, sdata->u.wds.remote_addr)); | ||
932 | |||
933 | /* Update WDS link data */ | ||
934 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
935 | |||
936 | rcu_read_unlock(); | ||
937 | |||
938 | if (sta) { | ||
939 | synchronize_rcu(); | ||
940 | sta_info_destroy(sta); | ||
941 | } | ||
942 | |||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | /* everything else */ | 931 | /* everything else */ |
947 | 932 | ||
948 | static int __ieee80211_if_config(struct net_device *dev, | 933 | static int __ieee80211_if_config(struct net_device *dev, |