diff options
author | Denis Kenzior | 2016-08-03 17:02:15 -0500 |
---|---|---|
committer | Johannes Berg | 2016-09-12 11:24:46 +0200 |
commit | b7fb44dacae04219c82f20897382ba34860d1a16 (patch) | |
tree | fb36f6d410bd78c8c53a0175ddae4e108f33ddfb | |
parent | 02154927c115c7599677df57203988e05b576346 (diff) |
nl80211: Allow GET_INTERFACE dumps to be filtered
This patch allows GET_INTERFACE dumps to be filtered based on
NL80211_ATTR_WIPHY or NL80211_ATTR_WDEV. The documentation for
GET_INTERFACE mentions that this is possible:
"Request an interface's configuration; either a dump request on
a %NL80211_ATTR_WIPHY or ..."
However, this behavior has not been implemented until now.
Johannes: rewrite most of the patch:
* use nl80211_dump_wiphy_parse() to also allow passing an interface
to be able to dump its siblings
* fix locking (must hold rtnl around using nl80211_fam.attrbuf)
* make init self-contained instead of relying on other cb->args
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/wireless/nl80211.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 499785778983..7ebad350abc1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2525,10 +2525,35 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * int if_idx = 0; int wp_start = cb->args[0]; int if_start = cb->args[1]; + int filter_wiphy = -1; struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; rtnl_lock(); + if (!cb->args[2]) { + struct nl80211_dump_wiphy_state state = { + .filter_wiphy = -1, + }; + int ret; + + ret = nl80211_dump_wiphy_parse(skb, cb, &state); + if (ret) + return ret; + + filter_wiphy = state.filter_wiphy; + + /* + * if filtering, set cb->args[2] to +1 since 0 is the default + * value needed to determine that parsing is necessary. + */ + if (filter_wiphy >= 0) + cb->args[2] = filter_wiphy + 1; + else + cb->args[2] = -1; + } else if (cb->args[2] > 0) { + filter_wiphy = cb->args[2] - 1; + } + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) continue; @@ -2536,6 +2561,10 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * wp_idx++; continue; } + + if (filter_wiphy >= 0 && filter_wiphy != rdev->wiphy_idx) + continue; + if_idx = 0; list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |