Commit b7fb44da authored by Denis Kenzior's avatar Denis Kenzior Committed by Johannes Berg
Browse files

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: default avatarDenis Kenzior <denkenz@gmail.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 02154927
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -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) {