aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-17 21:14:52 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:55:04 -0400
commit4e902c57417c4c285b98ba2722468d1c3ed83d1b (patch)
tree83251829a4bc9628a3543e5f70e7b11090fe22d9 /net/ipv4/fib_semantics.c
parentab32ea5d8a760e7dd4339634e95d7be24ee5b842 (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.c385
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
275void rtmsg_fib(int event, u32 key, struct fib_alias *fa, 276void 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);
297errout: 298errout:
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
345static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type) 346static 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
355static int
356fib_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
371static int 359static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
372fib_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
397int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, 392int 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
491static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh) 490static 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
649struct fib_info * 654struct fib_info *fib_create_info(struct fib_config *cfg)
650fib_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
848failure: 839failure:
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
1017int
1018fib_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