nl80211: add testmode dump support

This adds dump support to testmode. The testmode
dump support in nl80211 requires using two of the
six cb->args, the rest can be used by the driver
to figure out where the dump position is at or to
store other data across invocations.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Wey-Yi Guy
2011-05-20 09:05:54 -07:00
committed by John W. Linville
parent 2e5ef4599a
commit 71063f0e89
4 changed files with 117 additions and 0 deletions

View File

@@ -4361,6 +4361,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
return err;
}
static int nl80211_testmode_dump(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct cfg80211_registered_device *dev;
int err;
long phy_idx;
void *data = NULL;
int data_len = 0;
if (cb->args[0]) {
/*
* 0 is a valid index, but not valid for args[0],
* so we need to offset by 1.
*/
phy_idx = cb->args[0] - 1;
} else {
err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
nl80211_fam.attrbuf, nl80211_fam.maxattr,
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_TESTDATA])
cb->args[1] =
(long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
}
if (cb->args[1]) {
data = nla_data((void *)cb->args[1]);
data_len = nla_len((void *)cb->args[1]);
}
mutex_lock(&cfg80211_mutex);
dev = cfg80211_rdev_by_wiphy_idx(phy_idx);
if (!dev) {
mutex_unlock(&cfg80211_mutex);
return -ENOENT;
}
cfg80211_lock_rdev(dev);
mutex_unlock(&cfg80211_mutex);
if (!dev->ops->testmode_dump) {
err = -EOPNOTSUPP;
goto out_err;
}
while (1) {
void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
NL80211_CMD_TESTMODE);
struct nlattr *tmdata;
if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) {
genlmsg_cancel(skb, hdr);
break;
}
tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
if (!tmdata) {
genlmsg_cancel(skb, hdr);
break;
}
err = dev->ops->testmode_dump(&dev->wiphy, skb, cb,
data, data_len);
nla_nest_end(skb, tmdata);
if (err == -ENOBUFS || err == -ENOENT) {
genlmsg_cancel(skb, hdr);
break;
} else if (err) {
genlmsg_cancel(skb, hdr);
goto out_err;
}
genlmsg_end(skb, hdr);
}
err = skb->len;
/* see above */
cb->args[0] = phy_idx + 1;
out_err:
cfg80211_unlock_rdev(dev);
return err;
}
static struct sk_buff *
__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
int approxlen, u32 pid, u32 seq, gfp_t gfp)
@@ -5658,6 +5745,7 @@ static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_TESTMODE,
.doit = nl80211_testmode_do,
.dumpit = nl80211_testmode_dump,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |