diff options
-rw-r--r-- | net/ipv4/devinet.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index d122ebbe5980..67f382c560ba 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1713,6 +1713,32 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, | |||
1713 | return 0; | 1713 | return 0; |
1714 | } | 1714 | } |
1715 | 1715 | ||
1716 | static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb, | ||
1717 | struct netlink_callback *cb, int s_ip_idx, | ||
1718 | struct inet_fill_args *fillargs) | ||
1719 | { | ||
1720 | struct in_ifaddr *ifa; | ||
1721 | int ip_idx = 0; | ||
1722 | int err; | ||
1723 | |||
1724 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next, ip_idx++) { | ||
1725 | if (ip_idx < s_ip_idx) | ||
1726 | continue; | ||
1727 | |||
1728 | err = inet_fill_ifaddr(skb, ifa, fillargs); | ||
1729 | if (err < 0) | ||
1730 | goto done; | ||
1731 | |||
1732 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1733 | } | ||
1734 | err = 0; | ||
1735 | |||
1736 | done: | ||
1737 | cb->args[2] = ip_idx; | ||
1738 | |||
1739 | return err; | ||
1740 | } | ||
1741 | |||
1716 | static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 1742 | static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
1717 | { | 1743 | { |
1718 | const struct nlmsghdr *nlh = cb->nlh; | 1744 | const struct nlmsghdr *nlh = cb->nlh; |
@@ -1727,19 +1753,17 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
1727 | struct net *tgt_net = net; | 1753 | struct net *tgt_net = net; |
1728 | int h, s_h; | 1754 | int h, s_h; |
1729 | int idx, s_idx; | 1755 | int idx, s_idx; |
1730 | int ip_idx, s_ip_idx; | 1756 | int s_ip_idx; |
1731 | struct net_device *dev; | 1757 | struct net_device *dev; |
1732 | struct in_device *in_dev; | 1758 | struct in_device *in_dev; |
1733 | struct in_ifaddr *ifa; | ||
1734 | struct hlist_head *head; | 1759 | struct hlist_head *head; |
1760 | int err; | ||
1735 | 1761 | ||
1736 | s_h = cb->args[0]; | 1762 | s_h = cb->args[0]; |
1737 | s_idx = idx = cb->args[1]; | 1763 | s_idx = idx = cb->args[1]; |
1738 | s_ip_idx = ip_idx = cb->args[2]; | 1764 | s_ip_idx = cb->args[2]; |
1739 | 1765 | ||
1740 | if (cb->strict_check) { | 1766 | if (cb->strict_check) { |
1741 | int err; | ||
1742 | |||
1743 | err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, | 1767 | err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, |
1744 | skb->sk, cb->extack); | 1768 | skb->sk, cb->extack); |
1745 | if (err < 0) | 1769 | if (err < 0) |
@@ -1761,15 +1785,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
1761 | if (!in_dev) | 1785 | if (!in_dev) |
1762 | goto cont; | 1786 | goto cont; |
1763 | 1787 | ||
1764 | for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; | 1788 | err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, |
1765 | ifa = ifa->ifa_next, ip_idx++) { | 1789 | &fillargs); |
1766 | if (ip_idx < s_ip_idx) | 1790 | if (err < 0) { |
1767 | continue; | 1791 | rcu_read_unlock(); |
1768 | if (inet_fill_ifaddr(skb, ifa, &fillargs) < 0) { | 1792 | goto done; |
1769 | rcu_read_unlock(); | ||
1770 | goto done; | ||
1771 | } | ||
1772 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1773 | } | 1793 | } |
1774 | cont: | 1794 | cont: |
1775 | idx++; | 1795 | idx++; |
@@ -1780,7 +1800,6 @@ cont: | |||
1780 | done: | 1800 | done: |
1781 | cb->args[0] = h; | 1801 | cb->args[0] = h; |
1782 | cb->args[1] = idx; | 1802 | cb->args[1] = idx; |
1783 | cb->args[2] = ip_idx; | ||
1784 | if (fillargs.netnsid >= 0) | 1803 | if (fillargs.netnsid >= 0) |
1785 | put_net(tgt_net); | 1804 | put_net(tgt_net); |
1786 | 1805 | ||