diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-05-20 12:05:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-06-01 15:12:28 -0400 |
commit | 71063f0e8939b5b6ea5121faed47987e094ef018 (patch) | |
tree | 97936964a23ef6d26819c0267ea246cd0301ed9e /net/wireless/nl80211.c | |
parent | 2e5ef4599addb1046086b63743f41822858a23b7 (diff) |
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>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 88a565f130a5..6d0d44b19ee6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -4361,6 +4361,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4361 | return err; | 4361 | return err; |
4362 | } | 4362 | } |
4363 | 4363 | ||
4364 | static int nl80211_testmode_dump(struct sk_buff *skb, | ||
4365 | struct netlink_callback *cb) | ||
4366 | { | ||
4367 | struct cfg80211_registered_device *dev; | ||
4368 | int err; | ||
4369 | long phy_idx; | ||
4370 | void *data = NULL; | ||
4371 | int data_len = 0; | ||
4372 | |||
4373 | if (cb->args[0]) { | ||
4374 | /* | ||
4375 | * 0 is a valid index, but not valid for args[0], | ||
4376 | * so we need to offset by 1. | ||
4377 | */ | ||
4378 | phy_idx = cb->args[0] - 1; | ||
4379 | } else { | ||
4380 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
4381 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
4382 | nl80211_policy); | ||
4383 | if (err) | ||
4384 | return err; | ||
4385 | if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) | ||
4386 | return -EINVAL; | ||
4387 | phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
4388 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | ||
4389 | cb->args[1] = | ||
4390 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | ||
4391 | } | ||
4392 | |||
4393 | if (cb->args[1]) { | ||
4394 | data = nla_data((void *)cb->args[1]); | ||
4395 | data_len = nla_len((void *)cb->args[1]); | ||
4396 | } | ||
4397 | |||
4398 | mutex_lock(&cfg80211_mutex); | ||
4399 | dev = cfg80211_rdev_by_wiphy_idx(phy_idx); | ||
4400 | if (!dev) { | ||
4401 | mutex_unlock(&cfg80211_mutex); | ||
4402 | return -ENOENT; | ||
4403 | } | ||
4404 | cfg80211_lock_rdev(dev); | ||
4405 | mutex_unlock(&cfg80211_mutex); | ||
4406 | |||
4407 | if (!dev->ops->testmode_dump) { | ||
4408 | err = -EOPNOTSUPP; | ||
4409 | goto out_err; | ||
4410 | } | ||
4411 | |||
4412 | while (1) { | ||
4413 | void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid, | ||
4414 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
4415 | NL80211_CMD_TESTMODE); | ||
4416 | struct nlattr *tmdata; | ||
4417 | |||
4418 | if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) { | ||
4419 | genlmsg_cancel(skb, hdr); | ||
4420 | break; | ||
4421 | } | ||
4422 | |||
4423 | tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA); | ||
4424 | if (!tmdata) { | ||
4425 | genlmsg_cancel(skb, hdr); | ||
4426 | break; | ||
4427 | } | ||
4428 | err = dev->ops->testmode_dump(&dev->wiphy, skb, cb, | ||
4429 | data, data_len); | ||
4430 | nla_nest_end(skb, tmdata); | ||
4431 | |||
4432 | if (err == -ENOBUFS || err == -ENOENT) { | ||
4433 | genlmsg_cancel(skb, hdr); | ||
4434 | break; | ||
4435 | } else if (err) { | ||
4436 | genlmsg_cancel(skb, hdr); | ||
4437 | goto out_err; | ||
4438 | } | ||
4439 | |||
4440 | genlmsg_end(skb, hdr); | ||
4441 | } | ||
4442 | |||
4443 | err = skb->len; | ||
4444 | /* see above */ | ||
4445 | cb->args[0] = phy_idx + 1; | ||
4446 | out_err: | ||
4447 | cfg80211_unlock_rdev(dev); | ||
4448 | return err; | ||
4449 | } | ||
4450 | |||
4364 | static struct sk_buff * | 4451 | static struct sk_buff * |
4365 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, | 4452 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, |
4366 | int approxlen, u32 pid, u32 seq, gfp_t gfp) | 4453 | int approxlen, u32 pid, u32 seq, gfp_t gfp) |
@@ -5658,6 +5745,7 @@ static struct genl_ops nl80211_ops[] = { | |||
5658 | { | 5745 | { |
5659 | .cmd = NL80211_CMD_TESTMODE, | 5746 | .cmd = NL80211_CMD_TESTMODE, |
5660 | .doit = nl80211_testmode_do, | 5747 | .doit = nl80211_testmode_do, |
5748 | .dumpit = nl80211_testmode_dump, | ||
5661 | .policy = nl80211_policy, | 5749 | .policy = nl80211_policy, |
5662 | .flags = GENL_ADMIN_PERM, | 5750 | .flags = GENL_ADMIN_PERM, |
5663 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 5751 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |