diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6b659846ff8a..45b84dd5c4eb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4821,6 +4821,7 @@ struct inet6_fill_args { int event; unsigned int flags; int netnsid; + int ifindex; enum addr_type_t type; }; @@ -5018,8 +5019,9 @@ next: static int inet6_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, struct inet6_fill_args *fillargs, struct net **tgt_net, struct sock *sk, - struct netlink_ext_ack *extack) + struct netlink_callback *cb) { + struct netlink_ext_ack *extack = cb->extack; struct nlattr *tb[IFA_MAX+1]; struct ifaddrmsg *ifm; int err, i; @@ -5034,9 +5036,11 @@ static int inet6_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address dump request"); return -EINVAL; } - if (ifm->ifa_index) { - NL_SET_ERR_MSG_MOD(extack, "Filter by device index not supported for address dump"); - return -EINVAL; + + fillargs->ifindex = ifm->ifa_index; + if (fillargs->ifindex) { + cb->answer_flags |= NLM_F_DUMP_FILTERED; + fillargs->flags |= NLM_F_DUMP_FILTERED; } err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX, @@ -5094,9 +5098,21 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, int err; err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, - skb->sk, cb->extack); + skb->sk, cb); if (err < 0) return err; + + if (fillargs.ifindex) { + dev = __dev_get_by_index(tgt_net, fillargs.ifindex); + if (!dev) + return -ENODEV; + idev = __in6_dev_get(dev); + if (idev) { + err = in6_dump_addrs(idev, skb, cb, s_ip_idx, + &fillargs); + } + goto put_tgt_net; + } } rcu_read_lock(); @@ -5124,6 +5140,7 @@ done: rcu_read_unlock(); cb->args[0] = h; cb->args[1] = idx; +put_tgt_net: if (fillargs.netnsid >= 0) put_net(tgt_net); |