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 abd936d8a716..99d9e953fe39 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 | ||
