diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 884d176e0082..e63b8a98fb4d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev) | |||
273 | return -1; | 273 | return -1; |
274 | } | 274 | } |
275 | 275 | ||
276 | static inline size_t fib_nlmsg_size(struct fib_info *fi) | ||
277 | { | ||
278 | size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) | ||
279 | + nla_total_size(4) /* RTA_TABLE */ | ||
280 | + nla_total_size(4) /* RTA_DST */ | ||
281 | + nla_total_size(4) /* RTA_PRIORITY */ | ||
282 | + nla_total_size(4); /* RTA_PREFSRC */ | ||
283 | |||
284 | /* space for nested metrics */ | ||
285 | payload += nla_total_size((RTAX_MAX * nla_total_size(4))); | ||
286 | |||
287 | if (fi->fib_nhs) { | ||
288 | /* Also handles the special case fib_nhs == 1 */ | ||
289 | |||
290 | /* each nexthop is packed in an attribute */ | ||
291 | size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); | ||
292 | |||
293 | /* may contain flow and gateway attribute */ | ||
294 | nhsize += 2 * nla_total_size(4); | ||
295 | |||
296 | /* all nexthops are packed in a nested attribute */ | ||
297 | payload += nla_total_size(fi->fib_nhs * nhsize); | ||
298 | } | ||
299 | |||
300 | return payload; | ||
301 | } | ||
302 | |||
276 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | 303 | void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, |
277 | int dst_len, u32 tb_id, struct nl_info *info) | 304 | int dst_len, u32 tb_id, struct nl_info *info) |
278 | { | 305 | { |
279 | struct sk_buff *skb; | 306 | struct sk_buff *skb; |
280 | int payload = sizeof(struct rtmsg) + 256; | ||
281 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; | 307 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; |
282 | int err = -ENOBUFS; | 308 | int err = -ENOBUFS; |
283 | 309 | ||
284 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); | 310 | skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); |
285 | if (skb == NULL) | 311 | if (skb == NULL) |
286 | goto errout; | 312 | goto errout; |
287 | 313 | ||
288 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, | 314 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, |
289 | fa->fa_type, fa->fa_scope, key, dst_len, | 315 | fa->fa_type, fa->fa_scope, key, dst_len, |
290 | fa->fa_tos, fa->fa_info, 0); | 316 | fa->fa_tos, fa->fa_info, 0); |
291 | if (err < 0) { | 317 | /* failure implies BUG in fib_nlmsg_size() */ |
292 | kfree_skb(skb); | 318 | BUG_ON(err < 0); |
293 | goto errout; | ||
294 | } | ||
295 | 319 | ||
296 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, | 320 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, |
297 | info->nlh, GFP_KERNEL); | 321 | info->nlh, GFP_KERNEL); |