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. Signed-off-by: Denis Kenzior <denkenz@xxxxxxxxx> --- net/wireless/nl80211.c | 63 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4997857..aa85871 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2519,27 +2519,74 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag return -EMSGSIZE; } +static int nl80211_dump_interface_parse(struct sk_buff *skb, + struct netlink_callback *cb, + int *filter_wiphy) +{ + struct nlattr **tb = nl80211_fam.attrbuf; + int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + tb, nl80211_fam.maxattr, nl80211_policy); + + /* ignore parse errors for backward compatibility */ + if (ret) + return 0; + + if (tb[NL80211_ATTR_WIPHY]) + *filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + if (tb[NL80211_ATTR_WDEV]) + *filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; + + return 0; +} + +struct dump_interface_context { + unsigned int wp_start; + unsigned int if_start; + int filter_wiphy; +}; + static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) { - int wp_idx = 0; - int if_idx = 0; - int wp_start = cb->args[0]; - int if_start = cb->args[1]; struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; + unsigned int wp_idx = 0; + unsigned int if_idx; + static struct dump_interface_context static_ctx; + struct dump_interface_context *ctx = cb->args[0]; + + if (!ctx) { + int ret; + + static_ctx.wp_start = 0; + static_ctx.if_start = 0; + static_ctx.filter_wiphy = -1; + + ret = nl80211_dump_interface_parse(skb, cb, + &static_ctx.filter_wiphy); + if (ret) + return ret; + + ctx = &static_ctx; + cb->args[0] = ctx; + } rtnl_lock(); list_for_each_entry(rdev, &cfg80211_rdev_list, list) { if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) continue; - if (wp_idx < wp_start) { + if (wp_idx < ctx->wp_start) { wp_idx++; continue; } + + if (ctx->filter_wiphy != -1 && + ctx->filter_wiphy != rdev->wiphy_idx) + continue; + if_idx = 0; list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (if_idx < if_start) { + if (if_idx < ctx->if_start) { if_idx++; continue; } @@ -2556,8 +2603,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * out: rtnl_unlock(); - cb->args[0] = wp_idx; - cb->args[1] = if_idx; + ctx->wp_start = wp_idx; + ctx->if_start = if_idx; return skb->len; } -- 2.7.3 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html