Commit 50508d94 authored by Johannes Berg's avatar Johannes Berg

cfg80211: use parallel_ops for genl

Over time, we really need to get rid of all of our global locking.
One of the things needed is to use parallel_ops. This isn't really
the most important (RTNL is much more important) but OTOH we just
keep adding uses of genl_family_attrbuf() now. Use .parallel_ops to
disallow this.
Reviewed-By: default avatarDenis Kenzior <denkenz@gmail.com>
Link: https://lore.kernel.org/r/20190729143109.18683-1-johannes@sipsolutions.netSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 05d610af
...@@ -749,17 +749,25 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb, ...@@ -749,17 +749,25 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
int err; int err;
if (!cb->args[0]) { if (!cb->args[0]) {
struct nlattr **attrbuf;
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
GFP_KERNEL);
if (!attrbuf)
return -ENOMEM;
err = nlmsg_parse_deprecated(cb->nlh, err = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize, GENL_HDRLEN + nl80211_fam.hdrsize,
genl_family_attrbuf(&nl80211_fam), attrbuf, nl80211_fam.maxattr,
nl80211_fam.maxattr,
nl80211_policy, NULL); nl80211_policy, NULL);
if (err) if (err) {
kfree(attrbuf);
return err; return err;
}
*wdev = __cfg80211_wdev_from_attrs( *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
sock_net(cb->skb->sk), attrbuf);
genl_family_attrbuf(&nl80211_fam)); kfree(attrbuf);
if (IS_ERR(*wdev)) if (IS_ERR(*wdev))
return PTR_ERR(*wdev); return PTR_ERR(*wdev);
*rdev = wiphy_to_rdev((*wdev)->wiphy); *rdev = wiphy_to_rdev((*wdev)->wiphy);
...@@ -2390,14 +2398,21 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, ...@@ -2390,14 +2398,21 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
struct netlink_callback *cb, struct netlink_callback *cb,
struct nl80211_dump_wiphy_state *state) struct nl80211_dump_wiphy_state *state)
{ {
struct nlattr **tb = genl_family_attrbuf(&nl80211_fam); struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
int ret = nlmsg_parse_deprecated(cb->nlh, int ret;
GENL_HDRLEN + nl80211_fam.hdrsize,
tb, nl80211_fam.maxattr, if (!tb)
nl80211_policy, NULL); return -ENOMEM;
ret = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize,
tb, nl80211_fam.maxattr,
nl80211_policy, NULL);
/* ignore parse errors for backward compatibility */ /* ignore parse errors for backward compatibility */
if (ret) if (ret) {
return 0; ret = 0;
goto out;
}
state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
if (tb[NL80211_ATTR_WIPHY]) if (tb[NL80211_ATTR_WIPHY])
...@@ -2410,8 +2425,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, ...@@ -2410,8 +2425,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev) if (!netdev) {
return -ENODEV; ret = -ENODEV;
goto out;
}
if (netdev->ieee80211_ptr) { if (netdev->ieee80211_ptr) {
rdev = wiphy_to_rdev( rdev = wiphy_to_rdev(
netdev->ieee80211_ptr->wiphy); netdev->ieee80211_ptr->wiphy);
...@@ -2419,7 +2436,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb, ...@@ -2419,7 +2436,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
} }
} }
return 0; ret = 0;
out:
kfree(tb);
return ret;
} }
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
...@@ -8724,7 +8744,7 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, ...@@ -8724,7 +8744,7 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam); struct nlattr **attrbuf;
struct survey_info survey; struct survey_info survey;
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev; struct wireless_dev *wdev;
...@@ -8732,6 +8752,10 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -8732,6 +8752,10 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
int res; int res;
bool radio_stats; bool radio_stats;
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
if (!attrbuf)
return -ENOMEM;
rtnl_lock(); rtnl_lock();
res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev); res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
if (res) if (res)
...@@ -8776,6 +8800,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -8776,6 +8800,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[2] = survey_idx; cb->args[2] = survey_idx;
res = skb->len; res = skb->len;
out_err: out_err:
kfree(attrbuf);
rtnl_unlock(); rtnl_unlock();
return res; return res;
} }
...@@ -9635,6 +9660,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb, ...@@ -9635,6 +9660,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
struct netlink_callback *cb) struct netlink_callback *cb)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
struct nlattr **attrbuf = NULL;
int err; int err;
long phy_idx; long phy_idx;
void *data = NULL; void *data = NULL;
...@@ -9655,7 +9681,12 @@ static int nl80211_testmode_dump(struct sk_buff *skb, ...@@ -9655,7 +9681,12 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
goto out_err; goto out_err;
} }
} else { } else {
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam); attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
GFP_KERNEL);
if (!attrbuf) {
err = -ENOMEM;
goto out_err;
}
err = nlmsg_parse_deprecated(cb->nlh, err = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize, GENL_HDRLEN + nl80211_fam.hdrsize,
...@@ -9722,6 +9753,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb, ...@@ -9722,6 +9753,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
/* see above */ /* see above */
cb->args[0] = phy_idx + 1; cb->args[0] = phy_idx + 1;
out_err: out_err:
kfree(attrbuf);
rtnl_unlock(); rtnl_unlock();
return err; return err;
} }
...@@ -12815,7 +12847,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -12815,7 +12847,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
struct cfg80211_registered_device **rdev, struct cfg80211_registered_device **rdev,
struct wireless_dev **wdev) struct wireless_dev **wdev)
{ {
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam); struct nlattr **attrbuf;
u32 vid, subcmd; u32 vid, subcmd;
unsigned int i; unsigned int i;
int vcmd_idx = -1; int vcmd_idx = -1;
...@@ -12846,24 +12878,32 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -12846,24 +12878,32 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
return 0; return 0;
} }
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
if (!attrbuf)
return -ENOMEM;
err = nlmsg_parse_deprecated(cb->nlh, err = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize, GENL_HDRLEN + nl80211_fam.hdrsize,
attrbuf, nl80211_fam.maxattr, attrbuf, nl80211_fam.maxattr,
nl80211_policy, NULL); nl80211_policy, NULL);
if (err) if (err)
return err; goto out;
if (!attrbuf[NL80211_ATTR_VENDOR_ID] || if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
!attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
return -EINVAL; err = -EINVAL;
goto out;
}
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf); *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
if (IS_ERR(*wdev)) if (IS_ERR(*wdev))
*wdev = NULL; *wdev = NULL;
*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf); *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
if (IS_ERR(*rdev)) if (IS_ERR(*rdev)) {
return PTR_ERR(*rdev); err = PTR_ERR(*rdev);
goto out;
}
vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]); vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]); subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
...@@ -12876,15 +12916,19 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -12876,15 +12916,19 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd) if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
continue; continue;
if (!vcmd->dumpit) if (!vcmd->dumpit) {
return -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out;
}
vcmd_idx = i; vcmd_idx = i;
break; break;
} }
if (vcmd_idx < 0) if (vcmd_idx < 0) {
return -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out;
}
if (attrbuf[NL80211_ATTR_VENDOR_DATA]) { if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]); data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
...@@ -12895,7 +12939,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -12895,7 +12939,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
attrbuf[NL80211_ATTR_VENDOR_DATA], attrbuf[NL80211_ATTR_VENDOR_DATA],
cb->extack); cb->extack);
if (err) if (err)
return err; goto out;
} }
/* 0 is the first index - add 1 to parse only once */ /* 0 is the first index - add 1 to parse only once */
...@@ -12907,7 +12951,10 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -12907,7 +12951,10 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
cb->args[4] = data_len; cb->args[4] = data_len;
/* keep rtnl locked in successful case */ /* keep rtnl locked in successful case */
return 0; err = 0;
out:
kfree(attrbuf);
return err;
} }
static int nl80211_vendor_cmd_dump(struct sk_buff *skb, static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
...@@ -14585,6 +14632,7 @@ static struct genl_family nl80211_fam __ro_after_init = { ...@@ -14585,6 +14632,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
.n_ops = ARRAY_SIZE(nl80211_ops), .n_ops = ARRAY_SIZE(nl80211_ops),
.mcgrps = nl80211_mcgrps, .mcgrps = nl80211_mcgrps,
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps), .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
.parallel_ops = true,
}; };
/* notification functions */ /* notification functions */
......
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