diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-22 03:01:08 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:12 -0400 |
commit | 86872cb57925c46a6499887d77afb880a892c0ec (patch) | |
tree | bc0442efb85226adac5c7ae43e632639dd1b6899 | |
parent | 40e22e8f3d4d4f1ff68fb03683f007c53ee8b348 (diff) |
[IPv6] route: FIB6 configuration using struct fib6_config
Replaces the struct in6_rtmsg based interface orignating from
the ioctl interface with a struct fib6_config based on. Allows
changing the interface without breaking the ioctl interface
and avoids passing on tons of parameters.
The recently introduced struct nl_info is used to pass on
netlink authorship information for notifications.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip6_fib.h | 38 | ||||
-rw-r--r-- | include/net/ip6_route.h | 6 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 65 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 19 | ||||
-rw-r--r-- | net/ipv6/route.c | 331 |
5 files changed, 259 insertions, 200 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 69c444209781..9610b887ffb5 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -16,14 +16,35 @@ | |||
16 | #ifdef __KERNEL__ | 16 | #ifdef __KERNEL__ |
17 | 17 | ||
18 | #include <linux/ipv6_route.h> | 18 | #include <linux/ipv6_route.h> |
19 | |||
20 | #include <net/dst.h> | ||
21 | #include <net/flow.h> | ||
22 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
23 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <net/dst.h> | ||
22 | #include <net/flow.h> | ||
23 | #include <net/netlink.h> | ||
24 | 24 | ||
25 | struct rt6_info; | 25 | struct rt6_info; |
26 | 26 | ||
27 | struct fib6_config | ||
28 | { | ||
29 | u32 fc_table; | ||
30 | u32 fc_metric; | ||
31 | int fc_dst_len; | ||
32 | int fc_src_len; | ||
33 | int fc_ifindex; | ||
34 | u32 fc_flags; | ||
35 | u32 fc_protocol; | ||
36 | |||
37 | struct in6_addr fc_dst; | ||
38 | struct in6_addr fc_src; | ||
39 | struct in6_addr fc_gateway; | ||
40 | |||
41 | unsigned long fc_expires; | ||
42 | struct nlattr *fc_mx; | ||
43 | int fc_mx_len; | ||
44 | |||
45 | struct nl_info fc_nlinfo; | ||
46 | }; | ||
47 | |||
27 | struct fib6_node | 48 | struct fib6_node |
28 | { | 49 | { |
29 | struct fib6_node *parent; | 50 | struct fib6_node *parent; |
@@ -175,18 +196,13 @@ extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), | |||
175 | 196 | ||
176 | extern int fib6_add(struct fib6_node *root, | 197 | extern int fib6_add(struct fib6_node *root, |
177 | struct rt6_info *rt, | 198 | struct rt6_info *rt, |
178 | struct nlmsghdr *nlh, | 199 | struct nl_info *info); |
179 | void *rtattr, | ||
180 | struct netlink_skb_parms *req); | ||
181 | 200 | ||
182 | extern int fib6_del(struct rt6_info *rt, | 201 | extern int fib6_del(struct rt6_info *rt, |
183 | struct nlmsghdr *nlh, | 202 | struct nl_info *info); |
184 | void *rtattr, | ||
185 | struct netlink_skb_parms *req); | ||
186 | 203 | ||
187 | extern void inet6_rt_notify(int event, struct rt6_info *rt, | 204 | extern void inet6_rt_notify(int event, struct rt6_info *rt, |
188 | struct nlmsghdr *nlh, | 205 | struct nl_info *info); |
189 | struct netlink_skb_parms *req); | ||
190 | 206 | ||
191 | extern void fib6_run_gc(unsigned long dummy); | 207 | extern void fib6_run_gc(unsigned long dummy); |
192 | 208 | ||
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 172c4761e2bf..3f170f667c7b 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h | |||
@@ -60,11 +60,7 @@ extern void ip6_route_cleanup(void); | |||
60 | 60 | ||
61 | extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); | 61 | extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); |
62 | 62 | ||
63 | extern int ip6_route_add(struct in6_rtmsg *rtmsg, | 63 | extern int ip6_route_add(struct fib6_config *cfg); |
64 | struct nlmsghdr *, | ||
65 | void *rtattr, | ||
66 | struct netlink_skb_parms *req, | ||
67 | u32 table_id); | ||
68 | extern int ip6_ins_rt(struct rt6_info *); | 64 | extern int ip6_ins_rt(struct rt6_info *); |
69 | extern int ip6_del_rt(struct rt6_info *); | 65 | extern int ip6_del_rt(struct rt6_info *); |
70 | 66 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index aafba9ea9cb6..fc9cff3426c4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1509,59 +1509,56 @@ static void | |||
1509 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, | 1509 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, |
1510 | unsigned long expires, u32 flags) | 1510 | unsigned long expires, u32 flags) |
1511 | { | 1511 | { |
1512 | struct in6_rtmsg rtmsg; | 1512 | struct fib6_config cfg = { |
1513 | .fc_table = RT6_TABLE_PREFIX, | ||
1514 | .fc_metric = IP6_RT_PRIO_ADDRCONF, | ||
1515 | .fc_ifindex = dev->ifindex, | ||
1516 | .fc_expires = expires, | ||
1517 | .fc_dst_len = plen, | ||
1518 | .fc_flags = RTF_UP | flags, | ||
1519 | }; | ||
1513 | 1520 | ||
1514 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1521 | ipv6_addr_copy(&cfg.fc_dst, pfx); |
1515 | ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx); | ||
1516 | rtmsg.rtmsg_dst_len = plen; | ||
1517 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
1518 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1519 | rtmsg.rtmsg_info = expires; | ||
1520 | rtmsg.rtmsg_flags = RTF_UP|flags; | ||
1521 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1522 | 1522 | ||
1523 | /* Prevent useless cloning on PtP SIT. | 1523 | /* Prevent useless cloning on PtP SIT. |
1524 | This thing is done here expecting that the whole | 1524 | This thing is done here expecting that the whole |
1525 | class of non-broadcast devices need not cloning. | 1525 | class of non-broadcast devices need not cloning. |
1526 | */ | 1526 | */ |
1527 | if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) | 1527 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
1528 | rtmsg.rtmsg_flags |= RTF_NONEXTHOP; | 1528 | cfg.fc_flags |= RTF_NONEXTHOP; |
1529 | 1529 | ||
1530 | ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_PREFIX); | 1530 | ip6_route_add(&cfg); |
1531 | } | 1531 | } |
1532 | 1532 | ||
1533 | /* Create "default" multicast route to the interface */ | 1533 | /* Create "default" multicast route to the interface */ |
1534 | 1534 | ||
1535 | static void addrconf_add_mroute(struct net_device *dev) | 1535 | static void addrconf_add_mroute(struct net_device *dev) |
1536 | { | 1536 | { |
1537 | struct in6_rtmsg rtmsg; | 1537 | struct fib6_config cfg = { |
1538 | 1538 | .fc_table = RT6_TABLE_LOCAL, | |
1539 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1539 | .fc_metric = IP6_RT_PRIO_ADDRCONF, |
1540 | ipv6_addr_set(&rtmsg.rtmsg_dst, | 1540 | .fc_ifindex = dev->ifindex, |
1541 | htonl(0xFF000000), 0, 0, 0); | 1541 | .fc_dst_len = 8, |
1542 | rtmsg.rtmsg_dst_len = 8; | 1542 | .fc_flags = RTF_UP, |
1543 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | 1543 | }; |
1544 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1544 | |
1545 | rtmsg.rtmsg_flags = RTF_UP; | 1545 | ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); |
1546 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1546 | |
1547 | ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_LOCAL); | 1547 | ip6_route_add(&cfg); |
1548 | } | 1548 | } |
1549 | 1549 | ||
1550 | static void sit_route_add(struct net_device *dev) | 1550 | static void sit_route_add(struct net_device *dev) |
1551 | { | 1551 | { |
1552 | struct in6_rtmsg rtmsg; | 1552 | struct fib6_config cfg = { |
1553 | 1553 | .fc_table = RT6_TABLE_MAIN, | |
1554 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1554 | .fc_metric = IP6_RT_PRIO_ADDRCONF, |
1555 | 1555 | .fc_ifindex = dev->ifindex, | |
1556 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1556 | .fc_dst_len = 96, |
1557 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | 1557 | .fc_flags = RTF_UP | RTF_NONEXTHOP, |
1558 | }; | ||
1558 | 1559 | ||
1559 | /* prefix length - 96 bits "::d.d.d.d" */ | 1560 | /* prefix length - 96 bits "::d.d.d.d" */ |
1560 | rtmsg.rtmsg_dst_len = 96; | 1561 | ip6_route_add(&cfg); |
1561 | rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; | ||
1562 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1563 | |||
1564 | ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_MAIN); | ||
1565 | } | 1562 | } |
1566 | 1563 | ||
1567 | static void addrconf_add_lroute(struct net_device *dev) | 1564 | static void addrconf_add_lroute(struct net_device *dev) |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index be36f4acda94..667b1b1ea25d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -610,7 +610,7 @@ insert_above: | |||
610 | */ | 610 | */ |
611 | 611 | ||
612 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | 612 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, |
613 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) | 613 | struct nl_info *info) |
614 | { | 614 | { |
615 | struct rt6_info *iter = NULL; | 615 | struct rt6_info *iter = NULL; |
616 | struct rt6_info **ins; | 616 | struct rt6_info **ins; |
@@ -665,7 +665,7 @@ out: | |||
665 | *ins = rt; | 665 | *ins = rt; |
666 | rt->rt6i_node = fn; | 666 | rt->rt6i_node = fn; |
667 | atomic_inc(&rt->rt6i_ref); | 667 | atomic_inc(&rt->rt6i_ref); |
668 | inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); | 668 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
669 | rt6_stats.fib_rt_entries++; | 669 | rt6_stats.fib_rt_entries++; |
670 | 670 | ||
671 | if ((fn->fn_flags & RTN_RTINFO) == 0) { | 671 | if ((fn->fn_flags & RTN_RTINFO) == 0) { |
@@ -695,8 +695,7 @@ void fib6_force_start_gc(void) | |||
695 | * with source addr info in sub-trees | 695 | * with source addr info in sub-trees |
696 | */ | 696 | */ |
697 | 697 | ||
698 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, | 698 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) |
699 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | ||
700 | { | 699 | { |
701 | struct fib6_node *fn; | 700 | struct fib6_node *fn; |
702 | int err = -ENOMEM; | 701 | int err = -ENOMEM; |
@@ -769,7 +768,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
769 | } | 768 | } |
770 | #endif | 769 | #endif |
771 | 770 | ||
772 | err = fib6_add_rt2node(fn, rt, nlh, req); | 771 | err = fib6_add_rt2node(fn, rt, info); |
773 | 772 | ||
774 | if (err == 0) { | 773 | if (err == 0) { |
775 | fib6_start_gc(rt); | 774 | fib6_start_gc(rt); |
@@ -1076,7 +1075,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
1076 | } | 1075 | } |
1077 | 1076 | ||
1078 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | 1077 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, |
1079 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1078 | struct nl_info *info) |
1080 | { | 1079 | { |
1081 | struct fib6_walker_t *w; | 1080 | struct fib6_walker_t *w; |
1082 | struct rt6_info *rt = *rtp; | 1081 | struct rt6_info *rt = *rtp; |
@@ -1132,11 +1131,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
1132 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); | 1131 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); |
1133 | } | 1132 | } |
1134 | 1133 | ||
1135 | inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); | 1134 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
1136 | rt6_release(rt); | 1135 | rt6_release(rt); |
1137 | } | 1136 | } |
1138 | 1137 | ||
1139 | int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1138 | int fib6_del(struct rt6_info *rt, struct nl_info *info) |
1140 | { | 1139 | { |
1141 | struct fib6_node *fn = rt->rt6i_node; | 1140 | struct fib6_node *fn = rt->rt6i_node; |
1142 | struct rt6_info **rtp; | 1141 | struct rt6_info **rtp; |
@@ -1161,7 +1160,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
1161 | 1160 | ||
1162 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { | 1161 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { |
1163 | if (*rtp == rt) { | 1162 | if (*rtp == rt) { |
1164 | fib6_del_route(fn, rtp, nlh, _rtattr, req); | 1163 | fib6_del_route(fn, rtp, info); |
1165 | return 0; | 1164 | return 0; |
1166 | } | 1165 | } |
1167 | } | 1166 | } |
@@ -1290,7 +1289,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1290 | res = c->func(rt, c->arg); | 1289 | res = c->func(rt, c->arg); |
1291 | if (res < 0) { | 1290 | if (res < 0) { |
1292 | w->leaf = rt; | 1291 | w->leaf = rt; |
1293 | res = fib6_del(rt, NULL, NULL, NULL); | 1292 | res = fib6_del(rt, NULL); |
1294 | if (res) { | 1293 | if (res) { |
1295 | #if RT6_DEBUG >= 2 | 1294 | #if RT6_DEBUG >= 2 |
1296 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); | 1295 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 9ec348a72a95..7bcffa6ddba3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -546,15 +546,14 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | |||
546 | be destroyed. | 546 | be destroyed. |
547 | */ | 547 | */ |
548 | 548 | ||
549 | static int __ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | 549 | static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) |
550 | void *_rtattr, struct netlink_skb_parms *req) | ||
551 | { | 550 | { |
552 | int err; | 551 | int err; |
553 | struct fib6_table *table; | 552 | struct fib6_table *table; |
554 | 553 | ||
555 | table = rt->rt6i_table; | 554 | table = rt->rt6i_table; |
556 | write_lock_bh(&table->tb6_lock); | 555 | write_lock_bh(&table->tb6_lock); |
557 | err = fib6_add(&table->tb6_root, rt, nlh, _rtattr, req); | 556 | err = fib6_add(&table->tb6_root, rt, info); |
558 | write_unlock_bh(&table->tb6_lock); | 557 | write_unlock_bh(&table->tb6_lock); |
559 | 558 | ||
560 | return err; | 559 | return err; |
@@ -562,7 +561,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
562 | 561 | ||
563 | int ip6_ins_rt(struct rt6_info *rt) | 562 | int ip6_ins_rt(struct rt6_info *rt) |
564 | { | 563 | { |
565 | return __ip6_ins_rt(rt, NULL, NULL, NULL); | 564 | return __ip6_ins_rt(rt, NULL); |
566 | } | 565 | } |
567 | 566 | ||
568 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 567 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
@@ -1014,30 +1013,24 @@ int ipv6_get_hoplimit(struct net_device *dev) | |||
1014 | * | 1013 | * |
1015 | */ | 1014 | */ |
1016 | 1015 | ||
1017 | int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 1016 | int ip6_route_add(struct fib6_config *cfg) |
1018 | void *_rtattr, struct netlink_skb_parms *req, | ||
1019 | u32 table_id) | ||
1020 | { | 1017 | { |
1021 | int err; | 1018 | int err; |
1022 | struct rtmsg *r; | ||
1023 | struct rtattr **rta; | ||
1024 | struct rt6_info *rt = NULL; | 1019 | struct rt6_info *rt = NULL; |
1025 | struct net_device *dev = NULL; | 1020 | struct net_device *dev = NULL; |
1026 | struct inet6_dev *idev = NULL; | 1021 | struct inet6_dev *idev = NULL; |
1027 | struct fib6_table *table; | 1022 | struct fib6_table *table; |
1028 | int addr_type; | 1023 | int addr_type; |
1029 | 1024 | ||
1030 | rta = (struct rtattr **) _rtattr; | 1025 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
1031 | |||
1032 | if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128) | ||
1033 | return -EINVAL; | 1026 | return -EINVAL; |
1034 | #ifndef CONFIG_IPV6_SUBTREES | 1027 | #ifndef CONFIG_IPV6_SUBTREES |
1035 | if (rtmsg->rtmsg_src_len) | 1028 | if (cfg->fc_src_len) |
1036 | return -EINVAL; | 1029 | return -EINVAL; |
1037 | #endif | 1030 | #endif |
1038 | if (rtmsg->rtmsg_ifindex) { | 1031 | if (cfg->fc_ifindex) { |
1039 | err = -ENODEV; | 1032 | err = -ENODEV; |
1040 | dev = dev_get_by_index(rtmsg->rtmsg_ifindex); | 1033 | dev = dev_get_by_index(cfg->fc_ifindex); |
1041 | if (!dev) | 1034 | if (!dev) |
1042 | goto out; | 1035 | goto out; |
1043 | idev = in6_dev_get(dev); | 1036 | idev = in6_dev_get(dev); |
@@ -1045,10 +1038,10 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1045 | goto out; | 1038 | goto out; |
1046 | } | 1039 | } |
1047 | 1040 | ||
1048 | if (rtmsg->rtmsg_metric == 0) | 1041 | if (cfg->fc_metric == 0) |
1049 | rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; | 1042 | cfg->fc_metric = IP6_RT_PRIO_USER; |
1050 | 1043 | ||
1051 | table = fib6_new_table(table_id); | 1044 | table = fib6_new_table(cfg->fc_table); |
1052 | if (table == NULL) { | 1045 | if (table == NULL) { |
1053 | err = -ENOBUFS; | 1046 | err = -ENOBUFS; |
1054 | goto out; | 1047 | goto out; |
@@ -1062,14 +1055,13 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1062 | } | 1055 | } |
1063 | 1056 | ||
1064 | rt->u.dst.obsolete = -1; | 1057 | rt->u.dst.obsolete = -1; |
1065 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(rtmsg->rtmsg_info); | 1058 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires); |
1066 | if (nlh && (r = NLMSG_DATA(nlh))) { | 1059 | |
1067 | rt->rt6i_protocol = r->rtm_protocol; | 1060 | if (cfg->fc_protocol == RTPROT_UNSPEC) |
1068 | } else { | 1061 | cfg->fc_protocol = RTPROT_BOOT; |
1069 | rt->rt6i_protocol = RTPROT_BOOT; | 1062 | rt->rt6i_protocol = cfg->fc_protocol; |
1070 | } | ||
1071 | 1063 | ||
1072 | addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst); | 1064 | addr_type = ipv6_addr_type(&cfg->fc_dst); |
1073 | 1065 | ||
1074 | if (addr_type & IPV6_ADDR_MULTICAST) | 1066 | if (addr_type & IPV6_ADDR_MULTICAST) |
1075 | rt->u.dst.input = ip6_mc_input; | 1067 | rt->u.dst.input = ip6_mc_input; |
@@ -1078,24 +1070,22 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1078 | 1070 | ||
1079 | rt->u.dst.output = ip6_output; | 1071 | rt->u.dst.output = ip6_output; |
1080 | 1072 | ||
1081 | ipv6_addr_prefix(&rt->rt6i_dst.addr, | 1073 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
1082 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len); | 1074 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
1083 | rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len; | ||
1084 | if (rt->rt6i_dst.plen == 128) | 1075 | if (rt->rt6i_dst.plen == 128) |
1085 | rt->u.dst.flags = DST_HOST; | 1076 | rt->u.dst.flags = DST_HOST; |
1086 | 1077 | ||
1087 | #ifdef CONFIG_IPV6_SUBTREES | 1078 | #ifdef CONFIG_IPV6_SUBTREES |
1088 | ipv6_addr_prefix(&rt->rt6i_src.addr, | 1079 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
1089 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1080 | rt->rt6i_src.plen = cfg->fc_src_len; |
1090 | rt->rt6i_src.plen = rtmsg->rtmsg_src_len; | ||
1091 | #endif | 1081 | #endif |
1092 | 1082 | ||
1093 | rt->rt6i_metric = rtmsg->rtmsg_metric; | 1083 | rt->rt6i_metric = cfg->fc_metric; |
1094 | 1084 | ||
1095 | /* We cannot add true routes via loopback here, | 1085 | /* We cannot add true routes via loopback here, |
1096 | they would result in kernel looping; promote them to reject routes | 1086 | they would result in kernel looping; promote them to reject routes |
1097 | */ | 1087 | */ |
1098 | if ((rtmsg->rtmsg_flags&RTF_REJECT) || | 1088 | if ((cfg->fc_flags & RTF_REJECT) || |
1099 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1089 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { |
1100 | /* hold loopback dev/idev if we haven't done so. */ | 1090 | /* hold loopback dev/idev if we haven't done so. */ |
1101 | if (dev != &loopback_dev) { | 1091 | if (dev != &loopback_dev) { |
@@ -1118,12 +1108,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1118 | goto install_route; | 1108 | goto install_route; |
1119 | } | 1109 | } |
1120 | 1110 | ||
1121 | if (rtmsg->rtmsg_flags & RTF_GATEWAY) { | 1111 | if (cfg->fc_flags & RTF_GATEWAY) { |
1122 | struct in6_addr *gw_addr; | 1112 | struct in6_addr *gw_addr; |
1123 | int gwa_type; | 1113 | int gwa_type; |
1124 | 1114 | ||
1125 | gw_addr = &rtmsg->rtmsg_gateway; | 1115 | gw_addr = &cfg->fc_gateway; |
1126 | ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway); | 1116 | ipv6_addr_copy(&rt->rt6i_gateway, gw_addr); |
1127 | gwa_type = ipv6_addr_type(gw_addr); | 1117 | gwa_type = ipv6_addr_type(gw_addr); |
1128 | 1118 | ||
1129 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { | 1119 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { |
@@ -1140,7 +1130,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1140 | if (!(gwa_type&IPV6_ADDR_UNICAST)) | 1130 | if (!(gwa_type&IPV6_ADDR_UNICAST)) |
1141 | goto out; | 1131 | goto out; |
1142 | 1132 | ||
1143 | grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1); | 1133 | grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1); |
1144 | 1134 | ||
1145 | err = -EHOSTUNREACH; | 1135 | err = -EHOSTUNREACH; |
1146 | if (grt == NULL) | 1136 | if (grt == NULL) |
@@ -1172,7 +1162,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1172 | if (dev == NULL) | 1162 | if (dev == NULL) |
1173 | goto out; | 1163 | goto out; |
1174 | 1164 | ||
1175 | if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) { | 1165 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1176 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1166 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1177 | if (IS_ERR(rt->rt6i_nexthop)) { | 1167 | if (IS_ERR(rt->rt6i_nexthop)) { |
1178 | err = PTR_ERR(rt->rt6i_nexthop); | 1168 | err = PTR_ERR(rt->rt6i_nexthop); |
@@ -1181,24 +1171,24 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1181 | } | 1171 | } |
1182 | } | 1172 | } |
1183 | 1173 | ||
1184 | rt->rt6i_flags = rtmsg->rtmsg_flags; | 1174 | rt->rt6i_flags = cfg->fc_flags; |
1185 | 1175 | ||
1186 | install_route: | 1176 | install_route: |
1187 | if (rta && rta[RTA_METRICS-1]) { | 1177 | if (cfg->fc_mx) { |
1188 | int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); | 1178 | struct nlattr *nla; |
1189 | struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]); | 1179 | int remaining; |
1190 | 1180 | ||
1191 | while (RTA_OK(attr, attrlen)) { | 1181 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
1192 | unsigned flavor = attr->rta_type; | 1182 | int type = nla->nla_type; |
1193 | if (flavor) { | 1183 | |
1194 | if (flavor > RTAX_MAX) { | 1184 | if (type) { |
1185 | if (type > RTAX_MAX) { | ||
1195 | err = -EINVAL; | 1186 | err = -EINVAL; |
1196 | goto out; | 1187 | goto out; |
1197 | } | 1188 | } |
1198 | rt->u.dst.metrics[flavor-1] = | 1189 | |
1199 | *(u32 *)RTA_DATA(attr); | 1190 | rt->u.dst.metrics[type - 1] = nla_get_u32(nla); |
1200 | } | 1191 | } |
1201 | attr = RTA_NEXT(attr, attrlen); | ||
1202 | } | 1192 | } |
1203 | } | 1193 | } |
1204 | 1194 | ||
@@ -1211,7 +1201,7 @@ install_route: | |||
1211 | rt->u.dst.dev = dev; | 1201 | rt->u.dst.dev = dev; |
1212 | rt->rt6i_idev = idev; | 1202 | rt->rt6i_idev = idev; |
1213 | rt->rt6i_table = table; | 1203 | rt->rt6i_table = table; |
1214 | return __ip6_ins_rt(rt, nlh, _rtattr, req); | 1204 | return __ip6_ins_rt(rt, &cfg->fc_nlinfo); |
1215 | 1205 | ||
1216 | out: | 1206 | out: |
1217 | if (dev) | 1207 | if (dev) |
@@ -1223,8 +1213,7 @@ out: | |||
1223 | return err; | 1213 | return err; |
1224 | } | 1214 | } |
1225 | 1215 | ||
1226 | static int __ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | 1216 | static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) |
1227 | void *_rtattr, struct netlink_skb_parms *req) | ||
1228 | { | 1217 | { |
1229 | int err; | 1218 | int err; |
1230 | struct fib6_table *table; | 1219 | struct fib6_table *table; |
@@ -1235,7 +1224,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
1235 | table = rt->rt6i_table; | 1224 | table = rt->rt6i_table; |
1236 | write_lock_bh(&table->tb6_lock); | 1225 | write_lock_bh(&table->tb6_lock); |
1237 | 1226 | ||
1238 | err = fib6_del(rt, nlh, _rtattr, req); | 1227 | err = fib6_del(rt, info); |
1239 | dst_release(&rt->u.dst); | 1228 | dst_release(&rt->u.dst); |
1240 | 1229 | ||
1241 | write_unlock_bh(&table->tb6_lock); | 1230 | write_unlock_bh(&table->tb6_lock); |
@@ -1245,44 +1234,41 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
1245 | 1234 | ||
1246 | int ip6_del_rt(struct rt6_info *rt) | 1235 | int ip6_del_rt(struct rt6_info *rt) |
1247 | { | 1236 | { |
1248 | return __ip6_del_rt(rt, NULL, NULL, NULL); | 1237 | return __ip6_del_rt(rt, NULL); |
1249 | } | 1238 | } |
1250 | 1239 | ||
1251 | static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 1240 | static int ip6_route_del(struct fib6_config *cfg) |
1252 | void *_rtattr, struct netlink_skb_parms *req, | ||
1253 | u32 table_id) | ||
1254 | { | 1241 | { |
1255 | struct fib6_table *table; | 1242 | struct fib6_table *table; |
1256 | struct fib6_node *fn; | 1243 | struct fib6_node *fn; |
1257 | struct rt6_info *rt; | 1244 | struct rt6_info *rt; |
1258 | int err = -ESRCH; | 1245 | int err = -ESRCH; |
1259 | 1246 | ||
1260 | table = fib6_get_table(table_id); | 1247 | table = fib6_get_table(cfg->fc_table); |
1261 | if (table == NULL) | 1248 | if (table == NULL) |
1262 | return err; | 1249 | return err; |
1263 | 1250 | ||
1264 | read_lock_bh(&table->tb6_lock); | 1251 | read_lock_bh(&table->tb6_lock); |
1265 | 1252 | ||
1266 | fn = fib6_locate(&table->tb6_root, | 1253 | fn = fib6_locate(&table->tb6_root, |
1267 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, | 1254 | &cfg->fc_dst, cfg->fc_dst_len, |
1268 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1255 | &cfg->fc_src, cfg->fc_src_len); |
1269 | 1256 | ||
1270 | if (fn) { | 1257 | if (fn) { |
1271 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1258 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1272 | if (rtmsg->rtmsg_ifindex && | 1259 | if (cfg->fc_ifindex && |
1273 | (rt->rt6i_dev == NULL || | 1260 | (rt->rt6i_dev == NULL || |
1274 | rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex)) | 1261 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) |
1275 | continue; | 1262 | continue; |
1276 | if (rtmsg->rtmsg_flags&RTF_GATEWAY && | 1263 | if (cfg->fc_flags & RTF_GATEWAY && |
1277 | !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway)) | 1264 | !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) |
1278 | continue; | 1265 | continue; |
1279 | if (rtmsg->rtmsg_metric && | 1266 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
1280 | rtmsg->rtmsg_metric != rt->rt6i_metric) | ||
1281 | continue; | 1267 | continue; |
1282 | dst_hold(&rt->u.dst); | 1268 | dst_hold(&rt->u.dst); |
1283 | read_unlock_bh(&table->tb6_lock); | 1269 | read_unlock_bh(&table->tb6_lock); |
1284 | 1270 | ||
1285 | return __ip6_del_rt(rt, nlh, _rtattr, req); | 1271 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); |
1286 | } | 1272 | } |
1287 | } | 1273 | } |
1288 | read_unlock_bh(&table->tb6_lock); | 1274 | read_unlock_bh(&table->tb6_lock); |
@@ -1565,21 +1551,23 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
1565 | struct in6_addr *gwaddr, int ifindex, | 1551 | struct in6_addr *gwaddr, int ifindex, |
1566 | unsigned pref) | 1552 | unsigned pref) |
1567 | { | 1553 | { |
1568 | struct in6_rtmsg rtmsg; | 1554 | struct fib6_config cfg = { |
1555 | .fc_table = RT6_TABLE_INFO, | ||
1556 | .fc_metric = 1024, | ||
1557 | .fc_ifindex = ifindex, | ||
1558 | .fc_dst_len = prefixlen, | ||
1559 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | | ||
1560 | RTF_UP | RTF_PREF(pref), | ||
1561 | }; | ||
1562 | |||
1563 | ipv6_addr_copy(&cfg.fc_dst, prefix); | ||
1564 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); | ||
1569 | 1565 | ||
1570 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
1571 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1572 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
1573 | rtmsg.rtmsg_dst_len = prefixlen; | ||
1574 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1575 | rtmsg.rtmsg_metric = 1024; | ||
1576 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
1577 | /* We should treat it as a default route if prefix length is 0. */ | 1566 | /* We should treat it as a default route if prefix length is 0. */ |
1578 | if (!prefixlen) | 1567 | if (!prefixlen) |
1579 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | 1568 | cfg.fc_flags |= RTF_DEFAULT; |
1580 | rtmsg.rtmsg_ifindex = ifindex; | ||
1581 | 1569 | ||
1582 | ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_INFO); | 1570 | ip6_route_add(&cfg); |
1583 | 1571 | ||
1584 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | 1572 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); |
1585 | } | 1573 | } |
@@ -1611,18 +1599,18 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
1611 | struct net_device *dev, | 1599 | struct net_device *dev, |
1612 | unsigned int pref) | 1600 | unsigned int pref) |
1613 | { | 1601 | { |
1614 | struct in6_rtmsg rtmsg; | 1602 | struct fib6_config cfg = { |
1603 | .fc_table = RT6_TABLE_DFLT, | ||
1604 | .fc_metric = 1024, | ||
1605 | .fc_ifindex = dev->ifindex, | ||
1606 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | | ||
1607 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), | ||
1608 | }; | ||
1615 | 1609 | ||
1616 | memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); | 1610 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); |
1617 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1618 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1619 | rtmsg.rtmsg_metric = 1024; | ||
1620 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | | ||
1621 | RTF_PREF(pref); | ||
1622 | 1611 | ||
1623 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1612 | ip6_route_add(&cfg); |
1624 | 1613 | ||
1625 | ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_DFLT); | ||
1626 | return rt6_get_dflt_router(gwaddr, dev); | 1614 | return rt6_get_dflt_router(gwaddr, dev); |
1627 | } | 1615 | } |
1628 | 1616 | ||
@@ -1649,8 +1637,27 @@ restart: | |||
1649 | read_unlock_bh(&table->tb6_lock); | 1637 | read_unlock_bh(&table->tb6_lock); |
1650 | } | 1638 | } |
1651 | 1639 | ||
1640 | static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg, | ||
1641 | struct fib6_config *cfg) | ||
1642 | { | ||
1643 | memset(cfg, 0, sizeof(*cfg)); | ||
1644 | |||
1645 | cfg->fc_table = RT6_TABLE_MAIN; | ||
1646 | cfg->fc_ifindex = rtmsg->rtmsg_ifindex; | ||
1647 | cfg->fc_metric = rtmsg->rtmsg_metric; | ||
1648 | cfg->fc_expires = rtmsg->rtmsg_info; | ||
1649 | cfg->fc_dst_len = rtmsg->rtmsg_dst_len; | ||
1650 | cfg->fc_src_len = rtmsg->rtmsg_src_len; | ||
1651 | cfg->fc_flags = rtmsg->rtmsg_flags; | ||
1652 | |||
1653 | ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst); | ||
1654 | ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src); | ||
1655 | ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway); | ||
1656 | } | ||
1657 | |||
1652 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | 1658 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) |
1653 | { | 1659 | { |
1660 | struct fib6_config cfg; | ||
1654 | struct in6_rtmsg rtmsg; | 1661 | struct in6_rtmsg rtmsg; |
1655 | int err; | 1662 | int err; |
1656 | 1663 | ||
@@ -1663,16 +1670,16 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
1663 | sizeof(struct in6_rtmsg)); | 1670 | sizeof(struct in6_rtmsg)); |
1664 | if (err) | 1671 | if (err) |
1665 | return -EFAULT; | 1672 | return -EFAULT; |
1666 | 1673 | ||
1674 | rtmsg_to_fib6_config(&rtmsg, &cfg); | ||
1675 | |||
1667 | rtnl_lock(); | 1676 | rtnl_lock(); |
1668 | switch (cmd) { | 1677 | switch (cmd) { |
1669 | case SIOCADDRT: | 1678 | case SIOCADDRT: |
1670 | err = ip6_route_add(&rtmsg, NULL, NULL, NULL, | 1679 | err = ip6_route_add(&cfg); |
1671 | RT6_TABLE_MAIN); | ||
1672 | break; | 1680 | break; |
1673 | case SIOCDELRT: | 1681 | case SIOCDELRT: |
1674 | err = ip6_route_del(&rtmsg, NULL, NULL, NULL, | 1682 | err = ip6_route_del(&cfg); |
1675 | RT6_TABLE_MAIN); | ||
1676 | break; | 1683 | break; |
1677 | default: | 1684 | default: |
1678 | err = -EINVAL; | 1685 | err = -EINVAL; |
@@ -1823,66 +1830,104 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) | |||
1823 | fib6_clean_all(rt6_mtu_change_route, 0, &arg); | 1830 | fib6_clean_all(rt6_mtu_change_route, 0, &arg); |
1824 | } | 1831 | } |
1825 | 1832 | ||
1826 | static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, | 1833 | static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { |
1827 | struct in6_rtmsg *rtmsg) | 1834 | [RTA_GATEWAY] = { .minlen = sizeof(struct in6_addr) }, |
1835 | [RTA_OIF] = { .type = NLA_U32 }, | ||
1836 | [RTA_PRIORITY] = { .type = NLA_U32 }, | ||
1837 | [RTA_METRICS] = { .type = NLA_NESTED }, | ||
1838 | }; | ||
1839 | |||
1840 | static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
1841 | struct fib6_config *cfg) | ||
1828 | { | 1842 | { |
1829 | memset(rtmsg, 0, sizeof(*rtmsg)); | 1843 | struct rtmsg *rtm; |
1844 | struct nlattr *tb[RTA_MAX+1]; | ||
1845 | int err; | ||
1846 | |||
1847 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); | ||
1848 | if (err < 0) | ||
1849 | goto errout; | ||
1830 | 1850 | ||
1831 | rtmsg->rtmsg_dst_len = r->rtm_dst_len; | 1851 | err = -EINVAL; |
1832 | rtmsg->rtmsg_src_len = r->rtm_src_len; | 1852 | rtm = nlmsg_data(nlh); |
1833 | rtmsg->rtmsg_flags = RTF_UP; | 1853 | memset(cfg, 0, sizeof(*cfg)); |
1834 | if (r->rtm_type == RTN_UNREACHABLE) | ||
1835 | rtmsg->rtmsg_flags |= RTF_REJECT; | ||
1836 | 1854 | ||
1837 | if (rta[RTA_GATEWAY-1]) { | 1855 | cfg->fc_table = rtm->rtm_table; |
1838 | if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) | 1856 | cfg->fc_dst_len = rtm->rtm_dst_len; |
1839 | return -EINVAL; | 1857 | cfg->fc_src_len = rtm->rtm_src_len; |
1840 | memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16); | 1858 | cfg->fc_flags = RTF_UP; |
1841 | rtmsg->rtmsg_flags |= RTF_GATEWAY; | 1859 | cfg->fc_protocol = rtm->rtm_protocol; |
1842 | } | 1860 | |
1843 | if (rta[RTA_DST-1]) { | 1861 | if (rtm->rtm_type == RTN_UNREACHABLE) |
1844 | if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3)) | 1862 | cfg->fc_flags |= RTF_REJECT; |
1845 | return -EINVAL; | 1863 | |
1846 | memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3)); | 1864 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; |
1865 | cfg->fc_nlinfo.nlh = nlh; | ||
1866 | |||
1867 | if (tb[RTA_GATEWAY]) { | ||
1868 | nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16); | ||
1869 | cfg->fc_flags |= RTF_GATEWAY; | ||
1847 | } | 1870 | } |
1848 | if (rta[RTA_SRC-1]) { | 1871 | |
1849 | if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3)) | 1872 | if (tb[RTA_DST]) { |
1850 | return -EINVAL; | 1873 | int plen = (rtm->rtm_dst_len + 7) >> 3; |
1851 | memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3)); | 1874 | |
1875 | if (nla_len(tb[RTA_DST]) < plen) | ||
1876 | goto errout; | ||
1877 | |||
1878 | nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen); | ||
1852 | } | 1879 | } |
1853 | if (rta[RTA_OIF-1]) { | 1880 | |
1854 | if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int))) | 1881 | if (tb[RTA_SRC]) { |
1855 | return -EINVAL; | 1882 | int plen = (rtm->rtm_src_len + 7) >> 3; |
1856 | memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 1883 | |
1884 | if (nla_len(tb[RTA_SRC]) < plen) | ||
1885 | goto errout; | ||
1886 | |||
1887 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); | ||
1857 | } | 1888 | } |
1858 | if (rta[RTA_PRIORITY-1]) { | 1889 | |
1859 | if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4)) | 1890 | if (tb[RTA_OIF]) |
1860 | return -EINVAL; | 1891 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
1861 | memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4); | 1892 | |
1893 | if (tb[RTA_PRIORITY]) | ||
1894 | cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]); | ||
1895 | |||
1896 | if (tb[RTA_METRICS]) { | ||
1897 | cfg->fc_mx = nla_data(tb[RTA_METRICS]); | ||
1898 | cfg->fc_mx_len = nla_len(tb[RTA_METRICS]); | ||
1862 | } | 1899 | } |
1863 | return 0; | 1900 | |
1901 | if (tb[RTA_TABLE]) | ||
1902 | cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); | ||
1903 | |||
1904 | err = 0; | ||
1905 | errout: | ||
1906 | return err; | ||
1864 | } | 1907 | } |
1865 | 1908 | ||
1866 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1909 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1867 | { | 1910 | { |
1868 | struct rtmsg *r = NLMSG_DATA(nlh); | 1911 | struct fib6_config cfg; |
1869 | struct in6_rtmsg rtmsg; | 1912 | int err; |
1870 | 1913 | ||
1871 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1914 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1872 | return -EINVAL; | 1915 | if (err < 0) |
1873 | return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb), | 1916 | return err; |
1874 | rtm_get_table(arg, r->rtm_table)); | 1917 | |
1918 | return ip6_route_del(&cfg); | ||
1875 | } | 1919 | } |
1876 | 1920 | ||
1877 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1921 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1878 | { | 1922 | { |
1879 | struct rtmsg *r = NLMSG_DATA(nlh); | 1923 | struct fib6_config cfg; |
1880 | struct in6_rtmsg rtmsg; | 1924 | int err; |
1881 | 1925 | ||
1882 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1926 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1883 | return -EINVAL; | 1927 | if (err < 0) |
1884 | return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb), | 1928 | return err; |
1885 | rtm_get_table(arg, r->rtm_table)); | 1929 | |
1930 | return ip6_route_add(&cfg); | ||
1886 | } | 1931 | } |
1887 | 1932 | ||
1888 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | 1933 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, |
@@ -2063,15 +2108,21 @@ out_free: | |||
2063 | goto out; | 2108 | goto out; |
2064 | } | 2109 | } |
2065 | 2110 | ||
2066 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, | 2111 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) |
2067 | struct netlink_skb_parms *req) | ||
2068 | { | 2112 | { |
2069 | struct sk_buff *skb; | 2113 | struct sk_buff *skb; |
2070 | u32 pid = req ? req->pid : 0; | 2114 | u32 pid = 0, seq = 0; |
2071 | u32 seq = nlh ? nlh->nlmsg_seq : 0; | 2115 | struct nlmsghdr *nlh = NULL; |
2072 | int payload = sizeof(struct rtmsg) + 256; | 2116 | int payload = sizeof(struct rtmsg) + 256; |
2073 | int err = -ENOBUFS; | 2117 | int err = -ENOBUFS; |
2074 | 2118 | ||
2119 | if (info) { | ||
2120 | pid = info->pid; | ||
2121 | nlh = info->nlh; | ||
2122 | if (nlh) | ||
2123 | seq = nlh->nlmsg_seq; | ||
2124 | } | ||
2125 | |||
2075 | skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); | 2126 | skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); |
2076 | if (skb == NULL) | 2127 | if (skb == NULL) |
2077 | goto errout; | 2128 | goto errout; |