aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/rtnetlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r--net/core/rtnetlink.c64
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 @@
56struct rtnl_link { 56struct 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
61static DEFINE_MUTEX(rtnl_mutex); 62static DEFINE_MUTEX(rtnl_mutex);
63static u16 min_ifinfo_dump_size;
62 64
63void rtnl_lock(void) 65void 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
149static 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 */
164int __rtnl_register(int protocol, int msgtype, 182int __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}
190EXPORT_SYMBOL_GPL(__rtnl_register); 212EXPORT_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 */
201void rtnl_register(int protocol, int msgtype, 223void 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));
1023cont: 1050cont:
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
1848static u16 rtnl_calcit(struct sk_buff *skb)
1849{
1850 return min_ifinfo_dump_size;
1851}
1852
1821static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) 1853static 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