diff --git a/net/wireless/core.c b/net/wireless/core.c index fa56208f8c8e..fb1e2070494f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -57,13 +57,13 @@ module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, "Disable 40MHz support in the 2.4GHz band"); +/* requires RCU or rtnl */ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { struct cfg80211_registered_device *result = NULL, *rdev; - ASSERT_RTNL(); - - for_each_rdev(rdev) { + list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list, + lockdep_rtnl_is_held()) { if (rdev->wiphy_idx == wiphy_idx) { result = rdev; break; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c2d5c89598b..14b79a4a8c1c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -63,7 +63,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = { #endif }; -/* returns ERR_PTR values */ +/* returns ERR_PTR values, requires RCU or rtnl if rdev is %NULL */ static struct wireless_dev * __cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev, struct net *netns, struct nlattr **attrs) @@ -105,9 +105,8 @@ __cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev, return result ?: ERR_PTR(-ENODEV); } - ASSERT_RTNL(); - - for_each_rdev(rdev) { + list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list, + lockdep_rtnl_is_held()) { struct wireless_dev *wdev; if (wiphy_net(&rdev->wiphy) != netns) @@ -116,7 +115,8 @@ __cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev, if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) continue; - list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list, + lockdep_rtnl_is_held()) { if (have_ifidx && wdev->netdev && wdev->netdev->ifindex == ifidx) { result = wdev; @@ -137,14 +137,13 @@ __cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev, return ERR_PTR(-ENODEV); } +/* requires RCU or rtnl */ static struct cfg80211_registered_device * __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) { struct cfg80211_registered_device *rdev = NULL, *tmp; struct net_device *netdev; - ASSERT_RTNL(); - if (!attrs[NL80211_ATTR_WIPHY] && !attrs[NL80211_ATTR_IFINDEX] && !attrs[NL80211_ATTR_WDEV]) @@ -162,7 +161,8 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); if (tmp) { /* make sure wdev exists */ - list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) { + list_for_each_entry_rcu(wdev, &tmp->wiphy.wdev_list, + list, lockdep_rtnl_is_held()) { if (wdev->identifier != (u32)wdev_id) continue; found = true; @@ -181,14 +181,16 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) if (attrs[NL80211_ATTR_IFINDEX]) { int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); - netdev = __dev_get_by_index(netns, ifindex); - if (netdev) { - if (netdev->ieee80211_ptr) - tmp = wiphy_to_rdev( - netdev->ieee80211_ptr->wiphy); - else - tmp = NULL; + /* RCU required for dev_get_by_index_rcu() if we have RTNL */ + rcu_read_lock(); + netdev = dev_get_by_index_rcu(netns, ifindex); + if (netdev && netdev->ieee80211_ptr) + tmp = wiphy_to_rdev(netdev->ieee80211_ptr->wiphy); + else + tmp = NULL; + rcu_read_unlock(); + if (netdev) { /* not wireless device -- return error */ if (!tmp) return ERR_PTR(-EINVAL);