diff options
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r-- | net/ipv4/devinet.c | 83 |
1 files changed, 78 insertions, 5 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c6287cd978c2..dfc39d4d48b7 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -536,7 +536,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, | |||
536 | return NULL; | 536 | return NULL; |
537 | } | 537 | } |
538 | 538 | ||
539 | static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 539 | static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) |
540 | { | 540 | { |
541 | struct net *net = sock_net(skb->sk); | 541 | struct net *net = sock_net(skb->sk); |
542 | struct nlattr *tb[IFA_MAX+1]; | 542 | struct nlattr *tb[IFA_MAX+1]; |
@@ -801,7 +801,7 @@ static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa) | |||
801 | return NULL; | 801 | return NULL; |
802 | } | 802 | } |
803 | 803 | ||
804 | static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 804 | static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) |
805 | { | 805 | { |
806 | struct net *net = sock_net(skb->sk); | 806 | struct net *net = sock_net(skb->sk); |
807 | struct in_ifaddr *ifa; | 807 | struct in_ifaddr *ifa; |
@@ -1529,6 +1529,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
1529 | idx = 0; | 1529 | idx = 0; |
1530 | head = &net->dev_index_head[h]; | 1530 | head = &net->dev_index_head[h]; |
1531 | rcu_read_lock(); | 1531 | rcu_read_lock(); |
1532 | cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ | ||
1533 | net->dev_base_seq; | ||
1532 | hlist_for_each_entry_rcu(dev, head, index_hlist) { | 1534 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
1533 | if (idx < s_idx) | 1535 | if (idx < s_idx) |
1534 | goto cont; | 1536 | goto cont; |
@@ -1549,6 +1551,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
1549 | rcu_read_unlock(); | 1551 | rcu_read_unlock(); |
1550 | goto done; | 1552 | goto done; |
1551 | } | 1553 | } |
1554 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1552 | } | 1555 | } |
1553 | cont: | 1556 | cont: |
1554 | idx++; | 1557 | idx++; |
@@ -1760,8 +1763,7 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { | |||
1760 | }; | 1763 | }; |
1761 | 1764 | ||
1762 | static int inet_netconf_get_devconf(struct sk_buff *in_skb, | 1765 | static int inet_netconf_get_devconf(struct sk_buff *in_skb, |
1763 | struct nlmsghdr *nlh, | 1766 | struct nlmsghdr *nlh) |
1764 | void *arg) | ||
1765 | { | 1767 | { |
1766 | struct net *net = sock_net(in_skb->sk); | 1768 | struct net *net = sock_net(in_skb->sk); |
1767 | struct nlattr *tb[NETCONFA_MAX+1]; | 1769 | struct nlattr *tb[NETCONFA_MAX+1]; |
@@ -1821,6 +1823,77 @@ errout: | |||
1821 | return err; | 1823 | return err; |
1822 | } | 1824 | } |
1823 | 1825 | ||
1826 | static int inet_netconf_dump_devconf(struct sk_buff *skb, | ||
1827 | struct netlink_callback *cb) | ||
1828 | { | ||
1829 | struct net *net = sock_net(skb->sk); | ||
1830 | int h, s_h; | ||
1831 | int idx, s_idx; | ||
1832 | struct net_device *dev; | ||
1833 | struct in_device *in_dev; | ||
1834 | struct hlist_head *head; | ||
1835 | |||
1836 | s_h = cb->args[0]; | ||
1837 | s_idx = idx = cb->args[1]; | ||
1838 | |||
1839 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | ||
1840 | idx = 0; | ||
1841 | head = &net->dev_index_head[h]; | ||
1842 | rcu_read_lock(); | ||
1843 | cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ | ||
1844 | net->dev_base_seq; | ||
1845 | hlist_for_each_entry_rcu(dev, head, index_hlist) { | ||
1846 | if (idx < s_idx) | ||
1847 | goto cont; | ||
1848 | in_dev = __in_dev_get_rcu(dev); | ||
1849 | if (!in_dev) | ||
1850 | goto cont; | ||
1851 | |||
1852 | if (inet_netconf_fill_devconf(skb, dev->ifindex, | ||
1853 | &in_dev->cnf, | ||
1854 | NETLINK_CB(cb->skb).portid, | ||
1855 | cb->nlh->nlmsg_seq, | ||
1856 | RTM_NEWNETCONF, | ||
1857 | NLM_F_MULTI, | ||
1858 | -1) <= 0) { | ||
1859 | rcu_read_unlock(); | ||
1860 | goto done; | ||
1861 | } | ||
1862 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1863 | cont: | ||
1864 | idx++; | ||
1865 | } | ||
1866 | rcu_read_unlock(); | ||
1867 | } | ||
1868 | if (h == NETDEV_HASHENTRIES) { | ||
1869 | if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, | ||
1870 | net->ipv4.devconf_all, | ||
1871 | NETLINK_CB(cb->skb).portid, | ||
1872 | cb->nlh->nlmsg_seq, | ||
1873 | RTM_NEWNETCONF, NLM_F_MULTI, | ||
1874 | -1) <= 0) | ||
1875 | goto done; | ||
1876 | else | ||
1877 | h++; | ||
1878 | } | ||
1879 | if (h == NETDEV_HASHENTRIES + 1) { | ||
1880 | if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, | ||
1881 | net->ipv4.devconf_dflt, | ||
1882 | NETLINK_CB(cb->skb).portid, | ||
1883 | cb->nlh->nlmsg_seq, | ||
1884 | RTM_NEWNETCONF, NLM_F_MULTI, | ||
1885 | -1) <= 0) | ||
1886 | goto done; | ||
1887 | else | ||
1888 | h++; | ||
1889 | } | ||
1890 | done: | ||
1891 | cb->args[0] = h; | ||
1892 | cb->args[1] = idx; | ||
1893 | |||
1894 | return skb->len; | ||
1895 | } | ||
1896 | |||
1824 | #ifdef CONFIG_SYSCTL | 1897 | #ifdef CONFIG_SYSCTL |
1825 | 1898 | ||
1826 | static void devinet_copy_dflt_conf(struct net *net, int i) | 1899 | static void devinet_copy_dflt_conf(struct net *net, int i) |
@@ -2225,6 +2298,6 @@ void __init devinet_init(void) | |||
2225 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL); | 2298 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL); |
2226 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL); | 2299 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL); |
2227 | rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, | 2300 | rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, |
2228 | NULL, NULL); | 2301 | inet_netconf_dump_devconf, NULL); |
2229 | } | 2302 | } |
2230 | 2303 | ||