diff options
| -rw-r--r-- | include/net/mac80211.h | 5 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 31 | ||||
| -rw-r--r-- | net/mac80211/main.c | 3 | ||||
| -rw-r--r-- | net/mac80211/util.c | 4 |
5 files changed, 40 insertions, 5 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c1e8261e899e..8e65adf0a64c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -928,9 +928,8 @@ enum ieee80211_hw_flags { | |||
| 928 | * @workqueue: single threaded workqueue available for driver use, | 928 | * @workqueue: single threaded workqueue available for driver use, |
| 929 | * allocated by mac80211 on registration and flushed when an | 929 | * allocated by mac80211 on registration and flushed when an |
| 930 | * interface is removed. | 930 | * interface is removed. |
| 931 | * NOTICE: All work performed on this workqueue should NEVER | 931 | * NOTICE: All work performed on this workqueue must not |
| 932 | * acquire the RTNL lock (i.e. Don't use the function | 932 | * acquire the RTNL lock. |
| 933 | * ieee80211_iterate_active_interfaces()) | ||
| 934 | * | 933 | * |
| 935 | * @priv: pointer to private area that was allocated for driver use | 934 | * @priv: pointer to private area that was allocated for driver use |
| 936 | * along with this structure. | 935 | * along with this structure. |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 927cbde8c19c..eaf3603862b7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -643,7 +643,9 @@ struct ieee80211_local { | |||
| 643 | struct crypto_blkcipher *wep_rx_tfm; | 643 | struct crypto_blkcipher *wep_rx_tfm; |
| 644 | u32 wep_iv; | 644 | u32 wep_iv; |
| 645 | 645 | ||
| 646 | /* see iface.c */ | ||
| 646 | struct list_head interfaces; | 647 | struct list_head interfaces; |
| 648 | struct mutex iflist_mtx; | ||
| 647 | 649 | ||
| 648 | /* | 650 | /* |
| 649 | * Key lock, protects sdata's key_list and sta_info's | 651 | * Key lock, protects sdata's key_list and sta_info's |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8dc2c2188d92..00562a8b99cf 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -21,6 +21,23 @@ | |||
| 21 | #include "mesh.h" | 21 | #include "mesh.h" |
| 22 | #include "led.h" | 22 | #include "led.h" |
| 23 | 23 | ||
| 24 | /** | ||
| 25 | * DOC: Interface list locking | ||
| 26 | * | ||
| 27 | * The interface list in each struct ieee80211_local is protected | ||
| 28 | * three-fold: | ||
| 29 | * | ||
| 30 | * (1) modifications may only be done under the RTNL | ||
| 31 | * (2) modifications and readers are protected against each other by | ||
| 32 | * the iflist_mtx. | ||
| 33 | * (3) modifications are done in an RCU manner so atomic readers | ||
| 34 | * can traverse the list in RCU-safe blocks. | ||
| 35 | * | ||
| 36 | * As a consequence, reads (traversals) of the list can be protected | ||
| 37 | * by either the RTNL, the iflist_mtx or RCU. | ||
| 38 | */ | ||
| 39 | |||
| 40 | |||
| 24 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 41 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
| 25 | { | 42 | { |
| 26 | int meshhdrlen; | 43 | int meshhdrlen; |
| @@ -800,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 800 | params->mesh_id_len, | 817 | params->mesh_id_len, |
| 801 | params->mesh_id); | 818 | params->mesh_id); |
| 802 | 819 | ||
| 820 | mutex_lock(&local->iflist_mtx); | ||
| 803 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 821 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
| 822 | mutex_unlock(&local->iflist_mtx); | ||
| 804 | 823 | ||
| 805 | if (new_dev) | 824 | if (new_dev) |
| 806 | *new_dev = ndev; | 825 | *new_dev = ndev; |
| @@ -816,7 +835,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | |||
| 816 | { | 835 | { |
| 817 | ASSERT_RTNL(); | 836 | ASSERT_RTNL(); |
| 818 | 837 | ||
| 838 | mutex_lock(&sdata->local->iflist_mtx); | ||
| 819 | list_del_rcu(&sdata->list); | 839 | list_del_rcu(&sdata->list); |
| 840 | mutex_unlock(&sdata->local->iflist_mtx); | ||
| 841 | |||
| 820 | synchronize_rcu(); | 842 | synchronize_rcu(); |
| 821 | unregister_netdevice(sdata->dev); | 843 | unregister_netdevice(sdata->dev); |
| 822 | } | 844 | } |
| @@ -832,7 +854,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
| 832 | ASSERT_RTNL(); | 854 | ASSERT_RTNL(); |
| 833 | 855 | ||
| 834 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 856 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
| 857 | /* | ||
| 858 | * we cannot hold the iflist_mtx across unregister_netdevice, | ||
| 859 | * but we only need to hold it for list modifications to lock | ||
| 860 | * out readers since we're under the RTNL here as all other | ||
| 861 | * writers. | ||
| 862 | */ | ||
| 863 | mutex_lock(&local->iflist_mtx); | ||
| 835 | list_del(&sdata->list); | 864 | list_del(&sdata->list); |
| 865 | mutex_unlock(&local->iflist_mtx); | ||
| 866 | |||
| 836 | unregister_netdevice(sdata->dev); | 867 | unregister_netdevice(sdata->dev); |
| 837 | } | 868 | } |
| 838 | } | 869 | } |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 210dfe3cf6c3..a109c06e8e4e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -758,6 +758,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 758 | local->hw.conf.radio_enabled = true; | 758 | local->hw.conf.radio_enabled = true; |
| 759 | 759 | ||
| 760 | INIT_LIST_HEAD(&local->interfaces); | 760 | INIT_LIST_HEAD(&local->interfaces); |
| 761 | mutex_init(&local->iflist_mtx); | ||
| 761 | 762 | ||
| 762 | spin_lock_init(&local->key_lock); | 763 | spin_lock_init(&local->key_lock); |
| 763 | 764 | ||
| @@ -1008,6 +1009,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
| 1008 | { | 1009 | { |
| 1009 | struct ieee80211_local *local = hw_to_local(hw); | 1010 | struct ieee80211_local *local = hw_to_local(hw); |
| 1010 | 1011 | ||
| 1012 | mutex_destroy(&local->iflist_mtx); | ||
| 1013 | |||
| 1011 | wiphy_free(local->hw.wiphy); | 1014 | wiphy_free(local->hw.wiphy); |
| 1012 | } | 1015 | } |
| 1013 | EXPORT_SYMBOL(ieee80211_free_hw); | 1016 | EXPORT_SYMBOL(ieee80211_free_hw); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fc30f2940e1e..73c7d7345abd 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces( | |||
| 468 | struct ieee80211_local *local = hw_to_local(hw); | 468 | struct ieee80211_local *local = hw_to_local(hw); |
| 469 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
| 470 | 470 | ||
| 471 | rtnl_lock(); | 471 | mutex_lock(&local->iflist_mtx); |
| 472 | 472 | ||
| 473 | list_for_each_entry(sdata, &local->interfaces, list) { | 473 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 474 | switch (sdata->vif.type) { | 474 | switch (sdata->vif.type) { |
| @@ -489,7 +489,7 @@ void ieee80211_iterate_active_interfaces( | |||
| 489 | &sdata->vif); | 489 | &sdata->vif); |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | rtnl_unlock(); | 492 | mutex_unlock(&local->iflist_mtx); |
| 493 | } | 493 | } |
| 494 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 494 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
| 495 | 495 | ||
