diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-17 21:14:52 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:04 -0400 |
commit | 4e902c57417c4c285b98ba2722468d1c3ed83d1b (patch) | |
tree | 83251829a4bc9628a3543e5f70e7b11090fe22d9 /net/ipv4/fib_semantics.c | |
parent | ab32ea5d8a760e7dd4339634e95d7be24ee5b842 (diff) |
[IPv4]: FIB configuration using struct fib_config
Introduces struct fib_config replacing the ugly struct kern_rta
prone to ordering issues. Avoids creating faked netlink messages
for auto generated routes or requests via ioctl.
A new interface net/nexthop.h is added to help navigate through
nexthop configuration arrays.
A new struct nl_info will be used to carry the necessary netlink
information to be used for notifications later on.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 385 |
1 files changed, 116 insertions, 269 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 5dfdad5cbcd4..340f9db389e5 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <net/ip_fib.h> | 44 | #include <net/ip_fib.h> |
45 | #include <net/ip_mp_alg.h> | 45 | #include <net/ip_mp_alg.h> |
46 | #include <net/netlink.h> | 46 | #include <net/netlink.h> |
47 | #include <net/nexthop.h> | ||
47 | 48 | ||
48 | #include "fib_lookup.h" | 49 | #include "fib_lookup.h" |
49 | 50 | ||
@@ -273,27 +274,27 @@ int ip_fib_check_default(u32 gw, struct net_device *dev) | |||
273 | } | 274 | } |
274 | 275 | ||
275 | void rtmsg_fib(int event, u32 key, struct fib_alias *fa, | 276 | void rtmsg_fib(int event, u32 key, struct fib_alias *fa, |
276 | int z, u32 tb_id, | 277 | int dst_len, u32 tb_id, struct nl_info *info) |
277 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
278 | { | 278 | { |
279 | struct sk_buff *skb; | 279 | struct sk_buff *skb; |
280 | u32 pid = req ? req->pid : n->nlmsg_pid; | ||
281 | int payload = sizeof(struct rtmsg) + 256; | 280 | int payload = sizeof(struct rtmsg) + 256; |
281 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; | ||
282 | int err = -ENOBUFS; | 282 | int err = -ENOBUFS; |
283 | 283 | ||
284 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); | 284 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); |
285 | if (skb == NULL) | 285 | if (skb == NULL) |
286 | goto errout; | 286 | goto errout; |
287 | 287 | ||
288 | err = fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id, | 288 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, |
289 | fa->fa_type, fa->fa_scope, &key, z, fa->fa_tos, | 289 | fa->fa_type, fa->fa_scope, &key, dst_len, |
290 | fa->fa_info, 0); | 290 | fa->fa_tos, fa->fa_info, 0); |
291 | if (err < 0) { | 291 | if (err < 0) { |
292 | kfree_skb(skb); | 292 | kfree_skb(skb); |
293 | goto errout; | 293 | goto errout; |
294 | } | 294 | } |
295 | 295 | ||
296 | err = rtnl_notify(skb, pid, RTNLGRP_IPV4_ROUTE, n, GFP_KERNEL); | 296 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, |
297 | info->nlh, GFP_KERNEL); | ||
297 | errout: | 298 | errout: |
298 | if (err < 0) | 299 | if (err < 0) |
299 | rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err); | 300 | rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err); |
@@ -342,102 +343,100 @@ int fib_detect_death(struct fib_info *fi, int order, | |||
342 | 343 | ||
343 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 344 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
344 | 345 | ||
345 | static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type) | 346 | static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining) |
346 | { | ||
347 | while (RTA_OK(attr,attrlen)) { | ||
348 | if (attr->rta_type == type) | ||
349 | return *(u32*)RTA_DATA(attr); | ||
350 | attr = RTA_NEXT(attr, attrlen); | ||
351 | } | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int | ||
356 | fib_count_nexthops(struct rtattr *rta) | ||
357 | { | 347 | { |
358 | int nhs = 0; | 348 | int nhs = 0; |
359 | struct rtnexthop *nhp = RTA_DATA(rta); | ||
360 | int nhlen = RTA_PAYLOAD(rta); | ||
361 | 349 | ||
362 | while (nhlen >= (int)sizeof(struct rtnexthop)) { | 350 | while (rtnh_ok(rtnh, remaining)) { |
363 | if ((nhlen -= nhp->rtnh_len) < 0) | ||
364 | return 0; | ||
365 | nhs++; | 351 | nhs++; |
366 | nhp = RTNH_NEXT(nhp); | 352 | rtnh = rtnh_next(rtnh, &remaining); |
367 | }; | 353 | } |
368 | return nhs; | 354 | |
355 | /* leftover implies invalid nexthop configuration, discard it */ | ||
356 | return remaining > 0 ? 0 : nhs; | ||
369 | } | 357 | } |
370 | 358 | ||
371 | static int | 359 | static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, |
372 | fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) | 360 | int remaining, struct fib_config *cfg) |
373 | { | 361 | { |
374 | struct rtnexthop *nhp = RTA_DATA(rta); | ||
375 | int nhlen = RTA_PAYLOAD(rta); | ||
376 | |||
377 | change_nexthops(fi) { | 362 | change_nexthops(fi) { |
378 | int attrlen = nhlen - sizeof(struct rtnexthop); | 363 | int attrlen; |
379 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) | 364 | |
365 | if (!rtnh_ok(rtnh, remaining)) | ||
380 | return -EINVAL; | 366 | return -EINVAL; |
381 | nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; | 367 | |
382 | nh->nh_oif = nhp->rtnh_ifindex; | 368 | nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; |
383 | nh->nh_weight = nhp->rtnh_hops + 1; | 369 | nh->nh_oif = rtnh->rtnh_ifindex; |
384 | if (attrlen) { | 370 | nh->nh_weight = rtnh->rtnh_hops + 1; |
385 | nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 371 | |
372 | attrlen = rtnh_attrlen(rtnh); | ||
373 | if (attrlen > 0) { | ||
374 | struct nlattr *nla, *attrs = rtnh_attrs(rtnh); | ||
375 | |||
376 | nla = nla_find(attrs, attrlen, RTA_GATEWAY); | ||
377 | nh->nh_gw = nla ? nla_get_u32(nla) : 0; | ||
386 | #ifdef CONFIG_NET_CLS_ROUTE | 378 | #ifdef CONFIG_NET_CLS_ROUTE |
387 | nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); | 379 | nla = nla_find(attrs, attrlen, RTA_FLOW); |
380 | nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; | ||
388 | #endif | 381 | #endif |
389 | } | 382 | } |
390 | nhp = RTNH_NEXT(nhp); | 383 | |
384 | rtnh = rtnh_next(rtnh, &remaining); | ||
391 | } endfor_nexthops(fi); | 385 | } endfor_nexthops(fi); |
386 | |||
392 | return 0; | 387 | return 0; |
393 | } | 388 | } |
394 | 389 | ||
395 | #endif | 390 | #endif |
396 | 391 | ||
397 | int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, | 392 | int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) |
398 | struct fib_info *fi) | ||
399 | { | 393 | { |
400 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 394 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
401 | struct rtnexthop *nhp; | 395 | struct rtnexthop *rtnh; |
402 | int nhlen; | 396 | int remaining; |
403 | #endif | 397 | #endif |
404 | 398 | ||
405 | if (rta->rta_priority && | 399 | if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) |
406 | *rta->rta_priority != fi->fib_priority) | ||
407 | return 1; | 400 | return 1; |
408 | 401 | ||
409 | if (rta->rta_oif || rta->rta_gw) { | 402 | if (cfg->fc_oif || cfg->fc_gw) { |
410 | if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && | 403 | if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && |
411 | (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0)) | 404 | (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) |
412 | return 0; | 405 | return 0; |
413 | return 1; | 406 | return 1; |
414 | } | 407 | } |
415 | 408 | ||
416 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 409 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
417 | if (rta->rta_mp == NULL) | 410 | if (cfg->fc_mp == NULL) |
418 | return 0; | 411 | return 0; |
419 | nhp = RTA_DATA(rta->rta_mp); | 412 | |
420 | nhlen = RTA_PAYLOAD(rta->rta_mp); | 413 | rtnh = cfg->fc_mp; |
414 | remaining = cfg->fc_mp_len; | ||
421 | 415 | ||
422 | for_nexthops(fi) { | 416 | for_nexthops(fi) { |
423 | int attrlen = nhlen - sizeof(struct rtnexthop); | 417 | int attrlen; |
424 | u32 gw; | ||
425 | 418 | ||
426 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) | 419 | if (!rtnh_ok(rtnh, remaining)) |
427 | return -EINVAL; | 420 | return -EINVAL; |
428 | if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) | 421 | |
422 | if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif) | ||
429 | return 1; | 423 | return 1; |
430 | if (attrlen) { | 424 | |
431 | gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 425 | attrlen = rtnh_attrlen(rtnh); |
432 | if (gw && gw != nh->nh_gw) | 426 | if (attrlen < 0) { |
427 | struct nlattr *nla, *attrs = rtnh_attrs(rtnh); | ||
428 | |||
429 | nla = nla_find(attrs, attrlen, RTA_GATEWAY); | ||
430 | if (nla && nla_get_u32(nla) != nh->nh_gw) | ||
433 | return 1; | 431 | return 1; |
434 | #ifdef CONFIG_NET_CLS_ROUTE | 432 | #ifdef CONFIG_NET_CLS_ROUTE |
435 | gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); | 433 | nla = nla_find(attrs, attrlen, RTA_FLOW); |
436 | if (gw && gw != nh->nh_tclassid) | 434 | if (nla && nla_get_u32(nla) != nh->nh_tclassid) |
437 | return 1; | 435 | return 1; |
438 | #endif | 436 | #endif |
439 | } | 437 | } |
440 | nhp = RTNH_NEXT(nhp); | 438 | |
439 | rtnh = rtnh_next(rtnh, &remaining); | ||
441 | } endfor_nexthops(fi); | 440 | } endfor_nexthops(fi); |
442 | #endif | 441 | #endif |
443 | return 0; | 442 | return 0; |
@@ -488,7 +487,8 @@ int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, | |||
488 | |-> {local prefix} (terminal node) | 487 | |-> {local prefix} (terminal node) |
489 | */ | 488 | */ |
490 | 489 | ||
491 | static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh) | 490 | static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, |
491 | struct fib_nh *nh) | ||
492 | { | 492 | { |
493 | int err; | 493 | int err; |
494 | 494 | ||
@@ -502,7 +502,7 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n | |||
502 | if (nh->nh_flags&RTNH_F_ONLINK) { | 502 | if (nh->nh_flags&RTNH_F_ONLINK) { |
503 | struct net_device *dev; | 503 | struct net_device *dev; |
504 | 504 | ||
505 | if (r->rtm_scope >= RT_SCOPE_LINK) | 505 | if (cfg->fc_scope >= RT_SCOPE_LINK) |
506 | return -EINVAL; | 506 | return -EINVAL; |
507 | if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) | 507 | if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) |
508 | return -EINVAL; | 508 | return -EINVAL; |
@@ -516,10 +516,15 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n | |||
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
518 | { | 518 | { |
519 | struct flowi fl = { .nl_u = { .ip4_u = | 519 | struct flowi fl = { |
520 | { .daddr = nh->nh_gw, | 520 | .nl_u = { |
521 | .scope = r->rtm_scope + 1 } }, | 521 | .ip4_u = { |
522 | .oif = nh->nh_oif }; | 522 | .daddr = nh->nh_gw, |
523 | .scope = cfg->fc_scope + 1, | ||
524 | }, | ||
525 | }, | ||
526 | .oif = nh->nh_oif, | ||
527 | }; | ||
523 | 528 | ||
524 | /* It is not necessary, but requires a bit of thinking */ | 529 | /* It is not necessary, but requires a bit of thinking */ |
525 | if (fl.fl4_scope < RT_SCOPE_LINK) | 530 | if (fl.fl4_scope < RT_SCOPE_LINK) |
@@ -646,39 +651,28 @@ static void fib_hash_move(struct hlist_head *new_info_hash, | |||
646 | fib_hash_free(old_laddrhash, bytes); | 651 | fib_hash_free(old_laddrhash, bytes); |
647 | } | 652 | } |
648 | 653 | ||
649 | struct fib_info * | 654 | struct fib_info *fib_create_info(struct fib_config *cfg) |
650 | fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | ||
651 | const struct nlmsghdr *nlh, int *errp) | ||
652 | { | 655 | { |
653 | int err; | 656 | int err; |
654 | struct fib_info *fi = NULL; | 657 | struct fib_info *fi = NULL; |
655 | struct fib_info *ofi; | 658 | struct fib_info *ofi; |
656 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | ||
657 | int nhs = 1; | 659 | int nhs = 1; |
658 | #else | ||
659 | const int nhs = 1; | ||
660 | #endif | ||
661 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | ||
662 | u32 mp_alg = IP_MP_ALG_NONE; | ||
663 | #endif | ||
664 | 660 | ||
665 | /* Fast check to catch the most weird cases */ | 661 | /* Fast check to catch the most weird cases */ |
666 | if (fib_props[r->rtm_type].scope > r->rtm_scope) | 662 | if (fib_props[cfg->fc_type].scope > cfg->fc_scope) |
667 | goto err_inval; | 663 | goto err_inval; |
668 | 664 | ||
669 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 665 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
670 | if (rta->rta_mp) { | 666 | if (cfg->fc_mp) { |
671 | nhs = fib_count_nexthops(rta->rta_mp); | 667 | nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len); |
672 | if (nhs == 0) | 668 | if (nhs == 0) |
673 | goto err_inval; | 669 | goto err_inval; |
674 | } | 670 | } |
675 | #endif | 671 | #endif |
676 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 672 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
677 | if (rta->rta_mp_alg) { | 673 | if (cfg->fc_mp_alg) { |
678 | mp_alg = *rta->rta_mp_alg; | 674 | if (cfg->fc_mp_alg < IP_MP_ALG_NONE || |
679 | 675 | cfg->fc_mp_alg > IP_MP_ALG_MAX) | |
680 | if (mp_alg < IP_MP_ALG_NONE || | ||
681 | mp_alg > IP_MP_ALG_MAX) | ||
682 | goto err_inval; | 676 | goto err_inval; |
683 | } | 677 | } |
684 | #endif | 678 | #endif |
@@ -714,43 +708,42 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
714 | goto failure; | 708 | goto failure; |
715 | fib_info_cnt++; | 709 | fib_info_cnt++; |
716 | 710 | ||
717 | fi->fib_protocol = r->rtm_protocol; | 711 | fi->fib_protocol = cfg->fc_protocol; |
712 | fi->fib_flags = cfg->fc_flags; | ||
713 | fi->fib_priority = cfg->fc_priority; | ||
714 | fi->fib_prefsrc = cfg->fc_prefsrc; | ||
718 | 715 | ||
719 | fi->fib_nhs = nhs; | 716 | fi->fib_nhs = nhs; |
720 | change_nexthops(fi) { | 717 | change_nexthops(fi) { |
721 | nh->nh_parent = fi; | 718 | nh->nh_parent = fi; |
722 | } endfor_nexthops(fi) | 719 | } endfor_nexthops(fi) |
723 | 720 | ||
724 | fi->fib_flags = r->rtm_flags; | 721 | if (cfg->fc_mx) { |
725 | if (rta->rta_priority) | 722 | struct nlattr *nla; |
726 | fi->fib_priority = *rta->rta_priority; | 723 | int remaining; |
727 | if (rta->rta_mx) { | 724 | |
728 | int attrlen = RTA_PAYLOAD(rta->rta_mx); | 725 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
729 | struct rtattr *attr = RTA_DATA(rta->rta_mx); | 726 | int type = nla->nla_type; |
730 | 727 | ||
731 | while (RTA_OK(attr, attrlen)) { | 728 | if (type) { |
732 | unsigned flavor = attr->rta_type; | 729 | if (type > RTAX_MAX) |
733 | if (flavor) { | ||
734 | if (flavor > RTAX_MAX) | ||
735 | goto err_inval; | 730 | goto err_inval; |
736 | fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr); | 731 | fi->fib_metrics[type - 1] = nla_get_u32(nla); |
737 | } | 732 | } |
738 | attr = RTA_NEXT(attr, attrlen); | ||
739 | } | 733 | } |
740 | } | 734 | } |
741 | if (rta->rta_prefsrc) | ||
742 | memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4); | ||
743 | 735 | ||
744 | if (rta->rta_mp) { | 736 | if (cfg->fc_mp) { |
745 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 737 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
746 | if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0) | 738 | err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg); |
739 | if (err != 0) | ||
747 | goto failure; | 740 | goto failure; |
748 | if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) | 741 | if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif) |
749 | goto err_inval; | 742 | goto err_inval; |
750 | if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4)) | 743 | if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw) |
751 | goto err_inval; | 744 | goto err_inval; |
752 | #ifdef CONFIG_NET_CLS_ROUTE | 745 | #ifdef CONFIG_NET_CLS_ROUTE |
753 | if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4)) | 746 | if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) |
754 | goto err_inval; | 747 | goto err_inval; |
755 | #endif | 748 | #endif |
756 | #else | 749 | #else |
@@ -758,34 +751,32 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
758 | #endif | 751 | #endif |
759 | } else { | 752 | } else { |
760 | struct fib_nh *nh = fi->fib_nh; | 753 | struct fib_nh *nh = fi->fib_nh; |
761 | if (rta->rta_oif) | 754 | |
762 | nh->nh_oif = *rta->rta_oif; | 755 | nh->nh_oif = cfg->fc_oif; |
763 | if (rta->rta_gw) | 756 | nh->nh_gw = cfg->fc_gw; |
764 | memcpy(&nh->nh_gw, rta->rta_gw, 4); | 757 | nh->nh_flags = cfg->fc_flags; |
765 | #ifdef CONFIG_NET_CLS_ROUTE | 758 | #ifdef CONFIG_NET_CLS_ROUTE |
766 | if (rta->rta_flow) | 759 | nh->nh_tclassid = cfg->fc_flow; |
767 | memcpy(&nh->nh_tclassid, rta->rta_flow, 4); | ||
768 | #endif | 760 | #endif |
769 | nh->nh_flags = r->rtm_flags; | ||
770 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 761 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
771 | nh->nh_weight = 1; | 762 | nh->nh_weight = 1; |
772 | #endif | 763 | #endif |
773 | } | 764 | } |
774 | 765 | ||
775 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 766 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
776 | fi->fib_mp_alg = mp_alg; | 767 | fi->fib_mp_alg = cfg->fc_mp_alg; |
777 | #endif | 768 | #endif |
778 | 769 | ||
779 | if (fib_props[r->rtm_type].error) { | 770 | if (fib_props[cfg->fc_type].error) { |
780 | if (rta->rta_gw || rta->rta_oif || rta->rta_mp) | 771 | if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) |
781 | goto err_inval; | 772 | goto err_inval; |
782 | goto link_it; | 773 | goto link_it; |
783 | } | 774 | } |
784 | 775 | ||
785 | if (r->rtm_scope > RT_SCOPE_HOST) | 776 | if (cfg->fc_scope > RT_SCOPE_HOST) |
786 | goto err_inval; | 777 | goto err_inval; |
787 | 778 | ||
788 | if (r->rtm_scope == RT_SCOPE_HOST) { | 779 | if (cfg->fc_scope == RT_SCOPE_HOST) { |
789 | struct fib_nh *nh = fi->fib_nh; | 780 | struct fib_nh *nh = fi->fib_nh; |
790 | 781 | ||
791 | /* Local address is added. */ | 782 | /* Local address is added. */ |
@@ -798,14 +789,14 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
798 | goto failure; | 789 | goto failure; |
799 | } else { | 790 | } else { |
800 | change_nexthops(fi) { | 791 | change_nexthops(fi) { |
801 | if ((err = fib_check_nh(r, fi, nh)) != 0) | 792 | if ((err = fib_check_nh(cfg, fi, nh)) != 0) |
802 | goto failure; | 793 | goto failure; |
803 | } endfor_nexthops(fi) | 794 | } endfor_nexthops(fi) |
804 | } | 795 | } |
805 | 796 | ||
806 | if (fi->fib_prefsrc) { | 797 | if (fi->fib_prefsrc) { |
807 | if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || | 798 | if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || |
808 | memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) | 799 | fi->fib_prefsrc != cfg->fc_dst) |
809 | if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) | 800 | if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) |
810 | goto err_inval; | 801 | goto err_inval; |
811 | } | 802 | } |
@@ -846,12 +837,12 @@ err_inval: | |||
846 | err = -EINVAL; | 837 | err = -EINVAL; |
847 | 838 | ||
848 | failure: | 839 | failure: |
849 | *errp = err; | ||
850 | if (fi) { | 840 | if (fi) { |
851 | fi->fib_dead = 1; | 841 | fi->fib_dead = 1; |
852 | free_fib_info(fi); | 842 | free_fib_info(fi); |
853 | } | 843 | } |
854 | return NULL; | 844 | |
845 | return ERR_PTR(err); | ||
855 | } | 846 | } |
856 | 847 | ||
857 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ | 848 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ |
@@ -1012,150 +1003,6 @@ rtattr_failure: | |||
1012 | return -1; | 1003 | return -1; |
1013 | } | 1004 | } |
1014 | 1005 | ||
1015 | #ifndef CONFIG_IP_NOSIOCRT | ||
1016 | |||
1017 | int | ||
1018 | fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, | ||
1019 | struct kern_rta *rta, struct rtentry *r) | ||
1020 | { | ||
1021 | int plen; | ||
1022 | u32 *ptr; | ||
1023 | |||
1024 | memset(rtm, 0, sizeof(*rtm)); | ||
1025 | memset(rta, 0, sizeof(*rta)); | ||
1026 | |||
1027 | if (r->rt_dst.sa_family != AF_INET) | ||
1028 | return -EAFNOSUPPORT; | ||
1029 | |||
1030 | /* Check mask for validity: | ||
1031 | a) it must be contiguous. | ||
1032 | b) destination must have all host bits clear. | ||
1033 | c) if application forgot to set correct family (AF_INET), | ||
1034 | reject request unless it is absolutely clear i.e. | ||
1035 | both family and mask are zero. | ||
1036 | */ | ||
1037 | plen = 32; | ||
1038 | ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr; | ||
1039 | if (!(r->rt_flags&RTF_HOST)) { | ||
1040 | u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr; | ||
1041 | if (r->rt_genmask.sa_family != AF_INET) { | ||
1042 | if (mask || r->rt_genmask.sa_family) | ||
1043 | return -EAFNOSUPPORT; | ||
1044 | } | ||
1045 | if (bad_mask(mask, *ptr)) | ||
1046 | return -EINVAL; | ||
1047 | plen = inet_mask_len(mask); | ||
1048 | } | ||
1049 | |||
1050 | nl->nlmsg_flags = NLM_F_REQUEST; | ||
1051 | nl->nlmsg_pid = 0; | ||
1052 | nl->nlmsg_seq = 0; | ||
1053 | nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm)); | ||
1054 | if (cmd == SIOCDELRT) { | ||
1055 | nl->nlmsg_type = RTM_DELROUTE; | ||
1056 | nl->nlmsg_flags = 0; | ||
1057 | } else { | ||
1058 | nl->nlmsg_type = RTM_NEWROUTE; | ||
1059 | nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE; | ||
1060 | rtm->rtm_protocol = RTPROT_BOOT; | ||
1061 | } | ||
1062 | |||
1063 | rtm->rtm_dst_len = plen; | ||
1064 | rta->rta_dst = ptr; | ||
1065 | |||
1066 | if (r->rt_metric) { | ||
1067 | *(u32*)&r->rt_pad3 = r->rt_metric - 1; | ||
1068 | rta->rta_priority = (u32*)&r->rt_pad3; | ||
1069 | } | ||
1070 | if (r->rt_flags&RTF_REJECT) { | ||
1071 | rtm->rtm_scope = RT_SCOPE_HOST; | ||
1072 | rtm->rtm_type = RTN_UNREACHABLE; | ||
1073 | return 0; | ||
1074 | } | ||
1075 | rtm->rtm_scope = RT_SCOPE_NOWHERE; | ||
1076 | rtm->rtm_type = RTN_UNICAST; | ||
1077 | |||
1078 | if (r->rt_dev) { | ||
1079 | char *colon; | ||
1080 | struct net_device *dev; | ||
1081 | char devname[IFNAMSIZ]; | ||
1082 | |||
1083 | if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1)) | ||
1084 | return -EFAULT; | ||
1085 | devname[IFNAMSIZ-1] = 0; | ||
1086 | colon = strchr(devname, ':'); | ||
1087 | if (colon) | ||
1088 | *colon = 0; | ||
1089 | dev = __dev_get_by_name(devname); | ||
1090 | if (!dev) | ||
1091 | return -ENODEV; | ||
1092 | rta->rta_oif = &dev->ifindex; | ||
1093 | if (colon) { | ||
1094 | struct in_ifaddr *ifa; | ||
1095 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1096 | if (!in_dev) | ||
1097 | return -ENODEV; | ||
1098 | *colon = ':'; | ||
1099 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) | ||
1100 | if (strcmp(ifa->ifa_label, devname) == 0) | ||
1101 | break; | ||
1102 | if (ifa == NULL) | ||
1103 | return -ENODEV; | ||
1104 | rta->rta_prefsrc = &ifa->ifa_local; | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; | ||
1109 | if (r->rt_gateway.sa_family == AF_INET && *ptr) { | ||
1110 | rta->rta_gw = ptr; | ||
1111 | if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST) | ||
1112 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; | ||
1113 | } | ||
1114 | |||
1115 | if (cmd == SIOCDELRT) | ||
1116 | return 0; | ||
1117 | |||
1118 | if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL) | ||
1119 | return -EINVAL; | ||
1120 | |||
1121 | if (rtm->rtm_scope == RT_SCOPE_NOWHERE) | ||
1122 | rtm->rtm_scope = RT_SCOPE_LINK; | ||
1123 | |||
1124 | if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) { | ||
1125 | struct rtattr *rec; | ||
1126 | struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL); | ||
1127 | if (mx == NULL) | ||
1128 | return -ENOMEM; | ||
1129 | rta->rta_mx = mx; | ||
1130 | mx->rta_type = RTA_METRICS; | ||
1131 | mx->rta_len = RTA_LENGTH(0); | ||
1132 | if (r->rt_flags&RTF_MTU) { | ||
1133 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1134 | rec->rta_type = RTAX_ADVMSS; | ||
1135 | rec->rta_len = RTA_LENGTH(4); | ||
1136 | mx->rta_len += RTA_LENGTH(4); | ||
1137 | *(u32*)RTA_DATA(rec) = r->rt_mtu - 40; | ||
1138 | } | ||
1139 | if (r->rt_flags&RTF_WINDOW) { | ||
1140 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1141 | rec->rta_type = RTAX_WINDOW; | ||
1142 | rec->rta_len = RTA_LENGTH(4); | ||
1143 | mx->rta_len += RTA_LENGTH(4); | ||
1144 | *(u32*)RTA_DATA(rec) = r->rt_window; | ||
1145 | } | ||
1146 | if (r->rt_flags&RTF_IRTT) { | ||
1147 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1148 | rec->rta_type = RTAX_RTT; | ||
1149 | rec->rta_len = RTA_LENGTH(4); | ||
1150 | mx->rta_len += RTA_LENGTH(4); | ||
1151 | *(u32*)RTA_DATA(rec) = r->rt_irtt<<3; | ||
1152 | } | ||
1153 | } | ||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | #endif | ||
1158 | |||
1159 | /* | 1006 | /* |
1160 | Update FIB if: | 1007 | Update FIB if: |
1161 | - local address disappeared -> we must delete all the entries | 1008 | - local address disappeared -> we must delete all the entries |