Commit 024fcf5e authored by Johannes Berg's avatar Johannes Berg

nl80211: use RCU to read regdom in reg get/dump

Use RCU here to read the regdomain, this will allow us
to remove the RTNL locking from the setter.

Note in nl80211_get_reg_do() we still need the RTNL to
do the wiphy lookup.

Link: https://lore.kernel.org/r/20220214101820.5d4acbcf2a46.Ibfc91980439862125e983d9adeebaba73fe38e2d@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b59fb546
...@@ -7948,6 +7948,7 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) ...@@ -7948,6 +7948,7 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
struct wiphy *wiphy = NULL; struct wiphy *wiphy = NULL;
struct sk_buff *msg; struct sk_buff *msg;
int err = -EMSGSIZE;
void *hdr; void *hdr;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
...@@ -7966,34 +7967,35 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) ...@@ -7966,34 +7967,35 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
nlmsg_free(msg); err = PTR_ERR(rdev);
rtnl_unlock(); goto nla_put_failure;
return PTR_ERR(rdev);
} }
wiphy = &rdev->wiphy; wiphy = &rdev->wiphy;
self_managed = wiphy->regulatory_flags & self_managed = wiphy->regulatory_flags &
REGULATORY_WIPHY_SELF_MANAGED; REGULATORY_WIPHY_SELF_MANAGED;
rcu_read_lock();
regdom = get_wiphy_regdom(wiphy); regdom = get_wiphy_regdom(wiphy);
/* a self-managed-reg device must have a private regdom */ /* a self-managed-reg device must have a private regdom */
if (WARN_ON(!regdom && self_managed)) { if (WARN_ON(!regdom && self_managed)) {
nlmsg_free(msg); err = -EINVAL;
rtnl_unlock(); goto nla_put_failure_rcu;
return -EINVAL;
} }
if (regdom && if (regdom &&
nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
goto nla_put_failure; goto nla_put_failure_rcu;
} else {
rcu_read_lock();
} }
if (!wiphy && reg_last_request_cell_base() && if (!wiphy && reg_last_request_cell_base() &&
nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
NL80211_USER_REG_HINT_CELL_BASE)) NL80211_USER_REG_HINT_CELL_BASE))
goto nla_put_failure; goto nla_put_failure_rcu;
rcu_read_lock();
if (!regdom) if (!regdom)
regdom = rcu_dereference(cfg80211_regdomain); regdom = rcu_dereference(cfg80211_regdomain);
...@@ -8013,7 +8015,7 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) ...@@ -8013,7 +8015,7 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
rtnl_unlock(); rtnl_unlock();
put_failure: put_failure:
nlmsg_free(msg); nlmsg_free(msg);
return -EMSGSIZE; return err;
} }
static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb, static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
...@@ -8059,19 +8061,19 @@ static int nl80211_get_reg_dump(struct sk_buff *skb, ...@@ -8059,19 +8061,19 @@ static int nl80211_get_reg_dump(struct sk_buff *skb,
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
int err, reg_idx, start = cb->args[2]; int err, reg_idx, start = cb->args[2];
rtnl_lock(); rcu_read_lock();
if (cfg80211_regdomain && start == 0) { if (cfg80211_regdomain && start == 0) {
err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
NLM_F_MULTI, NULL, NLM_F_MULTI, NULL,
rtnl_dereference(cfg80211_regdomain)); rcu_dereference(cfg80211_regdomain));
if (err < 0) if (err < 0)
goto out_err; goto out_err;
} }
/* the global regdom is idx 0 */ /* the global regdom is idx 0 */
reg_idx = 1; reg_idx = 1;
list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
regdom = get_wiphy_regdom(&rdev->wiphy); regdom = get_wiphy_regdom(&rdev->wiphy);
if (!regdom) if (!regdom)
continue; continue;
...@@ -8090,7 +8092,7 @@ static int nl80211_get_reg_dump(struct sk_buff *skb, ...@@ -8090,7 +8092,7 @@ static int nl80211_get_reg_dump(struct sk_buff *skb,
cb->args[2] = reg_idx; cb->args[2] = reg_idx;
err = skb->len; err = skb->len;
out_err: out_err:
rtnl_unlock(); rcu_read_unlock();
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment