Skip to content

Commit

Permalink
nl80211: accept testmode dump with netdev
Browse files Browse the repository at this point in the history
All nl80211 commands that need only the wiphy
still allow identifying it by giving an interface
index, except, as Kenny pointed out, the testmode
dump support.

Fix this by looking up the wiphy via the ifidx in
this case as well.

Tested-by: Kenny Hsu <kenny.hsu@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Dec 14, 2011
1 parent 5d22df2 commit 00918d3
Showing 1 changed file with 31 additions and 19 deletions.
50 changes: 31 additions & 19 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,21 @@ static struct genl_family nl80211_fam = {
};

/* internal helper: get rdev and dev */
static int get_rdev_dev_by_info_ifindex(struct genl_info *info,
struct cfg80211_registered_device **rdev,
struct net_device **dev)
static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
struct cfg80211_registered_device **rdev,
struct net_device **dev)
{
struct nlattr **attrs = info->attrs;
int ifindex;

if (!attrs[NL80211_ATTR_IFINDEX])
return -EINVAL;

ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
*dev = dev_get_by_index(genl_info_net(info), ifindex);
*dev = dev_get_by_index(netns, ifindex);
if (!*dev)
return -ENODEV;

*rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex);
*rdev = cfg80211_get_dev_from_ifindex(netns, ifindex);
if (IS_ERR(*rdev)) {
dev_put(*dev);
return PTR_ERR(*rdev);
Expand Down Expand Up @@ -4795,7 +4794,7 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
static int nl80211_testmode_dump(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct cfg80211_registered_device *dev;
struct cfg80211_registered_device *rdev;
int err;
long phy_idx;
void *data = NULL;
Expand All @@ -4813,9 +4812,21 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
nl80211_policy);
if (err)
return err;
if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY])
return -EINVAL;
phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) {
phy_idx = nla_get_u32(
nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
} else {
struct net_device *netdev;

err = get_rdev_dev_by_ifindex(sock_net(skb->sk),
nl80211_fam.attrbuf,
&rdev, &netdev);
if (err)
return err;
dev_put(netdev);
phy_idx = rdev->wiphy_idx;
cfg80211_unlock_rdev(rdev);
}
if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
cb->args[1] =
(long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
Expand All @@ -4827,15 +4838,15 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
}

mutex_lock(&cfg80211_mutex);
dev = cfg80211_rdev_by_wiphy_idx(phy_idx);
if (!dev) {
rdev = cfg80211_rdev_by_wiphy_idx(phy_idx);
if (!rdev) {
mutex_unlock(&cfg80211_mutex);
return -ENOENT;
}
cfg80211_lock_rdev(dev);
cfg80211_lock_rdev(rdev);
mutex_unlock(&cfg80211_mutex);

if (!dev->ops->testmode_dump) {
if (!rdev->ops->testmode_dump) {
err = -EOPNOTSUPP;
goto out_err;
}
Expand All @@ -4846,7 +4857,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
NL80211_CMD_TESTMODE);
struct nlattr *tmdata;

if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) {
if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx) < 0) {
genlmsg_cancel(skb, hdr);
break;
}
Expand All @@ -4856,8 +4867,8 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
genlmsg_cancel(skb, hdr);
break;
}
err = dev->ops->testmode_dump(&dev->wiphy, skb, cb,
data, data_len);
err = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb,
data, data_len);
nla_nest_end(skb, tmdata);

if (err == -ENOBUFS || err == -ENOENT) {
Expand All @@ -4875,7 +4886,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
/* see above */
cb->args[0] = phy_idx + 1;
out_err:
cfg80211_unlock_rdev(dev);
cfg80211_unlock_rdev(rdev);
return err;
}

Expand Down Expand Up @@ -6110,7 +6121,8 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
}
info->user_ptr[0] = rdev;
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs,
&rdev, &dev);
if (err) {
if (rtnl)
rtnl_unlock();
Expand Down

0 comments on commit 00918d3

Please sign in to comment.