diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index abd936d8a71..99d9e953fe3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -56,9 +56,11 @@ | |||
56 | struct rtnl_link { | 56 | struct rtnl_link { |
57 | rtnl_doit_func doit; | 57 | rtnl_doit_func doit; |
58 | rtnl_dumpit_func dumpit; | 58 | rtnl_dumpit_func dumpit; |
59 | rtnl_calcit_func calcit; | ||
59 | }; | 60 | }; |
60 | 61 | ||
61 | static DEFINE_MUTEX(rtnl_mutex); | 62 | static DEFINE_MUTEX(rtnl_mutex); |
63 | static u16 min_ifinfo_dump_size; | ||
62 | 64 | ||
63 | void rtnl_lock(void) | 65 | void rtnl_lock(void) |
64 | { | 66 | { |
@@ -144,12 +146,28 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) | |||
144 | return tab ? tab[msgindex].dumpit : NULL; | 146 | return tab ? tab[msgindex].dumpit : NULL; |
145 | } | 147 | } |
146 | 148 | ||
149 | static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex) | ||
150 | { | ||
151 | struct rtnl_link *tab; | ||
152 | |||
153 | if (protocol <= RTNL_FAMILY_MAX) | ||
154 | tab = rtnl_msg_handlers[protocol]; | ||
155 | else | ||
156 | tab = NULL; | ||
157 | |||
158 | if (tab == NULL || tab[msgindex].calcit == NULL) | ||
159 | tab = rtnl_msg_handlers[PF_UNSPEC]; | ||
160 | |||
161 | return tab ? tab[msgindex].calcit : NULL; | ||
162 | } | ||
163 | |||
147 | /** | 164 | /** |
148 | * __rtnl_register - Register a rtnetlink message type | 165 | * __rtnl_register - Register a rtnetlink message type |
149 | * @protocol: Protocol family or PF_UNSPEC | 166 | * @protocol: Protocol family or PF_UNSPEC |
150 | * @msgtype: rtnetlink message type | 167 | * @msgtype: rtnetlink message type |
151 | * @doit: Function pointer called for each request message | 168 | * @doit: Function pointer called for each request message |
152 | * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message | 169 | * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message |
170 | * @calcit: Function pointer to calc size of dump message | ||
153 | * | 171 | * |
154 | * Registers the specified function pointers (at least one of them has | 172 | * Registers the specified function pointers (at least one of them has |
155 | * to be non-NULL) to be called whenever a request message for the | 173 | * to be non-NULL) to be called whenever a request message for the |
@@ -162,7 +180,8 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) | |||
162 | * Returns 0 on success or a negative error code. | 180 | * Returns 0 on success or a negative error code. |
163 | */ | 181 | */ |
164 | int __rtnl_register(int protocol, int msgtype, | 182 | int __rtnl_register(int protocol, int msgtype, |
165 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) | 183 | rtnl_doit_func doit, rtnl_dumpit_func dumpit, |
184 | rtnl_calcit_func calcit) | ||
166 | { | 185 | { |
167 | struct rtnl_link *tab; | 186 | struct rtnl_link *tab; |
168 | int msgindex; | 187 | int msgindex; |
@@ -185,6 +204,9 @@ int __rtnl_register(int protocol, int msgtype, | |||
185 | if (dumpit) | 204 | if (dumpit) |
186 | tab[msgindex].dumpit = dumpit; | 205 | tab[msgindex].dumpit = dumpit; |
187 | 206 | ||
207 | if (calcit) | ||
208 | tab[msgindex].calcit = calcit; | ||
209 | |||
188 | return 0; | 210 | return 0; |
189 | } | 211 | } |
190 | EXPORT_SYMBOL_GPL(__rtnl_register); | 212 | EXPORT_SYMBOL_GPL(__rtnl_register); |
@@ -199,9 +221,10 @@ EXPORT_SYMBOL_GPL(__rtnl_register); | |||
199 | * of memory implies no sense in continuing. | 221 | * of memory implies no sense in continuing. |
200 | */ | 222 | */ |
201 | void rtnl_register(int protocol, int msgtype, | 223 | void rtnl_register(int protocol, int msgtype, |
202 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) | 224 | rtnl_doit_func doit, rtnl_dumpit_func dumpit, |
225 | rtnl_calcit_func calcit) | ||
203 | { | 226 | { |
204 | if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0) | 227 | if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0) |
205 | panic("Unable to register rtnetlink message handler, " | 228 | panic("Unable to register rtnetlink message handler, " |
206 | "protocol = %d, message type = %d\n", | 229 | "protocol = %d, message type = %d\n", |
207 | protocol, msgtype); | 230 | protocol, msgtype); |
@@ -1009,6 +1032,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1009 | s_idx = cb->args[1]; | 1032 | s_idx = cb->args[1]; |
1010 | 1033 | ||
1011 | rcu_read_lock(); | 1034 | rcu_read_lock(); |
1035 | cb->seq = net->dev_base_seq; | ||
1036 | |||
1012 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 1037 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
1013 | idx = 0; | 1038 | idx = 0; |
1014 | head = &net->dev_index_head[h]; | 1039 | head = &net->dev_index_head[h]; |
@@ -1020,6 +1045,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1020 | cb->nlh->nlmsg_seq, 0, | 1045 | cb->nlh->nlmsg_seq, 0, |
1021 | NLM_F_MULTI) <= 0) | 1046 | NLM_F_MULTI) <= 0) |
1022 | goto out; | 1047 | goto out; |
1048 | |||
1049 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
1023 | cont: | 1050 | cont: |
1024 | idx++; | 1051 | idx++; |
1025 | } | 1052 | } |
@@ -1818,6 +1845,11 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
1818 | return err; | 1845 | return err; |
1819 | } | 1846 | } |
1820 | 1847 | ||
1848 | static u16 rtnl_calcit(struct sk_buff *skb) | ||
1849 | { | ||
1850 | return min_ifinfo_dump_size; | ||
1851 | } | ||
1852 | |||
1821 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 1853 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
1822 | { | 1854 | { |
1823 | int idx; | 1855 | int idx; |
@@ -1847,11 +1879,14 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
1847 | struct net *net = dev_net(dev); | 1879 | struct net *net = dev_net(dev); |
1848 | struct sk_buff *skb; | 1880 | struct sk_buff *skb; |
1849 | int err = -ENOBUFS; | 1881 | int err = -ENOBUFS; |
1882 | size_t if_info_size; | ||
1850 | 1883 | ||
1851 | skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); | 1884 | skb = nlmsg_new((if_info_size = if_nlmsg_size(dev)), GFP_KERNEL); |
1852 | if (skb == NULL) | 1885 | if (skb == NULL) |
1853 | goto errout; | 1886 | goto errout; |
1854 | 1887 | ||
1888 | min_ifinfo_dump_size = max_t(u16, if_info_size, min_ifinfo_dump_size); | ||
1889 | |||
1855 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); | 1890 | err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0); |
1856 | if (err < 0) { | 1891 | if (err < 0) { |
1857 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ | 1892 | /* -EMSGSIZE implies BUG in if_nlmsg_size() */ |
@@ -1902,14 +1937,20 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1902 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 1937 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
1903 | struct sock *rtnl; | 1938 | struct sock *rtnl; |
1904 | rtnl_dumpit_func dumpit; | 1939 | rtnl_dumpit_func dumpit; |
1940 | rtnl_calcit_func calcit; | ||
1941 | u16 min_dump_alloc = 0; | ||
1905 | 1942 | ||
1906 | dumpit = rtnl_get_dumpit(family, type); | 1943 | dumpit = rtnl_get_dumpit(family, type); |
1907 | if (dumpit == NULL) | 1944 | if (dumpit == NULL) |
1908 | return -EOPNOTSUPP; | 1945 | return -EOPNOTSUPP; |
1946 | calcit = rtnl_get_calcit(family, type); | ||
1947 | if (calcit) | ||
1948 | min_dump_alloc = calcit(skb); | ||
1909 | 1949 | ||
1910 | __rtnl_unlock(); | 1950 | __rtnl_unlock(); |
1911 | rtnl = net->rtnl; | 1951 | rtnl = net->rtnl; |
1912 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); | 1952 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, |
1953 | NULL, min_dump_alloc); | ||
1913 | rtnl_lock(); | 1954 | rtnl_lock(); |
1914 | return err; | 1955 | return err; |
1915 | } | 1956 | } |
@@ -2019,12 +2060,13 @@ void __init rtnetlink_init(void) | |||
2019 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); | 2060 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); |
2020 | register_netdevice_notifier(&rtnetlink_dev_notifier); | 2061 | register_netdevice_notifier(&rtnetlink_dev_notifier); |
2021 | 2062 | ||
2022 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo); | 2063 | rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, |
2023 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL); | 2064 | rtnl_dump_ifinfo, rtnl_calcit); |
2024 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL); | 2065 | rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL); |
2025 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL); | 2066 | rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL); |
2067 | rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL); | ||
2026 | 2068 | ||
2027 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all); | 2069 | rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL); |
2028 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); | 2070 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL); |
2029 | } | 2071 | } |
2030 | 2072 | ||