wifi: nl80211: allow device lookup under RCU

We already modify our wiphy/wdev lists in RCU-safe ways,
so we can do lookups in RCU critical sections. Prepare
more of the code to be able to do that.

Link: https://patch.msgid.link/20261006120655.86d9cf36d8bb.I07b7ce5a69391d5168dc31c598b5079917a29bff@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-10-06 12:04:01 +02:00
parent bf49114633
commit 57b1607464
2 changed files with 20 additions and 18 deletions

View File

@ -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;

View File

@ -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);