aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_fib.h38
-rw-r--r--include/net/ip6_route.h6
-rw-r--r--net/ipv6/addrconf.c65
-rw-r--r--net/ipv6/ip6_fib.c19
-rw-r--r--net/ipv6/route.c331
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
25struct rt6_info; 25struct rt6_info;
26 26
27struct 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
27struct fib6_node 48struct 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
176extern int fib6_add(struct fib6_node *root, 197extern 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
182extern int fib6_del(struct rt6_info *rt, 201extern 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
187extern void inet6_rt_notify(int event, struct rt6_info *rt, 204extern 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
191extern void fib6_run_gc(unsigned long dummy); 207extern 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
61extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); 61extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg);
62 62
63extern int ip6_route_add(struct in6_rtmsg *rtmsg, 63extern int ip6_route_add(struct fib6_config *cfg);
64 struct nlmsghdr *,
65 void *rtattr,
66 struct netlink_skb_parms *req,
67 u32 table_id);
68extern int ip6_ins_rt(struct rt6_info *); 64extern int ip6_ins_rt(struct rt6_info *);
69extern int ip6_del_rt(struct rt6_info *); 65extern 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
1509addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, 1509addrconf_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
1535static void addrconf_add_mroute(struct net_device *dev) 1535static 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
1550static void sit_route_add(struct net_device *dev) 1550static 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
1567static void addrconf_add_lroute(struct net_device *dev) 1564static 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
612static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, 612static 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
698int fib6_add(struct fib6_node *root, struct rt6_info *rt, 698int 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
1078static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, 1077static 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
1139int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 1138int 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
549static int __ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, 549static 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
563int ip6_ins_rt(struct rt6_info *rt) 562int 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
568static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, 567static 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
1017int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, 1016int 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
1186install_route: 1176install_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
1216out: 1206out:
1217 if (dev) 1207 if (dev)
@@ -1223,8 +1213,7 @@ out:
1223 return err; 1213 return err;
1224} 1214}
1225 1215
1226static int __ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, 1216static 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
1246int ip6_del_rt(struct rt6_info *rt) 1235int 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
1251static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, 1240static 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
1640static 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
1652int ipv6_route_ioctl(unsigned int cmd, void __user *arg) 1658int 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
1826static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, 1833static 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
1840static 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;
1905errout:
1906 return err;
1864} 1907}
1865 1908
1866int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1909int 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
1877int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1921int 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
1888static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, 1933static 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
2066void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, 2111void 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;