diff options
Diffstat (limited to 'net/decnet/dn_table.c')
-rw-r--r-- | net/decnet/dn_table.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 317904bb5896..e74b744254ab 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c | |||
@@ -263,6 +263,32 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern | |||
263 | return 0; | 263 | return 0; |
264 | } | 264 | } |
265 | 265 | ||
266 | static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi) | ||
267 | { | ||
268 | size_t payload = NLMSG_ALIGN(struct rtmsg) | ||
269 | + nla_total_size(4) /* RTA_TABLE */ | ||
270 | + nla_total_size(2) /* RTA_DST */ | ||
271 | + nla_total_size(4); /* RTA_PRIORITY */ | ||
272 | |||
273 | /* space for nested metrics */ | ||
274 | payload += nla_total_size((RTAX_MAX * nla_total_size(4))); | ||
275 | |||
276 | if (fi->fib_nhs) { | ||
277 | /* Also handles the special case fib_nhs == 1 */ | ||
278 | |||
279 | /* each nexthop is packed in an attribute */ | ||
280 | size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); | ||
281 | |||
282 | /* may contain a gateway attribute */ | ||
283 | nhsize += nla_total_size(4); | ||
284 | |||
285 | /* all nexthops are packed in a nested attribute */ | ||
286 | payload += nla_total_size(fi->fib_nhs * nhsize); | ||
287 | } | ||
288 | |||
289 | return payload; | ||
290 | } | ||
291 | |||
266 | static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 292 | static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
267 | u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, | 293 | u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, |
268 | struct dn_fib_info *fi, unsigned int flags) | 294 | struct dn_fib_info *fi, unsigned int flags) |
@@ -335,17 +361,15 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, | |||
335 | u32 pid = req ? req->pid : 0; | 361 | u32 pid = req ? req->pid : 0; |
336 | int err = -ENOBUFS; | 362 | int err = -ENOBUFS; |
337 | 363 | ||
338 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 364 | skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f), GFP_KERNEL)); |
339 | if (skb == NULL) | 365 | if (skb == NULL) |
340 | goto errout; | 366 | goto errout; |
341 | 367 | ||
342 | err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, | 368 | err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, |
343 | f->fn_type, f->fn_scope, &f->fn_key, z, | 369 | f->fn_type, f->fn_scope, &f->fn_key, z, |
344 | DN_FIB_INFO(f), 0); | 370 | DN_FIB_INFO(f), 0); |
345 | if (err < 0) { | 371 | /* failure implies BUG in dn_fib_nlmsg_size() */ |
346 | kfree_skb(skb); | 372 | BUG_ON(err < 0); |
347 | goto errout; | ||
348 | } | ||
349 | 373 | ||
350 | err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); | 374 | err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); |
351 | errout: | 375 | errout: |