aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211.c99
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/ieee80211_iface.c22
-rw-r--r--net/mac80211/ieee80211_ioctl.c18
-rw-r--r--net/mac80211/sta_info.c14
-rw-r--r--net/mac80211/sta_info.h2
6 files changed, 73 insertions, 83 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,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8e440c5706dd..7f10ff5d4a0b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -858,7 +858,6 @@ int ieee80211_hw_config(struct ieee80211_local *local);
858int ieee80211_if_config(struct net_device *dev); 858int ieee80211_if_config(struct net_device *dev);
859int ieee80211_if_config_beacon(struct net_device *dev); 859int ieee80211_if_config_beacon(struct net_device *dev);
860void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); 860void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
861int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
862void ieee80211_if_setup(struct net_device *dev); 861void ieee80211_if_setup(struct net_device *dev);
863int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, 862int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
864 struct ieee80211_ht_info *req_ht_cap, 863 struct ieee80211_ht_info *req_ht_cap,
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 98b22736e883..80954a512185 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -187,8 +187,8 @@ void ieee80211_if_reinit(struct net_device *dev)
187{ 187{
188 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 188 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
189 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 189 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
190 struct sta_info *sta;
191 struct sk_buff *skb; 190 struct sk_buff *skb;
191 int flushed;
192 192
193 ASSERT_RTNL(); 193 ASSERT_RTNL();
194 194
@@ -240,21 +240,7 @@ void ieee80211_if_reinit(struct net_device *dev)
240 break; 240 break;
241 } 241 }
242 case IEEE80211_IF_TYPE_WDS: 242 case IEEE80211_IF_TYPE_WDS:
243 rcu_read_lock(); 243 /* nothing to do */
244 sta = sta_info_get(local, sdata->u.wds.remote_addr);
245 if (sta) {
246 sta_info_unlink(&sta);
247 } else {
248#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
249 printk(KERN_DEBUG "%s: Someone had deleted my STA "
250 "entry for the WDS link\n", dev->name);
251#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
252 }
253 rcu_read_unlock();
254 if (sta) {
255 synchronize_rcu();
256 sta_info_destroy(sta);
257 }
258 break; 244 break;
259 case IEEE80211_IF_TYPE_MESH_POINT: 245 case IEEE80211_IF_TYPE_MESH_POINT:
260 case IEEE80211_IF_TYPE_STA: 246 case IEEE80211_IF_TYPE_STA:
@@ -279,8 +265,8 @@ void ieee80211_if_reinit(struct net_device *dev)
279 break; 265 break;
280 } 266 }
281 267
282 /* remove all STAs that are bound to this virtual interface */ 268 flushed = sta_info_flush(local, sdata);
283 sta_info_flush(local, sdata); 269 WARN_ON(flushed);
284 270
285 memset(&sdata->u, 0, sizeof(sdata->u)); 271 memset(&sdata->u, 0, sizeof(sdata->u));
286 ieee80211_if_sdata_init(sdata); 272 ieee80211_if_sdata_init(sdata);
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 5147152b9268..1d91575a0fe9 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -468,10 +468,20 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
468 ieee80211_sta_req_auth(dev, &sdata->u.sta); 468 ieee80211_sta_req_auth(dev, &sdata->u.sta);
469 return 0; 469 return 0;
470 } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { 470 } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
471 if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, 471 /*
472 ETH_ALEN) == 0) 472 * If it is necessary to update the WDS peer address
473 return 0; 473 * while the interface is running, then we need to do
474 return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data); 474 * more work here, namely if it is running we need to
475 * add a new and remove the old STA entry, this is
476 * normally handled by _open() and _stop().
477 */
478 if (netif_running(dev))
479 return -EBUSY;
480
481 memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
482 ETH_ALEN);
483
484 return 0;
475 } 485 }
476 486
477 return -EOPNOTSUPP; 487 return -EOPNOTSUPP;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a230a9597398..a767042ec4fd 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -258,6 +258,8 @@ int sta_info_insert(struct sta_info *sta)
258 unsigned long flags; 258 unsigned long flags;
259 DECLARE_MAC_BUF(mac); 259 DECLARE_MAC_BUF(mac);
260 260
261 WARN_ON(!netif_running(sdata->dev));
262
261 spin_lock_irqsave(&local->sta_lock, flags); 263 spin_lock_irqsave(&local->sta_lock, flags);
262 /* check if STA exists already */ 264 /* check if STA exists already */
263 if (__sta_info_find(local, sta->addr)) { 265 if (__sta_info_find(local, sta->addr)) {
@@ -608,14 +610,18 @@ void sta_info_stop(struct ieee80211_local *local)
608 610
609/** 611/**
610 * sta_info_flush - flush matching STA entries from the STA table 612 * sta_info_flush - flush matching STA entries from the STA table
613 *
614 * Returns the number of removed STA entries.
615 *
611 * @local: local interface data 616 * @local: local interface data
612 * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs 617 * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
613 */ 618 */
614void sta_info_flush(struct ieee80211_local *local, 619int sta_info_flush(struct ieee80211_local *local,
615 struct ieee80211_sub_if_data *sdata) 620 struct ieee80211_sub_if_data *sdata)
616{ 621{
617 struct sta_info *sta, *tmp; 622 struct sta_info *sta, *tmp;
618 LIST_HEAD(tmp_list); 623 LIST_HEAD(tmp_list);
624 int ret = 0;
619 unsigned long flags; 625 unsigned long flags;
620 626
621 might_sleep(); 627 might_sleep();
@@ -624,8 +630,10 @@ void sta_info_flush(struct ieee80211_local *local,
624 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { 630 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
625 if (!sdata || sdata == sta->sdata) { 631 if (!sdata || sdata == sta->sdata) {
626 __sta_info_unlink(&sta); 632 __sta_info_unlink(&sta);
627 if (sta) 633 if (sta) {
628 list_add_tail(&sta->list, &tmp_list); 634 list_add_tail(&sta->list, &tmp_list);
635 ret++;
636 }
629 } 637 }
630 } 638 }
631 spin_unlock_irqrestore(&local->sta_lock, flags); 639 spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -634,4 +642,6 @@ void sta_info_flush(struct ieee80211_local *local,
634 642
635 list_for_each_entry_safe(sta, tmp, &tmp_list, list) 643 list_for_each_entry_safe(sta, tmp, &tmp_list, list)
636 sta_info_destroy(sta); 644 sta_info_destroy(sta);
645
646 return ret;
637} 647}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index fb5411d01f82..547bfc3b2431 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -339,7 +339,7 @@ void sta_info_clear_tim_bit(struct sta_info *sta);
339void sta_info_init(struct ieee80211_local *local); 339void sta_info_init(struct ieee80211_local *local);
340int sta_info_start(struct ieee80211_local *local); 340int sta_info_start(struct ieee80211_local *local);
341void sta_info_stop(struct ieee80211_local *local); 341void sta_info_stop(struct ieee80211_local *local);
342void sta_info_flush(struct ieee80211_local *local, 342int sta_info_flush(struct ieee80211_local *local,
343 struct ieee80211_sub_if_data *sdata); 343 struct ieee80211_sub_if_data *sdata);
344 344
345#endif /* STA_INFO_H */ 345#endif /* STA_INFO_H */