aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c99
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
368static int ieee80211_stop(struct net_device *dev) 383static 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
897int 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
948static int __ieee80211_if_config(struct net_device *dev, 933static int __ieee80211_if_config(struct net_device *dev,