diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/ieee80211.c | 99 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 22 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 18 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 14 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 |
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 | ||
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, |
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); | |||
858 | int ieee80211_if_config(struct net_device *dev); | 858 | int ieee80211_if_config(struct net_device *dev); |
859 | int ieee80211_if_config_beacon(struct net_device *dev); | 859 | int ieee80211_if_config_beacon(struct net_device *dev); |
860 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | 860 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); |
861 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); | ||
862 | void ieee80211_if_setup(struct net_device *dev); | 861 | void ieee80211_if_setup(struct net_device *dev); |
863 | int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, | 862 | int 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 | */ |
614 | void sta_info_flush(struct ieee80211_local *local, | 619 | int 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); | |||
339 | void sta_info_init(struct ieee80211_local *local); | 339 | void sta_info_init(struct ieee80211_local *local); |
340 | int sta_info_start(struct ieee80211_local *local); | 340 | int sta_info_start(struct ieee80211_local *local); |
341 | void sta_info_stop(struct ieee80211_local *local); | 341 | void sta_info_stop(struct ieee80211_local *local); |
342 | void sta_info_flush(struct ieee80211_local *local, | 342 | int 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 */ |