diff options
Diffstat (limited to 'net/ipv6')
54 files changed, 3325 insertions, 1407 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 0ba06c0c5d39..a2d211da2aba 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -98,6 +98,15 @@ config INET6_IPCOMP | |||
98 | 98 | ||
99 | If unsure, say Y. | 99 | If unsure, say Y. |
100 | 100 | ||
101 | config IPV6_MIP6 | ||
102 | bool "IPv6: Mobility (EXPERIMENTAL)" | ||
103 | depends on IPV6 && EXPERIMENTAL | ||
104 | select XFRM | ||
105 | ---help--- | ||
106 | Support for IPv6 Mobility described in RFC 3775. | ||
107 | |||
108 | If unsure, say N. | ||
109 | |||
101 | config INET6_XFRM_TUNNEL | 110 | config INET6_XFRM_TUNNEL |
102 | tristate | 111 | tristate |
103 | select INET6_TUNNEL | 112 | select INET6_TUNNEL |
@@ -127,6 +136,13 @@ config INET6_XFRM_MODE_TUNNEL | |||
127 | 136 | ||
128 | If unsure, say Y. | 137 | If unsure, say Y. |
129 | 138 | ||
139 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION | ||
140 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" | ||
141 | depends on IPV6 && EXPERIMENTAL | ||
142 | select XFRM | ||
143 | ---help--- | ||
144 | Support for MIPv6 route optimization mode. | ||
145 | |||
130 | config IPV6_TUNNEL | 146 | config IPV6_TUNNEL |
131 | tristate "IPv6: IPv6-in-IPv6 tunnel" | 147 | tristate "IPv6: IPv6-in-IPv6 tunnel" |
132 | select INET6_TUNNEL | 148 | select INET6_TUNNEL |
@@ -136,3 +152,31 @@ config IPV6_TUNNEL | |||
136 | 152 | ||
137 | If unsure, say N. | 153 | If unsure, say N. |
138 | 154 | ||
155 | config IPV6_SUBTREES | ||
156 | bool "IPv6: source address based routing" | ||
157 | depends on IPV6 && EXPERIMENTAL | ||
158 | ---help--- | ||
159 | Enable routing by source address or prefix. | ||
160 | |||
161 | The destination address is still the primary routing key, so mixing | ||
162 | normal and source prefix specific routes in the same routing table | ||
163 | may sometimes lead to unintended routing behavior. This can be | ||
164 | avoided by defining different routing tables for the normal and | ||
165 | source prefix specific routes. | ||
166 | |||
167 | If unsure, say N. | ||
168 | |||
169 | config IPV6_MULTIPLE_TABLES | ||
170 | bool "IPv6: Multiple Routing Tables" | ||
171 | depends on IPV6 && EXPERIMENTAL | ||
172 | select FIB_RULES | ||
173 | ---help--- | ||
174 | Support multiple routing tables. | ||
175 | |||
176 | config IPV6_ROUTE_FWMARK | ||
177 | bool "IPv6: use netfilter MARK value as routing key" | ||
178 | depends on IPV6_MULTIPLE_TABLES && NETFILTER | ||
179 | ---help--- | ||
180 | If you say Y here, you will be able to specify different routes for | ||
181 | packets with different mark values (see iptables(8), MARK target). | ||
182 | |||
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 386e0a626948..0213c6612b58 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -13,6 +13,9 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \ | |||
13 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ | 13 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ |
14 | xfrm6_output.o | 14 | xfrm6_output.o |
15 | ipv6-$(CONFIG_NETFILTER) += netfilter.o | 15 | ipv6-$(CONFIG_NETFILTER) += netfilter.o |
16 | ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o | ||
17 | ipv6-$(CONFIG_IPV6_MIP6) += mip6.o | ||
18 | |||
16 | ipv6-objs += $(ipv6-y) | 19 | ipv6-objs += $(ipv6-y) |
17 | 20 | ||
18 | obj-$(CONFIG_INET6_AH) += ah6.o | 21 | obj-$(CONFIG_INET6_AH) += ah6.o |
@@ -22,6 +25,7 @@ obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o | |||
22 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | 25 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o |
23 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o | 26 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o |
24 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o | 27 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o |
28 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o | ||
25 | obj-$(CONFIG_NETFILTER) += netfilter/ | 29 | obj-$(CONFIG_NETFILTER) += netfilter/ |
26 | 30 | ||
27 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 31 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c7852b38e03e..c18676352397 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/net.h> | 48 | #include <linux/net.h> |
49 | #include <linux/in6.h> | 49 | #include <linux/in6.h> |
50 | #include <linux/netdevice.h> | 50 | #include <linux/netdevice.h> |
51 | #include <linux/if_addr.h> | ||
51 | #include <linux/if_arp.h> | 52 | #include <linux/if_arp.h> |
52 | #include <linux/if_arcnet.h> | 53 | #include <linux/if_arcnet.h> |
53 | #include <linux/if_infiniband.h> | 54 | #include <linux/if_infiniband.h> |
@@ -72,6 +73,7 @@ | |||
72 | #include <net/addrconf.h> | 73 | #include <net/addrconf.h> |
73 | #include <net/tcp.h> | 74 | #include <net/tcp.h> |
74 | #include <net/ip.h> | 75 | #include <net/ip.h> |
76 | #include <net/netlink.h> | ||
75 | #include <linux/if_tunnel.h> | 77 | #include <linux/if_tunnel.h> |
76 | #include <linux/rtnetlink.h> | 78 | #include <linux/rtnetlink.h> |
77 | 79 | ||
@@ -117,9 +119,6 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
117 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 119 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; |
118 | static DEFINE_RWLOCK(addrconf_hash_lock); | 120 | static DEFINE_RWLOCK(addrconf_hash_lock); |
119 | 121 | ||
120 | /* Protects inet6 devices */ | ||
121 | DEFINE_RWLOCK(addrconf_lock); | ||
122 | |||
123 | static void addrconf_verify(unsigned long); | 122 | static void addrconf_verify(unsigned long); |
124 | 123 | ||
125 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); | 124 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); |
@@ -144,7 +143,7 @@ static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *de | |||
144 | 143 | ||
145 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); | 144 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
146 | 145 | ||
147 | struct ipv6_devconf ipv6_devconf = { | 146 | struct ipv6_devconf ipv6_devconf __read_mostly = { |
148 | .forwarding = 0, | 147 | .forwarding = 0, |
149 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 148 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
150 | .mtu6 = IPV6_MIN_MTU, | 149 | .mtu6 = IPV6_MIN_MTU, |
@@ -173,9 +172,10 @@ struct ipv6_devconf ipv6_devconf = { | |||
173 | .accept_ra_rt_info_max_plen = 0, | 172 | .accept_ra_rt_info_max_plen = 0, |
174 | #endif | 173 | #endif |
175 | #endif | 174 | #endif |
175 | .proxy_ndp = 0, | ||
176 | }; | 176 | }; |
177 | 177 | ||
178 | static struct ipv6_devconf ipv6_devconf_dflt = { | 178 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
179 | .forwarding = 0, | 179 | .forwarding = 0, |
180 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 180 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
181 | .mtu6 = IPV6_MIN_MTU, | 181 | .mtu6 = IPV6_MIN_MTU, |
@@ -203,6 +203,7 @@ static struct ipv6_devconf ipv6_devconf_dflt = { | |||
203 | .accept_ra_rt_info_max_plen = 0, | 203 | .accept_ra_rt_info_max_plen = 0, |
204 | #endif | 204 | #endif |
205 | #endif | 205 | #endif |
206 | .proxy_ndp = 0, | ||
206 | }; | 207 | }; |
207 | 208 | ||
208 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
@@ -314,6 +315,12 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
314 | 315 | ||
315 | /* Nobody refers to this device, we may destroy it. */ | 316 | /* Nobody refers to this device, we may destroy it. */ |
316 | 317 | ||
318 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | ||
319 | { | ||
320 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); | ||
321 | kfree(idev); | ||
322 | } | ||
323 | |||
317 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 324 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
318 | { | 325 | { |
319 | struct net_device *dev = idev->dev; | 326 | struct net_device *dev = idev->dev; |
@@ -328,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
328 | return; | 335 | return; |
329 | } | 336 | } |
330 | snmp6_free_dev(idev); | 337 | snmp6_free_dev(idev); |
331 | kfree(idev); | 338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); |
332 | } | 339 | } |
333 | 340 | ||
334 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | 341 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) |
@@ -404,9 +411,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
404 | if (netif_carrier_ok(dev)) | 411 | if (netif_carrier_ok(dev)) |
405 | ndev->if_flags |= IF_READY; | 412 | ndev->if_flags |= IF_READY; |
406 | 413 | ||
407 | write_lock_bh(&addrconf_lock); | 414 | /* protected by rtnl_lock */ |
408 | dev->ip6_ptr = ndev; | 415 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
409 | write_unlock_bh(&addrconf_lock); | ||
410 | 416 | ||
411 | ipv6_mc_init_dev(ndev); | 417 | ipv6_mc_init_dev(ndev); |
412 | ndev->tstamp = jiffies; | 418 | ndev->tstamp = jiffies; |
@@ -470,7 +476,7 @@ static void addrconf_forward_change(void) | |||
470 | 476 | ||
471 | read_lock(&dev_base_lock); | 477 | read_lock(&dev_base_lock); |
472 | for (dev=dev_base; dev; dev=dev->next) { | 478 | for (dev=dev_base; dev; dev=dev->next) { |
473 | read_lock(&addrconf_lock); | 479 | rcu_read_lock(); |
474 | idev = __in6_dev_get(dev); | 480 | idev = __in6_dev_get(dev); |
475 | if (idev) { | 481 | if (idev) { |
476 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); | 482 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); |
@@ -478,7 +484,7 @@ static void addrconf_forward_change(void) | |||
478 | if (changed) | 484 | if (changed) |
479 | dev_forward_change(idev); | 485 | dev_forward_change(idev); |
480 | } | 486 | } |
481 | read_unlock(&addrconf_lock); | 487 | rcu_read_unlock(); |
482 | } | 488 | } |
483 | read_unlock(&dev_base_lock); | 489 | read_unlock(&dev_base_lock); |
484 | } | 490 | } |
@@ -539,7 +545,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
539 | int hash; | 545 | int hash; |
540 | int err = 0; | 546 | int err = 0; |
541 | 547 | ||
542 | read_lock_bh(&addrconf_lock); | 548 | rcu_read_lock_bh(); |
543 | if (idev->dead) { | 549 | if (idev->dead) { |
544 | err = -ENODEV; /*XXX*/ | 550 | err = -ENODEV; /*XXX*/ |
545 | goto out2; | 551 | goto out2; |
@@ -608,7 +614,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
608 | in6_ifa_hold(ifa); | 614 | in6_ifa_hold(ifa); |
609 | write_unlock(&idev->lock); | 615 | write_unlock(&idev->lock); |
610 | out2: | 616 | out2: |
611 | read_unlock_bh(&addrconf_lock); | 617 | rcu_read_unlock_bh(); |
612 | 618 | ||
613 | if (likely(err == 0)) | 619 | if (likely(err == 0)) |
614 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); | 620 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); |
@@ -734,7 +740,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
734 | 740 | ||
735 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 741 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
736 | if (onlink == 0) { | 742 | if (onlink == 0) { |
737 | ip6_del_rt(rt, NULL, NULL, NULL); | 743 | ip6_del_rt(rt); |
738 | rt = NULL; | 744 | rt = NULL; |
739 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { | 745 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { |
740 | rt->rt6i_expires = expires; | 746 | rt->rt6i_expires = expires; |
@@ -911,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
911 | memset(&hiscore, 0, sizeof(hiscore)); | 917 | memset(&hiscore, 0, sizeof(hiscore)); |
912 | 918 | ||
913 | read_lock(&dev_base_lock); | 919 | read_lock(&dev_base_lock); |
914 | read_lock(&addrconf_lock); | 920 | rcu_read_lock(); |
915 | 921 | ||
916 | for (dev = dev_base; dev; dev=dev->next) { | 922 | for (dev = dev_base; dev; dev=dev->next) { |
917 | struct inet6_dev *idev; | 923 | struct inet6_dev *idev; |
@@ -1032,9 +1038,27 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
1032 | continue; | 1038 | continue; |
1033 | } | 1039 | } |
1034 | 1040 | ||
1035 | /* Rule 4: Prefer home address -- not implemented yet */ | 1041 | /* Rule 4: Prefer home address */ |
1042 | #ifdef CONFIG_IPV6_MIP6 | ||
1043 | if (hiscore.rule < 4) { | ||
1044 | if (ifa_result->flags & IFA_F_HOMEADDRESS) | ||
1045 | hiscore.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1046 | hiscore.rule++; | ||
1047 | } | ||
1048 | if (ifa->flags & IFA_F_HOMEADDRESS) { | ||
1049 | score.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1050 | if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) { | ||
1051 | score.rule = 4; | ||
1052 | goto record_it; | ||
1053 | } | ||
1054 | } else { | ||
1055 | if (hiscore.attrs & IPV6_SADDR_SCORE_HOA) | ||
1056 | continue; | ||
1057 | } | ||
1058 | #else | ||
1036 | if (hiscore.rule < 4) | 1059 | if (hiscore.rule < 4) |
1037 | hiscore.rule++; | 1060 | hiscore.rule++; |
1061 | #endif | ||
1038 | 1062 | ||
1039 | /* Rule 5: Prefer outgoing interface */ | 1063 | /* Rule 5: Prefer outgoing interface */ |
1040 | if (hiscore.rule < 5) { | 1064 | if (hiscore.rule < 5) { |
@@ -1123,7 +1147,7 @@ record_it: | |||
1123 | } | 1147 | } |
1124 | read_unlock_bh(&idev->lock); | 1148 | read_unlock_bh(&idev->lock); |
1125 | } | 1149 | } |
1126 | read_unlock(&addrconf_lock); | 1150 | rcu_read_unlock(); |
1127 | read_unlock(&dev_base_lock); | 1151 | read_unlock(&dev_base_lock); |
1128 | 1152 | ||
1129 | if (!ifa_result) | 1153 | if (!ifa_result) |
@@ -1147,7 +1171,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1147 | struct inet6_dev *idev; | 1171 | struct inet6_dev *idev; |
1148 | int err = -EADDRNOTAVAIL; | 1172 | int err = -EADDRNOTAVAIL; |
1149 | 1173 | ||
1150 | read_lock(&addrconf_lock); | 1174 | rcu_read_lock(); |
1151 | if ((idev = __in6_dev_get(dev)) != NULL) { | 1175 | if ((idev = __in6_dev_get(dev)) != NULL) { |
1152 | struct inet6_ifaddr *ifp; | 1176 | struct inet6_ifaddr *ifp; |
1153 | 1177 | ||
@@ -1161,7 +1185,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1161 | } | 1185 | } |
1162 | read_unlock_bh(&idev->lock); | 1186 | read_unlock_bh(&idev->lock); |
1163 | } | 1187 | } |
1164 | read_unlock(&addrconf_lock); | 1188 | rcu_read_unlock(); |
1165 | return err; | 1189 | return err; |
1166 | } | 1190 | } |
1167 | 1191 | ||
@@ -1462,7 +1486,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1462 | struct inet6_dev *idev = (struct inet6_dev *) data; | 1486 | struct inet6_dev *idev = (struct inet6_dev *) data; |
1463 | unsigned long expires; | 1487 | unsigned long expires; |
1464 | 1488 | ||
1465 | read_lock_bh(&addrconf_lock); | 1489 | rcu_read_lock_bh(); |
1466 | write_lock_bh(&idev->lock); | 1490 | write_lock_bh(&idev->lock); |
1467 | 1491 | ||
1468 | if (idev->dead) | 1492 | if (idev->dead) |
@@ -1486,7 +1510,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1486 | 1510 | ||
1487 | out: | 1511 | out: |
1488 | write_unlock_bh(&idev->lock); | 1512 | write_unlock_bh(&idev->lock); |
1489 | read_unlock_bh(&addrconf_lock); | 1513 | rcu_read_unlock_bh(); |
1490 | in6_dev_put(idev); | 1514 | in6_dev_put(idev); |
1491 | } | 1515 | } |
1492 | 1516 | ||
@@ -1507,59 +1531,56 @@ static void | |||
1507 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, | 1531 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, |
1508 | unsigned long expires, u32 flags) | 1532 | unsigned long expires, u32 flags) |
1509 | { | 1533 | { |
1510 | struct in6_rtmsg rtmsg; | 1534 | struct fib6_config cfg = { |
1535 | .fc_table = RT6_TABLE_PREFIX, | ||
1536 | .fc_metric = IP6_RT_PRIO_ADDRCONF, | ||
1537 | .fc_ifindex = dev->ifindex, | ||
1538 | .fc_expires = expires, | ||
1539 | .fc_dst_len = plen, | ||
1540 | .fc_flags = RTF_UP | flags, | ||
1541 | }; | ||
1511 | 1542 | ||
1512 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1543 | ipv6_addr_copy(&cfg.fc_dst, pfx); |
1513 | ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx); | ||
1514 | rtmsg.rtmsg_dst_len = plen; | ||
1515 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
1516 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1517 | rtmsg.rtmsg_info = expires; | ||
1518 | rtmsg.rtmsg_flags = RTF_UP|flags; | ||
1519 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1520 | 1544 | ||
1521 | /* Prevent useless cloning on PtP SIT. | 1545 | /* Prevent useless cloning on PtP SIT. |
1522 | This thing is done here expecting that the whole | 1546 | This thing is done here expecting that the whole |
1523 | class of non-broadcast devices need not cloning. | 1547 | class of non-broadcast devices need not cloning. |
1524 | */ | 1548 | */ |
1525 | if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) | 1549 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
1526 | rtmsg.rtmsg_flags |= RTF_NONEXTHOP; | 1550 | cfg.fc_flags |= RTF_NONEXTHOP; |
1527 | 1551 | ||
1528 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1552 | ip6_route_add(&cfg); |
1529 | } | 1553 | } |
1530 | 1554 | ||
1531 | /* Create "default" multicast route to the interface */ | 1555 | /* Create "default" multicast route to the interface */ |
1532 | 1556 | ||
1533 | static void addrconf_add_mroute(struct net_device *dev) | 1557 | static void addrconf_add_mroute(struct net_device *dev) |
1534 | { | 1558 | { |
1535 | struct in6_rtmsg rtmsg; | 1559 | struct fib6_config cfg = { |
1560 | .fc_table = RT6_TABLE_LOCAL, | ||
1561 | .fc_metric = IP6_RT_PRIO_ADDRCONF, | ||
1562 | .fc_ifindex = dev->ifindex, | ||
1563 | .fc_dst_len = 8, | ||
1564 | .fc_flags = RTF_UP, | ||
1565 | }; | ||
1566 | |||
1567 | ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); | ||
1536 | 1568 | ||
1537 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1569 | ip6_route_add(&cfg); |
1538 | ipv6_addr_set(&rtmsg.rtmsg_dst, | ||
1539 | htonl(0xFF000000), 0, 0, 0); | ||
1540 | rtmsg.rtmsg_dst_len = 8; | ||
1541 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
1542 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1543 | rtmsg.rtmsg_flags = RTF_UP; | ||
1544 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1545 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1546 | } | 1570 | } |
1547 | 1571 | ||
1548 | static void sit_route_add(struct net_device *dev) | 1572 | static void sit_route_add(struct net_device *dev) |
1549 | { | 1573 | { |
1550 | struct in6_rtmsg rtmsg; | 1574 | struct fib6_config cfg = { |
1551 | 1575 | .fc_table = RT6_TABLE_MAIN, | |
1552 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1576 | .fc_metric = IP6_RT_PRIO_ADDRCONF, |
1553 | 1577 | .fc_ifindex = dev->ifindex, | |
1554 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1578 | .fc_dst_len = 96, |
1555 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | 1579 | .fc_flags = RTF_UP | RTF_NONEXTHOP, |
1580 | }; | ||
1556 | 1581 | ||
1557 | /* prefix length - 96 bits "::d.d.d.d" */ | 1582 | /* prefix length - 96 bits "::d.d.d.d" */ |
1558 | rtmsg.rtmsg_dst_len = 96; | 1583 | ip6_route_add(&cfg); |
1559 | rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; | ||
1560 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1561 | |||
1562 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1563 | } | 1584 | } |
1564 | 1585 | ||
1565 | static void addrconf_add_lroute(struct net_device *dev) | 1586 | static void addrconf_add_lroute(struct net_device *dev) |
@@ -1660,7 +1681,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1660 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 1681 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
1661 | if (rt->rt6i_flags&RTF_EXPIRES) { | 1682 | if (rt->rt6i_flags&RTF_EXPIRES) { |
1662 | if (valid_lft == 0) { | 1683 | if (valid_lft == 0) { |
1663 | ip6_del_rt(rt, NULL, NULL, NULL); | 1684 | ip6_del_rt(rt); |
1664 | rt = NULL; | 1685 | rt = NULL; |
1665 | } else { | 1686 | } else { |
1666 | rt->rt6i_expires = jiffies + rt_expires; | 1687 | rt->rt6i_expires = jiffies + rt_expires; |
@@ -1870,12 +1891,11 @@ err_exit: | |||
1870 | * Manual configuration of address on an interface | 1891 | * Manual configuration of address on an interface |
1871 | */ | 1892 | */ |
1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | 1893 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, |
1873 | __u32 prefered_lft, __u32 valid_lft) | 1894 | __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) |
1874 | { | 1895 | { |
1875 | struct inet6_ifaddr *ifp; | 1896 | struct inet6_ifaddr *ifp; |
1876 | struct inet6_dev *idev; | 1897 | struct inet6_dev *idev; |
1877 | struct net_device *dev; | 1898 | struct net_device *dev; |
1878 | __u8 ifa_flags = 0; | ||
1879 | int scope; | 1899 | int scope; |
1880 | 1900 | ||
1881 | ASSERT_RTNL(); | 1901 | ASSERT_RTNL(); |
@@ -1887,9 +1907,6 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | |||
1887 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | 1907 | if ((dev = __dev_get_by_index(ifindex)) == NULL) |
1888 | return -ENODEV; | 1908 | return -ENODEV; |
1889 | 1909 | ||
1890 | if (!(dev->flags&IFF_UP)) | ||
1891 | return -ENETDOWN; | ||
1892 | |||
1893 | if ((idev = addrconf_add_dev(dev)) == NULL) | 1910 | if ((idev = addrconf_add_dev(dev)) == NULL) |
1894 | return -ENOBUFS; | 1911 | return -ENOBUFS; |
1895 | 1912 | ||
@@ -1971,7 +1988,7 @@ int addrconf_add_ifaddr(void __user *arg) | |||
1971 | 1988 | ||
1972 | rtnl_lock(); | 1989 | rtnl_lock(); |
1973 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, | 1990 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, |
1974 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | 1991 | IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); |
1975 | rtnl_unlock(); | 1992 | rtnl_unlock(); |
1976 | return err; | 1993 | return err; |
1977 | } | 1994 | } |
@@ -2344,10 +2361,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2344 | Do not dev_put! | 2361 | Do not dev_put! |
2345 | */ | 2362 | */ |
2346 | if (how == 1) { | 2363 | if (how == 1) { |
2347 | write_lock_bh(&addrconf_lock); | ||
2348 | dev->ip6_ptr = NULL; | ||
2349 | idev->dead = 1; | 2364 | idev->dead = 1; |
2350 | write_unlock_bh(&addrconf_lock); | 2365 | |
2366 | /* protected by rtnl_lock */ | ||
2367 | rcu_assign_pointer(dev->ip6_ptr, NULL); | ||
2351 | 2368 | ||
2352 | /* Step 1.5: remove snmp6 entry */ | 2369 | /* Step 1.5: remove snmp6 entry */ |
2353 | snmp6_unregister_dev(idev); | 2370 | snmp6_unregister_dev(idev); |
@@ -2514,7 +2531,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2514 | spin_lock_bh(&ifp->lock); | 2531 | spin_lock_bh(&ifp->lock); |
2515 | 2532 | ||
2516 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2533 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2517 | !(ifp->flags&IFA_F_TENTATIVE)) { | 2534 | !(ifp->flags&IFA_F_TENTATIVE) || |
2535 | ifp->flags & IFA_F_NODAD) { | ||
2518 | ifp->flags &= ~IFA_F_TENTATIVE; | 2536 | ifp->flags &= ~IFA_F_TENTATIVE; |
2519 | spin_unlock_bh(&ifp->lock); | 2537 | spin_unlock_bh(&ifp->lock); |
2520 | read_unlock_bh(&idev->lock); | 2538 | read_unlock_bh(&idev->lock); |
@@ -2759,6 +2777,26 @@ void if6_proc_exit(void) | |||
2759 | } | 2777 | } |
2760 | #endif /* CONFIG_PROC_FS */ | 2778 | #endif /* CONFIG_PROC_FS */ |
2761 | 2779 | ||
2780 | #ifdef CONFIG_IPV6_MIP6 | ||
2781 | /* Check if address is a home address configured on any interface. */ | ||
2782 | int ipv6_chk_home_addr(struct in6_addr *addr) | ||
2783 | { | ||
2784 | int ret = 0; | ||
2785 | struct inet6_ifaddr * ifp; | ||
2786 | u8 hash = ipv6_addr_hash(addr); | ||
2787 | read_lock_bh(&addrconf_hash_lock); | ||
2788 | for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { | ||
2789 | if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && | ||
2790 | (ifp->flags & IFA_F_HOMEADDRESS)) { | ||
2791 | ret = 1; | ||
2792 | break; | ||
2793 | } | ||
2794 | } | ||
2795 | read_unlock_bh(&addrconf_hash_lock); | ||
2796 | return ret; | ||
2797 | } | ||
2798 | #endif | ||
2799 | |||
2762 | /* | 2800 | /* |
2763 | * Periodic address status verification | 2801 | * Periodic address status verification |
2764 | */ | 2802 | */ |
@@ -2869,66 +2907,68 @@ restart: | |||
2869 | spin_unlock_bh(&addrconf_verify_lock); | 2907 | spin_unlock_bh(&addrconf_verify_lock); |
2870 | } | 2908 | } |
2871 | 2909 | ||
2910 | static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) | ||
2911 | { | ||
2912 | struct in6_addr *pfx = NULL; | ||
2913 | |||
2914 | if (addr) | ||
2915 | pfx = nla_data(addr); | ||
2916 | |||
2917 | if (local) { | ||
2918 | if (pfx && nla_memcmp(local, pfx, sizeof(*pfx))) | ||
2919 | pfx = NULL; | ||
2920 | else | ||
2921 | pfx = nla_data(local); | ||
2922 | } | ||
2923 | |||
2924 | return pfx; | ||
2925 | } | ||
2926 | |||
2927 | static struct nla_policy ifa_ipv6_policy[IFA_MAX+1] __read_mostly = { | ||
2928 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, | ||
2929 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, | ||
2930 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, | ||
2931 | }; | ||
2932 | |||
2872 | static int | 2933 | static int |
2873 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2934 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2874 | { | 2935 | { |
2875 | struct rtattr **rta = arg; | 2936 | struct ifaddrmsg *ifm; |
2876 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2937 | struct nlattr *tb[IFA_MAX+1]; |
2877 | struct in6_addr *pfx; | 2938 | struct in6_addr *pfx; |
2939 | int err; | ||
2878 | 2940 | ||
2879 | pfx = NULL; | 2941 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
2880 | if (rta[IFA_ADDRESS-1]) { | 2942 | if (err < 0) |
2881 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2943 | return err; |
2882 | return -EINVAL; | 2944 | |
2883 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 2945 | ifm = nlmsg_data(nlh); |
2884 | } | 2946 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
2885 | if (rta[IFA_LOCAL-1]) { | ||
2886 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || | ||
2887 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
2888 | return -EINVAL; | ||
2889 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
2890 | } | ||
2891 | if (pfx == NULL) | 2947 | if (pfx == NULL) |
2892 | return -EINVAL; | 2948 | return -EINVAL; |
2893 | 2949 | ||
2894 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2950 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
2895 | } | 2951 | } |
2896 | 2952 | ||
2897 | static int | 2953 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, |
2898 | inet6_addr_modify(int ifindex, struct in6_addr *pfx, | 2954 | u32 prefered_lft, u32 valid_lft) |
2899 | __u32 prefered_lft, __u32 valid_lft) | ||
2900 | { | 2955 | { |
2901 | struct inet6_ifaddr *ifp = NULL; | ||
2902 | struct net_device *dev; | ||
2903 | int ifa_flags = 0; | ||
2904 | |||
2905 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | ||
2906 | return -ENODEV; | ||
2907 | |||
2908 | if (!(dev->flags&IFF_UP)) | ||
2909 | return -ENETDOWN; | ||
2910 | |||
2911 | if (!valid_lft || (prefered_lft > valid_lft)) | 2956 | if (!valid_lft || (prefered_lft > valid_lft)) |
2912 | return -EINVAL; | 2957 | return -EINVAL; |
2913 | 2958 | ||
2914 | ifp = ipv6_get_ifaddr(pfx, dev, 1); | ||
2915 | if (ifp == NULL) | ||
2916 | return -ENOENT; | ||
2917 | |||
2918 | if (valid_lft == INFINITY_LIFE_TIME) | 2959 | if (valid_lft == INFINITY_LIFE_TIME) |
2919 | ifa_flags = IFA_F_PERMANENT; | 2960 | ifa_flags |= IFA_F_PERMANENT; |
2920 | else if (valid_lft >= 0x7FFFFFFF/HZ) | 2961 | else if (valid_lft >= 0x7FFFFFFF/HZ) |
2921 | valid_lft = 0x7FFFFFFF/HZ; | 2962 | valid_lft = 0x7FFFFFFF/HZ; |
2922 | 2963 | ||
2923 | if (prefered_lft == 0) | 2964 | if (prefered_lft == 0) |
2924 | ifa_flags = IFA_F_DEPRECATED; | 2965 | ifa_flags |= IFA_F_DEPRECATED; |
2925 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 2966 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && |
2926 | (prefered_lft != INFINITY_LIFE_TIME)) | 2967 | (prefered_lft != INFINITY_LIFE_TIME)) |
2927 | prefered_lft = 0x7FFFFFFF/HZ; | 2968 | prefered_lft = 0x7FFFFFFF/HZ; |
2928 | 2969 | ||
2929 | spin_lock_bh(&ifp->lock); | 2970 | spin_lock_bh(&ifp->lock); |
2930 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags; | 2971 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; |
2931 | |||
2932 | ifp->tstamp = jiffies; | 2972 | ifp->tstamp = jiffies; |
2933 | ifp->valid_lft = valid_lft; | 2973 | ifp->valid_lft = valid_lft; |
2934 | ifp->prefered_lft = prefered_lft; | 2974 | ifp->prefered_lft = prefered_lft; |
@@ -2936,7 +2976,6 @@ inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |||
2936 | spin_unlock_bh(&ifp->lock); | 2976 | spin_unlock_bh(&ifp->lock); |
2937 | if (!(ifp->flags&IFA_F_TENTATIVE)) | 2977 | if (!(ifp->flags&IFA_F_TENTATIVE)) |
2938 | ipv6_ifa_notify(0, ifp); | 2978 | ipv6_ifa_notify(0, ifp); |
2939 | in6_ifa_put(ifp); | ||
2940 | 2979 | ||
2941 | addrconf_verify(0); | 2980 | addrconf_verify(0); |
2942 | 2981 | ||
@@ -2946,172 +2985,189 @@ inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |||
2946 | static int | 2985 | static int |
2947 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2986 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2948 | { | 2987 | { |
2949 | struct rtattr **rta = arg; | 2988 | struct ifaddrmsg *ifm; |
2950 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2989 | struct nlattr *tb[IFA_MAX+1]; |
2951 | struct in6_addr *pfx; | 2990 | struct in6_addr *pfx; |
2952 | __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME; | 2991 | struct inet6_ifaddr *ifa; |
2992 | struct net_device *dev; | ||
2993 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; | ||
2994 | u8 ifa_flags; | ||
2995 | int err; | ||
2953 | 2996 | ||
2954 | pfx = NULL; | 2997 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
2955 | if (rta[IFA_ADDRESS-1]) { | 2998 | if (err < 0) |
2956 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2999 | return err; |
2957 | return -EINVAL; | 3000 | |
2958 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 3001 | ifm = nlmsg_data(nlh); |
2959 | } | 3002 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
2960 | if (rta[IFA_LOCAL-1]) { | ||
2961 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || | ||
2962 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
2963 | return -EINVAL; | ||
2964 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
2965 | } | ||
2966 | if (pfx == NULL) | 3003 | if (pfx == NULL) |
2967 | return -EINVAL; | 3004 | return -EINVAL; |
2968 | 3005 | ||
2969 | if (rta[IFA_CACHEINFO-1]) { | 3006 | if (tb[IFA_CACHEINFO]) { |
2970 | struct ifa_cacheinfo *ci; | 3007 | struct ifa_cacheinfo *ci; |
2971 | if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci)) | 3008 | |
2972 | return -EINVAL; | 3009 | ci = nla_data(tb[IFA_CACHEINFO]); |
2973 | ci = RTA_DATA(rta[IFA_CACHEINFO-1]); | ||
2974 | valid_lft = ci->ifa_valid; | 3010 | valid_lft = ci->ifa_valid; |
2975 | prefered_lft = ci->ifa_prefered; | 3011 | preferred_lft = ci->ifa_prefered; |
3012 | } else { | ||
3013 | preferred_lft = INFINITY_LIFE_TIME; | ||
3014 | valid_lft = INFINITY_LIFE_TIME; | ||
2976 | } | 3015 | } |
2977 | 3016 | ||
2978 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | 3017 | dev = __dev_get_by_index(ifm->ifa_index); |
2979 | int ret; | 3018 | if (dev == NULL) |
2980 | ret = inet6_addr_modify(ifm->ifa_index, pfx, | 3019 | return -ENODEV; |
2981 | prefered_lft, valid_lft); | 3020 | |
2982 | if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | 3021 | /* We ignore other flags so far. */ |
2983 | return ret; | 3022 | ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS); |
3023 | |||
3024 | ifa = ipv6_get_ifaddr(pfx, dev, 1); | ||
3025 | if (ifa == NULL) { | ||
3026 | /* | ||
3027 | * It would be best to check for !NLM_F_CREATE here but | ||
3028 | * userspace alreay relies on not having to provide this. | ||
3029 | */ | ||
3030 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | ||
3031 | ifa_flags, preferred_lft, valid_lft); | ||
2984 | } | 3032 | } |
2985 | 3033 | ||
2986 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | 3034 | if (nlh->nlmsg_flags & NLM_F_EXCL || |
2987 | prefered_lft, valid_lft); | 3035 | !(nlh->nlmsg_flags & NLM_F_REPLACE)) |
3036 | err = -EEXIST; | ||
3037 | else | ||
3038 | err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft); | ||
3039 | |||
3040 | in6_ifa_put(ifa); | ||
3041 | |||
3042 | return err; | ||
3043 | } | ||
3044 | |||
3045 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, | ||
3046 | u8 scope, int ifindex) | ||
3047 | { | ||
3048 | struct ifaddrmsg *ifm; | ||
2988 | 3049 | ||
3050 | ifm = nlmsg_data(nlh); | ||
3051 | ifm->ifa_family = AF_INET6; | ||
3052 | ifm->ifa_prefixlen = prefixlen; | ||
3053 | ifm->ifa_flags = flags; | ||
3054 | ifm->ifa_scope = scope; | ||
3055 | ifm->ifa_index = ifindex; | ||
2989 | } | 3056 | } |
2990 | 3057 | ||
2991 | /* Maximum length of ifa_cacheinfo attributes */ | 3058 | static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, |
2992 | #define INET6_IFADDR_RTA_SPACE \ | 3059 | unsigned long tstamp, u32 preferred, u32 valid) |
2993 | RTA_SPACE(16) /* IFA_ADDRESS */ + \ | 3060 | { |
2994 | RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */ | 3061 | struct ifa_cacheinfo ci; |
3062 | |||
3063 | ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3064 | + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3065 | ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3066 | + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3067 | ci.ifa_prefered = preferred; | ||
3068 | ci.ifa_valid = valid; | ||
3069 | |||
3070 | return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3071 | } | ||
3072 | |||
3073 | static inline int rt_scope(int ifa_scope) | ||
3074 | { | ||
3075 | if (ifa_scope & IFA_HOST) | ||
3076 | return RT_SCOPE_HOST; | ||
3077 | else if (ifa_scope & IFA_LINK) | ||
3078 | return RT_SCOPE_LINK; | ||
3079 | else if (ifa_scope & IFA_SITE) | ||
3080 | return RT_SCOPE_SITE; | ||
3081 | else | ||
3082 | return RT_SCOPE_UNIVERSE; | ||
3083 | } | ||
3084 | |||
3085 | static inline int inet6_ifaddr_msgsize(void) | ||
3086 | { | ||
3087 | return nlmsg_total_size(sizeof(struct ifaddrmsg) + | ||
3088 | nla_total_size(16) + | ||
3089 | nla_total_size(sizeof(struct ifa_cacheinfo)) + | ||
3090 | 128); | ||
3091 | } | ||
2995 | 3092 | ||
2996 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3093 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
2997 | u32 pid, u32 seq, int event, unsigned int flags) | 3094 | u32 pid, u32 seq, int event, unsigned int flags) |
2998 | { | 3095 | { |
2999 | struct ifaddrmsg *ifm; | ||
3000 | struct nlmsghdr *nlh; | 3096 | struct nlmsghdr *nlh; |
3001 | struct ifa_cacheinfo ci; | 3097 | u32 preferred, valid; |
3002 | unsigned char *b = skb->tail; | 3098 | |
3099 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); | ||
3100 | if (nlh == NULL) | ||
3101 | return -ENOBUFS; | ||
3102 | |||
3103 | put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), | ||
3104 | ifa->idev->dev->ifindex); | ||
3003 | 3105 | ||
3004 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3005 | ifm = NLMSG_DATA(nlh); | ||
3006 | ifm->ifa_family = AF_INET6; | ||
3007 | ifm->ifa_prefixlen = ifa->prefix_len; | ||
3008 | ifm->ifa_flags = ifa->flags; | ||
3009 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3010 | if (ifa->scope&IFA_HOST) | ||
3011 | ifm->ifa_scope = RT_SCOPE_HOST; | ||
3012 | else if (ifa->scope&IFA_LINK) | ||
3013 | ifm->ifa_scope = RT_SCOPE_LINK; | ||
3014 | else if (ifa->scope&IFA_SITE) | ||
3015 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3016 | ifm->ifa_index = ifa->idev->dev->ifindex; | ||
3017 | RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr); | ||
3018 | if (!(ifa->flags&IFA_F_PERMANENT)) { | 3106 | if (!(ifa->flags&IFA_F_PERMANENT)) { |
3019 | ci.ifa_prefered = ifa->prefered_lft; | 3107 | preferred = ifa->prefered_lft; |
3020 | ci.ifa_valid = ifa->valid_lft; | 3108 | valid = ifa->valid_lft; |
3021 | if (ci.ifa_prefered != INFINITY_LIFE_TIME) { | 3109 | if (preferred != INFINITY_LIFE_TIME) { |
3022 | long tval = (jiffies - ifa->tstamp)/HZ; | 3110 | long tval = (jiffies - ifa->tstamp)/HZ; |
3023 | ci.ifa_prefered -= tval; | 3111 | preferred -= tval; |
3024 | if (ci.ifa_valid != INFINITY_LIFE_TIME) | 3112 | if (valid != INFINITY_LIFE_TIME) |
3025 | ci.ifa_valid -= tval; | 3113 | valid -= tval; |
3026 | } | 3114 | } |
3027 | } else { | 3115 | } else { |
3028 | ci.ifa_prefered = INFINITY_LIFE_TIME; | 3116 | preferred = INFINITY_LIFE_TIME; |
3029 | ci.ifa_valid = INFINITY_LIFE_TIME; | 3117 | valid = INFINITY_LIFE_TIME; |
3030 | } | 3118 | } |
3031 | ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3032 | + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3033 | ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3034 | + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3035 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3036 | nlh->nlmsg_len = skb->tail - b; | ||
3037 | return skb->len; | ||
3038 | 3119 | ||
3039 | nlmsg_failure: | 3120 | if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 || |
3040 | rtattr_failure: | 3121 | put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) |
3041 | skb_trim(skb, b - skb->data); | 3122 | return nlmsg_cancel(skb, nlh); |
3042 | return -1; | 3123 | |
3124 | return nlmsg_end(skb, nlh); | ||
3043 | } | 3125 | } |
3044 | 3126 | ||
3045 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | 3127 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, |
3046 | u32 pid, u32 seq, int event, u16 flags) | 3128 | u32 pid, u32 seq, int event, u16 flags) |
3047 | { | 3129 | { |
3048 | struct ifaddrmsg *ifm; | ||
3049 | struct nlmsghdr *nlh; | 3130 | struct nlmsghdr *nlh; |
3050 | struct ifa_cacheinfo ci; | 3131 | u8 scope = RT_SCOPE_UNIVERSE; |
3051 | unsigned char *b = skb->tail; | 3132 | int ifindex = ifmca->idev->dev->ifindex; |
3052 | |||
3053 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3054 | ifm = NLMSG_DATA(nlh); | ||
3055 | ifm->ifa_family = AF_INET6; | ||
3056 | ifm->ifa_prefixlen = 128; | ||
3057 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
3058 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3059 | if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE) | ||
3060 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3061 | ifm->ifa_index = ifmca->idev->dev->ifindex; | ||
3062 | RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr); | ||
3063 | ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ | ||
3064 | * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ | ||
3065 | * 100 / HZ); | ||
3066 | ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ | ||
3067 | * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ | ||
3068 | * 100 / HZ); | ||
3069 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
3070 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
3071 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3072 | nlh->nlmsg_len = skb->tail - b; | ||
3073 | return skb->len; | ||
3074 | 3133 | ||
3075 | nlmsg_failure: | 3134 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) |
3076 | rtattr_failure: | 3135 | scope = RT_SCOPE_SITE; |
3077 | skb_trim(skb, b - skb->data); | 3136 | |
3078 | return -1; | 3137 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); |
3138 | if (nlh == NULL) | ||
3139 | return -ENOBUFS; | ||
3140 | |||
3141 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); | ||
3142 | if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 || | ||
3143 | put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp, | ||
3144 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) | ||
3145 | return nlmsg_cancel(skb, nlh); | ||
3146 | |||
3147 | return nlmsg_end(skb, nlh); | ||
3079 | } | 3148 | } |
3080 | 3149 | ||
3081 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | 3150 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, |
3082 | u32 pid, u32 seq, int event, unsigned int flags) | 3151 | u32 pid, u32 seq, int event, unsigned int flags) |
3083 | { | 3152 | { |
3084 | struct ifaddrmsg *ifm; | ||
3085 | struct nlmsghdr *nlh; | 3153 | struct nlmsghdr *nlh; |
3086 | struct ifa_cacheinfo ci; | 3154 | u8 scope = RT_SCOPE_UNIVERSE; |
3087 | unsigned char *b = skb->tail; | 3155 | int ifindex = ifaca->aca_idev->dev->ifindex; |
3088 | |||
3089 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3090 | ifm = NLMSG_DATA(nlh); | ||
3091 | ifm->ifa_family = AF_INET6; | ||
3092 | ifm->ifa_prefixlen = 128; | ||
3093 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
3094 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3095 | if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE) | ||
3096 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3097 | ifm->ifa_index = ifaca->aca_idev->dev->ifindex; | ||
3098 | RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr); | ||
3099 | ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ | ||
3100 | * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ | ||
3101 | * 100 / HZ); | ||
3102 | ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ | ||
3103 | * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ | ||
3104 | * 100 / HZ); | ||
3105 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
3106 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
3107 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3108 | nlh->nlmsg_len = skb->tail - b; | ||
3109 | return skb->len; | ||
3110 | 3156 | ||
3111 | nlmsg_failure: | 3157 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) |
3112 | rtattr_failure: | 3158 | scope = RT_SCOPE_SITE; |
3113 | skb_trim(skb, b - skb->data); | 3159 | |
3114 | return -1; | 3160 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); |
3161 | if (nlh == NULL) | ||
3162 | return -ENOBUFS; | ||
3163 | |||
3164 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); | ||
3165 | if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 || | ||
3166 | put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp, | ||
3167 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) | ||
3168 | return nlmsg_cancel(skb, nlh); | ||
3169 | |||
3170 | return nlmsg_end(skb, nlh); | ||
3115 | } | 3171 | } |
3116 | 3172 | ||
3117 | enum addr_type_t | 3173 | enum addr_type_t |
@@ -3222,79 +3278,74 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
3222 | return inet6_dump_addr(skb, cb, type); | 3278 | return inet6_dump_addr(skb, cb, type); |
3223 | } | 3279 | } |
3224 | 3280 | ||
3225 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, | 3281 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
3226 | struct nlmsghdr* nlh, void *arg) | 3282 | void *arg) |
3227 | { | 3283 | { |
3228 | struct rtattr **rta = arg; | 3284 | struct ifaddrmsg *ifm; |
3229 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 3285 | struct nlattr *tb[IFA_MAX+1]; |
3230 | struct in6_addr *addr = NULL; | 3286 | struct in6_addr *addr = NULL; |
3231 | struct net_device *dev = NULL; | 3287 | struct net_device *dev = NULL; |
3232 | struct inet6_ifaddr *ifa; | 3288 | struct inet6_ifaddr *ifa; |
3233 | struct sk_buff *skb; | 3289 | struct sk_buff *skb; |
3234 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | ||
3235 | int err; | 3290 | int err; |
3236 | 3291 | ||
3237 | if (rta[IFA_ADDRESS-1]) { | 3292 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
3238 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr)) | 3293 | if (err < 0) |
3239 | return -EINVAL; | 3294 | goto errout; |
3240 | addr = RTA_DATA(rta[IFA_ADDRESS-1]); | 3295 | |
3241 | } | 3296 | addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
3242 | if (rta[IFA_LOCAL-1]) { | 3297 | if (addr == NULL) { |
3243 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) || | 3298 | err = -EINVAL; |
3244 | (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr)))) | 3299 | goto errout; |
3245 | return -EINVAL; | ||
3246 | addr = RTA_DATA(rta[IFA_LOCAL-1]); | ||
3247 | } | 3300 | } |
3248 | if (addr == NULL) | ||
3249 | return -EINVAL; | ||
3250 | 3301 | ||
3302 | ifm = nlmsg_data(nlh); | ||
3251 | if (ifm->ifa_index) | 3303 | if (ifm->ifa_index) |
3252 | dev = __dev_get_by_index(ifm->ifa_index); | 3304 | dev = __dev_get_by_index(ifm->ifa_index); |
3253 | 3305 | ||
3254 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) | 3306 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { |
3255 | return -EADDRNOTAVAIL; | 3307 | err = -EADDRNOTAVAIL; |
3308 | goto errout; | ||
3309 | } | ||
3256 | 3310 | ||
3257 | if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) { | 3311 | if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) { |
3258 | err = -ENOBUFS; | 3312 | err = -ENOBUFS; |
3259 | goto out; | 3313 | goto errout_ifa; |
3260 | } | 3314 | } |
3261 | 3315 | ||
3262 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
3263 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | 3316 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, |
3264 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | 3317 | nlh->nlmsg_seq, RTM_NEWADDR, 0); |
3265 | if (err < 0) { | 3318 | if (err < 0) { |
3266 | err = -EMSGSIZE; | 3319 | kfree_skb(skb); |
3267 | goto out_free; | 3320 | goto errout_ifa; |
3268 | } | 3321 | } |
3269 | 3322 | ||
3270 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 3323 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
3271 | if (err > 0) | 3324 | errout_ifa: |
3272 | err = 0; | ||
3273 | out: | ||
3274 | in6_ifa_put(ifa); | 3325 | in6_ifa_put(ifa); |
3326 | errout: | ||
3275 | return err; | 3327 | return err; |
3276 | out_free: | ||
3277 | kfree_skb(skb); | ||
3278 | goto out; | ||
3279 | } | 3328 | } |
3280 | 3329 | ||
3281 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3330 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) |
3282 | { | 3331 | { |
3283 | struct sk_buff *skb; | 3332 | struct sk_buff *skb; |
3284 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | 3333 | int err = -ENOBUFS; |
3285 | 3334 | ||
3286 | skb = alloc_skb(size, GFP_ATOMIC); | 3335 | skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); |
3287 | if (!skb) { | 3336 | if (skb == NULL) |
3288 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, ENOBUFS); | 3337 | goto errout; |
3289 | return; | 3338 | |
3290 | } | 3339 | err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
3291 | if (inet6_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) { | 3340 | if (err < 0) { |
3292 | kfree_skb(skb); | 3341 | kfree_skb(skb); |
3293 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, EINVAL); | 3342 | goto errout; |
3294 | return; | ||
3295 | } | 3343 | } |
3296 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR; | 3344 | |
3297 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC); | 3345 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3346 | errout: | ||
3347 | if (err < 0) | ||
3348 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | ||
3298 | } | 3349 | } |
3299 | 3350 | ||
3300 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | 3351 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, |
@@ -3329,6 +3380,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3329 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | 3380 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; |
3330 | #endif | 3381 | #endif |
3331 | #endif | 3382 | #endif |
3383 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | ||
3332 | } | 3384 | } |
3333 | 3385 | ||
3334 | /* Maximum length of ifinfomsg attributes */ | 3386 | /* Maximum length of ifinfomsg attributes */ |
@@ -3435,20 +3487,23 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
3435 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | 3487 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) |
3436 | { | 3488 | { |
3437 | struct sk_buff *skb; | 3489 | struct sk_buff *skb; |
3438 | int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE); | 3490 | int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE; |
3491 | int err = -ENOBUFS; | ||
3439 | 3492 | ||
3440 | skb = alloc_skb(size, GFP_ATOMIC); | 3493 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
3441 | if (!skb) { | 3494 | if (skb == NULL) |
3442 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, ENOBUFS); | 3495 | goto errout; |
3443 | return; | 3496 | |
3444 | } | 3497 | err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); |
3445 | if (inet6_fill_ifinfo(skb, idev, current->pid, 0, event, 0) < 0) { | 3498 | if (err < 0) { |
3446 | kfree_skb(skb); | 3499 | kfree_skb(skb); |
3447 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, EINVAL); | 3500 | goto errout; |
3448 | return; | ||
3449 | } | 3501 | } |
3450 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO; | 3502 | |
3451 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); | 3503 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3504 | errout: | ||
3505 | if (err < 0) | ||
3506 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | ||
3452 | } | 3507 | } |
3453 | 3508 | ||
3454 | /* Maximum length of prefix_cacheinfo attributes */ | 3509 | /* Maximum length of prefix_cacheinfo attributes */ |
@@ -3500,20 +3555,23 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |||
3500 | struct prefix_info *pinfo) | 3555 | struct prefix_info *pinfo) |
3501 | { | 3556 | { |
3502 | struct sk_buff *skb; | 3557 | struct sk_buff *skb; |
3503 | int size = NLMSG_SPACE(sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE); | 3558 | int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE; |
3559 | int err = -ENOBUFS; | ||
3504 | 3560 | ||
3505 | skb = alloc_skb(size, GFP_ATOMIC); | 3561 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
3506 | if (!skb) { | 3562 | if (skb == NULL) |
3507 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, ENOBUFS); | 3563 | goto errout; |
3508 | return; | 3564 | |
3509 | } | 3565 | err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); |
3510 | if (inet6_fill_prefix(skb, idev, pinfo, current->pid, 0, event, 0) < 0) { | 3566 | if (err < 0) { |
3511 | kfree_skb(skb); | 3567 | kfree_skb(skb); |
3512 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, EINVAL); | 3568 | goto errout; |
3513 | return; | ||
3514 | } | 3569 | } |
3515 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX; | 3570 | |
3516 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC); | 3571 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); |
3572 | errout: | ||
3573 | if (err < 0) | ||
3574 | rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err); | ||
3517 | } | 3575 | } |
3518 | 3576 | ||
3519 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | 3577 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { |
@@ -3528,6 +3586,9 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | |||
3528 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, | 3586 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, |
3529 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, | 3587 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, |
3530 | .dumpit = inet6_dump_fib, }, | 3588 | .dumpit = inet6_dump_fib, }, |
3589 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3590 | [RTM_GETRULE - RTM_BASE] = { .dumpit = fib6_rules_dump, }, | ||
3591 | #endif | ||
3531 | }; | 3592 | }; |
3532 | 3593 | ||
3533 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3594 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
@@ -3536,7 +3597,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3536 | 3597 | ||
3537 | switch (event) { | 3598 | switch (event) { |
3538 | case RTM_NEWADDR: | 3599 | case RTM_NEWADDR: |
3539 | ip6_ins_rt(ifp->rt, NULL, NULL, NULL); | 3600 | ip6_ins_rt(ifp->rt); |
3540 | if (ifp->idev->cnf.forwarding) | 3601 | if (ifp->idev->cnf.forwarding) |
3541 | addrconf_join_anycast(ifp); | 3602 | addrconf_join_anycast(ifp); |
3542 | break; | 3603 | break; |
@@ -3545,7 +3606,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3545 | addrconf_leave_anycast(ifp); | 3606 | addrconf_leave_anycast(ifp); |
3546 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 3607 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
3547 | dst_hold(&ifp->rt->u.dst); | 3608 | dst_hold(&ifp->rt->u.dst); |
3548 | if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) | 3609 | if (ip6_del_rt(ifp->rt)) |
3549 | dst_free(&ifp->rt->u.dst); | 3610 | dst_free(&ifp->rt->u.dst); |
3550 | break; | 3611 | break; |
3551 | } | 3612 | } |
@@ -3553,10 +3614,10 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3553 | 3614 | ||
3554 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3615 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
3555 | { | 3616 | { |
3556 | read_lock_bh(&addrconf_lock); | 3617 | rcu_read_lock_bh(); |
3557 | if (likely(ifp->idev->dead == 0)) | 3618 | if (likely(ifp->idev->dead == 0)) |
3558 | __ipv6_ifa_notify(event, ifp); | 3619 | __ipv6_ifa_notify(event, ifp); |
3559 | read_unlock_bh(&addrconf_lock); | 3620 | rcu_read_unlock_bh(); |
3560 | } | 3621 | } |
3561 | 3622 | ||
3562 | #ifdef CONFIG_SYSCTL | 3623 | #ifdef CONFIG_SYSCTL |
@@ -3653,7 +3714,7 @@ static struct addrconf_sysctl_table | |||
3653 | ctl_table addrconf_conf_dir[2]; | 3714 | ctl_table addrconf_conf_dir[2]; |
3654 | ctl_table addrconf_proto_dir[2]; | 3715 | ctl_table addrconf_proto_dir[2]; |
3655 | ctl_table addrconf_root_dir[2]; | 3716 | ctl_table addrconf_root_dir[2]; |
3656 | } addrconf_sysctl = { | 3717 | } addrconf_sysctl __read_mostly = { |
3657 | .sysctl_header = NULL, | 3718 | .sysctl_header = NULL, |
3658 | .addrconf_vars = { | 3719 | .addrconf_vars = { |
3659 | { | 3720 | { |
@@ -3843,6 +3904,14 @@ static struct addrconf_sysctl_table | |||
3843 | #endif | 3904 | #endif |
3844 | #endif | 3905 | #endif |
3845 | { | 3906 | { |
3907 | .ctl_name = NET_IPV6_PROXY_NDP, | ||
3908 | .procname = "proxy_ndp", | ||
3909 | .data = &ipv6_devconf.proxy_ndp, | ||
3910 | .maxlen = sizeof(int), | ||
3911 | .mode = 0644, | ||
3912 | .proc_handler = &proc_dointvec, | ||
3913 | }, | ||
3914 | { | ||
3846 | .ctl_name = 0, /* sentinel */ | 3915 | .ctl_name = 0, /* sentinel */ |
3847 | } | 3916 | } |
3848 | }, | 3917 | }, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index ac85e9c532c2..bf6e8aff19d4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -59,6 +59,9 @@ | |||
59 | #ifdef CONFIG_IPV6_TUNNEL | 59 | #ifdef CONFIG_IPV6_TUNNEL |
60 | #include <net/ip6_tunnel.h> | 60 | #include <net/ip6_tunnel.h> |
61 | #endif | 61 | #endif |
62 | #ifdef CONFIG_IPV6_MIP6 | ||
63 | #include <net/mip6.h> | ||
64 | #endif | ||
62 | 65 | ||
63 | #include <asm/uaccess.h> | 66 | #include <asm/uaccess.h> |
64 | #include <asm/system.h> | 67 | #include <asm/system.h> |
@@ -67,7 +70,7 @@ MODULE_AUTHOR("Cast of dozens"); | |||
67 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); | 70 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); |
68 | MODULE_LICENSE("GPL"); | 71 | MODULE_LICENSE("GPL"); |
69 | 72 | ||
70 | int sysctl_ipv6_bindv6only; | 73 | int sysctl_ipv6_bindv6only __read_mostly; |
71 | 74 | ||
72 | /* The inetsw table contains everything that inet_create needs to | 75 | /* The inetsw table contains everything that inet_create needs to |
73 | * build a new socket. | 76 | * build a new socket. |
@@ -637,6 +640,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
637 | fl.oif = sk->sk_bound_dev_if; | 640 | fl.oif = sk->sk_bound_dev_if; |
638 | fl.fl_ip_dport = inet->dport; | 641 | fl.fl_ip_dport = inet->dport; |
639 | fl.fl_ip_sport = inet->sport; | 642 | fl.fl_ip_sport = inet->sport; |
643 | security_sk_classify_flow(sk, &fl); | ||
640 | 644 | ||
641 | if (np->opt && np->opt->srcrt) { | 645 | if (np->opt && np->opt->srcrt) { |
642 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | 646 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; |
@@ -658,7 +662,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
658 | return err; | 662 | return err; |
659 | } | 663 | } |
660 | 664 | ||
661 | __ip6_dst_store(sk, dst, NULL); | 665 | __ip6_dst_store(sk, dst, NULL, NULL); |
662 | } | 666 | } |
663 | 667 | ||
664 | return 0; | 668 | return 0; |
@@ -757,6 +761,8 @@ static int __init inet6_init(void) | |||
757 | struct list_head *r; | 761 | struct list_head *r; |
758 | int err; | 762 | int err; |
759 | 763 | ||
764 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); | ||
765 | |||
760 | #ifdef MODULE | 766 | #ifdef MODULE |
761 | #if 0 /* FIXME --RR */ | 767 | #if 0 /* FIXME --RR */ |
762 | if (!mod_member_present(&__this_module, can_unload)) | 768 | if (!mod_member_present(&__this_module, can_unload)) |
@@ -766,11 +772,6 @@ static int __init inet6_init(void) | |||
766 | #endif | 772 | #endif |
767 | #endif | 773 | #endif |
768 | 774 | ||
769 | if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) { | ||
770 | printk(KERN_CRIT "inet6_proto_init: size fault\n"); | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | |||
774 | err = proto_register(&tcpv6_prot, 1); | 775 | err = proto_register(&tcpv6_prot, 1); |
775 | if (err) | 776 | if (err) |
776 | goto out; | 777 | goto out; |
@@ -856,6 +857,9 @@ static int __init inet6_init(void) | |||
856 | ipv6_frag_init(); | 857 | ipv6_frag_init(); |
857 | ipv6_nodata_init(); | 858 | ipv6_nodata_init(); |
858 | ipv6_destopt_init(); | 859 | ipv6_destopt_init(); |
860 | #ifdef CONFIG_IPV6_MIP6 | ||
861 | mip6_init(); | ||
862 | #endif | ||
859 | 863 | ||
860 | /* Init v6 transport protocols. */ | 864 | /* Init v6 transport protocols. */ |
861 | udpv6_init(); | 865 | udpv6_init(); |
@@ -919,6 +923,9 @@ static void __exit inet6_exit(void) | |||
919 | tcp6_proc_exit(); | 923 | tcp6_proc_exit(); |
920 | raw6_proc_exit(); | 924 | raw6_proc_exit(); |
921 | #endif | 925 | #endif |
926 | #ifdef CONFIG_IPV6_MIP6 | ||
927 | mip6_fini(); | ||
928 | #endif | ||
922 | /* Cleanup code parts. */ | 929 | /* Cleanup code parts. */ |
923 | sit_cleanup(); | 930 | sit_cleanup(); |
924 | ip6_flowlabel_cleanup(); | 931 | ip6_flowlabel_cleanup(); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 00ffa7bc6c9f..b0d83e8e4252 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -74,6 +74,66 @@ bad: | |||
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | #ifdef CONFIG_IPV6_MIP6 | ||
78 | /** | ||
79 | * ipv6_rearrange_destopt - rearrange IPv6 destination options header | ||
80 | * @iph: IPv6 header | ||
81 | * @destopt: destionation options header | ||
82 | */ | ||
83 | static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt) | ||
84 | { | ||
85 | u8 *opt = (u8 *)destopt; | ||
86 | int len = ipv6_optlen(destopt); | ||
87 | int off = 0; | ||
88 | int optlen = 0; | ||
89 | |||
90 | off += 2; | ||
91 | len -= 2; | ||
92 | |||
93 | while (len > 0) { | ||
94 | |||
95 | switch (opt[off]) { | ||
96 | |||
97 | case IPV6_TLV_PAD0: | ||
98 | optlen = 1; | ||
99 | break; | ||
100 | default: | ||
101 | if (len < 2) | ||
102 | goto bad; | ||
103 | optlen = opt[off+1]+2; | ||
104 | if (len < optlen) | ||
105 | goto bad; | ||
106 | |||
107 | /* Rearrange the source address in @iph and the | ||
108 | * addresses in home address option for final source. | ||
109 | * See 11.3.2 of RFC 3775 for details. | ||
110 | */ | ||
111 | if (opt[off] == IPV6_TLV_HAO) { | ||
112 | struct in6_addr final_addr; | ||
113 | struct ipv6_destopt_hao *hao; | ||
114 | |||
115 | hao = (struct ipv6_destopt_hao *)&opt[off]; | ||
116 | if (hao->length != sizeof(hao->addr)) { | ||
117 | if (net_ratelimit()) | ||
118 | printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length); | ||
119 | goto bad; | ||
120 | } | ||
121 | ipv6_addr_copy(&final_addr, &hao->addr); | ||
122 | ipv6_addr_copy(&hao->addr, &iph->saddr); | ||
123 | ipv6_addr_copy(&iph->saddr, &final_addr); | ||
124 | } | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | off += optlen; | ||
129 | len -= optlen; | ||
130 | } | ||
131 | /* Note: ok if len == 0 */ | ||
132 | bad: | ||
133 | return; | ||
134 | } | ||
135 | #endif | ||
136 | |||
77 | /** | 137 | /** |
78 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header | 138 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header |
79 | * @iph: IPv6 header | 139 | * @iph: IPv6 header |
@@ -113,7 +173,7 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) | |||
113 | ipv6_addr_copy(&iph->daddr, &final_addr); | 173 | ipv6_addr_copy(&iph->daddr, &final_addr); |
114 | } | 174 | } |
115 | 175 | ||
116 | static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) | 176 | static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) |
117 | { | 177 | { |
118 | union { | 178 | union { |
119 | struct ipv6hdr *iph; | 179 | struct ipv6hdr *iph; |
@@ -128,8 +188,12 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) | |||
128 | 188 | ||
129 | while (exthdr.raw < end) { | 189 | while (exthdr.raw < end) { |
130 | switch (nexthdr) { | 190 | switch (nexthdr) { |
131 | case NEXTHDR_HOP: | ||
132 | case NEXTHDR_DEST: | 191 | case NEXTHDR_DEST: |
192 | #ifdef CONFIG_IPV6_MIP6 | ||
193 | if (dir == XFRM_POLICY_OUT) | ||
194 | ipv6_rearrange_destopt(iph, exthdr.opth); | ||
195 | #endif | ||
196 | case NEXTHDR_HOP: | ||
133 | if (!zero_out_mutable_opts(exthdr.opth)) { | 197 | if (!zero_out_mutable_opts(exthdr.opth)) { |
134 | LIMIT_NETDEBUG( | 198 | LIMIT_NETDEBUG( |
135 | KERN_WARNING "overrun %sopts\n", | 199 | KERN_WARNING "overrun %sopts\n", |
@@ -164,6 +228,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
164 | u8 nexthdr; | 228 | u8 nexthdr; |
165 | char tmp_base[8]; | 229 | char tmp_base[8]; |
166 | struct { | 230 | struct { |
231 | #ifdef CONFIG_IPV6_MIP6 | ||
232 | struct in6_addr saddr; | ||
233 | #endif | ||
167 | struct in6_addr daddr; | 234 | struct in6_addr daddr; |
168 | char hdrs[0]; | 235 | char hdrs[0]; |
169 | } *tmp_ext; | 236 | } *tmp_ext; |
@@ -188,10 +255,15 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
188 | err = -ENOMEM; | 255 | err = -ENOMEM; |
189 | goto error; | 256 | goto error; |
190 | } | 257 | } |
258 | #ifdef CONFIG_IPV6_MIP6 | ||
259 | memcpy(tmp_ext, &top_iph->saddr, extlen); | ||
260 | #else | ||
191 | memcpy(tmp_ext, &top_iph->daddr, extlen); | 261 | memcpy(tmp_ext, &top_iph->daddr, extlen); |
262 | #endif | ||
192 | err = ipv6_clear_mutable_options(top_iph, | 263 | err = ipv6_clear_mutable_options(top_iph, |
193 | extlen - sizeof(*tmp_ext) + | 264 | extlen - sizeof(*tmp_ext) + |
194 | sizeof(*top_iph)); | 265 | sizeof(*top_iph), |
266 | XFRM_POLICY_OUT); | ||
195 | if (err) | 267 | if (err) |
196 | goto error_free_iph; | 268 | goto error_free_iph; |
197 | } | 269 | } |
@@ -222,7 +294,11 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
222 | 294 | ||
223 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); | 295 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); |
224 | if (tmp_ext) { | 296 | if (tmp_ext) { |
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | memcpy(&top_iph->saddr, tmp_ext, extlen); | ||
299 | #else | ||
225 | memcpy(&top_iph->daddr, tmp_ext, extlen); | 300 | memcpy(&top_iph->daddr, tmp_ext, extlen); |
301 | #endif | ||
226 | error_free_iph: | 302 | error_free_iph: |
227 | kfree(tmp_ext); | 303 | kfree(tmp_ext); |
228 | } | 304 | } |
@@ -282,7 +358,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
282 | if (!tmp_hdr) | 358 | if (!tmp_hdr) |
283 | goto out; | 359 | goto out; |
284 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); | 360 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); |
285 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len)) | 361 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN)) |
286 | goto free_out; | 362 | goto free_out; |
287 | skb->nh.ipv6h->priority = 0; | 363 | skb->nh.ipv6h->priority = 0; |
288 | skb->nh.ipv6h->flow_lbl[0] = 0; | 364 | skb->nh.ipv6h->flow_lbl[0] = 0; |
@@ -398,7 +474,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
398 | goto error; | 474 | goto error; |
399 | 475 | ||
400 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); | 476 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); |
401 | if (x->props.mode) | 477 | if (x->props.mode == XFRM_MODE_TUNNEL) |
402 | x->props.header_len += sizeof(struct ipv6hdr); | 478 | x->props.header_len += sizeof(struct ipv6hdr); |
403 | x->data = ahp; | 479 | x->data = ahp; |
404 | 480 | ||
@@ -435,7 +511,8 @@ static struct xfrm_type ah6_type = | |||
435 | .init_state = ah6_init_state, | 511 | .init_state = ah6_init_state, |
436 | .destructor = ah6_destroy, | 512 | .destructor = ah6_destroy, |
437 | .input = ah6_input, | 513 | .input = ah6_input, |
438 | .output = ah6_output | 514 | .output = ah6_output, |
515 | .hdr_offset = xfrm6_find_1stfragopt, | ||
439 | }; | 516 | }; |
440 | 517 | ||
441 | static struct inet6_protocol ah6_protocol = { | 518 | static struct inet6_protocol ah6_protocol = { |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f6881d7a0385..a9604764e015 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -56,7 +56,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
56 | int onlink; | 56 | int onlink; |
57 | 57 | ||
58 | onlink = 0; | 58 | onlink = 0; |
59 | read_lock(&addrconf_lock); | 59 | rcu_read_lock(); |
60 | idev = __in6_dev_get(dev); | 60 | idev = __in6_dev_get(dev); |
61 | if (idev) { | 61 | if (idev) { |
62 | read_lock_bh(&idev->lock); | 62 | read_lock_bh(&idev->lock); |
@@ -68,7 +68,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
68 | } | 68 | } |
69 | read_unlock_bh(&idev->lock); | 69 | read_unlock_bh(&idev->lock); |
70 | } | 70 | } |
71 | read_unlock(&addrconf_lock); | 71 | rcu_read_unlock(); |
72 | return onlink; | 72 | return onlink; |
73 | } | 73 | } |
74 | 74 | ||
@@ -335,7 +335,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
335 | write_unlock_bh(&idev->lock); | 335 | write_unlock_bh(&idev->lock); |
336 | 336 | ||
337 | dst_hold(&rt->u.dst); | 337 | dst_hold(&rt->u.dst); |
338 | if (ip6_ins_rt(rt, NULL, NULL, NULL)) | 338 | if (ip6_ins_rt(rt)) |
339 | dst_release(&rt->u.dst); | 339 | dst_release(&rt->u.dst); |
340 | 340 | ||
341 | addrconf_join_solict(dev, &aca->aca_addr); | 341 | addrconf_join_solict(dev, &aca->aca_addr); |
@@ -378,7 +378,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
378 | addrconf_leave_solict(idev, &aca->aca_addr); | 378 | addrconf_leave_solict(idev, &aca->aca_addr); |
379 | 379 | ||
380 | dst_hold(&aca->aca_rt->u.dst); | 380 | dst_hold(&aca->aca_rt->u.dst); |
381 | if (ip6_del_rt(aca->aca_rt, NULL, NULL, NULL)) | 381 | if (ip6_del_rt(aca->aca_rt)) |
382 | dst_free(&aca->aca_rt->u.dst); | 382 | dst_free(&aca->aca_rt->u.dst); |
383 | else | 383 | else |
384 | dst_release(&aca->aca_rt->u.dst); | 384 | dst_release(&aca->aca_rt->u.dst); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 3b55b4c8e2d1..7206747022fc 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -156,6 +156,8 @@ ipv4_connected: | |||
156 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) | 156 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) |
157 | fl.oif = np->mcast_oif; | 157 | fl.oif = np->mcast_oif; |
158 | 158 | ||
159 | security_sk_classify_flow(sk, &fl); | ||
160 | |||
159 | if (flowlabel) { | 161 | if (flowlabel) { |
160 | if (flowlabel->opt && flowlabel->opt->srcrt) { | 162 | if (flowlabel->opt && flowlabel->opt->srcrt) { |
161 | struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; | 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; |
@@ -191,7 +193,12 @@ ipv4_connected: | |||
191 | 193 | ||
192 | ip6_dst_store(sk, dst, | 194 | ip6_dst_store(sk, dst, |
193 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? | 195 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? |
194 | &np->daddr : NULL); | 196 | &np->daddr : NULL, |
197 | #ifdef CONFIG_IPV6_SUBTREES | ||
198 | ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? | ||
199 | &np->saddr : | ||
200 | #endif | ||
201 | NULL); | ||
195 | 202 | ||
196 | sk->sk_state = TCP_ESTABLISHED; | 203 | sk->sk_state = TCP_ESTABLISHED; |
197 | out: | 204 | out: |
@@ -641,10 +648,13 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
641 | 648 | ||
642 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); | 649 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); |
643 | 650 | ||
644 | /* | 651 | switch (rthdr->type) { |
645 | * TYPE 0 | 652 | case IPV6_SRCRT_TYPE_0: |
646 | */ | 653 | #ifdef CONFIG_IPV6_MIP6 |
647 | if (rthdr->type) { | 654 | case IPV6_SRCRT_TYPE_2: |
655 | #endif | ||
656 | break; | ||
657 | default: | ||
648 | err = -EINVAL; | 658 | err = -EINVAL; |
649 | goto exit_f; | 659 | goto exit_f; |
650 | } | 660 | } |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 2ebfd281e721..e78680a9985b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -99,8 +99,13 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
99 | esph->seq_no = htonl(++x->replay.oseq); | 99 | esph->seq_no = htonl(++x->replay.oseq); |
100 | xfrm_aevent_doreplay(x); | 100 | xfrm_aevent_doreplay(x); |
101 | 101 | ||
102 | if (esp->conf.ivlen) | 102 | if (esp->conf.ivlen) { |
103 | if (unlikely(!esp->conf.ivinitted)) { | ||
104 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | ||
105 | esp->conf.ivinitted = 1; | ||
106 | } | ||
103 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); | 107 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); |
108 | } | ||
104 | 109 | ||
105 | do { | 110 | do { |
106 | struct scatterlist *sg = &esp->sgbuf[0]; | 111 | struct scatterlist *sg = &esp->sgbuf[0]; |
@@ -237,7 +242,7 @@ static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) | |||
237 | struct esp_data *esp = x->data; | 242 | struct esp_data *esp = x->data; |
238 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); | 243 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
239 | 244 | ||
240 | if (x->props.mode) { | 245 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
241 | mtu = ALIGN(mtu + 2, blksize); | 246 | mtu = ALIGN(mtu + 2, blksize); |
242 | } else { | 247 | } else { |
243 | /* The worst case. */ | 248 | /* The worst case. */ |
@@ -353,12 +358,12 @@ static int esp6_init_state(struct xfrm_state *x) | |||
353 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); | 358 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); |
354 | if (unlikely(esp->conf.ivec == NULL)) | 359 | if (unlikely(esp->conf.ivec == NULL)) |
355 | goto error; | 360 | goto error; |
356 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | 361 | esp->conf.ivinitted = 0; |
357 | } | 362 | } |
358 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) | 363 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) |
359 | goto error; | 364 | goto error; |
360 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; | 365 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; |
361 | if (x->props.mode) | 366 | if (x->props.mode == XFRM_MODE_TUNNEL) |
362 | x->props.header_len += sizeof(struct ipv6hdr); | 367 | x->props.header_len += sizeof(struct ipv6hdr); |
363 | x->data = esp; | 368 | x->data = esp; |
364 | return 0; | 369 | return 0; |
@@ -379,7 +384,8 @@ static struct xfrm_type esp6_type = | |||
379 | .destructor = esp6_destroy, | 384 | .destructor = esp6_destroy, |
380 | .get_max_size = esp6_get_max_size, | 385 | .get_max_size = esp6_get_max_size, |
381 | .input = esp6_input, | 386 | .input = esp6_input, |
382 | .output = esp6_output | 387 | .output = esp6_output, |
388 | .hdr_offset = xfrm6_find_1stfragopt, | ||
383 | }; | 389 | }; |
384 | 390 | ||
385 | static struct inet6_protocol esp6_protocol = { | 391 | static struct inet6_protocol esp6_protocol = { |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 86dac106873b..88c96b10684c 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -43,9 +43,54 @@ | |||
43 | #include <net/ndisc.h> | 43 | #include <net/ndisc.h> |
44 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
45 | #include <net/addrconf.h> | 45 | #include <net/addrconf.h> |
46 | #ifdef CONFIG_IPV6_MIP6 | ||
47 | #include <net/xfrm.h> | ||
48 | #endif | ||
46 | 49 | ||
47 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
48 | 51 | ||
52 | int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | ||
53 | { | ||
54 | int packet_len = skb->tail - skb->nh.raw; | ||
55 | struct ipv6_opt_hdr *hdr; | ||
56 | int len; | ||
57 | |||
58 | if (offset + 2 > packet_len) | ||
59 | goto bad; | ||
60 | hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
61 | len = ((hdr->hdrlen + 1) << 3); | ||
62 | |||
63 | if (offset + len > packet_len) | ||
64 | goto bad; | ||
65 | |||
66 | offset += 2; | ||
67 | len -= 2; | ||
68 | |||
69 | while (len > 0) { | ||
70 | int opttype = skb->nh.raw[offset]; | ||
71 | int optlen; | ||
72 | |||
73 | if (opttype == type) | ||
74 | return offset; | ||
75 | |||
76 | switch (opttype) { | ||
77 | case IPV6_TLV_PAD0: | ||
78 | optlen = 1; | ||
79 | break; | ||
80 | default: | ||
81 | optlen = skb->nh.raw[offset + 1] + 2; | ||
82 | if (optlen > len) | ||
83 | goto bad; | ||
84 | break; | ||
85 | } | ||
86 | offset += optlen; | ||
87 | len -= optlen; | ||
88 | } | ||
89 | /* not_found */ | ||
90 | bad: | ||
91 | return -1; | ||
92 | } | ||
93 | |||
49 | /* | 94 | /* |
50 | * Parsing tlv encoded headers. | 95 | * Parsing tlv encoded headers. |
51 | * | 96 | * |
@@ -56,7 +101,7 @@ | |||
56 | 101 | ||
57 | struct tlvtype_proc { | 102 | struct tlvtype_proc { |
58 | int type; | 103 | int type; |
59 | int (*func)(struct sk_buff *skb, int offset); | 104 | int (*func)(struct sk_buff **skbp, int offset); |
60 | }; | 105 | }; |
61 | 106 | ||
62 | /********************* | 107 | /********************* |
@@ -65,8 +110,10 @@ struct tlvtype_proc { | |||
65 | 110 | ||
66 | /* An unknown option is detected, decide what to do */ | 111 | /* An unknown option is detected, decide what to do */ |
67 | 112 | ||
68 | static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | 113 | static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff) |
69 | { | 114 | { |
115 | struct sk_buff *skb = *skbp; | ||
116 | |||
70 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { | 117 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { |
71 | case 0: /* ignore */ | 118 | case 0: /* ignore */ |
72 | return 1; | 119 | return 1; |
@@ -91,8 +138,9 @@ static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | |||
91 | 138 | ||
92 | /* Parse tlv encoded option header (hop-by-hop or destination) */ | 139 | /* Parse tlv encoded option header (hop-by-hop or destination) */ |
93 | 140 | ||
94 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | 141 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp) |
95 | { | 142 | { |
143 | struct sk_buff *skb = *skbp; | ||
96 | struct tlvtype_proc *curr; | 144 | struct tlvtype_proc *curr; |
97 | int off = skb->h.raw - skb->nh.raw; | 145 | int off = skb->h.raw - skb->nh.raw; |
98 | int len = ((skb->h.raw[1]+1)<<3); | 146 | int len = ((skb->h.raw[1]+1)<<3); |
@@ -122,13 +170,13 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | |||
122 | /* type specific length/alignment | 170 | /* type specific length/alignment |
123 | checks will be performed in the | 171 | checks will be performed in the |
124 | func(). */ | 172 | func(). */ |
125 | if (curr->func(skb, off) == 0) | 173 | if (curr->func(skbp, off) == 0) |
126 | return 0; | 174 | return 0; |
127 | break; | 175 | break; |
128 | } | 176 | } |
129 | } | 177 | } |
130 | if (curr->type < 0) { | 178 | if (curr->type < 0) { |
131 | if (ip6_tlvopt_unknown(skb, off) == 0) | 179 | if (ip6_tlvopt_unknown(skbp, off) == 0) |
132 | return 0; | 180 | return 0; |
133 | } | 181 | } |
134 | break; | 182 | break; |
@@ -147,8 +195,85 @@ bad: | |||
147 | Destination options header. | 195 | Destination options header. |
148 | *****************************/ | 196 | *****************************/ |
149 | 197 | ||
198 | #ifdef CONFIG_IPV6_MIP6 | ||
199 | static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) | ||
200 | { | ||
201 | struct sk_buff *skb = *skbp; | ||
202 | struct ipv6_destopt_hao *hao; | ||
203 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
204 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw; | ||
205 | struct in6_addr tmp_addr; | ||
206 | int ret; | ||
207 | |||
208 | if (opt->dsthao) { | ||
209 | LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n"); | ||
210 | goto discard; | ||
211 | } | ||
212 | opt->dsthao = opt->dst1; | ||
213 | opt->dst1 = 0; | ||
214 | |||
215 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff); | ||
216 | |||
217 | if (hao->length != 16) { | ||
218 | LIMIT_NETDEBUG( | ||
219 | KERN_DEBUG "hao invalid option length = %d\n", hao->length); | ||
220 | goto discard; | ||
221 | } | ||
222 | |||
223 | if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { | ||
224 | LIMIT_NETDEBUG( | ||
225 | KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr)); | ||
226 | goto discard; | ||
227 | } | ||
228 | |||
229 | ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr, | ||
230 | (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); | ||
231 | if (unlikely(ret < 0)) | ||
232 | goto discard; | ||
233 | |||
234 | if (skb_cloned(skb)) { | ||
235 | struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); | ||
236 | struct inet6_skb_parm *opt2; | ||
237 | |||
238 | if (skb2 == NULL) | ||
239 | goto discard; | ||
240 | |||
241 | opt2 = IP6CB(skb2); | ||
242 | memcpy(opt2, opt, sizeof(*opt2)); | ||
243 | |||
244 | kfree_skb(skb); | ||
245 | |||
246 | /* update all variable using below by copied skbuff */ | ||
247 | *skbp = skb = skb2; | ||
248 | hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff); | ||
249 | ipv6h = (struct ipv6hdr *)skb2->nh.raw; | ||
250 | } | ||
251 | |||
252 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
253 | skb->ip_summed = CHECKSUM_NONE; | ||
254 | |||
255 | ipv6_addr_copy(&tmp_addr, &ipv6h->saddr); | ||
256 | ipv6_addr_copy(&ipv6h->saddr, &hao->addr); | ||
257 | ipv6_addr_copy(&hao->addr, &tmp_addr); | ||
258 | |||
259 | if (skb->tstamp.off_sec == 0) | ||
260 | __net_timestamp(skb); | ||
261 | |||
262 | return 1; | ||
263 | |||
264 | discard: | ||
265 | kfree_skb(skb); | ||
266 | return 0; | ||
267 | } | ||
268 | #endif | ||
269 | |||
150 | static struct tlvtype_proc tlvprocdestopt_lst[] = { | 270 | static struct tlvtype_proc tlvprocdestopt_lst[] = { |
151 | /* No destination options are defined now */ | 271 | #ifdef CONFIG_IPV6_MIP6 |
272 | { | ||
273 | .type = IPV6_TLV_HAO, | ||
274 | .func = ipv6_dest_hao, | ||
275 | }, | ||
276 | #endif | ||
152 | {-1, NULL} | 277 | {-1, NULL} |
153 | }; | 278 | }; |
154 | 279 | ||
@@ -156,6 +281,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
156 | { | 281 | { |
157 | struct sk_buff *skb = *skbp; | 282 | struct sk_buff *skb = *skbp; |
158 | struct inet6_skb_parm *opt = IP6CB(skb); | 283 | struct inet6_skb_parm *opt = IP6CB(skb); |
284 | #ifdef CONFIG_IPV6_MIP6 | ||
285 | __u16 dstbuf; | ||
286 | #endif | ||
159 | 287 | ||
160 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 288 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
161 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 289 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
@@ -166,10 +294,19 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
166 | 294 | ||
167 | opt->lastopt = skb->h.raw - skb->nh.raw; | 295 | opt->lastopt = skb->h.raw - skb->nh.raw; |
168 | opt->dst1 = skb->h.raw - skb->nh.raw; | 296 | opt->dst1 = skb->h.raw - skb->nh.raw; |
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | dstbuf = opt->dst1; | ||
299 | #endif | ||
169 | 300 | ||
170 | if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { | 301 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { |
302 | skb = *skbp; | ||
171 | skb->h.raw += ((skb->h.raw[1]+1)<<3); | 303 | skb->h.raw += ((skb->h.raw[1]+1)<<3); |
304 | opt = IP6CB(skb); | ||
305 | #ifdef CONFIG_IPV6_MIP6 | ||
306 | opt->nhoff = dstbuf; | ||
307 | #else | ||
172 | opt->nhoff = opt->dst1; | 308 | opt->nhoff = opt->dst1; |
309 | #endif | ||
173 | return 1; | 310 | return 1; |
174 | } | 311 | } |
175 | 312 | ||
@@ -219,7 +356,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
219 | { | 356 | { |
220 | struct sk_buff *skb = *skbp; | 357 | struct sk_buff *skb = *skbp; |
221 | struct inet6_skb_parm *opt = IP6CB(skb); | 358 | struct inet6_skb_parm *opt = IP6CB(skb); |
222 | struct in6_addr *addr; | 359 | struct in6_addr *addr = NULL; |
223 | struct in6_addr daddr; | 360 | struct in6_addr daddr; |
224 | int n, i; | 361 | int n, i; |
225 | 362 | ||
@@ -244,6 +381,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
244 | 381 | ||
245 | looped_back: | 382 | looped_back: |
246 | if (hdr->segments_left == 0) { | 383 | if (hdr->segments_left == 0) { |
384 | switch (hdr->type) { | ||
385 | #ifdef CONFIG_IPV6_MIP6 | ||
386 | case IPV6_SRCRT_TYPE_2: | ||
387 | /* Silently discard type 2 header unless it was | ||
388 | * processed by own | ||
389 | */ | ||
390 | if (!addr) { | ||
391 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
392 | kfree_skb(skb); | ||
393 | return -1; | ||
394 | } | ||
395 | break; | ||
396 | #endif | ||
397 | default: | ||
398 | break; | ||
399 | } | ||
400 | |||
247 | opt->lastopt = skb->h.raw - skb->nh.raw; | 401 | opt->lastopt = skb->h.raw - skb->nh.raw; |
248 | opt->srcrt = skb->h.raw - skb->nh.raw; | 402 | opt->srcrt = skb->h.raw - skb->nh.raw; |
249 | skb->h.raw += (hdr->hdrlen + 1) << 3; | 403 | skb->h.raw += (hdr->hdrlen + 1) << 3; |
@@ -253,17 +407,29 @@ looped_back: | |||
253 | return 1; | 407 | return 1; |
254 | } | 408 | } |
255 | 409 | ||
256 | if (hdr->type != IPV6_SRCRT_TYPE_0) { | 410 | switch (hdr->type) { |
411 | case IPV6_SRCRT_TYPE_0: | ||
412 | if (hdr->hdrlen & 0x01) { | ||
413 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
414 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
415 | return -1; | ||
416 | } | ||
417 | break; | ||
418 | #ifdef CONFIG_IPV6_MIP6 | ||
419 | case IPV6_SRCRT_TYPE_2: | ||
420 | /* Silently discard invalid RTH type 2 */ | ||
421 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { | ||
422 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
423 | kfree_skb(skb); | ||
424 | return -1; | ||
425 | } | ||
426 | break; | ||
427 | #endif | ||
428 | default: | ||
257 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 429 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
258 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | 430 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); |
259 | return -1; | 431 | return -1; |
260 | } | 432 | } |
261 | |||
262 | if (hdr->hdrlen & 0x01) { | ||
263 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
264 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
265 | return -1; | ||
266 | } | ||
267 | 433 | ||
268 | /* | 434 | /* |
269 | * This is the routing header forwarding algorithm from | 435 | * This is the routing header forwarding algorithm from |
@@ -294,7 +460,7 @@ looped_back: | |||
294 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; | 460 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; |
295 | } | 461 | } |
296 | 462 | ||
297 | if (skb->ip_summed == CHECKSUM_HW) | 463 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
298 | skb->ip_summed = CHECKSUM_NONE; | 464 | skb->ip_summed = CHECKSUM_NONE; |
299 | 465 | ||
300 | i = n - --hdr->segments_left; | 466 | i = n - --hdr->segments_left; |
@@ -303,6 +469,27 @@ looped_back: | |||
303 | addr = rthdr->addr; | 469 | addr = rthdr->addr; |
304 | addr += i - 1; | 470 | addr += i - 1; |
305 | 471 | ||
472 | switch (hdr->type) { | ||
473 | #ifdef CONFIG_IPV6_MIP6 | ||
474 | case IPV6_SRCRT_TYPE_2: | ||
475 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | ||
476 | (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
477 | IPPROTO_ROUTING) < 0) { | ||
478 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
479 | kfree_skb(skb); | ||
480 | return -1; | ||
481 | } | ||
482 | if (!ipv6_chk_home_addr(addr)) { | ||
483 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
484 | kfree_skb(skb); | ||
485 | return -1; | ||
486 | } | ||
487 | break; | ||
488 | #endif | ||
489 | default: | ||
490 | break; | ||
491 | } | ||
492 | |||
306 | if (ipv6_addr_is_multicast(addr)) { | 493 | if (ipv6_addr_is_multicast(addr)) { |
307 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 494 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); |
308 | kfree_skb(skb); | 495 | kfree_skb(skb); |
@@ -421,8 +608,10 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr); | |||
421 | 608 | ||
422 | /* Router Alert as of RFC 2711 */ | 609 | /* Router Alert as of RFC 2711 */ |
423 | 610 | ||
424 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | 611 | static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) |
425 | { | 612 | { |
613 | struct sk_buff *skb = *skbp; | ||
614 | |||
426 | if (skb->nh.raw[optoff+1] == 2) { | 615 | if (skb->nh.raw[optoff+1] == 2) { |
427 | IP6CB(skb)->ra = optoff; | 616 | IP6CB(skb)->ra = optoff; |
428 | return 1; | 617 | return 1; |
@@ -435,8 +624,9 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
435 | 624 | ||
436 | /* Jumbo payload */ | 625 | /* Jumbo payload */ |
437 | 626 | ||
438 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) | 627 | static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff) |
439 | { | 628 | { |
629 | struct sk_buff *skb = *skbp; | ||
440 | u32 pkt_len; | 630 | u32 pkt_len; |
441 | 631 | ||
442 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { | 632 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { |
@@ -485,8 +675,9 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { | |||
485 | { -1, } | 675 | { -1, } |
486 | }; | 676 | }; |
487 | 677 | ||
488 | int ipv6_parse_hopopts(struct sk_buff *skb) | 678 | int ipv6_parse_hopopts(struct sk_buff **skbp) |
489 | { | 679 | { |
680 | struct sk_buff *skb = *skbp; | ||
490 | struct inet6_skb_parm *opt = IP6CB(skb); | 681 | struct inet6_skb_parm *opt = IP6CB(skb); |
491 | 682 | ||
492 | /* | 683 | /* |
@@ -502,8 +693,10 @@ int ipv6_parse_hopopts(struct sk_buff *skb) | |||
502 | } | 693 | } |
503 | 694 | ||
504 | opt->hop = sizeof(struct ipv6hdr); | 695 | opt->hop = sizeof(struct ipv6hdr); |
505 | if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { | 696 | if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) { |
697 | skb = *skbp; | ||
506 | skb->h.raw += (skb->h.raw[1]+1)<<3; | 698 | skb->h.raw += (skb->h.raw[1]+1)<<3; |
699 | opt = IP6CB(skb); | ||
507 | opt->nhoff = sizeof(struct ipv6hdr); | 700 | opt->nhoff = sizeof(struct ipv6hdr); |
508 | return 1; | 701 | return 1; |
509 | } | 702 | } |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c new file mode 100644 index 000000000000..34f5bfaddfc2 --- /dev/null +++ b/net/ipv6/fib6_rules.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * net/ipv6/fib6_rules.c IPv6 Routing Policy Rules | ||
3 | * | ||
4 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
5 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation, version 2. | ||
10 | * | ||
11 | * Authors | ||
12 | * Thomas Graf <tgraf@suug.ch> | ||
13 | * Ville Nuorvala <vnuorval@tcs.hut.fi> | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | |||
19 | #include <net/fib_rules.h> | ||
20 | #include <net/ipv6.h> | ||
21 | #include <net/ip6_route.h> | ||
22 | #include <net/netlink.h> | ||
23 | |||
24 | struct fib6_rule | ||
25 | { | ||
26 | struct fib_rule common; | ||
27 | struct rt6key src; | ||
28 | struct rt6key dst; | ||
29 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
30 | u32 fwmark; | ||
31 | u32 fwmask; | ||
32 | #endif | ||
33 | u8 tclass; | ||
34 | }; | ||
35 | |||
36 | static struct fib_rules_ops fib6_rules_ops; | ||
37 | |||
38 | static struct fib6_rule main_rule = { | ||
39 | .common = { | ||
40 | .refcnt = ATOMIC_INIT(2), | ||
41 | .pref = 0x7FFE, | ||
42 | .action = FR_ACT_TO_TBL, | ||
43 | .table = RT6_TABLE_MAIN, | ||
44 | }, | ||
45 | }; | ||
46 | |||
47 | static struct fib6_rule local_rule = { | ||
48 | .common = { | ||
49 | .refcnt = ATOMIC_INIT(2), | ||
50 | .pref = 0, | ||
51 | .action = FR_ACT_TO_TBL, | ||
52 | .table = RT6_TABLE_LOCAL, | ||
53 | .flags = FIB_RULE_PERMANENT, | ||
54 | }, | ||
55 | }; | ||
56 | |||
57 | static LIST_HEAD(fib6_rules); | ||
58 | |||
59 | struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, | ||
60 | pol_lookup_t lookup) | ||
61 | { | ||
62 | struct fib_lookup_arg arg = { | ||
63 | .lookup_ptr = lookup, | ||
64 | }; | ||
65 | |||
66 | fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg); | ||
67 | if (arg.rule) | ||
68 | fib_rule_put(arg.rule); | ||
69 | |||
70 | if (arg.result) | ||
71 | return (struct dst_entry *) arg.result; | ||
72 | |||
73 | dst_hold(&ip6_null_entry.u.dst); | ||
74 | return &ip6_null_entry.u.dst; | ||
75 | } | ||
76 | |||
77 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | ||
78 | int flags, struct fib_lookup_arg *arg) | ||
79 | { | ||
80 | struct rt6_info *rt = NULL; | ||
81 | struct fib6_table *table; | ||
82 | pol_lookup_t lookup = arg->lookup_ptr; | ||
83 | |||
84 | switch (rule->action) { | ||
85 | case FR_ACT_TO_TBL: | ||
86 | break; | ||
87 | case FR_ACT_UNREACHABLE: | ||
88 | rt = &ip6_null_entry; | ||
89 | goto discard_pkt; | ||
90 | default: | ||
91 | case FR_ACT_BLACKHOLE: | ||
92 | rt = &ip6_blk_hole_entry; | ||
93 | goto discard_pkt; | ||
94 | case FR_ACT_PROHIBIT: | ||
95 | rt = &ip6_prohibit_entry; | ||
96 | goto discard_pkt; | ||
97 | } | ||
98 | |||
99 | table = fib6_get_table(rule->table); | ||
100 | if (table) | ||
101 | rt = lookup(table, flp, flags); | ||
102 | |||
103 | if (rt != &ip6_null_entry) | ||
104 | goto out; | ||
105 | dst_release(&rt->u.dst); | ||
106 | rt = NULL; | ||
107 | goto out; | ||
108 | |||
109 | discard_pkt: | ||
110 | dst_hold(&rt->u.dst); | ||
111 | out: | ||
112 | arg->result = rt; | ||
113 | return rt == NULL ? -EAGAIN : 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | ||
118 | { | ||
119 | struct fib6_rule *r = (struct fib6_rule *) rule; | ||
120 | |||
121 | if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) | ||
122 | return 0; | ||
123 | |||
124 | if ((flags & RT6_LOOKUP_F_HAS_SADDR) && | ||
125 | !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) | ||
126 | return 0; | ||
127 | |||
128 | if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) | ||
129 | return 0; | ||
130 | |||
131 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
132 | if ((r->fwmark ^ fl->fl6_fwmark) & r->fwmask) | ||
133 | return 0; | ||
134 | #endif | ||
135 | |||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { | ||
140 | [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | ||
141 | [FRA_PRIORITY] = { .type = NLA_U32 }, | ||
142 | [FRA_SRC] = { .len = sizeof(struct in6_addr) }, | ||
143 | [FRA_DST] = { .len = sizeof(struct in6_addr) }, | ||
144 | [FRA_FWMARK] = { .type = NLA_U32 }, | ||
145 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
146 | [FRA_TABLE] = { .type = NLA_U32 }, | ||
147 | }; | ||
148 | |||
149 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | ||
150 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh, | ||
151 | struct nlattr **tb) | ||
152 | { | ||
153 | int err = -EINVAL; | ||
154 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
155 | |||
156 | if (frh->src_len > 128 || frh->dst_len > 128 || | ||
157 | (frh->tos & ~IPV6_FLOWINFO_MASK)) | ||
158 | goto errout; | ||
159 | |||
160 | if (rule->action == FR_ACT_TO_TBL) { | ||
161 | if (rule->table == RT6_TABLE_UNSPEC) | ||
162 | goto errout; | ||
163 | |||
164 | if (fib6_new_table(rule->table) == NULL) { | ||
165 | err = -ENOBUFS; | ||
166 | goto errout; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (tb[FRA_SRC]) | ||
171 | nla_memcpy(&rule6->src.addr, tb[FRA_SRC], | ||
172 | sizeof(struct in6_addr)); | ||
173 | |||
174 | if (tb[FRA_DST]) | ||
175 | nla_memcpy(&rule6->dst.addr, tb[FRA_DST], | ||
176 | sizeof(struct in6_addr)); | ||
177 | |||
178 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
179 | if (tb[FRA_FWMARK]) { | ||
180 | rule6->fwmark = nla_get_u32(tb[FRA_FWMARK]); | ||
181 | if (rule6->fwmark) { | ||
182 | /* | ||
183 | * if the mark value is non-zero, | ||
184 | * all bits are compared by default | ||
185 | * unless a mask is explicitly specified. | ||
186 | */ | ||
187 | rule6->fwmask = 0xFFFFFFFF; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | if (tb[FRA_FWMASK]) | ||
192 | rule6->fwmask = nla_get_u32(tb[FRA_FWMASK]); | ||
193 | #endif | ||
194 | |||
195 | rule6->src.plen = frh->src_len; | ||
196 | rule6->dst.plen = frh->dst_len; | ||
197 | rule6->tclass = frh->tos; | ||
198 | |||
199 | err = 0; | ||
200 | errout: | ||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | ||
205 | struct nlattr **tb) | ||
206 | { | ||
207 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
208 | |||
209 | if (frh->src_len && (rule6->src.plen != frh->src_len)) | ||
210 | return 0; | ||
211 | |||
212 | if (frh->dst_len && (rule6->dst.plen != frh->dst_len)) | ||
213 | return 0; | ||
214 | |||
215 | if (frh->tos && (rule6->tclass != frh->tos)) | ||
216 | return 0; | ||
217 | |||
218 | if (tb[FRA_SRC] && | ||
219 | nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) | ||
220 | return 0; | ||
221 | |||
222 | if (tb[FRA_DST] && | ||
223 | nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) | ||
224 | return 0; | ||
225 | |||
226 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
227 | if (tb[FRA_FWMARK] && (rule6->fwmark != nla_get_u32(tb[FRA_FWMARK]))) | ||
228 | return 0; | ||
229 | |||
230 | if (tb[FRA_FWMASK] && (rule6->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
231 | return 0; | ||
232 | #endif | ||
233 | |||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | ||
238 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh) | ||
239 | { | ||
240 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
241 | |||
242 | frh->family = AF_INET6; | ||
243 | frh->dst_len = rule6->dst.plen; | ||
244 | frh->src_len = rule6->src.plen; | ||
245 | frh->tos = rule6->tclass; | ||
246 | |||
247 | if (rule6->dst.plen) | ||
248 | NLA_PUT(skb, FRA_DST, sizeof(struct in6_addr), | ||
249 | &rule6->dst.addr); | ||
250 | |||
251 | if (rule6->src.plen) | ||
252 | NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr), | ||
253 | &rule6->src.addr); | ||
254 | |||
255 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
256 | if (rule6->fwmark) | ||
257 | NLA_PUT_U32(skb, FRA_FWMARK, rule6->fwmark); | ||
258 | |||
259 | if (rule6->fwmask || rule6->fwmark) | ||
260 | NLA_PUT_U32(skb, FRA_FWMASK, rule6->fwmask); | ||
261 | #endif | ||
262 | |||
263 | return 0; | ||
264 | |||
265 | nla_put_failure: | ||
266 | return -ENOBUFS; | ||
267 | } | ||
268 | |||
269 | int fib6_rules_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
270 | { | ||
271 | return fib_rules_dump(skb, cb, AF_INET6); | ||
272 | } | ||
273 | |||
274 | static u32 fib6_rule_default_pref(void) | ||
275 | { | ||
276 | return 0x3FFF; | ||
277 | } | ||
278 | |||
279 | static struct fib_rules_ops fib6_rules_ops = { | ||
280 | .family = AF_INET6, | ||
281 | .rule_size = sizeof(struct fib6_rule), | ||
282 | .action = fib6_rule_action, | ||
283 | .match = fib6_rule_match, | ||
284 | .configure = fib6_rule_configure, | ||
285 | .compare = fib6_rule_compare, | ||
286 | .fill = fib6_rule_fill, | ||
287 | .default_pref = fib6_rule_default_pref, | ||
288 | .nlgroup = RTNLGRP_IPV6_RULE, | ||
289 | .policy = fib6_rule_policy, | ||
290 | .rules_list = &fib6_rules, | ||
291 | .owner = THIS_MODULE, | ||
292 | }; | ||
293 | |||
294 | void __init fib6_rules_init(void) | ||
295 | { | ||
296 | list_add_tail(&local_rule.common.list, &fib6_rules); | ||
297 | list_add_tail(&main_rule.common.list, &fib6_rules); | ||
298 | |||
299 | fib_rules_register(&fib6_rules_ops); | ||
300 | } | ||
301 | |||
302 | void fib6_rules_cleanup(void) | ||
303 | { | ||
304 | fib_rules_unregister(&fib6_rules_ops); | ||
305 | } | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 356a8a7ef22a..4ec876066b3f 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -151,7 +151,7 @@ static int is_ineligible(struct sk_buff *skb) | |||
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static int sysctl_icmpv6_time = 1*HZ; | 154 | static int sysctl_icmpv6_time __read_mostly = 1*HZ; |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * Check the ICMP output rate limit | 157 | * Check the ICMP output rate limit |
@@ -273,6 +273,29 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st | |||
273 | return 0; | 273 | return 0; |
274 | } | 274 | } |
275 | 275 | ||
276 | #ifdef CONFIG_IPV6_MIP6 | ||
277 | static void mip6_addr_swap(struct sk_buff *skb) | ||
278 | { | ||
279 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
280 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
281 | struct ipv6_destopt_hao *hao; | ||
282 | struct in6_addr tmp; | ||
283 | int off; | ||
284 | |||
285 | if (opt->dsthao) { | ||
286 | off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
287 | if (likely(off >= 0)) { | ||
288 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + off); | ||
289 | ipv6_addr_copy(&tmp, &iph->saddr); | ||
290 | ipv6_addr_copy(&iph->saddr, &hao->addr); | ||
291 | ipv6_addr_copy(&hao->addr, &tmp); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | #else | ||
296 | static inline void mip6_addr_swap(struct sk_buff *skb) {} | ||
297 | #endif | ||
298 | |||
276 | /* | 299 | /* |
277 | * Send an ICMP message in response to a packet in error | 300 | * Send an ICMP message in response to a packet in error |
278 | */ | 301 | */ |
@@ -350,6 +373,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
350 | return; | 373 | return; |
351 | } | 374 | } |
352 | 375 | ||
376 | mip6_addr_swap(skb); | ||
377 | |||
353 | memset(&fl, 0, sizeof(fl)); | 378 | memset(&fl, 0, sizeof(fl)); |
354 | fl.proto = IPPROTO_ICMPV6; | 379 | fl.proto = IPPROTO_ICMPV6; |
355 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); | 380 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); |
@@ -358,6 +383,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
358 | fl.oif = iif; | 383 | fl.oif = iif; |
359 | fl.fl_icmp_type = type; | 384 | fl.fl_icmp_type = type; |
360 | fl.fl_icmp_code = code; | 385 | fl.fl_icmp_code = code; |
386 | security_skb_classify_flow(skb, &fl); | ||
361 | 387 | ||
362 | if (icmpv6_xmit_lock()) | 388 | if (icmpv6_xmit_lock()) |
363 | return; | 389 | return; |
@@ -472,6 +498,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
472 | ipv6_addr_copy(&fl.fl6_src, saddr); | 498 | ipv6_addr_copy(&fl.fl6_src, saddr); |
473 | fl.oif = skb->dev->ifindex; | 499 | fl.oif = skb->dev->ifindex; |
474 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; | 500 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; |
501 | security_skb_classify_flow(skb, &fl); | ||
475 | 502 | ||
476 | if (icmpv6_xmit_lock()) | 503 | if (icmpv6_xmit_lock()) |
477 | return; | 504 | return; |
@@ -604,7 +631,7 @@ static int icmpv6_rcv(struct sk_buff **pskb) | |||
604 | 631 | ||
605 | /* Perform checksum. */ | 632 | /* Perform checksum. */ |
606 | switch (skb->ip_summed) { | 633 | switch (skb->ip_summed) { |
607 | case CHECKSUM_HW: | 634 | case CHECKSUM_COMPLETE: |
608 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 635 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, |
609 | skb->csum)) | 636 | skb->csum)) |
610 | break; | 637 | break; |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index bf491077b822..827f41d1478b 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -157,6 +157,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
157 | fl.oif = sk->sk_bound_dev_if; | 157 | fl.oif = sk->sk_bound_dev_if; |
158 | fl.fl_ip_sport = inet->sport; | 158 | fl.fl_ip_sport = inet->sport; |
159 | fl.fl_ip_dport = inet->dport; | 159 | fl.fl_ip_dport = inet->dport; |
160 | security_sk_classify_flow(sk, &fl); | ||
160 | 161 | ||
161 | if (np->opt && np->opt->srcrt) { | 162 | if (np->opt && np->opt->srcrt) { |
162 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
@@ -185,7 +186,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
185 | return err; | 186 | return err; |
186 | } | 187 | } |
187 | 188 | ||
188 | __ip6_dst_store(sk, dst, NULL); | 189 | __ip6_dst_store(sk, dst, NULL, NULL); |
189 | } | 190 | } |
190 | 191 | ||
191 | skb->dst = dst_clone(dst); | 192 | skb->dst = dst_clone(dst); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 764221220afd..8fcae7a6510b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Yuji SEKIYA @USAGI: Support default route on router node; | 18 | * Yuji SEKIYA @USAGI: Support default route on router node; |
19 | * remove ip6_null_entry from the top of | 19 | * remove ip6_null_entry from the top of |
20 | * routing table. | 20 | * routing table. |
21 | * Ville Nuorvala: Fixed routing subtrees. | ||
21 | */ | 22 | */ |
22 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
23 | #include <linux/types.h> | 24 | #include <linux/types.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <linux/netdevice.h> | 27 | #include <linux/netdevice.h> |
27 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/list.h> | ||
29 | 31 | ||
30 | #ifdef CONFIG_PROC_FS | 32 | #ifdef CONFIG_PROC_FS |
31 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
@@ -68,19 +70,19 @@ struct fib6_cleaner_t | |||
68 | void *arg; | 70 | void *arg; |
69 | }; | 71 | }; |
70 | 72 | ||
71 | DEFINE_RWLOCK(fib6_walker_lock); | 73 | static DEFINE_RWLOCK(fib6_walker_lock); |
72 | |||
73 | 74 | ||
74 | #ifdef CONFIG_IPV6_SUBTREES | 75 | #ifdef CONFIG_IPV6_SUBTREES |
75 | #define FWS_INIT FWS_S | 76 | #define FWS_INIT FWS_S |
76 | #define SUBTREE(fn) ((fn)->subtree) | ||
77 | #else | 77 | #else |
78 | #define FWS_INIT FWS_L | 78 | #define FWS_INIT FWS_L |
79 | #define SUBTREE(fn) NULL | ||
80 | #endif | 79 | #endif |
81 | 80 | ||
82 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); | 81 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); |
82 | static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); | ||
83 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); | 83 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); |
84 | static int fib6_walk(struct fib6_walker_t *w); | ||
85 | static int fib6_walk_continue(struct fib6_walker_t *w); | ||
84 | 86 | ||
85 | /* | 87 | /* |
86 | * A routing update causes an increase of the serial number on the | 88 | * A routing update causes an increase of the serial number on the |
@@ -93,13 +95,31 @@ static __u32 rt_sernum; | |||
93 | 95 | ||
94 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); | 96 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); |
95 | 97 | ||
96 | struct fib6_walker_t fib6_walker_list = { | 98 | static struct fib6_walker_t fib6_walker_list = { |
97 | .prev = &fib6_walker_list, | 99 | .prev = &fib6_walker_list, |
98 | .next = &fib6_walker_list, | 100 | .next = &fib6_walker_list, |
99 | }; | 101 | }; |
100 | 102 | ||
101 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) | 103 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) |
102 | 104 | ||
105 | static inline void fib6_walker_link(struct fib6_walker_t *w) | ||
106 | { | ||
107 | write_lock_bh(&fib6_walker_lock); | ||
108 | w->next = fib6_walker_list.next; | ||
109 | w->prev = &fib6_walker_list; | ||
110 | w->next->prev = w; | ||
111 | w->prev->next = w; | ||
112 | write_unlock_bh(&fib6_walker_lock); | ||
113 | } | ||
114 | |||
115 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | ||
116 | { | ||
117 | write_lock_bh(&fib6_walker_lock); | ||
118 | w->next->prev = w->prev; | ||
119 | w->prev->next = w->next; | ||
120 | w->prev = w->next = w; | ||
121 | write_unlock_bh(&fib6_walker_lock); | ||
122 | } | ||
103 | static __inline__ u32 fib6_new_sernum(void) | 123 | static __inline__ u32 fib6_new_sernum(void) |
104 | { | 124 | { |
105 | u32 n = ++rt_sernum; | 125 | u32 n = ++rt_sernum; |
@@ -147,6 +167,253 @@ static __inline__ void rt6_release(struct rt6_info *rt) | |||
147 | dst_free(&rt->u.dst); | 167 | dst_free(&rt->u.dst); |
148 | } | 168 | } |
149 | 169 | ||
170 | static struct fib6_table fib6_main_tbl = { | ||
171 | .tb6_id = RT6_TABLE_MAIN, | ||
172 | .tb6_lock = RW_LOCK_UNLOCKED, | ||
173 | .tb6_root = { | ||
174 | .leaf = &ip6_null_entry, | ||
175 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
180 | #define FIB_TABLE_HASHSZ 256 | ||
181 | #else | ||
182 | #define FIB_TABLE_HASHSZ 1 | ||
183 | #endif | ||
184 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
185 | |||
186 | static void fib6_link_table(struct fib6_table *tb) | ||
187 | { | ||
188 | unsigned int h; | ||
189 | |||
190 | h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1); | ||
191 | |||
192 | /* | ||
193 | * No protection necessary, this is the only list mutatation | ||
194 | * operation, tables never disappear once they exist. | ||
195 | */ | ||
196 | hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); | ||
197 | } | ||
198 | |||
199 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
200 | static struct fib6_table fib6_local_tbl = { | ||
201 | .tb6_id = RT6_TABLE_LOCAL, | ||
202 | .tb6_lock = RW_LOCK_UNLOCKED, | ||
203 | .tb6_root = { | ||
204 | .leaf = &ip6_null_entry, | ||
205 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
206 | }, | ||
207 | }; | ||
208 | |||
209 | static struct fib6_table *fib6_alloc_table(u32 id) | ||
210 | { | ||
211 | struct fib6_table *table; | ||
212 | |||
213 | table = kzalloc(sizeof(*table), GFP_ATOMIC); | ||
214 | if (table != NULL) { | ||
215 | table->tb6_id = id; | ||
216 | table->tb6_lock = RW_LOCK_UNLOCKED; | ||
217 | table->tb6_root.leaf = &ip6_null_entry; | ||
218 | table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; | ||
219 | } | ||
220 | |||
221 | return table; | ||
222 | } | ||
223 | |||
224 | struct fib6_table *fib6_new_table(u32 id) | ||
225 | { | ||
226 | struct fib6_table *tb; | ||
227 | |||
228 | if (id == 0) | ||
229 | id = RT6_TABLE_MAIN; | ||
230 | tb = fib6_get_table(id); | ||
231 | if (tb) | ||
232 | return tb; | ||
233 | |||
234 | tb = fib6_alloc_table(id); | ||
235 | if (tb != NULL) | ||
236 | fib6_link_table(tb); | ||
237 | |||
238 | return tb; | ||
239 | } | ||
240 | |||
241 | struct fib6_table *fib6_get_table(u32 id) | ||
242 | { | ||
243 | struct fib6_table *tb; | ||
244 | struct hlist_node *node; | ||
245 | unsigned int h; | ||
246 | |||
247 | if (id == 0) | ||
248 | id = RT6_TABLE_MAIN; | ||
249 | h = id & (FIB_TABLE_HASHSZ - 1); | ||
250 | rcu_read_lock(); | ||
251 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) { | ||
252 | if (tb->tb6_id == id) { | ||
253 | rcu_read_unlock(); | ||
254 | return tb; | ||
255 | } | ||
256 | } | ||
257 | rcu_read_unlock(); | ||
258 | |||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | static void __init fib6_tables_init(void) | ||
263 | { | ||
264 | fib6_link_table(&fib6_main_tbl); | ||
265 | fib6_link_table(&fib6_local_tbl); | ||
266 | } | ||
267 | |||
268 | #else | ||
269 | |||
270 | struct fib6_table *fib6_new_table(u32 id) | ||
271 | { | ||
272 | return fib6_get_table(id); | ||
273 | } | ||
274 | |||
275 | struct fib6_table *fib6_get_table(u32 id) | ||
276 | { | ||
277 | return &fib6_main_tbl; | ||
278 | } | ||
279 | |||
280 | struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, | ||
281 | pol_lookup_t lookup) | ||
282 | { | ||
283 | return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags); | ||
284 | } | ||
285 | |||
286 | static void __init fib6_tables_init(void) | ||
287 | { | ||
288 | fib6_link_table(&fib6_main_tbl); | ||
289 | } | ||
290 | |||
291 | #endif | ||
292 | |||
293 | static int fib6_dump_node(struct fib6_walker_t *w) | ||
294 | { | ||
295 | int res; | ||
296 | struct rt6_info *rt; | ||
297 | |||
298 | for (rt = w->leaf; rt; rt = rt->u.next) { | ||
299 | res = rt6_dump_route(rt, w->args); | ||
300 | if (res < 0) { | ||
301 | /* Frame is full, suspend walking */ | ||
302 | w->leaf = rt; | ||
303 | return 1; | ||
304 | } | ||
305 | BUG_TRAP(res!=0); | ||
306 | } | ||
307 | w->leaf = NULL; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static void fib6_dump_end(struct netlink_callback *cb) | ||
312 | { | ||
313 | struct fib6_walker_t *w = (void*)cb->args[2]; | ||
314 | |||
315 | if (w) { | ||
316 | cb->args[2] = 0; | ||
317 | kfree(w); | ||
318 | } | ||
319 | cb->done = (void*)cb->args[3]; | ||
320 | cb->args[1] = 3; | ||
321 | } | ||
322 | |||
323 | static int fib6_dump_done(struct netlink_callback *cb) | ||
324 | { | ||
325 | fib6_dump_end(cb); | ||
326 | return cb->done ? cb->done(cb) : 0; | ||
327 | } | ||
328 | |||
329 | static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | ||
330 | struct netlink_callback *cb) | ||
331 | { | ||
332 | struct fib6_walker_t *w; | ||
333 | int res; | ||
334 | |||
335 | w = (void *)cb->args[2]; | ||
336 | w->root = &table->tb6_root; | ||
337 | |||
338 | if (cb->args[4] == 0) { | ||
339 | read_lock_bh(&table->tb6_lock); | ||
340 | res = fib6_walk(w); | ||
341 | read_unlock_bh(&table->tb6_lock); | ||
342 | if (res > 0) | ||
343 | cb->args[4] = 1; | ||
344 | } else { | ||
345 | read_lock_bh(&table->tb6_lock); | ||
346 | res = fib6_walk_continue(w); | ||
347 | read_unlock_bh(&table->tb6_lock); | ||
348 | if (res != 0) { | ||
349 | if (res < 0) | ||
350 | fib6_walker_unlink(w); | ||
351 | goto end; | ||
352 | } | ||
353 | fib6_walker_unlink(w); | ||
354 | cb->args[4] = 0; | ||
355 | } | ||
356 | end: | ||
357 | return res; | ||
358 | } | ||
359 | |||
360 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | ||
361 | { | ||
362 | unsigned int h, s_h; | ||
363 | unsigned int e = 0, s_e; | ||
364 | struct rt6_rtnl_dump_arg arg; | ||
365 | struct fib6_walker_t *w; | ||
366 | struct fib6_table *tb; | ||
367 | struct hlist_node *node; | ||
368 | int res = 0; | ||
369 | |||
370 | s_h = cb->args[0]; | ||
371 | s_e = cb->args[1]; | ||
372 | |||
373 | w = (void *)cb->args[2]; | ||
374 | if (w == NULL) { | ||
375 | /* New dump: | ||
376 | * | ||
377 | * 1. hook callback destructor. | ||
378 | */ | ||
379 | cb->args[3] = (long)cb->done; | ||
380 | cb->done = fib6_dump_done; | ||
381 | |||
382 | /* | ||
383 | * 2. allocate and initialize walker. | ||
384 | */ | ||
385 | w = kzalloc(sizeof(*w), GFP_ATOMIC); | ||
386 | if (w == NULL) | ||
387 | return -ENOMEM; | ||
388 | w->func = fib6_dump_node; | ||
389 | cb->args[2] = (long)w; | ||
390 | } | ||
391 | |||
392 | arg.skb = skb; | ||
393 | arg.cb = cb; | ||
394 | w->args = &arg; | ||
395 | |||
396 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { | ||
397 | e = 0; | ||
398 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) { | ||
399 | if (e < s_e) | ||
400 | goto next; | ||
401 | res = fib6_dump_table(tb, skb, cb); | ||
402 | if (res != 0) | ||
403 | goto out; | ||
404 | next: | ||
405 | e++; | ||
406 | } | ||
407 | } | ||
408 | out: | ||
409 | cb->args[1] = e; | ||
410 | cb->args[0] = h; | ||
411 | |||
412 | res = res < 0 ? res : skb->len; | ||
413 | if (res <= 0) | ||
414 | fib6_dump_end(cb); | ||
415 | return res; | ||
416 | } | ||
150 | 417 | ||
151 | /* | 418 | /* |
152 | * Routing Table | 419 | * Routing Table |
@@ -343,7 +610,7 @@ insert_above: | |||
343 | */ | 610 | */ |
344 | 611 | ||
345 | 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, |
346 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) | 613 | struct nl_info *info) |
347 | { | 614 | { |
348 | struct rt6_info *iter = NULL; | 615 | struct rt6_info *iter = NULL; |
349 | struct rt6_info **ins; | 616 | struct rt6_info **ins; |
@@ -398,7 +665,7 @@ out: | |||
398 | *ins = rt; | 665 | *ins = rt; |
399 | rt->rt6i_node = fn; | 666 | rt->rt6i_node = fn; |
400 | atomic_inc(&rt->rt6i_ref); | 667 | atomic_inc(&rt->rt6i_ref); |
401 | inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); | 668 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
402 | rt6_stats.fib_rt_entries++; | 669 | rt6_stats.fib_rt_entries++; |
403 | 670 | ||
404 | if ((fn->fn_flags & RTN_RTINFO) == 0) { | 671 | if ((fn->fn_flags & RTN_RTINFO) == 0) { |
@@ -428,10 +695,9 @@ void fib6_force_start_gc(void) | |||
428 | * with source addr info in sub-trees | 695 | * with source addr info in sub-trees |
429 | */ | 696 | */ |
430 | 697 | ||
431 | 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) |
432 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | ||
433 | { | 699 | { |
434 | struct fib6_node *fn; | 700 | struct fib6_node *fn, *pn = NULL; |
435 | int err = -ENOMEM; | 701 | int err = -ENOMEM; |
436 | 702 | ||
437 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), | 703 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), |
@@ -440,6 +706,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
440 | if (fn == NULL) | 706 | if (fn == NULL) |
441 | goto out; | 707 | goto out; |
442 | 708 | ||
709 | pn = fn; | ||
710 | |||
443 | #ifdef CONFIG_IPV6_SUBTREES | 711 | #ifdef CONFIG_IPV6_SUBTREES |
444 | if (rt->rt6i_src.plen) { | 712 | if (rt->rt6i_src.plen) { |
445 | struct fib6_node *sn; | 713 | struct fib6_node *sn; |
@@ -485,10 +753,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
485 | /* Now link new subtree to main tree */ | 753 | /* Now link new subtree to main tree */ |
486 | sfn->parent = fn; | 754 | sfn->parent = fn; |
487 | fn->subtree = sfn; | 755 | fn->subtree = sfn; |
488 | if (fn->leaf == NULL) { | ||
489 | fn->leaf = rt; | ||
490 | atomic_inc(&rt->rt6i_ref); | ||
491 | } | ||
492 | } else { | 756 | } else { |
493 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, | 757 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, |
494 | sizeof(struct in6_addr), rt->rt6i_src.plen, | 758 | sizeof(struct in6_addr), rt->rt6i_src.plen, |
@@ -498,21 +762,42 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
498 | goto st_failure; | 762 | goto st_failure; |
499 | } | 763 | } |
500 | 764 | ||
765 | if (fn->leaf == NULL) { | ||
766 | fn->leaf = rt; | ||
767 | atomic_inc(&rt->rt6i_ref); | ||
768 | } | ||
501 | fn = sn; | 769 | fn = sn; |
502 | } | 770 | } |
503 | #endif | 771 | #endif |
504 | 772 | ||
505 | err = fib6_add_rt2node(fn, rt, nlh, req); | 773 | err = fib6_add_rt2node(fn, rt, info); |
506 | 774 | ||
507 | if (err == 0) { | 775 | if (err == 0) { |
508 | fib6_start_gc(rt); | 776 | fib6_start_gc(rt); |
509 | if (!(rt->rt6i_flags&RTF_CACHE)) | 777 | if (!(rt->rt6i_flags&RTF_CACHE)) |
510 | fib6_prune_clones(fn, rt); | 778 | fib6_prune_clones(pn, rt); |
511 | } | 779 | } |
512 | 780 | ||
513 | out: | 781 | out: |
514 | if (err) | 782 | if (err) { |
783 | #ifdef CONFIG_IPV6_SUBTREES | ||
784 | /* | ||
785 | * If fib6_add_1 has cleared the old leaf pointer in the | ||
786 | * super-tree leaf node we have to find a new one for it. | ||
787 | */ | ||
788 | if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { | ||
789 | pn->leaf = fib6_find_prefix(pn); | ||
790 | #if RT6_DEBUG >= 2 | ||
791 | if (!pn->leaf) { | ||
792 | BUG_TRAP(pn->leaf != NULL); | ||
793 | pn->leaf = &ip6_null_entry; | ||
794 | } | ||
795 | #endif | ||
796 | atomic_inc(&pn->leaf->rt6i_ref); | ||
797 | } | ||
798 | #endif | ||
515 | dst_free(&rt->u.dst); | 799 | dst_free(&rt->u.dst); |
800 | } | ||
516 | return err; | 801 | return err; |
517 | 802 | ||
518 | #ifdef CONFIG_IPV6_SUBTREES | 803 | #ifdef CONFIG_IPV6_SUBTREES |
@@ -543,6 +828,9 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
543 | struct fib6_node *fn; | 828 | struct fib6_node *fn; |
544 | int dir; | 829 | int dir; |
545 | 830 | ||
831 | if (unlikely(args->offset == 0)) | ||
832 | return NULL; | ||
833 | |||
546 | /* | 834 | /* |
547 | * Descend on a tree | 835 | * Descend on a tree |
548 | */ | 836 | */ |
@@ -564,33 +852,26 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
564 | break; | 852 | break; |
565 | } | 853 | } |
566 | 854 | ||
567 | while ((fn->fn_flags & RTN_ROOT) == 0) { | 855 | while(fn) { |
568 | #ifdef CONFIG_IPV6_SUBTREES | 856 | if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) { |
569 | if (fn->subtree) { | ||
570 | struct fib6_node *st; | ||
571 | struct lookup_args *narg; | ||
572 | |||
573 | narg = args + 1; | ||
574 | |||
575 | if (narg->addr) { | ||
576 | st = fib6_lookup_1(fn->subtree, narg); | ||
577 | |||
578 | if (st && !(st->fn_flags & RTN_ROOT)) | ||
579 | return st; | ||
580 | } | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | if (fn->fn_flags & RTN_RTINFO) { | ||
585 | struct rt6key *key; | 857 | struct rt6key *key; |
586 | 858 | ||
587 | key = (struct rt6key *) ((u8 *) fn->leaf + | 859 | key = (struct rt6key *) ((u8 *) fn->leaf + |
588 | args->offset); | 860 | args->offset); |
589 | 861 | ||
590 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) | 862 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) { |
591 | return fn; | 863 | #ifdef CONFIG_IPV6_SUBTREES |
864 | if (fn->subtree) | ||
865 | fn = fib6_lookup_1(fn->subtree, args + 1); | ||
866 | #endif | ||
867 | if (!fn || fn->fn_flags & RTN_RTINFO) | ||
868 | return fn; | ||
869 | } | ||
592 | } | 870 | } |
593 | 871 | ||
872 | if (fn->fn_flags & RTN_ROOT) | ||
873 | break; | ||
874 | |||
594 | fn = fn->parent; | 875 | fn = fn->parent; |
595 | } | 876 | } |
596 | 877 | ||
@@ -600,18 +881,24 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
600 | struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, | 881 | struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, |
601 | struct in6_addr *saddr) | 882 | struct in6_addr *saddr) |
602 | { | 883 | { |
603 | struct lookup_args args[2]; | ||
604 | struct fib6_node *fn; | 884 | struct fib6_node *fn; |
605 | 885 | struct lookup_args args[] = { | |
606 | args[0].offset = offsetof(struct rt6_info, rt6i_dst); | 886 | { |
607 | args[0].addr = daddr; | 887 | .offset = offsetof(struct rt6_info, rt6i_dst), |
608 | 888 | .addr = daddr, | |
889 | }, | ||
609 | #ifdef CONFIG_IPV6_SUBTREES | 890 | #ifdef CONFIG_IPV6_SUBTREES |
610 | args[1].offset = offsetof(struct rt6_info, rt6i_src); | 891 | { |
611 | args[1].addr = saddr; | 892 | .offset = offsetof(struct rt6_info, rt6i_src), |
893 | .addr = saddr, | ||
894 | }, | ||
612 | #endif | 895 | #endif |
896 | { | ||
897 | .offset = 0, /* sentinel */ | ||
898 | } | ||
899 | }; | ||
613 | 900 | ||
614 | fn = fib6_lookup_1(root, args); | 901 | fn = fib6_lookup_1(root, daddr ? args : args + 1); |
615 | 902 | ||
616 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) | 903 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) |
617 | fn = root; | 904 | fn = root; |
@@ -667,10 +954,8 @@ struct fib6_node * fib6_locate(struct fib6_node *root, | |||
667 | #ifdef CONFIG_IPV6_SUBTREES | 954 | #ifdef CONFIG_IPV6_SUBTREES |
668 | if (src_len) { | 955 | if (src_len) { |
669 | BUG_TRAP(saddr!=NULL); | 956 | BUG_TRAP(saddr!=NULL); |
670 | if (fn == NULL) | 957 | if (fn && fn->subtree) |
671 | fn = fn->subtree; | 958 | fn = fib6_locate_1(fn->subtree, saddr, src_len, |
672 | if (fn) | ||
673 | fn = fib6_locate_1(fn, saddr, src_len, | ||
674 | offsetof(struct rt6_info, rt6i_src)); | 959 | offsetof(struct rt6_info, rt6i_src)); |
675 | } | 960 | } |
676 | #endif | 961 | #endif |
@@ -699,7 +984,7 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) | |||
699 | if(fn->right) | 984 | if(fn->right) |
700 | return fn->right->leaf; | 985 | return fn->right->leaf; |
701 | 986 | ||
702 | fn = SUBTREE(fn); | 987 | fn = FIB6_SUBTREE(fn); |
703 | } | 988 | } |
704 | return NULL; | 989 | return NULL; |
705 | } | 990 | } |
@@ -730,7 +1015,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
730 | if (fn->right) child = fn->right, children |= 1; | 1015 | if (fn->right) child = fn->right, children |= 1; |
731 | if (fn->left) child = fn->left, children |= 2; | 1016 | if (fn->left) child = fn->left, children |= 2; |
732 | 1017 | ||
733 | if (children == 3 || SUBTREE(fn) | 1018 | if (children == 3 || FIB6_SUBTREE(fn) |
734 | #ifdef CONFIG_IPV6_SUBTREES | 1019 | #ifdef CONFIG_IPV6_SUBTREES |
735 | /* Subtree root (i.e. fn) may have one child */ | 1020 | /* Subtree root (i.e. fn) may have one child */ |
736 | || (children && fn->fn_flags&RTN_ROOT) | 1021 | || (children && fn->fn_flags&RTN_ROOT) |
@@ -749,9 +1034,9 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
749 | 1034 | ||
750 | pn = fn->parent; | 1035 | pn = fn->parent; |
751 | #ifdef CONFIG_IPV6_SUBTREES | 1036 | #ifdef CONFIG_IPV6_SUBTREES |
752 | if (SUBTREE(pn) == fn) { | 1037 | if (FIB6_SUBTREE(pn) == fn) { |
753 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1038 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
754 | SUBTREE(pn) = NULL; | 1039 | FIB6_SUBTREE(pn) = NULL; |
755 | nstate = FWS_L; | 1040 | nstate = FWS_L; |
756 | } else { | 1041 | } else { |
757 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); | 1042 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); |
@@ -799,7 +1084,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
799 | read_unlock(&fib6_walker_lock); | 1084 | read_unlock(&fib6_walker_lock); |
800 | 1085 | ||
801 | node_free(fn); | 1086 | node_free(fn); |
802 | if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) | 1087 | if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn)) |
803 | return pn; | 1088 | return pn; |
804 | 1089 | ||
805 | rt6_release(pn->leaf); | 1090 | rt6_release(pn->leaf); |
@@ -809,7 +1094,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
809 | } | 1094 | } |
810 | 1095 | ||
811 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | 1096 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, |
812 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1097 | struct nl_info *info) |
813 | { | 1098 | { |
814 | struct fib6_walker_t *w; | 1099 | struct fib6_walker_t *w; |
815 | struct rt6_info *rt = *rtp; | 1100 | struct rt6_info *rt = *rtp; |
@@ -865,11 +1150,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
865 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); | 1150 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); |
866 | } | 1151 | } |
867 | 1152 | ||
868 | inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); | 1153 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
869 | rt6_release(rt); | 1154 | rt6_release(rt); |
870 | } | 1155 | } |
871 | 1156 | ||
872 | int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1157 | int fib6_del(struct rt6_info *rt, struct nl_info *info) |
873 | { | 1158 | { |
874 | struct fib6_node *fn = rt->rt6i_node; | 1159 | struct fib6_node *fn = rt->rt6i_node; |
875 | struct rt6_info **rtp; | 1160 | struct rt6_info **rtp; |
@@ -885,8 +1170,18 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
885 | 1170 | ||
886 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); | 1171 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); |
887 | 1172 | ||
888 | if (!(rt->rt6i_flags&RTF_CACHE)) | 1173 | if (!(rt->rt6i_flags&RTF_CACHE)) { |
889 | fib6_prune_clones(fn, rt); | 1174 | struct fib6_node *pn = fn; |
1175 | #ifdef CONFIG_IPV6_SUBTREES | ||
1176 | /* clones of this route might be in another subtree */ | ||
1177 | if (rt->rt6i_src.plen) { | ||
1178 | while (!(pn->fn_flags&RTN_ROOT)) | ||
1179 | pn = pn->parent; | ||
1180 | pn = pn->parent; | ||
1181 | } | ||
1182 | #endif | ||
1183 | fib6_prune_clones(pn, rt); | ||
1184 | } | ||
890 | 1185 | ||
891 | /* | 1186 | /* |
892 | * Walk the leaf entries looking for ourself | 1187 | * Walk the leaf entries looking for ourself |
@@ -894,7 +1189,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
894 | 1189 | ||
895 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { | 1190 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { |
896 | if (*rtp == rt) { | 1191 | if (*rtp == rt) { |
897 | fib6_del_route(fn, rtp, nlh, _rtattr, req); | 1192 | fib6_del_route(fn, rtp, info); |
898 | return 0; | 1193 | return 0; |
899 | } | 1194 | } |
900 | } | 1195 | } |
@@ -925,7 +1220,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
925 | * <0 -> walk is terminated by an error. | 1220 | * <0 -> walk is terminated by an error. |
926 | */ | 1221 | */ |
927 | 1222 | ||
928 | int fib6_walk_continue(struct fib6_walker_t *w) | 1223 | static int fib6_walk_continue(struct fib6_walker_t *w) |
929 | { | 1224 | { |
930 | struct fib6_node *fn, *pn; | 1225 | struct fib6_node *fn, *pn; |
931 | 1226 | ||
@@ -942,8 +1237,8 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
942 | switch (w->state) { | 1237 | switch (w->state) { |
943 | #ifdef CONFIG_IPV6_SUBTREES | 1238 | #ifdef CONFIG_IPV6_SUBTREES |
944 | case FWS_S: | 1239 | case FWS_S: |
945 | if (SUBTREE(fn)) { | 1240 | if (FIB6_SUBTREE(fn)) { |
946 | w->node = SUBTREE(fn); | 1241 | w->node = FIB6_SUBTREE(fn); |
947 | continue; | 1242 | continue; |
948 | } | 1243 | } |
949 | w->state = FWS_L; | 1244 | w->state = FWS_L; |
@@ -977,7 +1272,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
977 | pn = fn->parent; | 1272 | pn = fn->parent; |
978 | w->node = pn; | 1273 | w->node = pn; |
979 | #ifdef CONFIG_IPV6_SUBTREES | 1274 | #ifdef CONFIG_IPV6_SUBTREES |
980 | if (SUBTREE(pn) == fn) { | 1275 | if (FIB6_SUBTREE(pn) == fn) { |
981 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1276 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
982 | w->state = FWS_L; | 1277 | w->state = FWS_L; |
983 | continue; | 1278 | continue; |
@@ -999,7 +1294,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
999 | } | 1294 | } |
1000 | } | 1295 | } |
1001 | 1296 | ||
1002 | int fib6_walk(struct fib6_walker_t *w) | 1297 | static int fib6_walk(struct fib6_walker_t *w) |
1003 | { | 1298 | { |
1004 | int res; | 1299 | int res; |
1005 | 1300 | ||
@@ -1023,7 +1318,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1023 | res = c->func(rt, c->arg); | 1318 | res = c->func(rt, c->arg); |
1024 | if (res < 0) { | 1319 | if (res < 0) { |
1025 | w->leaf = rt; | 1320 | w->leaf = rt; |
1026 | res = fib6_del(rt, NULL, NULL, NULL); | 1321 | res = fib6_del(rt, NULL); |
1027 | if (res) { | 1322 | if (res) { |
1028 | #if RT6_DEBUG >= 2 | 1323 | #if RT6_DEBUG >= 2 |
1029 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); | 1324 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); |
@@ -1049,9 +1344,9 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1049 | * ignoring pure split nodes) will be scanned. | 1344 | * ignoring pure split nodes) will be scanned. |
1050 | */ | 1345 | */ |
1051 | 1346 | ||
1052 | void fib6_clean_tree(struct fib6_node *root, | 1347 | static void fib6_clean_tree(struct fib6_node *root, |
1053 | int (*func)(struct rt6_info *, void *arg), | 1348 | int (*func)(struct rt6_info *, void *arg), |
1054 | int prune, void *arg) | 1349 | int prune, void *arg) |
1055 | { | 1350 | { |
1056 | struct fib6_cleaner_t c; | 1351 | struct fib6_cleaner_t c; |
1057 | 1352 | ||
@@ -1064,6 +1359,25 @@ void fib6_clean_tree(struct fib6_node *root, | |||
1064 | fib6_walk(&c.w); | 1359 | fib6_walk(&c.w); |
1065 | } | 1360 | } |
1066 | 1361 | ||
1362 | void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), | ||
1363 | int prune, void *arg) | ||
1364 | { | ||
1365 | struct fib6_table *table; | ||
1366 | struct hlist_node *node; | ||
1367 | unsigned int h; | ||
1368 | |||
1369 | rcu_read_lock(); | ||
1370 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { | ||
1371 | hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], | ||
1372 | tb6_hlist) { | ||
1373 | write_lock_bh(&table->tb6_lock); | ||
1374 | fib6_clean_tree(&table->tb6_root, func, prune, arg); | ||
1375 | write_unlock_bh(&table->tb6_lock); | ||
1376 | } | ||
1377 | } | ||
1378 | rcu_read_unlock(); | ||
1379 | } | ||
1380 | |||
1067 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) | 1381 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) |
1068 | { | 1382 | { |
1069 | if (rt->rt6i_flags & RTF_CACHE) { | 1383 | if (rt->rt6i_flags & RTF_CACHE) { |
@@ -1142,11 +1456,8 @@ void fib6_run_gc(unsigned long dummy) | |||
1142 | } | 1456 | } |
1143 | gc_args.more = 0; | 1457 | gc_args.more = 0; |
1144 | 1458 | ||
1145 | |||
1146 | write_lock_bh(&rt6_lock); | ||
1147 | ndisc_dst_gc(&gc_args.more); | 1459 | ndisc_dst_gc(&gc_args.more); |
1148 | fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); | 1460 | fib6_clean_all(fib6_age, 0, NULL); |
1149 | write_unlock_bh(&rt6_lock); | ||
1150 | 1461 | ||
1151 | if (gc_args.more) | 1462 | if (gc_args.more) |
1152 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); | 1463 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); |
@@ -1161,10 +1472,10 @@ void __init fib6_init(void) | |||
1161 | { | 1472 | { |
1162 | fib6_node_kmem = kmem_cache_create("fib6_nodes", | 1473 | fib6_node_kmem = kmem_cache_create("fib6_nodes", |
1163 | sizeof(struct fib6_node), | 1474 | sizeof(struct fib6_node), |
1164 | 0, SLAB_HWCACHE_ALIGN, | 1475 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1165 | NULL, NULL); | 1476 | NULL, NULL); |
1166 | if (!fib6_node_kmem) | 1477 | |
1167 | panic("cannot create fib6_nodes cache"); | 1478 | fib6_tables_init(); |
1168 | } | 1479 | } |
1169 | 1480 | ||
1170 | void fib6_gc_cleanup(void) | 1481 | void fib6_gc_cleanup(void) |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 25c2a9e03895..6b8e6d76a58b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -111,7 +111,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
111 | } | 111 | } |
112 | 112 | ||
113 | if (hdr->nexthdr == NEXTHDR_HOP) { | 113 | if (hdr->nexthdr == NEXTHDR_HOP) { |
114 | if (ipv6_parse_hopopts(skb) < 0) { | 114 | if (ipv6_parse_hopopts(&skb) < 0) { |
115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4fb47a252913..66716911962e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -308,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int ip6_forward_proxy_check(struct sk_buff *skb) | ||
312 | { | ||
313 | struct ipv6hdr *hdr = skb->nh.ipv6h; | ||
314 | u8 nexthdr = hdr->nexthdr; | ||
315 | int offset; | ||
316 | |||
317 | if (ipv6_ext_hdr(nexthdr)) { | ||
318 | offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr); | ||
319 | if (offset < 0) | ||
320 | return 0; | ||
321 | } else | ||
322 | offset = sizeof(struct ipv6hdr); | ||
323 | |||
324 | if (nexthdr == IPPROTO_ICMPV6) { | ||
325 | struct icmp6hdr *icmp6; | ||
326 | |||
327 | if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) | ||
328 | return 0; | ||
329 | |||
330 | icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset); | ||
331 | |||
332 | switch (icmp6->icmp6_type) { | ||
333 | case NDISC_ROUTER_SOLICITATION: | ||
334 | case NDISC_ROUTER_ADVERTISEMENT: | ||
335 | case NDISC_NEIGHBOUR_SOLICITATION: | ||
336 | case NDISC_NEIGHBOUR_ADVERTISEMENT: | ||
337 | case NDISC_REDIRECT: | ||
338 | /* For reaction involving unicast neighbor discovery | ||
339 | * message destined to the proxied address, pass it to | ||
340 | * input function. | ||
341 | */ | ||
342 | return 1; | ||
343 | default: | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * The proxying router can't forward traffic sent to a link-local | ||
350 | * address, so signal the sender and discard the packet. This | ||
351 | * behavior is clarified by the MIPv6 specification. | ||
352 | */ | ||
353 | if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) { | ||
354 | dst_link_failure(skb); | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
311 | static inline int ip6_forward_finish(struct sk_buff *skb) | 361 | static inline int ip6_forward_finish(struct sk_buff *skb) |
312 | { | 362 | { |
313 | return dst_output(skb); | 363 | return dst_output(skb); |
@@ -362,6 +412,18 @@ int ip6_forward(struct sk_buff *skb) | |||
362 | return -ETIMEDOUT; | 412 | return -ETIMEDOUT; |
363 | } | 413 | } |
364 | 414 | ||
415 | /* XXX: idev->cnf.proxy_ndp? */ | ||
416 | if (ipv6_devconf.proxy_ndp && | ||
417 | pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) { | ||
418 | int proxied = ip6_forward_proxy_check(skb); | ||
419 | if (proxied > 0) | ||
420 | return ip6_input(skb); | ||
421 | else if (proxied < 0) { | ||
422 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | ||
423 | goto drop; | ||
424 | } | ||
425 | } | ||
426 | |||
365 | if (!xfrm6_route_forward(skb)) { | 427 | if (!xfrm6_route_forward(skb)) { |
366 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 428 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); |
367 | goto drop; | 429 | goto drop; |
@@ -475,17 +537,25 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
475 | switch (**nexthdr) { | 537 | switch (**nexthdr) { |
476 | 538 | ||
477 | case NEXTHDR_HOP: | 539 | case NEXTHDR_HOP: |
540 | break; | ||
478 | case NEXTHDR_ROUTING: | 541 | case NEXTHDR_ROUTING: |
542 | found_rhdr = 1; | ||
543 | break; | ||
479 | case NEXTHDR_DEST: | 544 | case NEXTHDR_DEST: |
480 | if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1; | 545 | #ifdef CONFIG_IPV6_MIP6 |
481 | if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset; | 546 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) |
482 | offset += ipv6_optlen(exthdr); | 547 | break; |
483 | *nexthdr = &exthdr->nexthdr; | 548 | #endif |
484 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | 549 | if (found_rhdr) |
550 | return offset; | ||
485 | break; | 551 | break; |
486 | default : | 552 | default : |
487 | return offset; | 553 | return offset; |
488 | } | 554 | } |
555 | |||
556 | offset += ipv6_optlen(exthdr); | ||
557 | *nexthdr = &exthdr->nexthdr; | ||
558 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
489 | } | 559 | } |
490 | 560 | ||
491 | return offset; | 561 | return offset; |
@@ -726,6 +796,14 @@ fail: | |||
726 | return err; | 796 | return err; |
727 | } | 797 | } |
728 | 798 | ||
799 | static inline int ip6_rt_check(struct rt6key *rt_key, | ||
800 | struct in6_addr *fl_addr, | ||
801 | struct in6_addr *addr_cache) | ||
802 | { | ||
803 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | ||
804 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | ||
805 | } | ||
806 | |||
729 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 807 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
730 | struct dst_entry *dst, | 808 | struct dst_entry *dst, |
731 | struct flowi *fl) | 809 | struct flowi *fl) |
@@ -741,8 +819,8 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
741 | * that we do not support routing by source, TOS, | 819 | * that we do not support routing by source, TOS, |
742 | * and MSG_DONTROUTE --ANK (980726) | 820 | * and MSG_DONTROUTE --ANK (980726) |
743 | * | 821 | * |
744 | * 1. If route was host route, check that | 822 | * 1. ip6_rt_check(): If route was host route, |
745 | * cached destination is current. | 823 | * check that cached destination is current. |
746 | * If it is network route, we still may | 824 | * If it is network route, we still may |
747 | * check its validity using saved pointer | 825 | * check its validity using saved pointer |
748 | * to the last used address: daddr_cache. | 826 | * to the last used address: daddr_cache. |
@@ -753,11 +831,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
753 | * sockets. | 831 | * sockets. |
754 | * 2. oif also should be the same. | 832 | * 2. oif also should be the same. |
755 | */ | 833 | */ |
756 | if (((rt->rt6i_dst.plen != 128 || | 834 | if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) || |
757 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) | 835 | #ifdef CONFIG_IPV6_SUBTREES |
758 | && (np->daddr_cache == NULL || | 836 | ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) || |
759 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) | 837 | #endif |
760 | || (fl->oif && fl->oif != dst->dev->ifindex)) { | 838 | (fl->oif && fl->oif != dst->dev->ifindex)) { |
761 | dst_release(dst); | 839 | dst_release(dst); |
762 | dst = NULL; | 840 | dst = NULL; |
763 | } | 841 | } |
@@ -866,7 +944,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
866 | /* initialize protocol header pointer */ | 944 | /* initialize protocol header pointer */ |
867 | skb->h.raw = skb->data + fragheaderlen; | 945 | skb->h.raw = skb->data + fragheaderlen; |
868 | 946 | ||
869 | skb->ip_summed = CHECKSUM_HW; | 947 | skb->ip_summed = CHECKSUM_PARTIAL; |
870 | skb->csum = 0; | 948 | skb->csum = 0; |
871 | sk->sk_sndmsg_off = 0; | 949 | sk->sk_sndmsg_off = 0; |
872 | } | 950 | } |
@@ -963,7 +1041,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
963 | 1041 | ||
964 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | 1042 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); |
965 | 1043 | ||
966 | fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0); | 1044 | fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0); |
967 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1045 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
968 | 1046 | ||
969 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1047 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index a81e9e9d93bd..ad9c6e824e62 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -212,7 +212,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | |||
212 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); | 212 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); |
213 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); | 213 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
214 | t->props.family = AF_INET6; | 214 | t->props.family = AF_INET6; |
215 | t->props.mode = 1; | 215 | t->props.mode = XFRM_MODE_TUNNEL; |
216 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); | 216 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
217 | 217 | ||
218 | if (xfrm_init_state(t)) | 218 | if (xfrm_init_state(t)) |
@@ -417,7 +417,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
417 | goto out; | 417 | goto out; |
418 | 418 | ||
419 | x->props.header_len = 0; | 419 | x->props.header_len = 0; |
420 | if (x->props.mode) | 420 | if (x->props.mode == XFRM_MODE_TUNNEL) |
421 | x->props.header_len += sizeof(struct ipv6hdr); | 421 | x->props.header_len += sizeof(struct ipv6hdr); |
422 | 422 | ||
423 | mutex_lock(&ipcomp6_resource_mutex); | 423 | mutex_lock(&ipcomp6_resource_mutex); |
@@ -429,7 +429,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
429 | goto error; | 429 | goto error; |
430 | mutex_unlock(&ipcomp6_resource_mutex); | 430 | mutex_unlock(&ipcomp6_resource_mutex); |
431 | 431 | ||
432 | if (x->props.mode) { | 432 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
433 | err = ipcomp6_tunnel_attach(x); | 433 | err = ipcomp6_tunnel_attach(x); |
434 | if (err) | 434 | if (err) |
435 | goto error_tunnel; | 435 | goto error_tunnel; |
@@ -461,6 +461,7 @@ static struct xfrm_type ipcomp6_type = | |||
461 | .destructor = ipcomp6_destroy, | 461 | .destructor = ipcomp6_destroy, |
462 | .input = ipcomp6_input, | 462 | .input = ipcomp6_input, |
463 | .output = ipcomp6_output, | 463 | .output = ipcomp6_output, |
464 | .hdr_offset = xfrm6_find_1stfragopt, | ||
464 | }; | 465 | }; |
465 | 466 | ||
466 | static struct inet6_protocol ipcomp6_protocol = | 467 | static struct inet6_protocol ipcomp6_protocol = |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a5eaaf693abf..4f3bb7fcc8b5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -407,8 +407,16 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
407 | /* routing header option needs extra check */ | 407 | /* routing header option needs extra check */ |
408 | if (optname == IPV6_RTHDR && opt->srcrt) { | 408 | if (optname == IPV6_RTHDR && opt->srcrt) { |
409 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | 409 | struct ipv6_rt_hdr *rthdr = opt->srcrt; |
410 | if (rthdr->type) | 410 | switch (rthdr->type) { |
411 | case IPV6_SRCRT_TYPE_0: | ||
412 | #ifdef CONFIG_IPV6_MIP6 | ||
413 | case IPV6_SRCRT_TYPE_2: | ||
414 | #endif | ||
415 | break; | ||
416 | default: | ||
411 | goto sticky_done; | 417 | goto sticky_done; |
418 | } | ||
419 | |||
412 | if ((rthdr->hdrlen & 1) || | 420 | if ((rthdr->hdrlen & 1) || |
413 | (rthdr->hdrlen >> 1) != rthdr->segments_left) | 421 | (rthdr->hdrlen >> 1) != rthdr->segments_left) |
414 | goto sticky_done; | 422 | goto sticky_done; |
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index dd4d1ce77769..0e8e0676a033 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c | |||
@@ -14,7 +14,6 @@ EXPORT_SYMBOL(ndisc_mc_map); | |||
14 | EXPORT_SYMBOL(register_inet6addr_notifier); | 14 | EXPORT_SYMBOL(register_inet6addr_notifier); |
15 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 15 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
16 | EXPORT_SYMBOL(ip6_route_output); | 16 | EXPORT_SYMBOL(ip6_route_output); |
17 | EXPORT_SYMBOL(addrconf_lock); | ||
18 | EXPORT_SYMBOL(ipv6_setsockopt); | 17 | EXPORT_SYMBOL(ipv6_setsockopt); |
19 | EXPORT_SYMBOL(ipv6_getsockopt); | 18 | EXPORT_SYMBOL(ipv6_getsockopt); |
20 | EXPORT_SYMBOL(inet6_register_protosw); | 19 | EXPORT_SYMBOL(inet6_register_protosw); |
@@ -31,6 +30,8 @@ EXPORT_SYMBOL(ipv6_chk_addr); | |||
31 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 30 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
32 | #ifdef CONFIG_XFRM | 31 | #ifdef CONFIG_XFRM |
33 | EXPORT_SYMBOL(xfrm6_rcv); | 32 | EXPORT_SYMBOL(xfrm6_rcv); |
33 | EXPORT_SYMBOL(xfrm6_input_addr); | ||
34 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); | ||
34 | #endif | 35 | #endif |
35 | EXPORT_SYMBOL(rt6_lookup); | 36 | EXPORT_SYMBOL(rt6_lookup); |
36 | EXPORT_SYMBOL(ipv6_push_nfrag_opts); | 37 | EXPORT_SYMBOL(ipv6_push_nfrag_opts); |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 639eb20c9f1f..3b114e3fa2f8 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -171,7 +171,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
171 | 171 | ||
172 | #define IPV6_MLD_MAX_MSF 64 | 172 | #define IPV6_MLD_MAX_MSF 64 |
173 | 173 | ||
174 | int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF; | 174 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * socket join on multicast group | 177 | * socket join on multicast group |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c new file mode 100644 index 000000000000..99d116caecda --- /dev/null +++ b/net/ipv6/mip6.c | |||
@@ -0,0 +1,519 @@ | |||
1 | /* | ||
2 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
3 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | /* | ||
20 | * Authors: | ||
21 | * Noriaki TAKAMIYA @USAGI | ||
22 | * Masahide NAKAMURA @USAGI | ||
23 | */ | ||
24 | |||
25 | #include <linux/config.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/ipv6.h> | ||
30 | #include <linux/icmpv6.h> | ||
31 | #include <net/sock.h> | ||
32 | #include <net/ipv6.h> | ||
33 | #include <net/ip6_checksum.h> | ||
34 | #include <net/xfrm.h> | ||
35 | #include <net/mip6.h> | ||
36 | |||
37 | static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr) | ||
38 | { | ||
39 | return x->coaddr; | ||
40 | } | ||
41 | |||
42 | static inline unsigned int calc_padlen(unsigned int len, unsigned int n) | ||
43 | { | ||
44 | return (n - len + 16) & 0x7; | ||
45 | } | ||
46 | |||
47 | static inline void *mip6_padn(__u8 *data, __u8 padlen) | ||
48 | { | ||
49 | if (!data) | ||
50 | return NULL; | ||
51 | if (padlen == 1) { | ||
52 | data[0] = MIP6_OPT_PAD_1; | ||
53 | } else if (padlen > 1) { | ||
54 | data[0] = MIP6_OPT_PAD_N; | ||
55 | data[1] = padlen - 2; | ||
56 | if (padlen > 2) | ||
57 | memset(data+2, 0, data[1]); | ||
58 | } | ||
59 | return data + padlen; | ||
60 | } | ||
61 | |||
62 | static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos) | ||
63 | { | ||
64 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | ||
65 | } | ||
66 | |||
67 | static int mip6_mh_len(int type) | ||
68 | { | ||
69 | int len = 0; | ||
70 | |||
71 | switch (type) { | ||
72 | case IP6_MH_TYPE_BRR: | ||
73 | len = 0; | ||
74 | break; | ||
75 | case IP6_MH_TYPE_HOTI: | ||
76 | case IP6_MH_TYPE_COTI: | ||
77 | case IP6_MH_TYPE_BU: | ||
78 | case IP6_MH_TYPE_BACK: | ||
79 | len = 1; | ||
80 | break; | ||
81 | case IP6_MH_TYPE_HOT: | ||
82 | case IP6_MH_TYPE_COT: | ||
83 | case IP6_MH_TYPE_BERROR: | ||
84 | len = 2; | ||
85 | break; | ||
86 | } | ||
87 | return len; | ||
88 | } | ||
89 | |||
90 | int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) | ||
91 | { | ||
92 | struct ip6_mh *mh; | ||
93 | int mhlen; | ||
94 | |||
95 | if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) || | ||
96 | !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3))) | ||
97 | return -1; | ||
98 | |||
99 | mh = (struct ip6_mh *)skb->h.raw; | ||
100 | |||
101 | if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { | ||
102 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", | ||
103 | mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); | ||
104 | mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw); | ||
105 | return -1; | ||
106 | } | ||
107 | mhlen = (mh->ip6mh_hdrlen + 1) << 3; | ||
108 | |||
109 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | ||
110 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
111 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
112 | &skb->nh.ipv6h->daddr, | ||
113 | mhlen, IPPROTO_MH, | ||
114 | skb->csum)) { | ||
115 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n"); | ||
116 | skb->ip_summed = CHECKSUM_NONE; | ||
117 | } | ||
118 | } | ||
119 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
120 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
121 | &skb->nh.ipv6h->daddr, | ||
122 | mhlen, IPPROTO_MH, | ||
123 | skb_checksum(skb, 0, mhlen, 0))) { | ||
124 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed " | ||
125 | "[" NIP6_FMT " > " NIP6_FMT "]\n", | ||
126 | NIP6(skb->nh.ipv6h->saddr), | ||
127 | NIP6(skb->nh.ipv6h->daddr)); | ||
128 | return -1; | ||
129 | } | ||
130 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
131 | } | ||
132 | |||
133 | if (mh->ip6mh_proto != IPPROTO_NONE) { | ||
134 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", | ||
135 | mh->ip6mh_proto); | ||
136 | mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw); | ||
137 | return -1; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | struct mip6_report_rate_limiter { | ||
144 | spinlock_t lock; | ||
145 | struct timeval stamp; | ||
146 | int iif; | ||
147 | struct in6_addr src; | ||
148 | struct in6_addr dst; | ||
149 | }; | ||
150 | |||
151 | static struct mip6_report_rate_limiter mip6_report_rl = { | ||
152 | .lock = SPIN_LOCK_UNLOCKED | ||
153 | }; | ||
154 | |||
155 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) | ||
156 | { | ||
157 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
158 | struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; | ||
159 | |||
160 | if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) && | ||
161 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) | ||
162 | return -ENOENT; | ||
163 | |||
164 | return destopt->nexthdr; | ||
165 | } | ||
166 | |||
167 | /* Destination Option Header is inserted. | ||
168 | * IP Header's src address is replaced with Home Address Option in | ||
169 | * Destination Option Header. | ||
170 | */ | ||
171 | static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) | ||
172 | { | ||
173 | struct ipv6hdr *iph; | ||
174 | struct ipv6_destopt_hdr *dstopt; | ||
175 | struct ipv6_destopt_hao *hao; | ||
176 | u8 nexthdr; | ||
177 | int len; | ||
178 | |||
179 | iph = (struct ipv6hdr *)skb->data; | ||
180 | iph->payload_len = htons(skb->len - sizeof(*iph)); | ||
181 | |||
182 | nexthdr = *skb->nh.raw; | ||
183 | *skb->nh.raw = IPPROTO_DSTOPTS; | ||
184 | |||
185 | dstopt = (struct ipv6_destopt_hdr *)skb->h.raw; | ||
186 | dstopt->nexthdr = nexthdr; | ||
187 | |||
188 | hao = mip6_padn((char *)(dstopt + 1), | ||
189 | calc_padlen(sizeof(*dstopt), 6)); | ||
190 | |||
191 | hao->type = IPV6_TLV_HAO; | ||
192 | hao->length = sizeof(*hao) - 2; | ||
193 | BUG_TRAP(hao->length == 16); | ||
194 | |||
195 | len = ((char *)hao - (char *)dstopt) + sizeof(*hao); | ||
196 | |||
197 | memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr)); | ||
198 | memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr)); | ||
199 | |||
200 | BUG_TRAP(len == x->props.header_len); | ||
201 | dstopt->hdrlen = (x->props.header_len >> 3) - 1; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static inline int mip6_report_rl_allow(struct timeval *stamp, | ||
207 | struct in6_addr *dst, | ||
208 | struct in6_addr *src, int iif) | ||
209 | { | ||
210 | int allow = 0; | ||
211 | |||
212 | spin_lock_bh(&mip6_report_rl.lock); | ||
213 | if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec || | ||
214 | mip6_report_rl.stamp.tv_usec != stamp->tv_usec || | ||
215 | mip6_report_rl.iif != iif || | ||
216 | !ipv6_addr_equal(&mip6_report_rl.src, src) || | ||
217 | !ipv6_addr_equal(&mip6_report_rl.dst, dst)) { | ||
218 | mip6_report_rl.stamp.tv_sec = stamp->tv_sec; | ||
219 | mip6_report_rl.stamp.tv_usec = stamp->tv_usec; | ||
220 | mip6_report_rl.iif = iif; | ||
221 | ipv6_addr_copy(&mip6_report_rl.src, src); | ||
222 | ipv6_addr_copy(&mip6_report_rl.dst, dst); | ||
223 | allow = 1; | ||
224 | } | ||
225 | spin_unlock_bh(&mip6_report_rl.lock); | ||
226 | return allow; | ||
227 | } | ||
228 | |||
229 | static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl) | ||
230 | { | ||
231 | struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; | ||
232 | struct ipv6_destopt_hao *hao = NULL; | ||
233 | struct xfrm_selector sel; | ||
234 | int offset; | ||
235 | struct timeval stamp; | ||
236 | int err = 0; | ||
237 | |||
238 | if (unlikely(fl->proto == IPPROTO_MH && | ||
239 | fl->fl_mh_type <= IP6_MH_TYPE_MAX)) | ||
240 | goto out; | ||
241 | |||
242 | if (likely(opt->dsthao)) { | ||
243 | offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
244 | if (likely(offset >= 0)) | ||
245 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + offset); | ||
246 | } | ||
247 | |||
248 | skb_get_timestamp(skb, &stamp); | ||
249 | |||
250 | if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr, | ||
251 | hao ? &hao->addr : &skb->nh.ipv6h->saddr, | ||
252 | opt->iif)) | ||
253 | goto out; | ||
254 | |||
255 | memset(&sel, 0, sizeof(sel)); | ||
256 | memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr, | ||
257 | sizeof(sel.daddr)); | ||
258 | sel.prefixlen_d = 128; | ||
259 | memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
260 | sizeof(sel.saddr)); | ||
261 | sel.prefixlen_s = 128; | ||
262 | sel.family = AF_INET6; | ||
263 | sel.proto = fl->proto; | ||
264 | sel.dport = xfrm_flowi_dport(fl); | ||
265 | if (sel.dport) | ||
266 | sel.dport_mask = ~((__u16)0); | ||
267 | sel.sport = xfrm_flowi_sport(fl); | ||
268 | if (sel.sport) | ||
269 | sel.sport_mask = ~((__u16)0); | ||
270 | sel.ifindex = fl->oif; | ||
271 | |||
272 | err = km_report(IPPROTO_DSTOPTS, &sel, | ||
273 | (hao ? (xfrm_address_t *)&hao->addr : NULL)); | ||
274 | |||
275 | out: | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, | ||
280 | u8 **nexthdr) | ||
281 | { | ||
282 | u16 offset = sizeof(struct ipv6hdr); | ||
283 | struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); | ||
284 | unsigned int packet_len = skb->tail - skb->nh.raw; | ||
285 | int found_rhdr = 0; | ||
286 | |||
287 | *nexthdr = &skb->nh.ipv6h->nexthdr; | ||
288 | |||
289 | while (offset + 1 <= packet_len) { | ||
290 | |||
291 | switch (**nexthdr) { | ||
292 | case NEXTHDR_HOP: | ||
293 | break; | ||
294 | case NEXTHDR_ROUTING: | ||
295 | found_rhdr = 1; | ||
296 | break; | ||
297 | case NEXTHDR_DEST: | ||
298 | /* | ||
299 | * HAO MUST NOT appear more than once. | ||
300 | * XXX: It is better to try to find by the end of | ||
301 | * XXX: packet if HAO exists. | ||
302 | */ | ||
303 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) { | ||
304 | LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n"); | ||
305 | return offset; | ||
306 | } | ||
307 | |||
308 | if (found_rhdr) | ||
309 | return offset; | ||
310 | |||
311 | break; | ||
312 | default: | ||
313 | return offset; | ||
314 | } | ||
315 | |||
316 | offset += ipv6_optlen(exthdr); | ||
317 | *nexthdr = &exthdr->nexthdr; | ||
318 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
319 | } | ||
320 | |||
321 | return offset; | ||
322 | } | ||
323 | |||
324 | static int mip6_destopt_init_state(struct xfrm_state *x) | ||
325 | { | ||
326 | if (x->id.spi) { | ||
327 | printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, | ||
328 | x->id.spi); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { | ||
332 | printk(KERN_INFO "%s: state's mode is not %u: %u\n", | ||
333 | __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | x->props.header_len = sizeof(struct ipv6_destopt_hdr) + | ||
338 | calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) + | ||
339 | sizeof(struct ipv6_destopt_hao); | ||
340 | BUG_TRAP(x->props.header_len == 24); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Do nothing about destroying since it has no specific operation for | ||
347 | * destination options header unlike IPsec protocols. | ||
348 | */ | ||
349 | static void mip6_destopt_destroy(struct xfrm_state *x) | ||
350 | { | ||
351 | } | ||
352 | |||
353 | static struct xfrm_type mip6_destopt_type = | ||
354 | { | ||
355 | .description = "MIP6DESTOPT", | ||
356 | .owner = THIS_MODULE, | ||
357 | .proto = IPPROTO_DSTOPTS, | ||
358 | .flags = XFRM_TYPE_NON_FRAGMENT, | ||
359 | .init_state = mip6_destopt_init_state, | ||
360 | .destructor = mip6_destopt_destroy, | ||
361 | .input = mip6_destopt_input, | ||
362 | .output = mip6_destopt_output, | ||
363 | .reject = mip6_destopt_reject, | ||
364 | .hdr_offset = mip6_destopt_offset, | ||
365 | .local_addr = mip6_xfrm_addr, | ||
366 | }; | ||
367 | |||
368 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) | ||
369 | { | ||
370 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; | ||
371 | |||
372 | if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) && | ||
373 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) | ||
374 | return -ENOENT; | ||
375 | |||
376 | return rt2->rt_hdr.nexthdr; | ||
377 | } | ||
378 | |||
379 | /* Routing Header type 2 is inserted. | ||
380 | * IP Header's dst address is replaced with Routing Header's Home Address. | ||
381 | */ | ||
382 | static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) | ||
383 | { | ||
384 | struct ipv6hdr *iph; | ||
385 | struct rt2_hdr *rt2; | ||
386 | u8 nexthdr; | ||
387 | |||
388 | iph = (struct ipv6hdr *)skb->data; | ||
389 | iph->payload_len = htons(skb->len - sizeof(*iph)); | ||
390 | |||
391 | nexthdr = *skb->nh.raw; | ||
392 | *skb->nh.raw = IPPROTO_ROUTING; | ||
393 | |||
394 | rt2 = (struct rt2_hdr *)skb->h.raw; | ||
395 | rt2->rt_hdr.nexthdr = nexthdr; | ||
396 | rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1; | ||
397 | rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2; | ||
398 | rt2->rt_hdr.segments_left = 1; | ||
399 | memset(&rt2->reserved, 0, sizeof(rt2->reserved)); | ||
400 | |||
401 | BUG_TRAP(rt2->rt_hdr.hdrlen == 2); | ||
402 | |||
403 | memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr)); | ||
404 | memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr)); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb, | ||
410 | u8 **nexthdr) | ||
411 | { | ||
412 | u16 offset = sizeof(struct ipv6hdr); | ||
413 | struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); | ||
414 | unsigned int packet_len = skb->tail - skb->nh.raw; | ||
415 | int found_rhdr = 0; | ||
416 | |||
417 | *nexthdr = &skb->nh.ipv6h->nexthdr; | ||
418 | |||
419 | while (offset + 1 <= packet_len) { | ||
420 | |||
421 | switch (**nexthdr) { | ||
422 | case NEXTHDR_HOP: | ||
423 | break; | ||
424 | case NEXTHDR_ROUTING: | ||
425 | if (offset + 3 <= packet_len) { | ||
426 | struct ipv6_rt_hdr *rt; | ||
427 | rt = (struct ipv6_rt_hdr *)(skb->nh.raw + offset); | ||
428 | if (rt->type != 0) | ||
429 | return offset; | ||
430 | } | ||
431 | found_rhdr = 1; | ||
432 | break; | ||
433 | case NEXTHDR_DEST: | ||
434 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) | ||
435 | return offset; | ||
436 | |||
437 | if (found_rhdr) | ||
438 | return offset; | ||
439 | |||
440 | break; | ||
441 | default: | ||
442 | return offset; | ||
443 | } | ||
444 | |||
445 | offset += ipv6_optlen(exthdr); | ||
446 | *nexthdr = &exthdr->nexthdr; | ||
447 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
448 | } | ||
449 | |||
450 | return offset; | ||
451 | } | ||
452 | |||
453 | static int mip6_rthdr_init_state(struct xfrm_state *x) | ||
454 | { | ||
455 | if (x->id.spi) { | ||
456 | printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, | ||
457 | x->id.spi); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { | ||
461 | printk(KERN_INFO "%s: state's mode is not %u: %u\n", | ||
462 | __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | x->props.header_len = sizeof(struct rt2_hdr); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Do nothing about destroying since it has no specific operation for routing | ||
473 | * header type 2 unlike IPsec protocols. | ||
474 | */ | ||
475 | static void mip6_rthdr_destroy(struct xfrm_state *x) | ||
476 | { | ||
477 | } | ||
478 | |||
479 | static struct xfrm_type mip6_rthdr_type = | ||
480 | { | ||
481 | .description = "MIP6RT", | ||
482 | .owner = THIS_MODULE, | ||
483 | .proto = IPPROTO_ROUTING, | ||
484 | .flags = XFRM_TYPE_NON_FRAGMENT, | ||
485 | .init_state = mip6_rthdr_init_state, | ||
486 | .destructor = mip6_rthdr_destroy, | ||
487 | .input = mip6_rthdr_input, | ||
488 | .output = mip6_rthdr_output, | ||
489 | .hdr_offset = mip6_rthdr_offset, | ||
490 | .remote_addr = mip6_xfrm_addr, | ||
491 | }; | ||
492 | |||
493 | int __init mip6_init(void) | ||
494 | { | ||
495 | printk(KERN_INFO "Mobile IPv6\n"); | ||
496 | |||
497 | if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) { | ||
498 | printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__); | ||
499 | goto mip6_destopt_xfrm_fail; | ||
500 | } | ||
501 | if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) { | ||
502 | printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__); | ||
503 | goto mip6_rthdr_xfrm_fail; | ||
504 | } | ||
505 | return 0; | ||
506 | |||
507 | mip6_rthdr_xfrm_fail: | ||
508 | xfrm_unregister_type(&mip6_destopt_type, AF_INET6); | ||
509 | mip6_destopt_xfrm_fail: | ||
510 | return -EAGAIN; | ||
511 | } | ||
512 | |||
513 | void __exit mip6_fini(void) | ||
514 | { | ||
515 | if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) | ||
516 | printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__); | ||
517 | if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0) | ||
518 | printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__); | ||
519 | } | ||
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b50055b9278d..0304b5fe8d6a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/sysctl.h> | 62 | #include <linux/sysctl.h> |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | #include <linux/if_addr.h> | ||
65 | #include <linux/if_arp.h> | 66 | #include <linux/if_arp.h> |
66 | #include <linux/ipv6.h> | 67 | #include <linux/ipv6.h> |
67 | #include <linux/icmpv6.h> | 68 | #include <linux/icmpv6.h> |
@@ -411,7 +412,8 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
411 | */ | 412 | */ |
412 | 413 | ||
413 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, |
414 | struct in6_addr *saddr, struct in6_addr *daddr) | 415 | struct in6_addr *saddr, struct in6_addr *daddr, |
416 | int oif) | ||
415 | { | 417 | { |
416 | memset(fl, 0, sizeof(*fl)); | 418 | memset(fl, 0, sizeof(*fl)); |
417 | ipv6_addr_copy(&fl->fl6_src, saddr); | 419 | ipv6_addr_copy(&fl->fl6_src, saddr); |
@@ -419,6 +421,8 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type, | |||
419 | fl->proto = IPPROTO_ICMPV6; | 421 | fl->proto = IPPROTO_ICMPV6; |
420 | fl->fl_icmp_type = type; | 422 | fl->fl_icmp_type = type; |
421 | fl->fl_icmp_code = 0; | 423 | fl->fl_icmp_code = 0; |
424 | fl->oif = oif; | ||
425 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
422 | } | 426 | } |
423 | 427 | ||
424 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 428 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
@@ -450,7 +454,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
450 | src_addr = &tmpaddr; | 454 | src_addr = &tmpaddr; |
451 | } | 455 | } |
452 | 456 | ||
453 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); | 457 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr, |
458 | dev->ifindex); | ||
454 | 459 | ||
455 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 460 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
456 | if (!dst) | 461 | if (!dst) |
@@ -491,7 +496,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
491 | msg->icmph.icmp6_unused = 0; | 496 | msg->icmph.icmp6_unused = 0; |
492 | msg->icmph.icmp6_router = router; | 497 | msg->icmph.icmp6_router = router; |
493 | msg->icmph.icmp6_solicited = solicited; | 498 | msg->icmph.icmp6_solicited = solicited; |
494 | msg->icmph.icmp6_override = !!override; | 499 | msg->icmph.icmp6_override = override; |
495 | 500 | ||
496 | /* Set the target address. */ | 501 | /* Set the target address. */ |
497 | ipv6_addr_copy(&msg->target, solicited_addr); | 502 | ipv6_addr_copy(&msg->target, solicited_addr); |
@@ -540,7 +545,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
540 | saddr = &addr_buf; | 545 | saddr = &addr_buf; |
541 | } | 546 | } |
542 | 547 | ||
543 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); | 548 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr, |
549 | dev->ifindex); | ||
544 | 550 | ||
545 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 551 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
546 | if (!dst) | 552 | if (!dst) |
@@ -615,7 +621,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
615 | int len; | 621 | int len; |
616 | int err; | 622 | int err; |
617 | 623 | ||
618 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); | 624 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, |
625 | dev->ifindex); | ||
619 | 626 | ||
620 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); | 627 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); |
621 | if (!dst) | 628 | if (!dst) |
@@ -729,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
729 | struct inet6_ifaddr *ifp; | 736 | struct inet6_ifaddr *ifp; |
730 | struct inet6_dev *idev = NULL; | 737 | struct inet6_dev *idev = NULL; |
731 | struct neighbour *neigh; | 738 | struct neighbour *neigh; |
739 | struct pneigh_entry *pneigh = NULL; | ||
732 | int dad = ipv6_addr_any(saddr); | 740 | int dad = ipv6_addr_any(saddr); |
733 | int inc; | 741 | int inc; |
742 | int is_router; | ||
734 | 743 | ||
735 | if (ipv6_addr_is_multicast(&msg->target)) { | 744 | if (ipv6_addr_is_multicast(&msg->target)) { |
736 | ND_PRINTK2(KERN_WARNING | 745 | ND_PRINTK2(KERN_WARNING |
@@ -815,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
815 | 824 | ||
816 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 825 | if (ipv6_chk_acast_addr(dev, &msg->target) || |
817 | (idev->cnf.forwarding && | 826 | (idev->cnf.forwarding && |
818 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) { | 827 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && |
828 | (pneigh = pneigh_lookup(&nd_tbl, | ||
829 | &msg->target, dev, 0)) != NULL)) { | ||
819 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 830 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
820 | skb->pkt_type != PACKET_HOST && | 831 | skb->pkt_type != PACKET_HOST && |
821 | inc != 0 && | 832 | inc != 0 && |
@@ -836,12 +847,14 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
836 | goto out; | 847 | goto out; |
837 | } | 848 | } |
838 | 849 | ||
850 | is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding); | ||
851 | |||
839 | if (dad) { | 852 | if (dad) { |
840 | struct in6_addr maddr; | 853 | struct in6_addr maddr; |
841 | 854 | ||
842 | ipv6_addr_all_nodes(&maddr); | 855 | ipv6_addr_all_nodes(&maddr); |
843 | ndisc_send_na(dev, NULL, &maddr, &msg->target, | 856 | ndisc_send_na(dev, NULL, &maddr, &msg->target, |
844 | idev->cnf.forwarding, 0, (ifp != NULL), 1); | 857 | is_router, 0, (ifp != NULL), 1); |
845 | goto out; | 858 | goto out; |
846 | } | 859 | } |
847 | 860 | ||
@@ -862,7 +875,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
862 | NEIGH_UPDATE_F_OVERRIDE); | 875 | NEIGH_UPDATE_F_OVERRIDE); |
863 | if (neigh || !dev->hard_header) { | 876 | if (neigh || !dev->hard_header) { |
864 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 877 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
865 | idev->cnf.forwarding, | 878 | is_router, |
866 | 1, (ifp != NULL && inc), inc); | 879 | 1, (ifp != NULL && inc), inc); |
867 | if (neigh) | 880 | if (neigh) |
868 | neigh_release(neigh); | 881 | neigh_release(neigh); |
@@ -945,6 +958,20 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
945 | if (neigh->nud_state & NUD_FAILED) | 958 | if (neigh->nud_state & NUD_FAILED) |
946 | goto out; | 959 | goto out; |
947 | 960 | ||
961 | /* | ||
962 | * Don't update the neighbor cache entry on a proxy NA from | ||
963 | * ourselves because either the proxied node is off link or it | ||
964 | * has already sent a NA to us. | ||
965 | */ | ||
966 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | ||
967 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && | ||
968 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { | ||
969 | /* XXX: idev->cnf.prixy_ndp */ | ||
970 | WARN_ON(skb->dst != NULL && | ||
971 | ((struct rt6_info *)skb->dst)->rt6i_idev); | ||
972 | goto out; | ||
973 | } | ||
974 | |||
948 | neigh_update(neigh, lladdr, | 975 | neigh_update(neigh, lladdr, |
949 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, | 976 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, |
950 | NEIGH_UPDATE_F_WEAK_OVERRIDE| | 977 | NEIGH_UPDATE_F_WEAK_OVERRIDE| |
@@ -959,7 +986,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
959 | struct rt6_info *rt; | 986 | struct rt6_info *rt; |
960 | rt = rt6_get_dflt_router(saddr, dev); | 987 | rt = rt6_get_dflt_router(saddr, dev); |
961 | if (rt) | 988 | if (rt) |
962 | ip6_del_rt(rt, NULL, NULL, NULL); | 989 | ip6_del_rt(rt); |
963 | } | 990 | } |
964 | 991 | ||
965 | out: | 992 | out: |
@@ -1112,7 +1139,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1112 | 1139 | ||
1113 | if (rt && lifetime == 0) { | 1140 | if (rt && lifetime == 0) { |
1114 | neigh_clone(neigh); | 1141 | neigh_clone(neigh); |
1115 | ip6_del_rt(rt, NULL, NULL, NULL); | 1142 | ip6_del_rt(rt); |
1116 | rt = NULL; | 1143 | rt = NULL; |
1117 | } | 1144 | } |
1118 | 1145 | ||
@@ -1344,7 +1371,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1344 | 1371 | ||
1345 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1372 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
1346 | if (neigh) { | 1373 | if (neigh) { |
1347 | rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, lladdr, | 1374 | rt6_redirect(dest, &skb->nh.ipv6h->daddr, |
1375 | &skb->nh.ipv6h->saddr, neigh, lladdr, | ||
1348 | on_link); | 1376 | on_link); |
1349 | neigh_release(neigh); | 1377 | neigh_release(neigh); |
1350 | } | 1378 | } |
@@ -1380,7 +1408,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1380 | return; | 1408 | return; |
1381 | } | 1409 | } |
1382 | 1410 | ||
1383 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr); | 1411 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr, |
1412 | dev->ifindex); | ||
1384 | 1413 | ||
1385 | dst = ip6_route_output(NULL, &fl); | 1414 | dst = ip6_route_output(NULL, &fl); |
1386 | if (dst == NULL) | 1415 | if (dst == NULL) |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 395a417ba955..580b1aba6722 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -87,7 +87,7 @@ unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, | |||
87 | unsigned int csum = 0; | 87 | unsigned int csum = 0; |
88 | 88 | ||
89 | switch (skb->ip_summed) { | 89 | switch (skb->ip_summed) { |
90 | case CHECKSUM_HW: | 90 | case CHECKSUM_COMPLETE: |
91 | if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) | 91 | if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) |
92 | break; | 92 | break; |
93 | if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, | 93 | if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index eeeb57d4c9c5..ac1dfebde175 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | # Link order matters here. | 5 | # Link order matters here. |
6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o | 6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o |
7 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 7 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
8 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o | 8 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o |
9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o | 9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o | 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
11 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 11 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 968a14be0d05..9510c24ca8d2 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -56,15 +56,15 @@ struct ipq_queue_entry { | |||
56 | 56 | ||
57 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); | 57 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); |
58 | 58 | ||
59 | static unsigned char copy_mode = IPQ_COPY_NONE; | 59 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; |
60 | static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT; | 60 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; |
61 | static DEFINE_RWLOCK(queue_lock); | 61 | static DEFINE_RWLOCK(queue_lock); |
62 | static int peer_pid; | 62 | static int peer_pid __read_mostly; |
63 | static unsigned int copy_range; | 63 | static unsigned int copy_range __read_mostly; |
64 | static unsigned int queue_total; | 64 | static unsigned int queue_total; |
65 | static unsigned int queue_dropped = 0; | 65 | static unsigned int queue_dropped = 0; |
66 | static unsigned int queue_user_dropped = 0; | 66 | static unsigned int queue_user_dropped = 0; |
67 | static struct sock *ipqnl; | 67 | static struct sock *ipqnl __read_mostly; |
68 | static LIST_HEAD(queue_list); | 68 | static LIST_HEAD(queue_list); |
69 | static DEFINE_MUTEX(ipqnl_mutex); | 69 | static DEFINE_MUTEX(ipqnl_mutex); |
70 | 70 | ||
@@ -206,9 +206,9 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) | |||
206 | break; | 206 | break; |
207 | 207 | ||
208 | case IPQ_COPY_PACKET: | 208 | case IPQ_COPY_PACKET: |
209 | if (entry->skb->ip_summed == CHECKSUM_HW && | 209 | if ((entry->skb->ip_summed == CHECKSUM_PARTIAL || |
210 | (*errp = skb_checksum_help(entry->skb, | 210 | entry->skb->ip_summed == CHECKSUM_COMPLETE) && |
211 | entry->info->outdev == NULL))) { | 211 | (*errp = skb_checksum_help(entry->skb))) { |
212 | read_unlock_bh(&queue_lock); | 212 | read_unlock_bh(&queue_lock); |
213 | return NULL; | 213 | return NULL; |
214 | } | 214 | } |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c9d6b23cd3f7..4ab368fa0b8f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -70,9 +70,6 @@ do { \ | |||
70 | #define IP_NF_ASSERT(x) | 70 | #define IP_NF_ASSERT(x) |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | |||
74 | #include <linux/netfilter_ipv4/listhelp.h> | ||
75 | |||
76 | #if 0 | 73 | #if 0 |
77 | /* All the better to debug you with... */ | 74 | /* All the better to debug you with... */ |
78 | #define static | 75 | #define static |
@@ -220,8 +217,7 @@ ip6t_error(struct sk_buff **pskb, | |||
220 | const struct net_device *out, | 217 | const struct net_device *out, |
221 | unsigned int hooknum, | 218 | unsigned int hooknum, |
222 | const struct xt_target *target, | 219 | const struct xt_target *target, |
223 | const void *targinfo, | 220 | const void *targinfo) |
224 | void *userinfo) | ||
225 | { | 221 | { |
226 | if (net_ratelimit()) | 222 | if (net_ratelimit()) |
227 | printk("ip6_tables: error: `%s'\n", (char *)targinfo); | 223 | printk("ip6_tables: error: `%s'\n", (char *)targinfo); |
@@ -258,8 +254,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
258 | unsigned int hook, | 254 | unsigned int hook, |
259 | const struct net_device *in, | 255 | const struct net_device *in, |
260 | const struct net_device *out, | 256 | const struct net_device *out, |
261 | struct xt_table *table, | 257 | struct xt_table *table) |
262 | void *userdata) | ||
263 | { | 258 | { |
264 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | 259 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
265 | int offset = 0; | 260 | int offset = 0; |
@@ -349,8 +344,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
349 | in, out, | 344 | in, out, |
350 | hook, | 345 | hook, |
351 | t->u.kernel.target, | 346 | t->u.kernel.target, |
352 | t->data, | 347 | t->data); |
353 | userdata); | ||
354 | 348 | ||
355 | #ifdef CONFIG_NETFILTER_DEBUG | 349 | #ifdef CONFIG_NETFILTER_DEBUG |
356 | if (((struct ip6t_entry *)table_base)->comefrom | 350 | if (((struct ip6t_entry *)table_base)->comefrom |
@@ -507,8 +501,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | |||
507 | return 1; | 501 | return 1; |
508 | 502 | ||
509 | if (m->u.kernel.match->destroy) | 503 | if (m->u.kernel.match->destroy) |
510 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, | 504 | m->u.kernel.match->destroy(m->u.kernel.match, m->data); |
511 | m->u.match_size - sizeof(*m)); | ||
512 | module_put(m->u.kernel.match->me); | 505 | module_put(m->u.kernel.match->me); |
513 | return 0; | 506 | return 0; |
514 | } | 507 | } |
@@ -561,7 +554,6 @@ check_match(struct ip6t_entry_match *m, | |||
561 | 554 | ||
562 | if (m->u.kernel.match->checkentry | 555 | if (m->u.kernel.match->checkentry |
563 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, | 556 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, |
564 | m->u.match_size - sizeof(*m), | ||
565 | hookmask)) { | 557 | hookmask)) { |
566 | duprintf("ip_tables: check failed for `%s'.\n", | 558 | duprintf("ip_tables: check failed for `%s'.\n", |
567 | m->u.kernel.match->name); | 559 | m->u.kernel.match->name); |
@@ -618,12 +610,10 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
618 | if (t->u.kernel.target == &ip6t_standard_target) { | 610 | if (t->u.kernel.target == &ip6t_standard_target) { |
619 | if (!standard_check(t, size)) { | 611 | if (!standard_check(t, size)) { |
620 | ret = -EINVAL; | 612 | ret = -EINVAL; |
621 | goto cleanup_matches; | 613 | goto err; |
622 | } | 614 | } |
623 | } else if (t->u.kernel.target->checkentry | 615 | } else if (t->u.kernel.target->checkentry |
624 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | 616 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
625 | t->u.target_size | ||
626 | - sizeof(*t), | ||
627 | e->comefrom)) { | 617 | e->comefrom)) { |
628 | duprintf("ip_tables: check failed for `%s'.\n", | 618 | duprintf("ip_tables: check failed for `%s'.\n", |
629 | t->u.kernel.target->name); | 619 | t->u.kernel.target->name); |
@@ -695,8 +685,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) | |||
695 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 685 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); |
696 | t = ip6t_get_target(e); | 686 | t = ip6t_get_target(e); |
697 | if (t->u.kernel.target->destroy) | 687 | if (t->u.kernel.target->destroy) |
698 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, | 688 | t->u.kernel.target->destroy(t->u.kernel.target, t->data); |
699 | t->u.target_size - sizeof(*t)); | ||
700 | module_put(t->u.kernel.target->me); | 689 | module_put(t->u.kernel.target->me); |
701 | return 0; | 690 | return 0; |
702 | } | 691 | } |
@@ -1352,7 +1341,6 @@ icmp6_checkentry(const char *tablename, | |||
1352 | const void *entry, | 1341 | const void *entry, |
1353 | const struct xt_match *match, | 1342 | const struct xt_match *match, |
1354 | void *matchinfo, | 1343 | void *matchinfo, |
1355 | unsigned int matchsize, | ||
1356 | unsigned int hook_mask) | 1344 | unsigned int hook_mask) |
1357 | { | 1345 | { |
1358 | const struct ip6t_icmp *icmpinfo = matchinfo; | 1346 | const struct ip6t_icmp *icmpinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index b8eff8ee69b1..435750f664dd 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c | |||
@@ -22,11 +22,10 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
22 | const struct net_device *out, | 22 | const struct net_device *out, |
23 | unsigned int hooknum, | 23 | unsigned int hooknum, |
24 | const struct xt_target *target, | 24 | const struct xt_target *target, |
25 | const void *targinfo, void *userinfo) | 25 | const void *targinfo) |
26 | { | 26 | { |
27 | struct ipv6hdr *ip6h; | 27 | struct ipv6hdr *ip6h; |
28 | const struct ip6t_HL_info *info = targinfo; | 28 | const struct ip6t_HL_info *info = targinfo; |
29 | u_int16_t diffs[2]; | ||
30 | int new_hl; | 29 | int new_hl; |
31 | 30 | ||
32 | if (!skb_make_writable(pskb, (*pskb)->len)) | 31 | if (!skb_make_writable(pskb, (*pskb)->len)) |
@@ -53,11 +52,8 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
53 | break; | 52 | break; |
54 | } | 53 | } |
55 | 54 | ||
56 | if (new_hl != ip6h->hop_limit) { | 55 | if (new_hl != ip6h->hop_limit) |
57 | diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF; | ||
58 | ip6h->hop_limit = new_hl; | 56 | ip6h->hop_limit = new_hl; |
59 | diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8); | ||
60 | } | ||
61 | 57 | ||
62 | return IP6T_CONTINUE; | 58 | return IP6T_CONTINUE; |
63 | } | 59 | } |
@@ -66,7 +62,6 @@ static int ip6t_hl_checkentry(const char *tablename, | |||
66 | const void *entry, | 62 | const void *entry, |
67 | const struct xt_target *target, | 63 | const struct xt_target *target, |
68 | void *targinfo, | 64 | void *targinfo, |
69 | unsigned int targinfosize, | ||
70 | unsigned int hook_mask) | 65 | unsigned int hook_mask) |
71 | { | 66 | { |
72 | struct ip6t_HL_info *info = targinfo; | 67 | struct ip6t_HL_info *info = targinfo; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 73c6300109d6..0cf537d30185 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -427,8 +427,7 @@ ip6t_log_target(struct sk_buff **pskb, | |||
427 | const struct net_device *out, | 427 | const struct net_device *out, |
428 | unsigned int hooknum, | 428 | unsigned int hooknum, |
429 | const struct xt_target *target, | 429 | const struct xt_target *target, |
430 | const void *targinfo, | 430 | const void *targinfo) |
431 | void *userinfo) | ||
432 | { | 431 | { |
433 | const struct ip6t_log_info *loginfo = targinfo; | 432 | const struct ip6t_log_info *loginfo = targinfo; |
434 | struct nf_loginfo li; | 433 | struct nf_loginfo li; |
@@ -452,7 +451,6 @@ static int ip6t_log_checkentry(const char *tablename, | |||
452 | const void *entry, | 451 | const void *entry, |
453 | const struct xt_target *target, | 452 | const struct xt_target *target, |
454 | void *targinfo, | 453 | void *targinfo, |
455 | unsigned int targinfosize, | ||
456 | unsigned int hook_mask) | 454 | unsigned int hook_mask) |
457 | { | 455 | { |
458 | const struct ip6t_log_info *loginfo = targinfo; | 456 | const struct ip6t_log_info *loginfo = targinfo; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 8629ba195d2d..311eae82feb3 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -96,6 +96,7 @@ static void send_reset(struct sk_buff *oldskb) | |||
96 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); | 96 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); |
97 | fl.fl_ip_sport = otcph.dest; | 97 | fl.fl_ip_sport = otcph.dest; |
98 | fl.fl_ip_dport = otcph.source; | 98 | fl.fl_ip_dport = otcph.source; |
99 | security_skb_classify_flow(oldskb, &fl); | ||
99 | dst = ip6_route_output(NULL, &fl); | 100 | dst = ip6_route_output(NULL, &fl); |
100 | if (dst == NULL) | 101 | if (dst == NULL) |
101 | return; | 102 | return; |
@@ -179,8 +180,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
179 | const struct net_device *out, | 180 | const struct net_device *out, |
180 | unsigned int hooknum, | 181 | unsigned int hooknum, |
181 | const struct xt_target *target, | 182 | const struct xt_target *target, |
182 | const void *targinfo, | 183 | const void *targinfo) |
183 | void *userinfo) | ||
184 | { | 184 | { |
185 | const struct ip6t_reject_info *reject = targinfo; | 185 | const struct ip6t_reject_info *reject = targinfo; |
186 | 186 | ||
@@ -223,7 +223,6 @@ static int check(const char *tablename, | |||
223 | const void *entry, | 223 | const void *entry, |
224 | const struct xt_target *target, | 224 | const struct xt_target *target, |
225 | void *targinfo, | 225 | void *targinfo, |
226 | unsigned int targinfosize, | ||
227 | unsigned int hook_mask) | 226 | unsigned int hook_mask) |
228 | { | 227 | { |
229 | const struct ip6t_reject_info *rejinfo = targinfo; | 228 | const struct ip6t_reject_info *rejinfo = targinfo; |
@@ -256,9 +255,7 @@ static struct ip6t_target ip6t_reject_reg = { | |||
256 | 255 | ||
257 | static int __init ip6t_reject_init(void) | 256 | static int __init ip6t_reject_init(void) |
258 | { | 257 | { |
259 | if (ip6t_register_target(&ip6t_reject_reg)) | 258 | return ip6t_register_target(&ip6t_reject_reg); |
260 | return -EINVAL; | ||
261 | return 0; | ||
262 | } | 259 | } |
263 | 260 | ||
264 | static void __exit ip6t_reject_fini(void) | 261 | static void __exit ip6t_reject_fini(void) |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 2f7bb20c758b..ec1b1608156c 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -102,7 +102,6 @@ checkentry(const char *tablename, | |||
102 | const void *entry, | 102 | const void *entry, |
103 | const struct xt_match *match, | 103 | const struct xt_match *match, |
104 | void *matchinfo, | 104 | void *matchinfo, |
105 | unsigned int matchinfosize, | ||
106 | unsigned int hook_mask) | 105 | unsigned int hook_mask) |
107 | { | 106 | { |
108 | const struct ip6t_ah *ahinfo = matchinfo; | 107 | const struct ip6t_ah *ahinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c deleted file mode 100644 index 9422413d0571..000000000000 --- a/net/ipv6/netfilter/ip6t_dst.c +++ /dev/null | |||
@@ -1,220 +0,0 @@ | |||
1 | /* Kernel module to match Hop-by-Hop and Destination parameters. */ | ||
2 | |||
3 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/ipv6.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <net/checksum.h> | ||
15 | #include <net/ipv6.h> | ||
16 | |||
17 | #include <asm/byteorder.h> | ||
18 | |||
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
20 | #include <linux/netfilter_ipv6/ip6t_opts.h> | ||
21 | |||
22 | #define HOPBYHOP 0 | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | ||
25 | #if HOPBYHOP | ||
26 | MODULE_DESCRIPTION("IPv6 HbH match"); | ||
27 | #else | ||
28 | MODULE_DESCRIPTION("IPv6 DST match"); | ||
29 | #endif | ||
30 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | ||
31 | |||
32 | #if 0 | ||
33 | #define DEBUGP printk | ||
34 | #else | ||
35 | #define DEBUGP(format, args...) | ||
36 | #endif | ||
37 | |||
38 | /* | ||
39 | * (Type & 0xC0) >> 6 | ||
40 | * 0 -> ignorable | ||
41 | * 1 -> must drop the packet | ||
42 | * 2 -> send ICMP PARM PROB regardless and drop packet | ||
43 | * 3 -> Send ICMP if not a multicast address and drop packet | ||
44 | * (Type & 0x20) >> 5 | ||
45 | * 0 -> invariant | ||
46 | * 1 -> can change the routing | ||
47 | * (Type & 0x1F) Type | ||
48 | * 0 -> Pad1 (only 1 byte!) | ||
49 | * 1 -> PadN LENGTH info (total length = length + 2) | ||
50 | * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) | ||
51 | * 5 -> RTALERT 2 x x | ||
52 | */ | ||
53 | |||
54 | static int | ||
55 | match(const struct sk_buff *skb, | ||
56 | const struct net_device *in, | ||
57 | const struct net_device *out, | ||
58 | const struct xt_match *match, | ||
59 | const void *matchinfo, | ||
60 | int offset, | ||
61 | unsigned int protoff, | ||
62 | int *hotdrop) | ||
63 | { | ||
64 | struct ipv6_opt_hdr _optsh, *oh; | ||
65 | const struct ip6t_opts *optinfo = matchinfo; | ||
66 | unsigned int temp; | ||
67 | unsigned int ptr; | ||
68 | unsigned int hdrlen = 0; | ||
69 | unsigned int ret = 0; | ||
70 | u8 _opttype, *tp = NULL; | ||
71 | u8 _optlen, *lp = NULL; | ||
72 | unsigned int optlen; | ||
73 | |||
74 | #if HOPBYHOP | ||
75 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) | ||
76 | #else | ||
77 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | ||
78 | #endif | ||
79 | return 0; | ||
80 | |||
81 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | ||
82 | if (oh == NULL) { | ||
83 | *hotdrop = 1; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | hdrlen = ipv6_optlen(oh); | ||
88 | if (skb->len - ptr < hdrlen) { | ||
89 | /* Packet smaller than it's length field */ | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); | ||
94 | |||
95 | DEBUGP("len %02X %04X %02X ", | ||
96 | optinfo->hdrlen, hdrlen, | ||
97 | (!(optinfo->flags & IP6T_OPTS_LEN) || | ||
98 | ((optinfo->hdrlen == hdrlen) ^ | ||
99 | !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); | ||
100 | |||
101 | ret = (oh != NULL) && | ||
102 | (!(optinfo->flags & IP6T_OPTS_LEN) || | ||
103 | ((optinfo->hdrlen == hdrlen) ^ | ||
104 | !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); | ||
105 | |||
106 | ptr += 2; | ||
107 | hdrlen -= 2; | ||
108 | if (!(optinfo->flags & IP6T_OPTS_OPTS)) { | ||
109 | return ret; | ||
110 | } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { | ||
111 | DEBUGP("Not strict - not implemented"); | ||
112 | } else { | ||
113 | DEBUGP("Strict "); | ||
114 | DEBUGP("#%d ", optinfo->optsnr); | ||
115 | for (temp = 0; temp < optinfo->optsnr; temp++) { | ||
116 | /* type field exists ? */ | ||
117 | if (hdrlen < 1) | ||
118 | break; | ||
119 | tp = skb_header_pointer(skb, ptr, sizeof(_opttype), | ||
120 | &_opttype); | ||
121 | if (tp == NULL) | ||
122 | break; | ||
123 | |||
124 | /* Type check */ | ||
125 | if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) { | ||
126 | DEBUGP("Tbad %02X %02X\n", | ||
127 | *tp, | ||
128 | (optinfo->opts[temp] & 0xFF00) >> 8); | ||
129 | return 0; | ||
130 | } else { | ||
131 | DEBUGP("Tok "); | ||
132 | } | ||
133 | /* Length check */ | ||
134 | if (*tp) { | ||
135 | u16 spec_len; | ||
136 | |||
137 | /* length field exists ? */ | ||
138 | if (hdrlen < 2) | ||
139 | break; | ||
140 | lp = skb_header_pointer(skb, ptr + 1, | ||
141 | sizeof(_optlen), | ||
142 | &_optlen); | ||
143 | if (lp == NULL) | ||
144 | break; | ||
145 | spec_len = optinfo->opts[temp] & 0x00FF; | ||
146 | |||
147 | if (spec_len != 0x00FF && spec_len != *lp) { | ||
148 | DEBUGP("Lbad %02X %04X\n", *lp, | ||
149 | spec_len); | ||
150 | return 0; | ||
151 | } | ||
152 | DEBUGP("Lok "); | ||
153 | optlen = *lp + 2; | ||
154 | } else { | ||
155 | DEBUGP("Pad1\n"); | ||
156 | optlen = 1; | ||
157 | } | ||
158 | |||
159 | /* Step to the next */ | ||
160 | DEBUGP("len%04X \n", optlen); | ||
161 | |||
162 | if ((ptr > skb->len - optlen || hdrlen < optlen) && | ||
163 | (temp < optinfo->optsnr - 1)) { | ||
164 | DEBUGP("new pointer is too large! \n"); | ||
165 | break; | ||
166 | } | ||
167 | ptr += optlen; | ||
168 | hdrlen -= optlen; | ||
169 | } | ||
170 | if (temp == optinfo->optsnr) | ||
171 | return ret; | ||
172 | else | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* Called when user tries to insert an entry of this type. */ | ||
180 | static int | ||
181 | checkentry(const char *tablename, | ||
182 | const void *info, | ||
183 | const struct xt_match *match, | ||
184 | void *matchinfo, | ||
185 | unsigned int matchinfosize, | ||
186 | unsigned int hook_mask) | ||
187 | { | ||
188 | const struct ip6t_opts *optsinfo = matchinfo; | ||
189 | |||
190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | ||
191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | ||
192 | return 0; | ||
193 | } | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | static struct ip6t_match opts_match = { | ||
198 | #if HOPBYHOP | ||
199 | .name = "hbh", | ||
200 | #else | ||
201 | .name = "dst", | ||
202 | #endif | ||
203 | .match = match, | ||
204 | .matchsize = sizeof(struct ip6t_opts), | ||
205 | .checkentry = checkentry, | ||
206 | .me = THIS_MODULE, | ||
207 | }; | ||
208 | |||
209 | static int __init ip6t_dst_init(void) | ||
210 | { | ||
211 | return ip6t_register_match(&opts_match); | ||
212 | } | ||
213 | |||
214 | static void __exit ip6t_dst_fini(void) | ||
215 | { | ||
216 | ip6t_unregister_match(&opts_match); | ||
217 | } | ||
218 | |||
219 | module_init(ip6t_dst_init); | ||
220 | module_exit(ip6t_dst_fini); | ||
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 06768c84bd31..78d9c8b9e28a 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -119,7 +119,6 @@ checkentry(const char *tablename, | |||
119 | const void *ip, | 119 | const void *ip, |
120 | const struct xt_match *match, | 120 | const struct xt_match *match, |
121 | void *matchinfo, | 121 | void *matchinfo, |
122 | unsigned int matchinfosize, | ||
123 | unsigned int hook_mask) | 122 | unsigned int hook_mask) |
124 | { | 123 | { |
125 | const struct ip6t_frag *fraginfo = matchinfo; | 124 | const struct ip6t_frag *fraginfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 374f1be85c0d..d32a205e3af2 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
@@ -19,15 +19,10 @@ | |||
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
20 | #include <linux/netfilter_ipv6/ip6t_opts.h> | 20 | #include <linux/netfilter_ipv6/ip6t_opts.h> |
21 | 21 | ||
22 | #define HOPBYHOP 1 | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
25 | #if HOPBYHOP | 23 | MODULE_DESCRIPTION("IPv6 opts match"); |
26 | MODULE_DESCRIPTION("IPv6 HbH match"); | ||
27 | #else | ||
28 | MODULE_DESCRIPTION("IPv6 DST match"); | ||
29 | #endif | ||
30 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | 24 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
25 | MODULE_ALIAS("ip6t_dst"); | ||
31 | 26 | ||
32 | #if 0 | 27 | #if 0 |
33 | #define DEBUGP printk | 28 | #define DEBUGP printk |
@@ -71,11 +66,7 @@ match(const struct sk_buff *skb, | |||
71 | u8 _optlen, *lp = NULL; | 66 | u8 _optlen, *lp = NULL; |
72 | unsigned int optlen; | 67 | unsigned int optlen; |
73 | 68 | ||
74 | #if HOPBYHOP | 69 | if (ipv6_find_hdr(skb, &ptr, match->data, NULL) < 0) |
75 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) | ||
76 | #else | ||
77 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | ||
78 | #endif | ||
79 | return 0; | 70 | return 0; |
80 | 71 | ||
81 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | 72 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); |
@@ -182,7 +173,6 @@ checkentry(const char *tablename, | |||
182 | const void *entry, | 173 | const void *entry, |
183 | const struct xt_match *match, | 174 | const struct xt_match *match, |
184 | void *matchinfo, | 175 | void *matchinfo, |
185 | unsigned int matchinfosize, | ||
186 | unsigned int hook_mask) | 176 | unsigned int hook_mask) |
187 | { | 177 | { |
188 | const struct ip6t_opts *optsinfo = matchinfo; | 178 | const struct ip6t_opts *optsinfo = matchinfo; |
@@ -194,26 +184,35 @@ checkentry(const char *tablename, | |||
194 | return 1; | 184 | return 1; |
195 | } | 185 | } |
196 | 186 | ||
197 | static struct ip6t_match opts_match = { | 187 | static struct xt_match opts_match[] = { |
198 | #if HOPBYHOP | 188 | { |
199 | .name = "hbh", | 189 | .name = "hbh", |
200 | #else | 190 | .family = AF_INET6, |
201 | .name = "dst", | 191 | .match = match, |
202 | #endif | 192 | .matchsize = sizeof(struct ip6t_opts), |
203 | .match = match, | 193 | .checkentry = checkentry, |
204 | .matchsize = sizeof(struct ip6t_opts), | 194 | .me = THIS_MODULE, |
205 | .checkentry = checkentry, | 195 | .data = NEXTHDR_HOP, |
206 | .me = THIS_MODULE, | 196 | }, |
197 | { | ||
198 | .name = "dst", | ||
199 | .family = AF_INET6, | ||
200 | .match = match, | ||
201 | .matchsize = sizeof(struct ip6t_opts), | ||
202 | .checkentry = checkentry, | ||
203 | .me = THIS_MODULE, | ||
204 | .data = NEXTHDR_DEST, | ||
205 | }, | ||
207 | }; | 206 | }; |
208 | 207 | ||
209 | static int __init ip6t_hbh_init(void) | 208 | static int __init ip6t_hbh_init(void) |
210 | { | 209 | { |
211 | return ip6t_register_match(&opts_match); | 210 | return xt_register_matches(opts_match, ARRAY_SIZE(opts_match)); |
212 | } | 211 | } |
213 | 212 | ||
214 | static void __exit ip6t_hbh_fini(void) | 213 | static void __exit ip6t_hbh_fini(void) |
215 | { | 214 | { |
216 | ip6t_unregister_match(&opts_match); | 215 | xt_unregister_matches(opts_match, ARRAY_SIZE(opts_match)); |
217 | } | 216 | } |
218 | 217 | ||
219 | module_init(ip6t_hbh_init); | 218 | module_init(ip6t_hbh_init); |
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 9375eeb1369f..3093c398002f 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
@@ -128,7 +128,6 @@ ipv6header_checkentry(const char *tablename, | |||
128 | const void *ip, | 128 | const void *ip, |
129 | const struct xt_match *match, | 129 | const struct xt_match *match, |
130 | void *matchinfo, | 130 | void *matchinfo, |
131 | unsigned int matchsize, | ||
132 | unsigned int hook_mask) | 131 | unsigned int hook_mask) |
133 | { | 132 | { |
134 | const struct ip6t_ipv6header_info *info = matchinfo; | 133 | const struct ip6t_ipv6header_info *info = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 5d047990cd44..4eb9bbc4ebc3 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c | |||
@@ -57,7 +57,6 @@ checkentry(const char *tablename, | |||
57 | const void *ip, | 57 | const void *ip, |
58 | const struct xt_match *match, | 58 | const struct xt_match *match, |
59 | void *matchinfo, | 59 | void *matchinfo, |
60 | unsigned int matchsize, | ||
61 | unsigned int hook_mask) | 60 | unsigned int hook_mask) |
62 | { | 61 | { |
63 | const struct ip6t_owner_info *info = matchinfo; | 62 | const struct ip6t_owner_info *info = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index fbb0184a41d8..bcb2e168a5bc 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -197,7 +197,6 @@ checkentry(const char *tablename, | |||
197 | const void *entry, | 197 | const void *entry, |
198 | const struct xt_match *match, | 198 | const struct xt_match *match, |
199 | void *matchinfo, | 199 | void *matchinfo, |
200 | unsigned int matchinfosize, | ||
201 | unsigned int hook_mask) | 200 | unsigned int hook_mask) |
202 | { | 201 | { |
203 | const struct ip6t_rt *rtinfo = matchinfo; | 202 | const struct ip6t_rt *rtinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 60976c0c58e8..2fc07c74decf 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -108,7 +108,7 @@ ip6t_hook(unsigned int hook, | |||
108 | const struct net_device *out, | 108 | const struct net_device *out, |
109 | int (*okfn)(struct sk_buff *)) | 109 | int (*okfn)(struct sk_buff *)) |
110 | { | 110 | { |
111 | return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL); | 111 | return ip6t_do_table(pskb, hook, in, out, &packet_filter); |
112 | } | 112 | } |
113 | 113 | ||
114 | static unsigned int | 114 | static unsigned int |
@@ -128,7 +128,7 @@ ip6t_local_out_hook(unsigned int hook, | |||
128 | } | 128 | } |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL); | 131 | return ip6t_do_table(pskb, hook, in, out, &packet_filter); |
132 | } | 132 | } |
133 | 133 | ||
134 | static struct nf_hook_ops ip6t_ops[] = { | 134 | static struct nf_hook_ops ip6t_ops[] = { |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 03a13eab1dae..386ea260e767 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -138,7 +138,7 @@ ip6t_route_hook(unsigned int hook, | |||
138 | const struct net_device *out, | 138 | const struct net_device *out, |
139 | int (*okfn)(struct sk_buff *)) | 139 | int (*okfn)(struct sk_buff *)) |
140 | { | 140 | { |
141 | return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 141 | return ip6t_do_table(pskb, hook, in, out, &packet_mangler); |
142 | } | 142 | } |
143 | 143 | ||
144 | static unsigned int | 144 | static unsigned int |
@@ -174,18 +174,14 @@ ip6t_local_hook(unsigned int hook, | |||
174 | /* flowlabel and prio (includes version, which shouldn't change either */ | 174 | /* flowlabel and prio (includes version, which shouldn't change either */ |
175 | flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); | 175 | flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); |
176 | 176 | ||
177 | ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 177 | ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler); |
178 | 178 | ||
179 | if (ret != NF_DROP && ret != NF_STOLEN | 179 | if (ret != NF_DROP && ret != NF_STOLEN |
180 | && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) | 180 | && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) |
181 | || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) | 181 | || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) |
182 | || (*pskb)->nfmark != nfmark | 182 | || (*pskb)->nfmark != nfmark |
183 | || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) { | 183 | || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) |
184 | 184 | return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP; | |
185 | /* something which could affect routing has changed */ | ||
186 | |||
187 | DEBUGP("ip6table_mangle: we'd need to re-route a packet\n"); | ||
188 | } | ||
189 | 185 | ||
190 | return ret; | 186 | return ret; |
191 | } | 187 | } |
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 61a7c58e99f8..b4154da575c0 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -122,7 +122,7 @@ ip6t_hook(unsigned int hook, | |||
122 | const struct net_device *out, | 122 | const struct net_device *out, |
123 | int (*okfn)(struct sk_buff *)) | 123 | int (*okfn)(struct sk_buff *)) |
124 | { | 124 | { |
125 | return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL); | 125 | return ip6t_do_table(pskb, hook, in, out, &packet_raw); |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct nf_hook_ops ip6t_ops[] = { | 128 | static struct nf_hook_ops ip6t_ops[] = { |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c2ab38ff46af..e5e53fff9e38 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -335,7 +335,7 @@ static struct nf_hook_ops ipv6_conntrack_ops[] = { | |||
335 | /* From nf_conntrack_proto_icmpv6.c */ | 335 | /* From nf_conntrack_proto_icmpv6.c */ |
336 | extern unsigned int nf_ct_icmpv6_timeout; | 336 | extern unsigned int nf_ct_icmpv6_timeout; |
337 | 337 | ||
338 | /* From nf_conntrack_frag6.c */ | 338 | /* From nf_conntrack_reasm.c */ |
339 | extern unsigned int nf_ct_frag6_timeout; | 339 | extern unsigned int nf_ct_frag6_timeout; |
340 | extern unsigned int nf_ct_frag6_low_thresh; | 340 | extern unsigned int nf_ct_frag6_low_thresh; |
341 | extern unsigned int nf_ct_frag6_high_thresh; | 341 | extern unsigned int nf_ct_frag6_high_thresh; |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index ef18a7b7014b..34d447208ffd 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <net/netfilter/nf_conntrack_core.h> | 33 | #include <net/netfilter/nf_conntrack_core.h> |
34 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | 34 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
35 | 35 | ||
36 | unsigned long nf_ct_icmpv6_timeout = 30*HZ; | 36 | unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ; |
37 | 37 | ||
38 | #if 0 | 38 | #if 0 |
39 | #define DEBUGP printk | 39 | #define DEBUGP printk |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 00d5583807f7..bf93c1ea6be9 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -54,9 +54,9 @@ | |||
54 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | 54 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ |
55 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | 55 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT |
56 | 56 | ||
57 | unsigned int nf_ct_frag6_high_thresh = 256*1024; | 57 | unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024; |
58 | unsigned int nf_ct_frag6_low_thresh = 192*1024; | 58 | unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024; |
59 | unsigned long nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT; | 59 | unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT; |
60 | 60 | ||
61 | struct nf_ct_frag6_skb_cb | 61 | struct nf_ct_frag6_skb_cb |
62 | { | 62 | { |
@@ -408,7 +408,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
408 | return -1; | 408 | return -1; |
409 | } | 409 | } |
410 | 410 | ||
411 | if (skb->ip_summed == CHECKSUM_HW) | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
412 | skb->csum = csum_sub(skb->csum, | 412 | skb->csum = csum_sub(skb->csum, |
413 | csum_partial(skb->nh.raw, | 413 | csum_partial(skb->nh.raw, |
414 | (u8*)(fhdr + 1) - skb->nh.raw, | 414 | (u8*)(fhdr + 1) - skb->nh.raw, |
@@ -640,7 +640,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
640 | head->len += fp->len; | 640 | head->len += fp->len; |
641 | if (head->ip_summed != fp->ip_summed) | 641 | if (head->ip_summed != fp->ip_summed) |
642 | head->ip_summed = CHECKSUM_NONE; | 642 | head->ip_summed = CHECKSUM_NONE; |
643 | else if (head->ip_summed == CHECKSUM_HW) | 643 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
644 | head->csum = csum_add(head->csum, fp->csum); | 644 | head->csum = csum_add(head->csum, fp->csum); |
645 | head->truesize += fp->truesize; | 645 | head->truesize += fp->truesize; |
646 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); | 646 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); |
@@ -652,7 +652,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
652 | head->nh.ipv6h->payload_len = htons(payload_len); | 652 | head->nh.ipv6h->payload_len = htons(payload_len); |
653 | 653 | ||
654 | /* Yes, and fold redundant checksum back. 8) */ | 654 | /* Yes, and fold redundant checksum back. 8) */ |
655 | if (head->ip_summed == CHECKSUM_HW) | 655 | if (head->ip_summed == CHECKSUM_COMPLETE) |
656 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 656 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); |
657 | 657 | ||
658 | fq->fragments = NULL; | 658 | fq->fragments = NULL; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 15b862d8acab..d09329ca3267 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -50,6 +50,9 @@ | |||
50 | #include <net/udp.h> | 50 | #include <net/udp.h> |
51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
52 | #include <net/tcp_states.h> | 52 | #include <net/tcp_states.h> |
53 | #ifdef CONFIG_IPV6_MIP6 | ||
54 | #include <net/mip6.h> | ||
55 | #endif | ||
53 | 56 | ||
54 | #include <net/rawv6.h> | 57 | #include <net/rawv6.h> |
55 | #include <net/xfrm.h> | 58 | #include <net/xfrm.h> |
@@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); | 172 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
170 | 173 | ||
171 | while (sk) { | 174 | while (sk) { |
175 | int filtered; | ||
176 | |||
172 | delivered = 1; | 177 | delivered = 1; |
173 | if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { | 178 | switch (nexthdr) { |
179 | case IPPROTO_ICMPV6: | ||
180 | filtered = icmpv6_filter(sk, skb); | ||
181 | break; | ||
182 | #ifdef CONFIG_IPV6_MIP6 | ||
183 | case IPPROTO_MH: | ||
184 | /* XXX: To validate MH only once for each packet, | ||
185 | * this is placed here. It should be after checking | ||
186 | * xfrm policy, however it doesn't. The checking xfrm | ||
187 | * policy is placed in rawv6_rcv() because it is | ||
188 | * required for each socket. | ||
189 | */ | ||
190 | filtered = mip6_mh_filter(sk, skb); | ||
191 | break; | ||
192 | #endif | ||
193 | default: | ||
194 | filtered = 0; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | if (filtered < 0) | ||
199 | break; | ||
200 | if (filtered == 0) { | ||
174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 201 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
175 | 202 | ||
176 | /* Not releasing hash table! */ | 203 | /* Not releasing hash table! */ |
@@ -334,7 +361,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
334 | if (!rp->checksum) | 361 | if (!rp->checksum) |
335 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 362 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
336 | 363 | ||
337 | if (skb->ip_summed == CHECKSUM_HW) { | 364 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
338 | skb_postpull_rcsum(skb, skb->nh.raw, | 365 | skb_postpull_rcsum(skb, skb->nh.raw, |
339 | skb->h.raw - skb->nh.raw); | 366 | skb->h.raw - skb->nh.raw); |
340 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, | 367 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, |
@@ -582,6 +609,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
582 | struct iovec *iov; | 609 | struct iovec *iov; |
583 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
584 | u8 __user *code = NULL; | 611 | u8 __user *code = NULL; |
612 | #ifdef CONFIG_IPV6_MIP6 | ||
613 | u8 len = 0; | ||
614 | #endif | ||
585 | int probed = 0; | 615 | int probed = 0; |
586 | int i; | 616 | int i; |
587 | 617 | ||
@@ -613,6 +643,20 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
613 | probed = 1; | 643 | probed = 1; |
614 | } | 644 | } |
615 | break; | 645 | break; |
646 | #ifdef CONFIG_IPV6_MIP6 | ||
647 | case IPPROTO_MH: | ||
648 | if (iov->iov_base && iov->iov_len < 1) | ||
649 | break; | ||
650 | /* check if type field is readable or not. */ | ||
651 | if (iov->iov_len > 2 - len) { | ||
652 | u8 __user *p = iov->iov_base; | ||
653 | get_user(fl->fl_mh_type, &p[2 - len]); | ||
654 | probed = 1; | ||
655 | } else | ||
656 | len += iov->iov_len; | ||
657 | |||
658 | break; | ||
659 | #endif | ||
616 | default: | 660 | default: |
617 | probed = 1; | 661 | probed = 1; |
618 | break; | 662 | break; |
@@ -759,6 +803,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
759 | 803 | ||
760 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 804 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
761 | fl.oif = np->mcast_oif; | 805 | fl.oif = np->mcast_oif; |
806 | security_sk_classify_flow(sk, &fl); | ||
762 | 807 | ||
763 | err = ip6_dst_lookup(sk, &dst, &fl); | 808 | err = ip6_dst_lookup(sk, &dst, &fl); |
764 | if (err) | 809 | if (err) |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 4e299c69e1c6..f39bbedd1327 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -53,10 +53,10 @@ | |||
53 | #include <net/ndisc.h> | 53 | #include <net/ndisc.h> |
54 | #include <net/addrconf.h> | 54 | #include <net/addrconf.h> |
55 | 55 | ||
56 | int sysctl_ip6frag_high_thresh = 256*1024; | 56 | int sysctl_ip6frag_high_thresh __read_mostly = 256*1024; |
57 | int sysctl_ip6frag_low_thresh = 192*1024; | 57 | int sysctl_ip6frag_low_thresh __read_mostly = 192*1024; |
58 | 58 | ||
59 | int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT; | 59 | int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT; |
60 | 60 | ||
61 | struct ip6frag_skb_cb | 61 | struct ip6frag_skb_cb |
62 | { | 62 | { |
@@ -152,7 +152,7 @@ static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct timer_list ip6_frag_secret_timer; | 154 | static struct timer_list ip6_frag_secret_timer; |
155 | int sysctl_ip6frag_secret_interval = 10 * 60 * HZ; | 155 | int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ; |
156 | 156 | ||
157 | static void ip6_frag_secret_rebuild(unsigned long dummy) | 157 | static void ip6_frag_secret_rebuild(unsigned long dummy) |
158 | { | 158 | { |
@@ -433,7 +433,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
433 | return; | 433 | return; |
434 | } | 434 | } |
435 | 435 | ||
436 | if (skb->ip_summed == CHECKSUM_HW) | 436 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
437 | skb->csum = csum_sub(skb->csum, | 437 | skb->csum = csum_sub(skb->csum, |
438 | csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); | 438 | csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); |
439 | 439 | ||
@@ -647,7 +647,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
647 | head->len += fp->len; | 647 | head->len += fp->len; |
648 | if (head->ip_summed != fp->ip_summed) | 648 | if (head->ip_summed != fp->ip_summed) |
649 | head->ip_summed = CHECKSUM_NONE; | 649 | head->ip_summed = CHECKSUM_NONE; |
650 | else if (head->ip_summed == CHECKSUM_HW) | 650 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
651 | head->csum = csum_add(head->csum, fp->csum); | 651 | head->csum = csum_add(head->csum, fp->csum); |
652 | head->truesize += fp->truesize; | 652 | head->truesize += fp->truesize; |
653 | atomic_sub(fp->truesize, &ip6_frag_mem); | 653 | atomic_sub(fp->truesize, &ip6_frag_mem); |
@@ -662,7 +662,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
662 | *skb_in = head; | 662 | *skb_in = head; |
663 | 663 | ||
664 | /* Yes, and fold redundant checksum back. 8) */ | 664 | /* Yes, and fold redundant checksum back. 8) */ |
665 | if (head->ip_summed == CHECKSUM_HW) | 665 | if (head->ip_summed == CHECKSUM_COMPLETE) |
666 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 666 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); |
667 | 667 | ||
668 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); | 668 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d9baca062d24..d6b4b4f48d18 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -22,6 +22,8 @@ | |||
22 | * routers in REACHABLE, STALE, DELAY or PROBE states). | 22 | * routers in REACHABLE, STALE, DELAY or PROBE states). |
23 | * - always select the same router if it is (probably) | 23 | * - always select the same router if it is (probably) |
24 | * reachable. otherwise, round-robin the list. | 24 | * reachable. otherwise, round-robin the list. |
25 | * Ville Nuorvala | ||
26 | * Fixed routing subtrees. | ||
25 | */ | 27 | */ |
26 | 28 | ||
27 | #include <linux/capability.h> | 29 | #include <linux/capability.h> |
@@ -35,7 +37,6 @@ | |||
35 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
36 | #include <linux/in6.h> | 38 | #include <linux/in6.h> |
37 | #include <linux/init.h> | 39 | #include <linux/init.h> |
38 | #include <linux/netlink.h> | ||
39 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
40 | 41 | ||
41 | #ifdef CONFIG_PROC_FS | 42 | #ifdef CONFIG_PROC_FS |
@@ -54,6 +55,7 @@ | |||
54 | #include <net/dst.h> | 55 | #include <net/dst.h> |
55 | #include <net/xfrm.h> | 56 | #include <net/xfrm.h> |
56 | #include <net/netevent.h> | 57 | #include <net/netevent.h> |
58 | #include <net/netlink.h> | ||
57 | 59 | ||
58 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
59 | 61 | ||
@@ -74,9 +76,6 @@ | |||
74 | 76 | ||
75 | #define CLONE_OFFLINK_ROUTE 0 | 77 | #define CLONE_OFFLINK_ROUTE 0 |
76 | 78 | ||
77 | #define RT6_SELECT_F_IFACE 0x1 | ||
78 | #define RT6_SELECT_F_REACHABLE 0x2 | ||
79 | |||
80 | static int ip6_rt_max_size = 4096; | 79 | static int ip6_rt_max_size = 4096; |
81 | static int ip6_rt_gc_min_interval = HZ / 2; | 80 | static int ip6_rt_gc_min_interval = HZ / 2; |
82 | static int ip6_rt_gc_timeout = 60*HZ; | 81 | static int ip6_rt_gc_timeout = 60*HZ; |
@@ -140,15 +139,49 @@ struct rt6_info ip6_null_entry = { | |||
140 | .rt6i_ref = ATOMIC_INIT(1), | 139 | .rt6i_ref = ATOMIC_INIT(1), |
141 | }; | 140 | }; |
142 | 141 | ||
143 | struct fib6_node ip6_routing_table = { | 142 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
144 | .leaf = &ip6_null_entry, | ||
145 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
146 | }; | ||
147 | 143 | ||
148 | /* Protects all the ip6 fib */ | 144 | struct rt6_info ip6_prohibit_entry = { |
145 | .u = { | ||
146 | .dst = { | ||
147 | .__refcnt = ATOMIC_INIT(1), | ||
148 | .__use = 1, | ||
149 | .dev = &loopback_dev, | ||
150 | .obsolete = -1, | ||
151 | .error = -EACCES, | ||
152 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
153 | .input = ip6_pkt_discard, | ||
154 | .output = ip6_pkt_discard_out, | ||
155 | .ops = &ip6_dst_ops, | ||
156 | .path = (struct dst_entry*)&ip6_prohibit_entry, | ||
157 | } | ||
158 | }, | ||
159 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | ||
160 | .rt6i_metric = ~(u32) 0, | ||
161 | .rt6i_ref = ATOMIC_INIT(1), | ||
162 | }; | ||
149 | 163 | ||
150 | DEFINE_RWLOCK(rt6_lock); | 164 | struct rt6_info ip6_blk_hole_entry = { |
165 | .u = { | ||
166 | .dst = { | ||
167 | .__refcnt = ATOMIC_INIT(1), | ||
168 | .__use = 1, | ||
169 | .dev = &loopback_dev, | ||
170 | .obsolete = -1, | ||
171 | .error = -EINVAL, | ||
172 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
173 | .input = ip6_pkt_discard, | ||
174 | .output = ip6_pkt_discard_out, | ||
175 | .ops = &ip6_dst_ops, | ||
176 | .path = (struct dst_entry*)&ip6_blk_hole_entry, | ||
177 | } | ||
178 | }, | ||
179 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | ||
180 | .rt6i_metric = ~(u32) 0, | ||
181 | .rt6i_ref = ATOMIC_INIT(1), | ||
182 | }; | ||
151 | 183 | ||
184 | #endif | ||
152 | 185 | ||
153 | /* allocate dst with ip6_dst_ops */ | 186 | /* allocate dst with ip6_dst_ops */ |
154 | static __inline__ struct rt6_info *ip6_dst_alloc(void) | 187 | static __inline__ struct rt6_info *ip6_dst_alloc(void) |
@@ -188,8 +221,14 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) | |||
188 | time_after(jiffies, rt->rt6i_expires)); | 221 | time_after(jiffies, rt->rt6i_expires)); |
189 | } | 222 | } |
190 | 223 | ||
224 | static inline int rt6_need_strict(struct in6_addr *daddr) | ||
225 | { | ||
226 | return (ipv6_addr_type(daddr) & | ||
227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); | ||
228 | } | ||
229 | |||
191 | /* | 230 | /* |
192 | * Route lookup. Any rt6_lock is implied. | 231 | * Route lookup. Any table->tb6_lock is implied. |
193 | */ | 232 | */ |
194 | 233 | ||
195 | static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, | 234 | static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, |
@@ -298,7 +337,7 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
298 | int m, n; | 337 | int m, n; |
299 | 338 | ||
300 | m = rt6_check_dev(rt, oif); | 339 | m = rt6_check_dev(rt, oif); |
301 | if (!m && (strict & RT6_SELECT_F_IFACE)) | 340 | if (!m && (strict & RT6_LOOKUP_F_IFACE)) |
302 | return -1; | 341 | return -1; |
303 | #ifdef CONFIG_IPV6_ROUTER_PREF | 342 | #ifdef CONFIG_IPV6_ROUTER_PREF |
304 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; | 343 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; |
@@ -306,7 +345,7 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
306 | n = rt6_check_neigh(rt); | 345 | n = rt6_check_neigh(rt); |
307 | if (n > 1) | 346 | if (n > 1) |
308 | m |= 16; | 347 | m |= 16; |
309 | else if (!n && strict & RT6_SELECT_F_REACHABLE) | 348 | else if (!n && strict & RT6_LOOKUP_F_REACHABLE) |
310 | return -1; | 349 | return -1; |
311 | return m; | 350 | return m; |
312 | } | 351 | } |
@@ -346,7 +385,7 @@ static struct rt6_info *rt6_select(struct rt6_info **head, int oif, | |||
346 | } | 385 | } |
347 | 386 | ||
348 | if (!match && | 387 | if (!match && |
349 | (strict & RT6_SELECT_F_REACHABLE) && | 388 | (strict & RT6_LOOKUP_F_REACHABLE) && |
350 | last && last != rt0) { | 389 | last && last != rt0) { |
351 | /* no entries matched; do round-robin */ | 390 | /* no entries matched; do round-robin */ |
352 | static DEFINE_SPINLOCK(lock); | 391 | static DEFINE_SPINLOCK(lock); |
@@ -417,7 +456,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
417 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); | 456 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); |
418 | 457 | ||
419 | if (rt && !lifetime) { | 458 | if (rt && !lifetime) { |
420 | ip6_del_rt(rt, NULL, NULL, NULL); | 459 | ip6_del_rt(rt); |
421 | rt = NULL; | 460 | rt = NULL; |
422 | } | 461 | } |
423 | 462 | ||
@@ -441,44 +480,95 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
441 | } | 480 | } |
442 | #endif | 481 | #endif |
443 | 482 | ||
444 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | 483 | #define BACKTRACK(saddr) \ |
445 | int oif, int strict) | 484 | do { \ |
485 | if (rt == &ip6_null_entry) { \ | ||
486 | struct fib6_node *pn; \ | ||
487 | while (fn) { \ | ||
488 | if (fn->fn_flags & RTN_TL_ROOT) \ | ||
489 | goto out; \ | ||
490 | pn = fn->parent; \ | ||
491 | if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \ | ||
492 | fn = fib6_lookup(pn->subtree, NULL, saddr); \ | ||
493 | else \ | ||
494 | fn = pn; \ | ||
495 | if (fn->fn_flags & RTN_RTINFO) \ | ||
496 | goto restart; \ | ||
497 | } \ | ||
498 | } \ | ||
499 | } while(0) | ||
500 | |||
501 | static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, | ||
502 | struct flowi *fl, int flags) | ||
446 | { | 503 | { |
447 | struct fib6_node *fn; | 504 | struct fib6_node *fn; |
448 | struct rt6_info *rt; | 505 | struct rt6_info *rt; |
449 | 506 | ||
450 | read_lock_bh(&rt6_lock); | 507 | read_lock_bh(&table->tb6_lock); |
451 | fn = fib6_lookup(&ip6_routing_table, daddr, saddr); | 508 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
452 | rt = rt6_device_match(fn->leaf, oif, strict); | 509 | restart: |
510 | rt = fn->leaf; | ||
511 | rt = rt6_device_match(rt, fl->oif, flags); | ||
512 | BACKTRACK(&fl->fl6_src); | ||
513 | out: | ||
453 | dst_hold(&rt->u.dst); | 514 | dst_hold(&rt->u.dst); |
454 | rt->u.dst.__use++; | 515 | read_unlock_bh(&table->tb6_lock); |
455 | read_unlock_bh(&rt6_lock); | ||
456 | 516 | ||
457 | rt->u.dst.lastuse = jiffies; | 517 | rt->u.dst.lastuse = jiffies; |
458 | if (rt->u.dst.error == 0) | 518 | rt->u.dst.__use++; |
459 | return rt; | 519 | |
460 | dst_release(&rt->u.dst); | 520 | return rt; |
521 | |||
522 | } | ||
523 | |||
524 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | ||
525 | int oif, int strict) | ||
526 | { | ||
527 | struct flowi fl = { | ||
528 | .oif = oif, | ||
529 | .nl_u = { | ||
530 | .ip6_u = { | ||
531 | .daddr = *daddr, | ||
532 | /* TODO: saddr */ | ||
533 | }, | ||
534 | }, | ||
535 | }; | ||
536 | struct dst_entry *dst; | ||
537 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | ||
538 | |||
539 | dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); | ||
540 | if (dst->error == 0) | ||
541 | return (struct rt6_info *) dst; | ||
542 | |||
543 | dst_release(dst); | ||
544 | |||
461 | return NULL; | 545 | return NULL; |
462 | } | 546 | } |
463 | 547 | ||
464 | /* ip6_ins_rt is called with FREE rt6_lock. | 548 | /* ip6_ins_rt is called with FREE table->tb6_lock. |
465 | It takes new route entry, the addition fails by any reason the | 549 | It takes new route entry, the addition fails by any reason the |
466 | route is freed. In any case, if caller does not hold it, it may | 550 | route is freed. In any case, if caller does not hold it, it may |
467 | be destroyed. | 551 | be destroyed. |
468 | */ | 552 | */ |
469 | 553 | ||
470 | int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | 554 | static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) |
471 | void *_rtattr, struct netlink_skb_parms *req) | ||
472 | { | 555 | { |
473 | int err; | 556 | int err; |
557 | struct fib6_table *table; | ||
474 | 558 | ||
475 | write_lock_bh(&rt6_lock); | 559 | table = rt->rt6i_table; |
476 | err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req); | 560 | write_lock_bh(&table->tb6_lock); |
477 | write_unlock_bh(&rt6_lock); | 561 | err = fib6_add(&table->tb6_root, rt, info); |
562 | write_unlock_bh(&table->tb6_lock); | ||
478 | 563 | ||
479 | return err; | 564 | return err; |
480 | } | 565 | } |
481 | 566 | ||
567 | int ip6_ins_rt(struct rt6_info *rt) | ||
568 | { | ||
569 | return __ip6_ins_rt(rt, NULL); | ||
570 | } | ||
571 | |||
482 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 572 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
483 | struct in6_addr *saddr) | 573 | struct in6_addr *saddr) |
484 | { | 574 | { |
@@ -532,51 +622,39 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
532 | return rt; | 622 | return rt; |
533 | } | 623 | } |
534 | 624 | ||
535 | #define BACKTRACK() \ | 625 | static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, |
536 | if (rt == &ip6_null_entry) { \ | 626 | struct flowi *fl, int flags) |
537 | while ((fn = fn->parent) != NULL) { \ | ||
538 | if (fn->fn_flags & RTN_ROOT) { \ | ||
539 | goto out; \ | ||
540 | } \ | ||
541 | if (fn->fn_flags & RTN_RTINFO) \ | ||
542 | goto restart; \ | ||
543 | } \ | ||
544 | } | ||
545 | |||
546 | |||
547 | void ip6_route_input(struct sk_buff *skb) | ||
548 | { | 627 | { |
549 | struct fib6_node *fn; | 628 | struct fib6_node *fn; |
550 | struct rt6_info *rt, *nrt; | 629 | struct rt6_info *rt, *nrt; |
551 | int strict; | 630 | int strict = 0; |
552 | int attempts = 3; | 631 | int attempts = 3; |
553 | int err; | 632 | int err; |
554 | int reachable = RT6_SELECT_F_REACHABLE; | 633 | int reachable = RT6_LOOKUP_F_REACHABLE; |
555 | 634 | ||
556 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; | 635 | strict |= flags & RT6_LOOKUP_F_IFACE; |
557 | 636 | ||
558 | relookup: | 637 | relookup: |
559 | read_lock_bh(&rt6_lock); | 638 | read_lock_bh(&table->tb6_lock); |
560 | 639 | ||
561 | restart_2: | 640 | restart_2: |
562 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, | 641 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
563 | &skb->nh.ipv6h->saddr); | ||
564 | 642 | ||
565 | restart: | 643 | restart: |
566 | rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable); | 644 | rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); |
567 | BACKTRACK(); | 645 | BACKTRACK(&fl->fl6_src); |
568 | if (rt == &ip6_null_entry || | 646 | if (rt == &ip6_null_entry || |
569 | rt->rt6i_flags & RTF_CACHE) | 647 | rt->rt6i_flags & RTF_CACHE) |
570 | goto out; | 648 | goto out; |
571 | 649 | ||
572 | dst_hold(&rt->u.dst); | 650 | dst_hold(&rt->u.dst); |
573 | read_unlock_bh(&rt6_lock); | 651 | read_unlock_bh(&table->tb6_lock); |
574 | 652 | ||
575 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 653 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
576 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); | 654 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
577 | else { | 655 | else { |
578 | #if CLONE_OFFLINK_ROUTE | 656 | #if CLONE_OFFLINK_ROUTE |
579 | nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); | 657 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); |
580 | #else | 658 | #else |
581 | goto out2; | 659 | goto out2; |
582 | #endif | 660 | #endif |
@@ -587,7 +665,7 @@ restart: | |||
587 | 665 | ||
588 | dst_hold(&rt->u.dst); | 666 | dst_hold(&rt->u.dst); |
589 | if (nrt) { | 667 | if (nrt) { |
590 | err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); | 668 | err = ip6_ins_rt(nrt); |
591 | if (!err) | 669 | if (!err) |
592 | goto out2; | 670 | goto out2; |
593 | } | 671 | } |
@@ -596,7 +674,7 @@ restart: | |||
596 | goto out2; | 674 | goto out2; |
597 | 675 | ||
598 | /* | 676 | /* |
599 | * Race condition! In the gap, when rt6_lock was | 677 | * Race condition! In the gap, when table->tb6_lock was |
600 | * released someone could insert this route. Relookup. | 678 | * released someone could insert this route. Relookup. |
601 | */ | 679 | */ |
602 | dst_release(&rt->u.dst); | 680 | dst_release(&rt->u.dst); |
@@ -608,40 +686,63 @@ out: | |||
608 | goto restart_2; | 686 | goto restart_2; |
609 | } | 687 | } |
610 | dst_hold(&rt->u.dst); | 688 | dst_hold(&rt->u.dst); |
611 | read_unlock_bh(&rt6_lock); | 689 | read_unlock_bh(&table->tb6_lock); |
612 | out2: | 690 | out2: |
613 | rt->u.dst.lastuse = jiffies; | 691 | rt->u.dst.lastuse = jiffies; |
614 | rt->u.dst.__use++; | 692 | rt->u.dst.__use++; |
615 | skb->dst = (struct dst_entry *) rt; | 693 | |
616 | return; | 694 | return rt; |
617 | } | 695 | } |
618 | 696 | ||
619 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 697 | void ip6_route_input(struct sk_buff *skb) |
698 | { | ||
699 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
700 | struct flowi fl = { | ||
701 | .iif = skb->dev->ifindex, | ||
702 | .nl_u = { | ||
703 | .ip6_u = { | ||
704 | .daddr = iph->daddr, | ||
705 | .saddr = iph->saddr, | ||
706 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
707 | .fwmark = skb->nfmark, | ||
708 | #endif | ||
709 | .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK, | ||
710 | }, | ||
711 | }, | ||
712 | .proto = iph->nexthdr, | ||
713 | }; | ||
714 | int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0; | ||
715 | |||
716 | skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); | ||
717 | } | ||
718 | |||
719 | static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, | ||
720 | struct flowi *fl, int flags) | ||
620 | { | 721 | { |
621 | struct fib6_node *fn; | 722 | struct fib6_node *fn; |
622 | struct rt6_info *rt, *nrt; | 723 | struct rt6_info *rt, *nrt; |
623 | int strict; | 724 | int strict = 0; |
624 | int attempts = 3; | 725 | int attempts = 3; |
625 | int err; | 726 | int err; |
626 | int reachable = RT6_SELECT_F_REACHABLE; | 727 | int reachable = RT6_LOOKUP_F_REACHABLE; |
627 | 728 | ||
628 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; | 729 | strict |= flags & RT6_LOOKUP_F_IFACE; |
629 | 730 | ||
630 | relookup: | 731 | relookup: |
631 | read_lock_bh(&rt6_lock); | 732 | read_lock_bh(&table->tb6_lock); |
632 | 733 | ||
633 | restart_2: | 734 | restart_2: |
634 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); | 735 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
635 | 736 | ||
636 | restart: | 737 | restart: |
637 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); | 738 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); |
638 | BACKTRACK(); | 739 | BACKTRACK(&fl->fl6_src); |
639 | if (rt == &ip6_null_entry || | 740 | if (rt == &ip6_null_entry || |
640 | rt->rt6i_flags & RTF_CACHE) | 741 | rt->rt6i_flags & RTF_CACHE) |
641 | goto out; | 742 | goto out; |
642 | 743 | ||
643 | dst_hold(&rt->u.dst); | 744 | dst_hold(&rt->u.dst); |
644 | read_unlock_bh(&rt6_lock); | 745 | read_unlock_bh(&table->tb6_lock); |
645 | 746 | ||
646 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 747 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
647 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 748 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
@@ -658,7 +759,7 @@ restart: | |||
658 | 759 | ||
659 | dst_hold(&rt->u.dst); | 760 | dst_hold(&rt->u.dst); |
660 | if (nrt) { | 761 | if (nrt) { |
661 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | 762 | err = ip6_ins_rt(nrt); |
662 | if (!err) | 763 | if (!err) |
663 | goto out2; | 764 | goto out2; |
664 | } | 765 | } |
@@ -667,7 +768,7 @@ restart: | |||
667 | goto out2; | 768 | goto out2; |
668 | 769 | ||
669 | /* | 770 | /* |
670 | * Race condition! In the gap, when rt6_lock was | 771 | * Race condition! In the gap, when table->tb6_lock was |
671 | * released someone could insert this route. Relookup. | 772 | * released someone could insert this route. Relookup. |
672 | */ | 773 | */ |
673 | dst_release(&rt->u.dst); | 774 | dst_release(&rt->u.dst); |
@@ -679,11 +780,21 @@ out: | |||
679 | goto restart_2; | 780 | goto restart_2; |
680 | } | 781 | } |
681 | dst_hold(&rt->u.dst); | 782 | dst_hold(&rt->u.dst); |
682 | read_unlock_bh(&rt6_lock); | 783 | read_unlock_bh(&table->tb6_lock); |
683 | out2: | 784 | out2: |
684 | rt->u.dst.lastuse = jiffies; | 785 | rt->u.dst.lastuse = jiffies; |
685 | rt->u.dst.__use++; | 786 | rt->u.dst.__use++; |
686 | return &rt->u.dst; | 787 | return rt; |
788 | } | ||
789 | |||
790 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | ||
791 | { | ||
792 | int flags = 0; | ||
793 | |||
794 | if (rt6_need_strict(&fl->fl6_dst)) | ||
795 | flags |= RT6_LOOKUP_F_IFACE; | ||
796 | |||
797 | return fib6_rule_lookup(fl, flags, ip6_pol_route_output); | ||
687 | } | 798 | } |
688 | 799 | ||
689 | 800 | ||
@@ -709,7 +820,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) | |||
709 | 820 | ||
710 | if (rt) { | 821 | if (rt) { |
711 | if (rt->rt6i_flags & RTF_CACHE) | 822 | if (rt->rt6i_flags & RTF_CACHE) |
712 | ip6_del_rt(rt, NULL, NULL, NULL); | 823 | ip6_del_rt(rt); |
713 | else | 824 | else |
714 | dst_release(dst); | 825 | dst_release(dst); |
715 | } | 826 | } |
@@ -747,8 +858,6 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
747 | } | 858 | } |
748 | } | 859 | } |
749 | 860 | ||
750 | /* Protected by rt6_lock. */ | ||
751 | static struct dst_entry *ndisc_dst_gc_list; | ||
752 | static int ipv6_get_mtu(struct net_device *dev); | 861 | static int ipv6_get_mtu(struct net_device *dev); |
753 | 862 | ||
754 | static inline unsigned int ipv6_advmss(unsigned int mtu) | 863 | static inline unsigned int ipv6_advmss(unsigned int mtu) |
@@ -769,6 +878,9 @@ static inline unsigned int ipv6_advmss(unsigned int mtu) | |||
769 | return mtu; | 878 | return mtu; |
770 | } | 879 | } |
771 | 880 | ||
881 | static struct dst_entry *ndisc_dst_gc_list; | ||
882 | static DEFINE_SPINLOCK(ndisc_lock); | ||
883 | |||
772 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | 884 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, |
773 | struct neighbour *neigh, | 885 | struct neighbour *neigh, |
774 | struct in6_addr *addr, | 886 | struct in6_addr *addr, |
@@ -809,10 +921,10 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | |||
809 | rt->rt6i_dst.plen = 128; | 921 | rt->rt6i_dst.plen = 128; |
810 | #endif | 922 | #endif |
811 | 923 | ||
812 | write_lock_bh(&rt6_lock); | 924 | spin_lock_bh(&ndisc_lock); |
813 | rt->u.dst.next = ndisc_dst_gc_list; | 925 | rt->u.dst.next = ndisc_dst_gc_list; |
814 | ndisc_dst_gc_list = &rt->u.dst; | 926 | ndisc_dst_gc_list = &rt->u.dst; |
815 | write_unlock_bh(&rt6_lock); | 927 | spin_unlock_bh(&ndisc_lock); |
816 | 928 | ||
817 | fib6_force_start_gc(); | 929 | fib6_force_start_gc(); |
818 | 930 | ||
@@ -826,8 +938,11 @@ int ndisc_dst_gc(int *more) | |||
826 | int freed; | 938 | int freed; |
827 | 939 | ||
828 | next = NULL; | 940 | next = NULL; |
941 | freed = 0; | ||
942 | |||
943 | spin_lock_bh(&ndisc_lock); | ||
829 | pprev = &ndisc_dst_gc_list; | 944 | pprev = &ndisc_dst_gc_list; |
830 | freed = 0; | 945 | |
831 | while ((dst = *pprev) != NULL) { | 946 | while ((dst = *pprev) != NULL) { |
832 | if (!atomic_read(&dst->__refcnt)) { | 947 | if (!atomic_read(&dst->__refcnt)) { |
833 | *pprev = dst->next; | 948 | *pprev = dst->next; |
@@ -839,6 +954,8 @@ int ndisc_dst_gc(int *more) | |||
839 | } | 954 | } |
840 | } | 955 | } |
841 | 956 | ||
957 | spin_unlock_bh(&ndisc_lock); | ||
958 | |||
842 | return freed; | 959 | return freed; |
843 | } | 960 | } |
844 | 961 | ||
@@ -899,28 +1016,24 @@ int ipv6_get_hoplimit(struct net_device *dev) | |||
899 | * | 1016 | * |
900 | */ | 1017 | */ |
901 | 1018 | ||
902 | int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 1019 | int ip6_route_add(struct fib6_config *cfg) |
903 | void *_rtattr, struct netlink_skb_parms *req) | ||
904 | { | 1020 | { |
905 | int err; | 1021 | int err; |
906 | struct rtmsg *r; | ||
907 | struct rtattr **rta; | ||
908 | struct rt6_info *rt = NULL; | 1022 | struct rt6_info *rt = NULL; |
909 | struct net_device *dev = NULL; | 1023 | struct net_device *dev = NULL; |
910 | struct inet6_dev *idev = NULL; | 1024 | struct inet6_dev *idev = NULL; |
1025 | struct fib6_table *table; | ||
911 | int addr_type; | 1026 | int addr_type; |
912 | 1027 | ||
913 | rta = (struct rtattr **) _rtattr; | 1028 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
914 | |||
915 | if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128) | ||
916 | return -EINVAL; | 1029 | return -EINVAL; |
917 | #ifndef CONFIG_IPV6_SUBTREES | 1030 | #ifndef CONFIG_IPV6_SUBTREES |
918 | if (rtmsg->rtmsg_src_len) | 1031 | if (cfg->fc_src_len) |
919 | return -EINVAL; | 1032 | return -EINVAL; |
920 | #endif | 1033 | #endif |
921 | if (rtmsg->rtmsg_ifindex) { | 1034 | if (cfg->fc_ifindex) { |
922 | err = -ENODEV; | 1035 | err = -ENODEV; |
923 | dev = dev_get_by_index(rtmsg->rtmsg_ifindex); | 1036 | dev = dev_get_by_index(cfg->fc_ifindex); |
924 | if (!dev) | 1037 | if (!dev) |
925 | goto out; | 1038 | goto out; |
926 | idev = in6_dev_get(dev); | 1039 | idev = in6_dev_get(dev); |
@@ -928,8 +1041,14 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
928 | goto out; | 1041 | goto out; |
929 | } | 1042 | } |
930 | 1043 | ||
931 | if (rtmsg->rtmsg_metric == 0) | 1044 | if (cfg->fc_metric == 0) |
932 | rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; | 1045 | cfg->fc_metric = IP6_RT_PRIO_USER; |
1046 | |||
1047 | table = fib6_new_table(cfg->fc_table); | ||
1048 | if (table == NULL) { | ||
1049 | err = -ENOBUFS; | ||
1050 | goto out; | ||
1051 | } | ||
933 | 1052 | ||
934 | rt = ip6_dst_alloc(); | 1053 | rt = ip6_dst_alloc(); |
935 | 1054 | ||
@@ -939,14 +1058,13 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
939 | } | 1058 | } |
940 | 1059 | ||
941 | rt->u.dst.obsolete = -1; | 1060 | rt->u.dst.obsolete = -1; |
942 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(rtmsg->rtmsg_info); | 1061 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires); |
943 | if (nlh && (r = NLMSG_DATA(nlh))) { | ||
944 | rt->rt6i_protocol = r->rtm_protocol; | ||
945 | } else { | ||
946 | rt->rt6i_protocol = RTPROT_BOOT; | ||
947 | } | ||
948 | 1062 | ||
949 | addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst); | 1063 | if (cfg->fc_protocol == RTPROT_UNSPEC) |
1064 | cfg->fc_protocol = RTPROT_BOOT; | ||
1065 | rt->rt6i_protocol = cfg->fc_protocol; | ||
1066 | |||
1067 | addr_type = ipv6_addr_type(&cfg->fc_dst); | ||
950 | 1068 | ||
951 | if (addr_type & IPV6_ADDR_MULTICAST) | 1069 | if (addr_type & IPV6_ADDR_MULTICAST) |
952 | rt->u.dst.input = ip6_mc_input; | 1070 | rt->u.dst.input = ip6_mc_input; |
@@ -955,24 +1073,22 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
955 | 1073 | ||
956 | rt->u.dst.output = ip6_output; | 1074 | rt->u.dst.output = ip6_output; |
957 | 1075 | ||
958 | ipv6_addr_prefix(&rt->rt6i_dst.addr, | 1076 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
959 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len); | 1077 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
960 | rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len; | ||
961 | if (rt->rt6i_dst.plen == 128) | 1078 | if (rt->rt6i_dst.plen == 128) |
962 | rt->u.dst.flags = DST_HOST; | 1079 | rt->u.dst.flags = DST_HOST; |
963 | 1080 | ||
964 | #ifdef CONFIG_IPV6_SUBTREES | 1081 | #ifdef CONFIG_IPV6_SUBTREES |
965 | ipv6_addr_prefix(&rt->rt6i_src.addr, | 1082 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
966 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1083 | rt->rt6i_src.plen = cfg->fc_src_len; |
967 | rt->rt6i_src.plen = rtmsg->rtmsg_src_len; | ||
968 | #endif | 1084 | #endif |
969 | 1085 | ||
970 | rt->rt6i_metric = rtmsg->rtmsg_metric; | 1086 | rt->rt6i_metric = cfg->fc_metric; |
971 | 1087 | ||
972 | /* We cannot add true routes via loopback here, | 1088 | /* We cannot add true routes via loopback here, |
973 | they would result in kernel looping; promote them to reject routes | 1089 | they would result in kernel looping; promote them to reject routes |
974 | */ | 1090 | */ |
975 | if ((rtmsg->rtmsg_flags&RTF_REJECT) || | 1091 | if ((cfg->fc_flags & RTF_REJECT) || |
976 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1092 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { |
977 | /* hold loopback dev/idev if we haven't done so. */ | 1093 | /* hold loopback dev/idev if we haven't done so. */ |
978 | if (dev != &loopback_dev) { | 1094 | if (dev != &loopback_dev) { |
@@ -995,12 +1111,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
995 | goto install_route; | 1111 | goto install_route; |
996 | } | 1112 | } |
997 | 1113 | ||
998 | if (rtmsg->rtmsg_flags & RTF_GATEWAY) { | 1114 | if (cfg->fc_flags & RTF_GATEWAY) { |
999 | struct in6_addr *gw_addr; | 1115 | struct in6_addr *gw_addr; |
1000 | int gwa_type; | 1116 | int gwa_type; |
1001 | 1117 | ||
1002 | gw_addr = &rtmsg->rtmsg_gateway; | 1118 | gw_addr = &cfg->fc_gateway; |
1003 | ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway); | 1119 | ipv6_addr_copy(&rt->rt6i_gateway, gw_addr); |
1004 | gwa_type = ipv6_addr_type(gw_addr); | 1120 | gwa_type = ipv6_addr_type(gw_addr); |
1005 | 1121 | ||
1006 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { | 1122 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { |
@@ -1017,7 +1133,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1017 | if (!(gwa_type&IPV6_ADDR_UNICAST)) | 1133 | if (!(gwa_type&IPV6_ADDR_UNICAST)) |
1018 | goto out; | 1134 | goto out; |
1019 | 1135 | ||
1020 | grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1); | 1136 | grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1); |
1021 | 1137 | ||
1022 | err = -EHOSTUNREACH; | 1138 | err = -EHOSTUNREACH; |
1023 | if (grt == NULL) | 1139 | if (grt == NULL) |
@@ -1049,7 +1165,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1049 | if (dev == NULL) | 1165 | if (dev == NULL) |
1050 | goto out; | 1166 | goto out; |
1051 | 1167 | ||
1052 | if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) { | 1168 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1053 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1169 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1054 | if (IS_ERR(rt->rt6i_nexthop)) { | 1170 | if (IS_ERR(rt->rt6i_nexthop)) { |
1055 | err = PTR_ERR(rt->rt6i_nexthop); | 1171 | err = PTR_ERR(rt->rt6i_nexthop); |
@@ -1058,24 +1174,24 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1058 | } | 1174 | } |
1059 | } | 1175 | } |
1060 | 1176 | ||
1061 | rt->rt6i_flags = rtmsg->rtmsg_flags; | 1177 | rt->rt6i_flags = cfg->fc_flags; |
1062 | 1178 | ||
1063 | install_route: | 1179 | install_route: |
1064 | if (rta && rta[RTA_METRICS-1]) { | 1180 | if (cfg->fc_mx) { |
1065 | int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); | 1181 | struct nlattr *nla; |
1066 | struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]); | 1182 | int remaining; |
1067 | 1183 | ||
1068 | while (RTA_OK(attr, attrlen)) { | 1184 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
1069 | unsigned flavor = attr->rta_type; | 1185 | int type = nla->nla_type; |
1070 | if (flavor) { | 1186 | |
1071 | if (flavor > RTAX_MAX) { | 1187 | if (type) { |
1188 | if (type > RTAX_MAX) { | ||
1072 | err = -EINVAL; | 1189 | err = -EINVAL; |
1073 | goto out; | 1190 | goto out; |
1074 | } | 1191 | } |
1075 | rt->u.dst.metrics[flavor-1] = | 1192 | |
1076 | *(u32 *)RTA_DATA(attr); | 1193 | rt->u.dst.metrics[type - 1] = nla_get_u32(nla); |
1077 | } | 1194 | } |
1078 | attr = RTA_NEXT(attr, attrlen); | ||
1079 | } | 1195 | } |
1080 | } | 1196 | } |
1081 | 1197 | ||
@@ -1087,7 +1203,8 @@ install_route: | |||
1087 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); | 1203 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); |
1088 | rt->u.dst.dev = dev; | 1204 | rt->u.dst.dev = dev; |
1089 | rt->rt6i_idev = idev; | 1205 | rt->rt6i_idev = idev; |
1090 | return ip6_ins_rt(rt, nlh, _rtattr, req); | 1206 | rt->rt6i_table = table; |
1207 | return __ip6_ins_rt(rt, &cfg->fc_nlinfo); | ||
1091 | 1208 | ||
1092 | out: | 1209 | out: |
1093 | if (dev) | 1210 | if (dev) |
@@ -1099,51 +1216,65 @@ out: | |||
1099 | return err; | 1216 | return err; |
1100 | } | 1217 | } |
1101 | 1218 | ||
1102 | int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1219 | static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) |
1103 | { | 1220 | { |
1104 | int err; | 1221 | int err; |
1222 | struct fib6_table *table; | ||
1105 | 1223 | ||
1106 | write_lock_bh(&rt6_lock); | 1224 | if (rt == &ip6_null_entry) |
1225 | return -ENOENT; | ||
1107 | 1226 | ||
1108 | err = fib6_del(rt, nlh, _rtattr, req); | 1227 | table = rt->rt6i_table; |
1228 | write_lock_bh(&table->tb6_lock); | ||
1229 | |||
1230 | err = fib6_del(rt, info); | ||
1109 | dst_release(&rt->u.dst); | 1231 | dst_release(&rt->u.dst); |
1110 | 1232 | ||
1111 | write_unlock_bh(&rt6_lock); | 1233 | write_unlock_bh(&table->tb6_lock); |
1112 | 1234 | ||
1113 | return err; | 1235 | return err; |
1114 | } | 1236 | } |
1115 | 1237 | ||
1116 | static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1238 | int ip6_del_rt(struct rt6_info *rt) |
1117 | { | 1239 | { |
1240 | return __ip6_del_rt(rt, NULL); | ||
1241 | } | ||
1242 | |||
1243 | static int ip6_route_del(struct fib6_config *cfg) | ||
1244 | { | ||
1245 | struct fib6_table *table; | ||
1118 | struct fib6_node *fn; | 1246 | struct fib6_node *fn; |
1119 | struct rt6_info *rt; | 1247 | struct rt6_info *rt; |
1120 | int err = -ESRCH; | 1248 | int err = -ESRCH; |
1121 | 1249 | ||
1122 | read_lock_bh(&rt6_lock); | 1250 | table = fib6_get_table(cfg->fc_table); |
1251 | if (table == NULL) | ||
1252 | return err; | ||
1123 | 1253 | ||
1124 | fn = fib6_locate(&ip6_routing_table, | 1254 | read_lock_bh(&table->tb6_lock); |
1125 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, | 1255 | |
1126 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1256 | fn = fib6_locate(&table->tb6_root, |
1257 | &cfg->fc_dst, cfg->fc_dst_len, | ||
1258 | &cfg->fc_src, cfg->fc_src_len); | ||
1127 | 1259 | ||
1128 | if (fn) { | 1260 | if (fn) { |
1129 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1261 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1130 | if (rtmsg->rtmsg_ifindex && | 1262 | if (cfg->fc_ifindex && |
1131 | (rt->rt6i_dev == NULL || | 1263 | (rt->rt6i_dev == NULL || |
1132 | rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex)) | 1264 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) |
1133 | continue; | 1265 | continue; |
1134 | if (rtmsg->rtmsg_flags&RTF_GATEWAY && | 1266 | if (cfg->fc_flags & RTF_GATEWAY && |
1135 | !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway)) | 1267 | !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) |
1136 | continue; | 1268 | continue; |
1137 | if (rtmsg->rtmsg_metric && | 1269 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
1138 | rtmsg->rtmsg_metric != rt->rt6i_metric) | ||
1139 | continue; | 1270 | continue; |
1140 | dst_hold(&rt->u.dst); | 1271 | dst_hold(&rt->u.dst); |
1141 | read_unlock_bh(&rt6_lock); | 1272 | read_unlock_bh(&table->tb6_lock); |
1142 | 1273 | ||
1143 | return ip6_del_rt(rt, nlh, _rtattr, req); | 1274 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); |
1144 | } | 1275 | } |
1145 | } | 1276 | } |
1146 | read_unlock_bh(&rt6_lock); | 1277 | read_unlock_bh(&table->tb6_lock); |
1147 | 1278 | ||
1148 | return err; | 1279 | return err; |
1149 | } | 1280 | } |
@@ -1151,13 +1282,18 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r | |||
1151 | /* | 1282 | /* |
1152 | * Handle redirects | 1283 | * Handle redirects |
1153 | */ | 1284 | */ |
1154 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1285 | struct ip6rd_flowi { |
1155 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1286 | struct flowi fl; |
1287 | struct in6_addr gateway; | ||
1288 | }; | ||
1289 | |||
1290 | static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, | ||
1291 | struct flowi *fl, | ||
1292 | int flags) | ||
1156 | { | 1293 | { |
1157 | struct rt6_info *rt, *nrt = NULL; | 1294 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; |
1158 | int strict; | 1295 | struct rt6_info *rt; |
1159 | struct fib6_node *fn; | 1296 | struct fib6_node *fn; |
1160 | struct netevent_redirect netevent; | ||
1161 | 1297 | ||
1162 | /* | 1298 | /* |
1163 | * Get the "current" route for this destination and | 1299 | * Get the "current" route for this destination and |
@@ -1169,10 +1305,9 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | |||
1169 | * is a bit fuzzy and one might need to check all possible | 1305 | * is a bit fuzzy and one might need to check all possible |
1170 | * routes. | 1306 | * routes. |
1171 | */ | 1307 | */ |
1172 | strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); | ||
1173 | 1308 | ||
1174 | read_lock_bh(&rt6_lock); | 1309 | read_lock_bh(&table->tb6_lock); |
1175 | fn = fib6_lookup(&ip6_routing_table, dest, NULL); | 1310 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
1176 | restart: | 1311 | restart: |
1177 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1312 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1178 | /* | 1313 | /* |
@@ -1187,29 +1322,60 @@ restart: | |||
1187 | continue; | 1322 | continue; |
1188 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1323 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1189 | continue; | 1324 | continue; |
1190 | if (neigh->dev != rt->rt6i_dev) | 1325 | if (fl->oif != rt->rt6i_dev->ifindex) |
1191 | continue; | 1326 | continue; |
1192 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) | 1327 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1193 | continue; | 1328 | continue; |
1194 | break; | 1329 | break; |
1195 | } | 1330 | } |
1196 | if (rt) | ||
1197 | dst_hold(&rt->u.dst); | ||
1198 | else if (strict) { | ||
1199 | while ((fn = fn->parent) != NULL) { | ||
1200 | if (fn->fn_flags & RTN_ROOT) | ||
1201 | break; | ||
1202 | if (fn->fn_flags & RTN_RTINFO) | ||
1203 | goto restart; | ||
1204 | } | ||
1205 | } | ||
1206 | read_unlock_bh(&rt6_lock); | ||
1207 | 1331 | ||
1208 | if (!rt) { | 1332 | if (!rt) |
1333 | rt = &ip6_null_entry; | ||
1334 | BACKTRACK(&fl->fl6_src); | ||
1335 | out: | ||
1336 | dst_hold(&rt->u.dst); | ||
1337 | |||
1338 | read_unlock_bh(&table->tb6_lock); | ||
1339 | |||
1340 | return rt; | ||
1341 | }; | ||
1342 | |||
1343 | static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | ||
1344 | struct in6_addr *src, | ||
1345 | struct in6_addr *gateway, | ||
1346 | struct net_device *dev) | ||
1347 | { | ||
1348 | struct ip6rd_flowi rdfl = { | ||
1349 | .fl = { | ||
1350 | .oif = dev->ifindex, | ||
1351 | .nl_u = { | ||
1352 | .ip6_u = { | ||
1353 | .daddr = *dest, | ||
1354 | .saddr = *src, | ||
1355 | }, | ||
1356 | }, | ||
1357 | }, | ||
1358 | .gateway = *gateway, | ||
1359 | }; | ||
1360 | int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0; | ||
1361 | |||
1362 | return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); | ||
1363 | } | ||
1364 | |||
1365 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | ||
1366 | struct in6_addr *saddr, | ||
1367 | struct neighbour *neigh, u8 *lladdr, int on_link) | ||
1368 | { | ||
1369 | struct rt6_info *rt, *nrt = NULL; | ||
1370 | struct netevent_redirect netevent; | ||
1371 | |||
1372 | rt = ip6_route_redirect(dest, src, saddr, neigh->dev); | ||
1373 | |||
1374 | if (rt == &ip6_null_entry) { | ||
1209 | if (net_ratelimit()) | 1375 | if (net_ratelimit()) |
1210 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1376 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
1211 | "for redirect target\n"); | 1377 | "for redirect target\n"); |
1212 | return; | 1378 | goto out; |
1213 | } | 1379 | } |
1214 | 1380 | ||
1215 | /* | 1381 | /* |
@@ -1252,7 +1418,7 @@ restart: | |||
1252 | nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); | 1418 | nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); |
1253 | nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); | 1419 | nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); |
1254 | 1420 | ||
1255 | if (ip6_ins_rt(nrt, NULL, NULL, NULL)) | 1421 | if (ip6_ins_rt(nrt)) |
1256 | goto out; | 1422 | goto out; |
1257 | 1423 | ||
1258 | netevent.old = &rt->u.dst; | 1424 | netevent.old = &rt->u.dst; |
@@ -1260,7 +1426,7 @@ restart: | |||
1260 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1426 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
1261 | 1427 | ||
1262 | if (rt->rt6i_flags&RTF_CACHE) { | 1428 | if (rt->rt6i_flags&RTF_CACHE) { |
1263 | ip6_del_rt(rt, NULL, NULL, NULL); | 1429 | ip6_del_rt(rt); |
1264 | return; | 1430 | return; |
1265 | } | 1431 | } |
1266 | 1432 | ||
@@ -1342,7 +1508,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1342 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | 1508 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); |
1343 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | 1509 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; |
1344 | 1510 | ||
1345 | ip6_ins_rt(nrt, NULL, NULL, NULL); | 1511 | ip6_ins_rt(nrt); |
1346 | } | 1512 | } |
1347 | out: | 1513 | out: |
1348 | dst_release(&rt->u.dst); | 1514 | dst_release(&rt->u.dst); |
@@ -1378,6 +1544,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1378 | #ifdef CONFIG_IPV6_SUBTREES | 1544 | #ifdef CONFIG_IPV6_SUBTREES |
1379 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1545 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
1380 | #endif | 1546 | #endif |
1547 | rt->rt6i_table = ort->rt6i_table; | ||
1381 | } | 1548 | } |
1382 | return rt; | 1549 | return rt; |
1383 | } | 1550 | } |
@@ -1388,9 +1555,14 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
1388 | { | 1555 | { |
1389 | struct fib6_node *fn; | 1556 | struct fib6_node *fn; |
1390 | struct rt6_info *rt = NULL; | 1557 | struct rt6_info *rt = NULL; |
1558 | struct fib6_table *table; | ||
1559 | |||
1560 | table = fib6_get_table(RT6_TABLE_INFO); | ||
1561 | if (table == NULL) | ||
1562 | return NULL; | ||
1391 | 1563 | ||
1392 | write_lock_bh(&rt6_lock); | 1564 | write_lock_bh(&table->tb6_lock); |
1393 | fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); | 1565 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); |
1394 | if (!fn) | 1566 | if (!fn) |
1395 | goto out; | 1567 | goto out; |
1396 | 1568 | ||
@@ -1405,7 +1577,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
1405 | break; | 1577 | break; |
1406 | } | 1578 | } |
1407 | out: | 1579 | out: |
1408 | write_unlock_bh(&rt6_lock); | 1580 | write_unlock_bh(&table->tb6_lock); |
1409 | return rt; | 1581 | return rt; |
1410 | } | 1582 | } |
1411 | 1583 | ||
@@ -1413,21 +1585,23 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
1413 | struct in6_addr *gwaddr, int ifindex, | 1585 | struct in6_addr *gwaddr, int ifindex, |
1414 | unsigned pref) | 1586 | unsigned pref) |
1415 | { | 1587 | { |
1416 | struct in6_rtmsg rtmsg; | 1588 | struct fib6_config cfg = { |
1589 | .fc_table = RT6_TABLE_INFO, | ||
1590 | .fc_metric = 1024, | ||
1591 | .fc_ifindex = ifindex, | ||
1592 | .fc_dst_len = prefixlen, | ||
1593 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | | ||
1594 | RTF_UP | RTF_PREF(pref), | ||
1595 | }; | ||
1596 | |||
1597 | ipv6_addr_copy(&cfg.fc_dst, prefix); | ||
1598 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); | ||
1417 | 1599 | ||
1418 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
1419 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1420 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
1421 | rtmsg.rtmsg_dst_len = prefixlen; | ||
1422 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1423 | rtmsg.rtmsg_metric = 1024; | ||
1424 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
1425 | /* We should treat it as a default route if prefix length is 0. */ | 1600 | /* We should treat it as a default route if prefix length is 0. */ |
1426 | if (!prefixlen) | 1601 | if (!prefixlen) |
1427 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | 1602 | cfg.fc_flags |= RTF_DEFAULT; |
1428 | rtmsg.rtmsg_ifindex = ifindex; | ||
1429 | 1603 | ||
1430 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1604 | ip6_route_add(&cfg); |
1431 | 1605 | ||
1432 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | 1606 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); |
1433 | } | 1607 | } |
@@ -1436,12 +1610,14 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
1436 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1610 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) |
1437 | { | 1611 | { |
1438 | struct rt6_info *rt; | 1612 | struct rt6_info *rt; |
1439 | struct fib6_node *fn; | 1613 | struct fib6_table *table; |
1440 | 1614 | ||
1441 | fn = &ip6_routing_table; | 1615 | table = fib6_get_table(RT6_TABLE_DFLT); |
1616 | if (table == NULL) | ||
1617 | return NULL; | ||
1442 | 1618 | ||
1443 | write_lock_bh(&rt6_lock); | 1619 | write_lock_bh(&table->tb6_lock); |
1444 | for (rt = fn->leaf; rt; rt=rt->u.next) { | 1620 | for (rt = table->tb6_root.leaf; rt; rt=rt->u.next) { |
1445 | if (dev == rt->rt6i_dev && | 1621 | if (dev == rt->rt6i_dev && |
1446 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1622 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
1447 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1623 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
@@ -1449,7 +1625,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1449 | } | 1625 | } |
1450 | if (rt) | 1626 | if (rt) |
1451 | dst_hold(&rt->u.dst); | 1627 | dst_hold(&rt->u.dst); |
1452 | write_unlock_bh(&rt6_lock); | 1628 | write_unlock_bh(&table->tb6_lock); |
1453 | return rt; | 1629 | return rt; |
1454 | } | 1630 | } |
1455 | 1631 | ||
@@ -1457,43 +1633,65 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
1457 | struct net_device *dev, | 1633 | struct net_device *dev, |
1458 | unsigned int pref) | 1634 | unsigned int pref) |
1459 | { | 1635 | { |
1460 | struct in6_rtmsg rtmsg; | 1636 | struct fib6_config cfg = { |
1637 | .fc_table = RT6_TABLE_DFLT, | ||
1638 | .fc_metric = 1024, | ||
1639 | .fc_ifindex = dev->ifindex, | ||
1640 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | | ||
1641 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), | ||
1642 | }; | ||
1461 | 1643 | ||
1462 | memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); | 1644 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); |
1463 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1464 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1465 | rtmsg.rtmsg_metric = 1024; | ||
1466 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | | ||
1467 | RTF_PREF(pref); | ||
1468 | 1645 | ||
1469 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1646 | ip6_route_add(&cfg); |
1470 | 1647 | ||
1471 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1472 | return rt6_get_dflt_router(gwaddr, dev); | 1648 | return rt6_get_dflt_router(gwaddr, dev); |
1473 | } | 1649 | } |
1474 | 1650 | ||
1475 | void rt6_purge_dflt_routers(void) | 1651 | void rt6_purge_dflt_routers(void) |
1476 | { | 1652 | { |
1477 | struct rt6_info *rt; | 1653 | struct rt6_info *rt; |
1654 | struct fib6_table *table; | ||
1655 | |||
1656 | /* NOTE: Keep consistent with rt6_get_dflt_router */ | ||
1657 | table = fib6_get_table(RT6_TABLE_DFLT); | ||
1658 | if (table == NULL) | ||
1659 | return; | ||
1478 | 1660 | ||
1479 | restart: | 1661 | restart: |
1480 | read_lock_bh(&rt6_lock); | 1662 | read_lock_bh(&table->tb6_lock); |
1481 | for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { | 1663 | for (rt = table->tb6_root.leaf; rt; rt = rt->u.next) { |
1482 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1664 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
1483 | dst_hold(&rt->u.dst); | 1665 | dst_hold(&rt->u.dst); |
1484 | 1666 | read_unlock_bh(&table->tb6_lock); | |
1485 | read_unlock_bh(&rt6_lock); | 1667 | ip6_del_rt(rt); |
1486 | |||
1487 | ip6_del_rt(rt, NULL, NULL, NULL); | ||
1488 | |||
1489 | goto restart; | 1668 | goto restart; |
1490 | } | 1669 | } |
1491 | } | 1670 | } |
1492 | read_unlock_bh(&rt6_lock); | 1671 | read_unlock_bh(&table->tb6_lock); |
1672 | } | ||
1673 | |||
1674 | static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg, | ||
1675 | struct fib6_config *cfg) | ||
1676 | { | ||
1677 | memset(cfg, 0, sizeof(*cfg)); | ||
1678 | |||
1679 | cfg->fc_table = RT6_TABLE_MAIN; | ||
1680 | cfg->fc_ifindex = rtmsg->rtmsg_ifindex; | ||
1681 | cfg->fc_metric = rtmsg->rtmsg_metric; | ||
1682 | cfg->fc_expires = rtmsg->rtmsg_info; | ||
1683 | cfg->fc_dst_len = rtmsg->rtmsg_dst_len; | ||
1684 | cfg->fc_src_len = rtmsg->rtmsg_src_len; | ||
1685 | cfg->fc_flags = rtmsg->rtmsg_flags; | ||
1686 | |||
1687 | ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst); | ||
1688 | ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src); | ||
1689 | ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway); | ||
1493 | } | 1690 | } |
1494 | 1691 | ||
1495 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | 1692 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) |
1496 | { | 1693 | { |
1694 | struct fib6_config cfg; | ||
1497 | struct in6_rtmsg rtmsg; | 1695 | struct in6_rtmsg rtmsg; |
1498 | int err; | 1696 | int err; |
1499 | 1697 | ||
@@ -1506,14 +1704,16 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
1506 | sizeof(struct in6_rtmsg)); | 1704 | sizeof(struct in6_rtmsg)); |
1507 | if (err) | 1705 | if (err) |
1508 | return -EFAULT; | 1706 | return -EFAULT; |
1509 | 1707 | ||
1708 | rtmsg_to_fib6_config(&rtmsg, &cfg); | ||
1709 | |||
1510 | rtnl_lock(); | 1710 | rtnl_lock(); |
1511 | switch (cmd) { | 1711 | switch (cmd) { |
1512 | case SIOCADDRT: | 1712 | case SIOCADDRT: |
1513 | err = ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1713 | err = ip6_route_add(&cfg); |
1514 | break; | 1714 | break; |
1515 | case SIOCDELRT: | 1715 | case SIOCDELRT: |
1516 | err = ip6_route_del(&rtmsg, NULL, NULL, NULL); | 1716 | err = ip6_route_del(&cfg); |
1517 | break; | 1717 | break; |
1518 | default: | 1718 | default: |
1519 | err = -EINVAL; | 1719 | err = -EINVAL; |
@@ -1587,6 +1787,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1587 | 1787 | ||
1588 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 1788 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
1589 | rt->rt6i_dst.plen = 128; | 1789 | rt->rt6i_dst.plen = 128; |
1790 | rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL); | ||
1590 | 1791 | ||
1591 | atomic_set(&rt->u.dst.__refcnt, 1); | 1792 | atomic_set(&rt->u.dst.__refcnt, 1); |
1592 | 1793 | ||
@@ -1605,9 +1806,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) | |||
1605 | 1806 | ||
1606 | void rt6_ifdown(struct net_device *dev) | 1807 | void rt6_ifdown(struct net_device *dev) |
1607 | { | 1808 | { |
1608 | write_lock_bh(&rt6_lock); | 1809 | fib6_clean_all(fib6_ifdown, 0, dev); |
1609 | fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); | ||
1610 | write_unlock_bh(&rt6_lock); | ||
1611 | } | 1810 | } |
1612 | 1811 | ||
1613 | struct rt6_mtu_change_arg | 1812 | struct rt6_mtu_change_arg |
@@ -1657,80 +1856,114 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
1657 | 1856 | ||
1658 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) | 1857 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) |
1659 | { | 1858 | { |
1660 | struct rt6_mtu_change_arg arg; | 1859 | struct rt6_mtu_change_arg arg = { |
1860 | .dev = dev, | ||
1861 | .mtu = mtu, | ||
1862 | }; | ||
1661 | 1863 | ||
1662 | arg.dev = dev; | 1864 | fib6_clean_all(rt6_mtu_change_route, 0, &arg); |
1663 | arg.mtu = mtu; | ||
1664 | read_lock_bh(&rt6_lock); | ||
1665 | fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg); | ||
1666 | read_unlock_bh(&rt6_lock); | ||
1667 | } | 1865 | } |
1668 | 1866 | ||
1669 | static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, | 1867 | static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { |
1670 | struct in6_rtmsg *rtmsg) | 1868 | [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, |
1869 | [RTA_OIF] = { .type = NLA_U32 }, | ||
1870 | [RTA_IIF] = { .type = NLA_U32 }, | ||
1871 | [RTA_PRIORITY] = { .type = NLA_U32 }, | ||
1872 | [RTA_METRICS] = { .type = NLA_NESTED }, | ||
1873 | }; | ||
1874 | |||
1875 | static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
1876 | struct fib6_config *cfg) | ||
1671 | { | 1877 | { |
1672 | memset(rtmsg, 0, sizeof(*rtmsg)); | 1878 | struct rtmsg *rtm; |
1879 | struct nlattr *tb[RTA_MAX+1]; | ||
1880 | int err; | ||
1673 | 1881 | ||
1674 | rtmsg->rtmsg_dst_len = r->rtm_dst_len; | 1882 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
1675 | rtmsg->rtmsg_src_len = r->rtm_src_len; | 1883 | if (err < 0) |
1676 | rtmsg->rtmsg_flags = RTF_UP; | 1884 | goto errout; |
1677 | if (r->rtm_type == RTN_UNREACHABLE) | ||
1678 | rtmsg->rtmsg_flags |= RTF_REJECT; | ||
1679 | 1885 | ||
1680 | if (rta[RTA_GATEWAY-1]) { | 1886 | err = -EINVAL; |
1681 | if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) | 1887 | rtm = nlmsg_data(nlh); |
1682 | return -EINVAL; | 1888 | memset(cfg, 0, sizeof(*cfg)); |
1683 | memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16); | 1889 | |
1684 | rtmsg->rtmsg_flags |= RTF_GATEWAY; | 1890 | cfg->fc_table = rtm->rtm_table; |
1685 | } | 1891 | cfg->fc_dst_len = rtm->rtm_dst_len; |
1686 | if (rta[RTA_DST-1]) { | 1892 | cfg->fc_src_len = rtm->rtm_src_len; |
1687 | if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3)) | 1893 | cfg->fc_flags = RTF_UP; |
1688 | return -EINVAL; | 1894 | cfg->fc_protocol = rtm->rtm_protocol; |
1689 | memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3)); | 1895 | |
1896 | if (rtm->rtm_type == RTN_UNREACHABLE) | ||
1897 | cfg->fc_flags |= RTF_REJECT; | ||
1898 | |||
1899 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | ||
1900 | cfg->fc_nlinfo.nlh = nlh; | ||
1901 | |||
1902 | if (tb[RTA_GATEWAY]) { | ||
1903 | nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16); | ||
1904 | cfg->fc_flags |= RTF_GATEWAY; | ||
1690 | } | 1905 | } |
1691 | if (rta[RTA_SRC-1]) { | 1906 | |
1692 | if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3)) | 1907 | if (tb[RTA_DST]) { |
1693 | return -EINVAL; | 1908 | int plen = (rtm->rtm_dst_len + 7) >> 3; |
1694 | memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3)); | 1909 | |
1910 | if (nla_len(tb[RTA_DST]) < plen) | ||
1911 | goto errout; | ||
1912 | |||
1913 | nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen); | ||
1695 | } | 1914 | } |
1696 | if (rta[RTA_OIF-1]) { | 1915 | |
1697 | if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int))) | 1916 | if (tb[RTA_SRC]) { |
1698 | return -EINVAL; | 1917 | int plen = (rtm->rtm_src_len + 7) >> 3; |
1699 | memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 1918 | |
1919 | if (nla_len(tb[RTA_SRC]) < plen) | ||
1920 | goto errout; | ||
1921 | |||
1922 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); | ||
1700 | } | 1923 | } |
1701 | if (rta[RTA_PRIORITY-1]) { | 1924 | |
1702 | if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4)) | 1925 | if (tb[RTA_OIF]) |
1703 | return -EINVAL; | 1926 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
1704 | memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4); | 1927 | |
1928 | if (tb[RTA_PRIORITY]) | ||
1929 | cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]); | ||
1930 | |||
1931 | if (tb[RTA_METRICS]) { | ||
1932 | cfg->fc_mx = nla_data(tb[RTA_METRICS]); | ||
1933 | cfg->fc_mx_len = nla_len(tb[RTA_METRICS]); | ||
1705 | } | 1934 | } |
1706 | return 0; | 1935 | |
1936 | if (tb[RTA_TABLE]) | ||
1937 | cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); | ||
1938 | |||
1939 | err = 0; | ||
1940 | errout: | ||
1941 | return err; | ||
1707 | } | 1942 | } |
1708 | 1943 | ||
1709 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1944 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1710 | { | 1945 | { |
1711 | struct rtmsg *r = NLMSG_DATA(nlh); | 1946 | struct fib6_config cfg; |
1712 | struct in6_rtmsg rtmsg; | 1947 | int err; |
1713 | 1948 | ||
1714 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1949 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1715 | return -EINVAL; | 1950 | if (err < 0) |
1716 | return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1951 | return err; |
1952 | |||
1953 | return ip6_route_del(&cfg); | ||
1717 | } | 1954 | } |
1718 | 1955 | ||
1719 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1956 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1720 | { | 1957 | { |
1721 | struct rtmsg *r = NLMSG_DATA(nlh); | 1958 | struct fib6_config cfg; |
1722 | struct in6_rtmsg rtmsg; | 1959 | int err; |
1723 | 1960 | ||
1724 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1961 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1725 | return -EINVAL; | 1962 | if (err < 0) |
1726 | return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1963 | return err; |
1727 | } | ||
1728 | 1964 | ||
1729 | struct rt6_rtnl_dump_arg | 1965 | return ip6_route_add(&cfg); |
1730 | { | 1966 | } |
1731 | struct sk_buff *skb; | ||
1732 | struct netlink_callback *cb; | ||
1733 | }; | ||
1734 | 1967 | ||
1735 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | 1968 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, |
1736 | struct in6_addr *dst, struct in6_addr *src, | 1969 | struct in6_addr *dst, struct in6_addr *src, |
@@ -1738,9 +1971,9 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1738 | int prefix, unsigned int flags) | 1971 | int prefix, unsigned int flags) |
1739 | { | 1972 | { |
1740 | struct rtmsg *rtm; | 1973 | struct rtmsg *rtm; |
1741 | struct nlmsghdr *nlh; | 1974 | struct nlmsghdr *nlh; |
1742 | unsigned char *b = skb->tail; | ||
1743 | struct rta_cacheinfo ci; | 1975 | struct rta_cacheinfo ci; |
1976 | u32 table; | ||
1744 | 1977 | ||
1745 | if (prefix) { /* user wants prefix routes only */ | 1978 | if (prefix) { /* user wants prefix routes only */ |
1746 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 1979 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -1749,13 +1982,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1749 | } | 1982 | } |
1750 | } | 1983 | } |
1751 | 1984 | ||
1752 | nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*rtm), flags); | 1985 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); |
1753 | rtm = NLMSG_DATA(nlh); | 1986 | if (nlh == NULL) |
1987 | return -ENOBUFS; | ||
1988 | |||
1989 | rtm = nlmsg_data(nlh); | ||
1754 | rtm->rtm_family = AF_INET6; | 1990 | rtm->rtm_family = AF_INET6; |
1755 | rtm->rtm_dst_len = rt->rt6i_dst.plen; | 1991 | rtm->rtm_dst_len = rt->rt6i_dst.plen; |
1756 | rtm->rtm_src_len = rt->rt6i_src.plen; | 1992 | rtm->rtm_src_len = rt->rt6i_src.plen; |
1757 | rtm->rtm_tos = 0; | 1993 | rtm->rtm_tos = 0; |
1758 | rtm->rtm_table = RT_TABLE_MAIN; | 1994 | if (rt->rt6i_table) |
1995 | table = rt->rt6i_table->tb6_id; | ||
1996 | else | ||
1997 | table = RT6_TABLE_UNSPEC; | ||
1998 | rtm->rtm_table = table; | ||
1999 | NLA_PUT_U32(skb, RTA_TABLE, table); | ||
1759 | if (rt->rt6i_flags&RTF_REJECT) | 2000 | if (rt->rt6i_flags&RTF_REJECT) |
1760 | rtm->rtm_type = RTN_UNREACHABLE; | 2001 | rtm->rtm_type = RTN_UNREACHABLE; |
1761 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) | 2002 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) |
@@ -1776,31 +2017,35 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1776 | rtm->rtm_flags |= RTM_F_CLONED; | 2017 | rtm->rtm_flags |= RTM_F_CLONED; |
1777 | 2018 | ||
1778 | if (dst) { | 2019 | if (dst) { |
1779 | RTA_PUT(skb, RTA_DST, 16, dst); | 2020 | NLA_PUT(skb, RTA_DST, 16, dst); |
1780 | rtm->rtm_dst_len = 128; | 2021 | rtm->rtm_dst_len = 128; |
1781 | } else if (rtm->rtm_dst_len) | 2022 | } else if (rtm->rtm_dst_len) |
1782 | RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); | 2023 | NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); |
1783 | #ifdef CONFIG_IPV6_SUBTREES | 2024 | #ifdef CONFIG_IPV6_SUBTREES |
1784 | if (src) { | 2025 | if (src) { |
1785 | RTA_PUT(skb, RTA_SRC, 16, src); | 2026 | NLA_PUT(skb, RTA_SRC, 16, src); |
1786 | rtm->rtm_src_len = 128; | 2027 | rtm->rtm_src_len = 128; |
1787 | } else if (rtm->rtm_src_len) | 2028 | } else if (rtm->rtm_src_len) |
1788 | RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); | 2029 | NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); |
1789 | #endif | 2030 | #endif |
1790 | if (iif) | 2031 | if (iif) |
1791 | RTA_PUT(skb, RTA_IIF, 4, &iif); | 2032 | NLA_PUT_U32(skb, RTA_IIF, iif); |
1792 | else if (dst) { | 2033 | else if (dst) { |
1793 | struct in6_addr saddr_buf; | 2034 | struct in6_addr saddr_buf; |
1794 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) | 2035 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) |
1795 | RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2036 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
1796 | } | 2037 | } |
2038 | |||
1797 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2039 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
1798 | goto rtattr_failure; | 2040 | goto nla_put_failure; |
2041 | |||
1799 | if (rt->u.dst.neighbour) | 2042 | if (rt->u.dst.neighbour) |
1800 | RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); | 2043 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); |
2044 | |||
1801 | if (rt->u.dst.dev) | 2045 | if (rt->u.dst.dev) |
1802 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex); | 2046 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
1803 | RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric); | 2047 | |
2048 | NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); | ||
1804 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 2049 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); |
1805 | if (rt->rt6i_expires) | 2050 | if (rt->rt6i_expires) |
1806 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); | 2051 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); |
@@ -1812,23 +2057,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1812 | ci.rta_id = 0; | 2057 | ci.rta_id = 0; |
1813 | ci.rta_ts = 0; | 2058 | ci.rta_ts = 0; |
1814 | ci.rta_tsage = 0; | 2059 | ci.rta_tsage = 0; |
1815 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 2060 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
1816 | nlh->nlmsg_len = skb->tail - b; | ||
1817 | return skb->len; | ||
1818 | 2061 | ||
1819 | nlmsg_failure: | 2062 | return nlmsg_end(skb, nlh); |
1820 | rtattr_failure: | 2063 | |
1821 | skb_trim(skb, b - skb->data); | 2064 | nla_put_failure: |
1822 | return -1; | 2065 | return nlmsg_cancel(skb, nlh); |
1823 | } | 2066 | } |
1824 | 2067 | ||
1825 | static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | 2068 | int rt6_dump_route(struct rt6_info *rt, void *p_arg) |
1826 | { | 2069 | { |
1827 | struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; | 2070 | struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; |
1828 | int prefix; | 2071 | int prefix; |
1829 | 2072 | ||
1830 | if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) { | 2073 | if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { |
1831 | struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh); | 2074 | struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); |
1832 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; | 2075 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; |
1833 | } else | 2076 | } else |
1834 | prefix = 0; | 2077 | prefix = 0; |
@@ -1838,189 +2081,108 @@ static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
1838 | prefix, NLM_F_MULTI); | 2081 | prefix, NLM_F_MULTI); |
1839 | } | 2082 | } |
1840 | 2083 | ||
1841 | static int fib6_dump_node(struct fib6_walker_t *w) | 2084 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
1842 | { | 2085 | { |
1843 | int res; | 2086 | struct nlattr *tb[RTA_MAX+1]; |
1844 | struct rt6_info *rt; | 2087 | struct rt6_info *rt; |
2088 | struct sk_buff *skb; | ||
2089 | struct rtmsg *rtm; | ||
2090 | struct flowi fl; | ||
2091 | int err, iif = 0; | ||
1845 | 2092 | ||
1846 | for (rt = w->leaf; rt; rt = rt->u.next) { | 2093 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
1847 | res = rt6_dump_route(rt, w->args); | 2094 | if (err < 0) |
1848 | if (res < 0) { | 2095 | goto errout; |
1849 | /* Frame is full, suspend walking */ | ||
1850 | w->leaf = rt; | ||
1851 | return 1; | ||
1852 | } | ||
1853 | BUG_TRAP(res!=0); | ||
1854 | } | ||
1855 | w->leaf = NULL; | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | static void fib6_dump_end(struct netlink_callback *cb) | ||
1860 | { | ||
1861 | struct fib6_walker_t *w = (void*)cb->args[0]; | ||
1862 | |||
1863 | if (w) { | ||
1864 | cb->args[0] = 0; | ||
1865 | fib6_walker_unlink(w); | ||
1866 | kfree(w); | ||
1867 | } | ||
1868 | cb->done = (void*)cb->args[1]; | ||
1869 | cb->args[1] = 0; | ||
1870 | } | ||
1871 | |||
1872 | static int fib6_dump_done(struct netlink_callback *cb) | ||
1873 | { | ||
1874 | fib6_dump_end(cb); | ||
1875 | return cb->done ? cb->done(cb) : 0; | ||
1876 | } | ||
1877 | |||
1878 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | ||
1879 | { | ||
1880 | struct rt6_rtnl_dump_arg arg; | ||
1881 | struct fib6_walker_t *w; | ||
1882 | int res; | ||
1883 | 2096 | ||
1884 | arg.skb = skb; | 2097 | err = -EINVAL; |
1885 | arg.cb = cb; | 2098 | memset(&fl, 0, sizeof(fl)); |
1886 | 2099 | ||
1887 | w = (void*)cb->args[0]; | 2100 | if (tb[RTA_SRC]) { |
1888 | if (w == NULL) { | 2101 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
1889 | /* New dump: | 2102 | goto errout; |
1890 | * | ||
1891 | * 1. hook callback destructor. | ||
1892 | */ | ||
1893 | cb->args[1] = (long)cb->done; | ||
1894 | cb->done = fib6_dump_done; | ||
1895 | 2103 | ||
1896 | /* | 2104 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); |
1897 | * 2. allocate and initialize walker. | ||
1898 | */ | ||
1899 | w = kzalloc(sizeof(*w), GFP_ATOMIC); | ||
1900 | if (w == NULL) | ||
1901 | return -ENOMEM; | ||
1902 | RT6_TRACE("dump<%p", w); | ||
1903 | w->root = &ip6_routing_table; | ||
1904 | w->func = fib6_dump_node; | ||
1905 | w->args = &arg; | ||
1906 | cb->args[0] = (long)w; | ||
1907 | read_lock_bh(&rt6_lock); | ||
1908 | res = fib6_walk(w); | ||
1909 | read_unlock_bh(&rt6_lock); | ||
1910 | } else { | ||
1911 | w->args = &arg; | ||
1912 | read_lock_bh(&rt6_lock); | ||
1913 | res = fib6_walk_continue(w); | ||
1914 | read_unlock_bh(&rt6_lock); | ||
1915 | } | 2105 | } |
1916 | #if RT6_DEBUG >= 3 | ||
1917 | if (res <= 0 && skb->len == 0) | ||
1918 | RT6_TRACE("%p>dump end\n", w); | ||
1919 | #endif | ||
1920 | res = res < 0 ? res : skb->len; | ||
1921 | /* res < 0 is an error. (really, impossible) | ||
1922 | res == 0 means that dump is complete, but skb still can contain data. | ||
1923 | res > 0 dump is not complete, but frame is full. | ||
1924 | */ | ||
1925 | /* Destroy walker, if dump of this table is complete. */ | ||
1926 | if (res <= 0) | ||
1927 | fib6_dump_end(cb); | ||
1928 | return res; | ||
1929 | } | ||
1930 | |||
1931 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | ||
1932 | { | ||
1933 | struct rtattr **rta = arg; | ||
1934 | int iif = 0; | ||
1935 | int err = -ENOBUFS; | ||
1936 | struct sk_buff *skb; | ||
1937 | struct flowi fl; | ||
1938 | struct rt6_info *rt; | ||
1939 | 2106 | ||
1940 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2107 | if (tb[RTA_DST]) { |
1941 | if (skb == NULL) | 2108 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
1942 | goto out; | 2109 | goto errout; |
1943 | 2110 | ||
1944 | /* Reserve room for dummy headers, this skb can pass | 2111 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); |
1945 | through good chunk of routing engine. | 2112 | } |
1946 | */ | ||
1947 | skb->mac.raw = skb->data; | ||
1948 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
1949 | 2113 | ||
1950 | memset(&fl, 0, sizeof(fl)); | 2114 | if (tb[RTA_IIF]) |
1951 | if (rta[RTA_SRC-1]) | 2115 | iif = nla_get_u32(tb[RTA_IIF]); |
1952 | ipv6_addr_copy(&fl.fl6_src, | ||
1953 | (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); | ||
1954 | if (rta[RTA_DST-1]) | ||
1955 | ipv6_addr_copy(&fl.fl6_dst, | ||
1956 | (struct in6_addr*)RTA_DATA(rta[RTA_DST-1])); | ||
1957 | 2116 | ||
1958 | if (rta[RTA_IIF-1]) | 2117 | if (tb[RTA_OIF]) |
1959 | memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 2118 | fl.oif = nla_get_u32(tb[RTA_OIF]); |
1960 | 2119 | ||
1961 | if (iif) { | 2120 | if (iif) { |
1962 | struct net_device *dev; | 2121 | struct net_device *dev; |
1963 | dev = __dev_get_by_index(iif); | 2122 | dev = __dev_get_by_index(iif); |
1964 | if (!dev) { | 2123 | if (!dev) { |
1965 | err = -ENODEV; | 2124 | err = -ENODEV; |
1966 | goto out_free; | 2125 | goto errout; |
1967 | } | 2126 | } |
1968 | } | 2127 | } |
1969 | 2128 | ||
1970 | fl.oif = 0; | 2129 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1971 | if (rta[RTA_OIF-1]) | 2130 | if (skb == NULL) { |
1972 | memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 2131 | err = -ENOBUFS; |
2132 | goto errout; | ||
2133 | } | ||
1973 | 2134 | ||
1974 | rt = (struct rt6_info*)ip6_route_output(NULL, &fl); | 2135 | /* Reserve room for dummy headers, this skb can pass |
2136 | through good chunk of routing engine. | ||
2137 | */ | ||
2138 | skb->mac.raw = skb->data; | ||
2139 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
1975 | 2140 | ||
2141 | rt = (struct rt6_info*) ip6_route_output(NULL, &fl); | ||
1976 | skb->dst = &rt->u.dst; | 2142 | skb->dst = &rt->u.dst; |
1977 | 2143 | ||
1978 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | 2144 | err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, |
1979 | err = rt6_fill_node(skb, rt, | ||
1980 | &fl.fl6_dst, &fl.fl6_src, | ||
1981 | iif, | ||
1982 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2145 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
1983 | nlh->nlmsg_seq, 0, 0); | 2146 | nlh->nlmsg_seq, 0, 0); |
1984 | if (err < 0) { | 2147 | if (err < 0) { |
1985 | err = -EMSGSIZE; | 2148 | kfree_skb(skb); |
1986 | goto out_free; | 2149 | goto errout; |
1987 | } | 2150 | } |
1988 | 2151 | ||
1989 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 2152 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
1990 | if (err > 0) | 2153 | errout: |
1991 | err = 0; | ||
1992 | out: | ||
1993 | return err; | 2154 | return err; |
1994 | out_free: | ||
1995 | kfree_skb(skb); | ||
1996 | goto out; | ||
1997 | } | 2155 | } |
1998 | 2156 | ||
1999 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, | 2157 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) |
2000 | struct netlink_skb_parms *req) | ||
2001 | { | 2158 | { |
2002 | struct sk_buff *skb; | 2159 | struct sk_buff *skb; |
2003 | int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); | 2160 | u32 pid = 0, seq = 0; |
2004 | u32 pid = current->pid; | 2161 | struct nlmsghdr *nlh = NULL; |
2005 | u32 seq = 0; | 2162 | int payload = sizeof(struct rtmsg) + 256; |
2006 | 2163 | int err = -ENOBUFS; | |
2007 | if (req) | 2164 | |
2008 | pid = req->pid; | 2165 | if (info) { |
2009 | if (nlh) | 2166 | pid = info->pid; |
2010 | seq = nlh->nlmsg_seq; | 2167 | nlh = info->nlh; |
2011 | 2168 | if (nlh) | |
2012 | skb = alloc_skb(size, gfp_any()); | 2169 | seq = nlh->nlmsg_seq; |
2013 | if (!skb) { | ||
2014 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, ENOBUFS); | ||
2015 | return; | ||
2016 | } | 2170 | } |
2017 | if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0) < 0) { | 2171 | |
2172 | skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); | ||
2173 | if (skb == NULL) | ||
2174 | goto errout; | ||
2175 | |||
2176 | err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0); | ||
2177 | if (err < 0) { | ||
2018 | kfree_skb(skb); | 2178 | kfree_skb(skb); |
2019 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, EINVAL); | 2179 | goto errout; |
2020 | return; | ||
2021 | } | 2180 | } |
2022 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE; | 2181 | |
2023 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_ROUTE, gfp_any()); | 2182 | err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); |
2183 | errout: | ||
2184 | if (err < 0) | ||
2185 | rtnl_set_sk_err(RTNLGRP_IPV6_ROUTE, err); | ||
2024 | } | 2186 | } |
2025 | 2187 | ||
2026 | /* | 2188 | /* |
@@ -2096,16 +2258,13 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2096 | 2258 | ||
2097 | static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) | 2259 | static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) |
2098 | { | 2260 | { |
2099 | struct rt6_proc_arg arg; | 2261 | struct rt6_proc_arg arg = { |
2100 | arg.buffer = buffer; | 2262 | .buffer = buffer, |
2101 | arg.offset = offset; | 2263 | .offset = offset, |
2102 | arg.length = length; | 2264 | .length = length, |
2103 | arg.skip = 0; | 2265 | }; |
2104 | arg.len = 0; | ||
2105 | 2266 | ||
2106 | read_lock_bh(&rt6_lock); | 2267 | fib6_clean_all(rt6_info_route, 0, &arg); |
2107 | fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg); | ||
2108 | read_unlock_bh(&rt6_lock); | ||
2109 | 2268 | ||
2110 | *start = buffer; | 2269 | *start = buffer; |
2111 | if (offset) | 2270 | if (offset) |
@@ -2260,13 +2419,9 @@ void __init ip6_route_init(void) | |||
2260 | { | 2419 | { |
2261 | struct proc_dir_entry *p; | 2420 | struct proc_dir_entry *p; |
2262 | 2421 | ||
2263 | ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", | 2422 | ip6_dst_ops.kmem_cachep = |
2264 | sizeof(struct rt6_info), | 2423 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, |
2265 | 0, SLAB_HWCACHE_ALIGN, | 2424 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
2266 | NULL, NULL); | ||
2267 | if (!ip6_dst_ops.kmem_cachep) | ||
2268 | panic("cannot create ip6_dst_cache"); | ||
2269 | |||
2270 | fib6_init(); | 2425 | fib6_init(); |
2271 | #ifdef CONFIG_PROC_FS | 2426 | #ifdef CONFIG_PROC_FS |
2272 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); | 2427 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); |
@@ -2278,10 +2433,16 @@ void __init ip6_route_init(void) | |||
2278 | #ifdef CONFIG_XFRM | 2433 | #ifdef CONFIG_XFRM |
2279 | xfrm6_init(); | 2434 | xfrm6_init(); |
2280 | #endif | 2435 | #endif |
2436 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
2437 | fib6_rules_init(); | ||
2438 | #endif | ||
2281 | } | 2439 | } |
2282 | 2440 | ||
2283 | void ip6_route_cleanup(void) | 2441 | void ip6_route_cleanup(void) |
2284 | { | 2442 | { |
2443 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
2444 | fib6_rules_cleanup(); | ||
2445 | #endif | ||
2285 | #ifdef CONFIG_PROC_FS | 2446 | #ifdef CONFIG_PROC_FS |
2286 | proc_net_remove("ipv6_route"); | 2447 | proc_net_remove("ipv6_route"); |
2287 | proc_net_remove("rt6_stats"); | 2448 | proc_net_remove("rt6_stats"); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 802a1a6b1037..2546fc9f0a78 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -251,6 +251,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
251 | final_p = &final; | 251 | final_p = &final; |
252 | } | 252 | } |
253 | 253 | ||
254 | security_sk_classify_flow(sk, &fl); | ||
255 | |||
254 | err = ip6_dst_lookup(sk, &dst, &fl); | 256 | err = ip6_dst_lookup(sk, &dst, &fl); |
255 | if (err) | 257 | if (err) |
256 | goto failure; | 258 | goto failure; |
@@ -270,7 +272,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
270 | inet->rcv_saddr = LOOPBACK4_IPV6; | 272 | inet->rcv_saddr = LOOPBACK4_IPV6; |
271 | 273 | ||
272 | sk->sk_gso_type = SKB_GSO_TCPV6; | 274 | sk->sk_gso_type = SKB_GSO_TCPV6; |
273 | __ip6_dst_store(sk, dst, NULL); | 275 | __ip6_dst_store(sk, dst, NULL, NULL); |
274 | 276 | ||
275 | icsk->icsk_ext_hdr_len = 0; | 277 | icsk->icsk_ext_hdr_len = 0; |
276 | if (np->opt) | 278 | if (np->opt) |
@@ -374,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
374 | fl.oif = sk->sk_bound_dev_if; | 376 | fl.oif = sk->sk_bound_dev_if; |
375 | fl.fl_ip_dport = inet->dport; | 377 | fl.fl_ip_dport = inet->dport; |
376 | fl.fl_ip_sport = inet->sport; | 378 | fl.fl_ip_sport = inet->sport; |
379 | security_skb_classify_flow(skb, &fl); | ||
377 | 380 | ||
378 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 381 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { |
379 | sk->sk_err_soft = -err; | 382 | sk->sk_err_soft = -err; |
@@ -467,6 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
467 | fl.oif = treq->iif; | 470 | fl.oif = treq->iif; |
468 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
469 | fl.fl_ip_sport = inet_sk(sk)->sport; | 472 | fl.fl_ip_sport = inet_sk(sk)->sport; |
473 | security_req_classify_flow(req, &fl); | ||
470 | 474 | ||
471 | if (dst == NULL) { | 475 | if (dst == NULL) { |
472 | opt = np->opt; | 476 | opt = np->opt; |
@@ -541,7 +545,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
541 | struct ipv6_pinfo *np = inet6_sk(sk); | 545 | struct ipv6_pinfo *np = inet6_sk(sk); |
542 | struct tcphdr *th = skb->h.th; | 546 | struct tcphdr *th = skb->h.th; |
543 | 547 | ||
544 | if (skb->ip_summed == CHECKSUM_HW) { | 548 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
545 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 549 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); |
546 | skb->csum = offsetof(struct tcphdr, check); | 550 | skb->csum = offsetof(struct tcphdr, check); |
547 | } else { | 551 | } else { |
@@ -566,7 +570,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
566 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | 570 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, |
567 | IPPROTO_TCP, 0); | 571 | IPPROTO_TCP, 0); |
568 | skb->csum = offsetof(struct tcphdr, check); | 572 | skb->csum = offsetof(struct tcphdr, check); |
569 | skb->ip_summed = CHECKSUM_HW; | 573 | skb->ip_summed = CHECKSUM_PARTIAL; |
570 | return 0; | 574 | return 0; |
571 | } | 575 | } |
572 | 576 | ||
@@ -625,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) | |||
625 | fl.oif = inet6_iif(skb); | 629 | fl.oif = inet6_iif(skb); |
626 | fl.fl_ip_dport = t1->dest; | 630 | fl.fl_ip_dport = t1->dest; |
627 | fl.fl_ip_sport = t1->source; | 631 | fl.fl_ip_sport = t1->source; |
632 | security_skb_classify_flow(skb, &fl); | ||
628 | 633 | ||
629 | /* sk = NULL, but it is safe for now. RST socket required. */ | 634 | /* sk = NULL, but it is safe for now. RST socket required. */ |
630 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 635 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
@@ -691,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
691 | fl.oif = inet6_iif(skb); | 696 | fl.oif = inet6_iif(skb); |
692 | fl.fl_ip_dport = t1->dest; | 697 | fl.fl_ip_dport = t1->dest; |
693 | fl.fl_ip_sport = t1->source; | 698 | fl.fl_ip_sport = t1->source; |
699 | security_skb_classify_flow(skb, &fl); | ||
694 | 700 | ||
695 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 701 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
696 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 702 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
@@ -820,6 +826,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
820 | 826 | ||
821 | tcp_rsk(req)->snt_isn = isn; | 827 | tcp_rsk(req)->snt_isn = isn; |
822 | 828 | ||
829 | security_inet_conn_request(sk, skb, req); | ||
830 | |||
823 | if (tcp_v6_send_synack(sk, req, NULL)) | 831 | if (tcp_v6_send_synack(sk, req, NULL)) |
824 | goto drop; | 832 | goto drop; |
825 | 833 | ||
@@ -923,6 +931,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
923 | fl.oif = sk->sk_bound_dev_if; | 931 | fl.oif = sk->sk_bound_dev_if; |
924 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 932 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
925 | fl.fl_ip_sport = inet_sk(sk)->sport; | 933 | fl.fl_ip_sport = inet_sk(sk)->sport; |
934 | security_req_classify_flow(req, &fl); | ||
926 | 935 | ||
927 | if (ip6_dst_lookup(sk, &dst, &fl)) | 936 | if (ip6_dst_lookup(sk, &dst, &fl)) |
928 | goto out; | 937 | goto out; |
@@ -945,7 +954,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
945 | */ | 954 | */ |
946 | 955 | ||
947 | newsk->sk_gso_type = SKB_GSO_TCPV6; | 956 | newsk->sk_gso_type = SKB_GSO_TCPV6; |
948 | __ip6_dst_store(newsk, dst, NULL); | 957 | __ip6_dst_store(newsk, dst, NULL, NULL); |
949 | 958 | ||
950 | newtcp6sk = (struct tcp6_sock *)newsk; | 959 | newtcp6sk = (struct tcp6_sock *)newsk; |
951 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 960 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
@@ -1024,7 +1033,7 @@ out: | |||
1024 | 1033 | ||
1025 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1034 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
1026 | { | 1035 | { |
1027 | if (skb->ip_summed == CHECKSUM_HW) { | 1036 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1028 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1037 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, |
1029 | &skb->nh.ipv6h->daddr,skb->csum)) { | 1038 | &skb->nh.ipv6h->daddr,skb->csum)) { |
1030 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1039 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -1066,7 +1075,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1066 | if (skb->protocol == htons(ETH_P_IP)) | 1075 | if (skb->protocol == htons(ETH_P_IP)) |
1067 | return tcp_v4_do_rcv(sk, skb); | 1076 | return tcp_v4_do_rcv(sk, skb); |
1068 | 1077 | ||
1069 | if (sk_filter(sk, skb, 0)) | 1078 | if (sk_filter(sk, skb)) |
1070 | goto discard; | 1079 | goto discard; |
1071 | 1080 | ||
1072 | /* | 1081 | /* |
@@ -1223,7 +1232,7 @@ process: | |||
1223 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1232 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1224 | goto discard_and_relse; | 1233 | goto discard_and_relse; |
1225 | 1234 | ||
1226 | if (sk_filter(sk, skb, 0)) | 1235 | if (sk_filter(sk, skb)) |
1227 | goto discard_and_relse; | 1236 | goto discard_and_relse; |
1228 | 1237 | ||
1229 | skb->dev = NULL; | 1238 | skb->dev = NULL; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3d54f246411e..9662561701d1 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -61,81 +61,9 @@ | |||
61 | 61 | ||
62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
63 | 63 | ||
64 | /* Grrr, addr_type already calculated by caller, but I don't want | 64 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) |
65 | * to add some silly "cookie" argument to this method just for that. | ||
66 | */ | ||
67 | static int udp_v6_get_port(struct sock *sk, unsigned short snum) | ||
68 | { | 65 | { |
69 | struct sock *sk2; | 66 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
70 | struct hlist_node *node; | ||
71 | |||
72 | write_lock_bh(&udp_hash_lock); | ||
73 | if (snum == 0) { | ||
74 | int best_size_so_far, best, result, i; | ||
75 | |||
76 | if (udp_port_rover > sysctl_local_port_range[1] || | ||
77 | udp_port_rover < sysctl_local_port_range[0]) | ||
78 | udp_port_rover = sysctl_local_port_range[0]; | ||
79 | best_size_so_far = 32767; | ||
80 | best = result = udp_port_rover; | ||
81 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | ||
82 | int size; | ||
83 | struct hlist_head *list; | ||
84 | |||
85 | list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | ||
86 | if (hlist_empty(list)) { | ||
87 | if (result > sysctl_local_port_range[1]) | ||
88 | result = sysctl_local_port_range[0] + | ||
89 | ((result - sysctl_local_port_range[0]) & | ||
90 | (UDP_HTABLE_SIZE - 1)); | ||
91 | goto gotit; | ||
92 | } | ||
93 | size = 0; | ||
94 | sk_for_each(sk2, node, list) | ||
95 | if (++size >= best_size_so_far) | ||
96 | goto next; | ||
97 | best_size_so_far = size; | ||
98 | best = result; | ||
99 | next:; | ||
100 | } | ||
101 | result = best; | ||
102 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { | ||
103 | if (result > sysctl_local_port_range[1]) | ||
104 | result = sysctl_local_port_range[0] | ||
105 | + ((result - sysctl_local_port_range[0]) & | ||
106 | (UDP_HTABLE_SIZE - 1)); | ||
107 | if (!udp_lport_inuse(result)) | ||
108 | break; | ||
109 | } | ||
110 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | ||
111 | goto fail; | ||
112 | gotit: | ||
113 | udp_port_rover = snum = result; | ||
114 | } else { | ||
115 | sk_for_each(sk2, node, | ||
116 | &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) { | ||
117 | if (inet_sk(sk2)->num == snum && | ||
118 | sk2 != sk && | ||
119 | (!sk2->sk_bound_dev_if || | ||
120 | !sk->sk_bound_dev_if || | ||
121 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | ||
122 | (!sk2->sk_reuse || !sk->sk_reuse) && | ||
123 | ipv6_rcv_saddr_equal(sk, sk2)) | ||
124 | goto fail; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | inet_sk(sk)->num = snum; | ||
129 | if (sk_unhashed(sk)) { | ||
130 | sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]); | ||
131 | sock_prot_inc_use(sk->sk_prot); | ||
132 | } | ||
133 | write_unlock_bh(&udp_hash_lock); | ||
134 | return 0; | ||
135 | |||
136 | fail: | ||
137 | write_unlock_bh(&udp_hash_lock); | ||
138 | return 1; | ||
139 | } | 67 | } |
140 | 68 | ||
141 | static void udp_v6_hash(struct sock *sk) | 69 | static void udp_v6_hash(struct sock *sk) |
@@ -345,6 +273,8 @@ out: | |||
345 | 273 | ||
346 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 274 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
347 | { | 275 | { |
276 | int rc; | ||
277 | |||
348 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { | 278 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { |
349 | kfree_skb(skb); | 279 | kfree_skb(skb); |
350 | return -1; | 280 | return -1; |
@@ -356,7 +286,10 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
356 | return 0; | 286 | return 0; |
357 | } | 287 | } |
358 | 288 | ||
359 | if (sock_queue_rcv_skb(sk,skb)<0) { | 289 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
290 | /* Note that an ENOMEM error is charged twice */ | ||
291 | if (rc == -ENOMEM) | ||
292 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | ||
360 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 293 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); |
361 | kfree_skb(skb); | 294 | kfree_skb(skb); |
362 | return 0; | 295 | return 0; |
@@ -475,7 +408,7 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
475 | uh = skb->h.uh; | 408 | uh = skb->h.uh; |
476 | } | 409 | } |
477 | 410 | ||
478 | if (skb->ip_summed == CHECKSUM_HW && | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE && |
479 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | 412 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) |
480 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 413 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
481 | 414 | ||
@@ -782,6 +715,8 @@ do_udp_sendmsg: | |||
782 | connected = 0; | 715 | connected = 0; |
783 | } | 716 | } |
784 | 717 | ||
718 | security_sk_classify_flow(sk, fl); | ||
719 | |||
785 | err = ip6_sk_dst_lookup(sk, &dst, fl); | 720 | err = ip6_sk_dst_lookup(sk, &dst, fl); |
786 | if (err) | 721 | if (err) |
787 | goto out; | 722 | goto out; |
@@ -840,7 +775,12 @@ do_append_data: | |||
840 | if (connected) { | 775 | if (connected) { |
841 | ip6_dst_store(sk, dst, | 776 | ip6_dst_store(sk, dst, |
842 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? | 777 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? |
843 | &np->daddr : NULL); | 778 | &np->daddr : NULL, |
779 | #ifdef CONFIG_IPV6_SUBTREES | ||
780 | ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? | ||
781 | &np->saddr : | ||
782 | #endif | ||
783 | NULL); | ||
844 | } else { | 784 | } else { |
845 | dst_release(dst); | 785 | dst_release(dst); |
846 | } | 786 | } |
@@ -855,6 +795,16 @@ out: | |||
855 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 795 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); |
856 | return len; | 796 | return len; |
857 | } | 797 | } |
798 | /* | ||
799 | * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting | ||
800 | * ENOBUFS might not be good (it's not tunable per se), but otherwise | ||
801 | * we don't have a good statistic (IpOutDiscards but it can be too many | ||
802 | * things). We could add another new stat but at least for now that | ||
803 | * seems like overkill. | ||
804 | */ | ||
805 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | ||
806 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | ||
807 | } | ||
858 | return err; | 808 | return err; |
859 | 809 | ||
860 | do_confirm: | 810 | do_confirm: |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 0405d74ff910..a40a05789013 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -72,7 +72,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | |||
72 | if (x->mode->input(x, skb)) | 72 | if (x->mode->input(x, skb)) |
73 | goto drop; | 73 | goto drop; |
74 | 74 | ||
75 | if (x->props.mode) { /* XXX */ | 75 | if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ |
76 | decaps = 1; | 76 | decaps = 1; |
77 | break; | 77 | break; |
78 | } | 78 | } |
@@ -138,3 +138,111 @@ int xfrm6_rcv(struct sk_buff **pskb) | |||
138 | { | 138 | { |
139 | return xfrm6_rcv_spi(*pskb, 0); | 139 | return xfrm6_rcv_spi(*pskb, 0); |
140 | } | 140 | } |
141 | |||
142 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
143 | xfrm_address_t *saddr, u8 proto) | ||
144 | { | ||
145 | struct xfrm_state *x = NULL; | ||
146 | int wildcard = 0; | ||
147 | struct in6_addr any; | ||
148 | xfrm_address_t *xany; | ||
149 | struct xfrm_state *xfrm_vec_one = NULL; | ||
150 | int nh = 0; | ||
151 | int i = 0; | ||
152 | |||
153 | ipv6_addr_set(&any, 0, 0, 0, 0); | ||
154 | xany = (xfrm_address_t *)&any; | ||
155 | |||
156 | for (i = 0; i < 3; i++) { | ||
157 | xfrm_address_t *dst, *src; | ||
158 | switch (i) { | ||
159 | case 0: | ||
160 | dst = daddr; | ||
161 | src = saddr; | ||
162 | break; | ||
163 | case 1: | ||
164 | /* lookup state with wild-card source address */ | ||
165 | wildcard = 1; | ||
166 | dst = daddr; | ||
167 | src = xany; | ||
168 | break; | ||
169 | case 2: | ||
170 | default: | ||
171 | /* lookup state with wild-card addresses */ | ||
172 | wildcard = 1; /* XXX */ | ||
173 | dst = xany; | ||
174 | src = xany; | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); | ||
179 | if (!x) | ||
180 | continue; | ||
181 | |||
182 | spin_lock(&x->lock); | ||
183 | |||
184 | if (wildcard) { | ||
185 | if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { | ||
186 | spin_unlock(&x->lock); | ||
187 | xfrm_state_put(x); | ||
188 | x = NULL; | ||
189 | continue; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | if (unlikely(x->km.state != XFRM_STATE_VALID)) { | ||
194 | spin_unlock(&x->lock); | ||
195 | xfrm_state_put(x); | ||
196 | x = NULL; | ||
197 | continue; | ||
198 | } | ||
199 | if (xfrm_state_check_expire(x)) { | ||
200 | spin_unlock(&x->lock); | ||
201 | xfrm_state_put(x); | ||
202 | x = NULL; | ||
203 | continue; | ||
204 | } | ||
205 | |||
206 | nh = x->type->input(x, skb); | ||
207 | if (nh <= 0) { | ||
208 | spin_unlock(&x->lock); | ||
209 | xfrm_state_put(x); | ||
210 | x = NULL; | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | x->curlft.bytes += skb->len; | ||
215 | x->curlft.packets++; | ||
216 | |||
217 | spin_unlock(&x->lock); | ||
218 | |||
219 | xfrm_vec_one = x; | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | if (!xfrm_vec_one) | ||
224 | goto drop; | ||
225 | |||
226 | /* Allocate new secpath or COW existing one. */ | ||
227 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
228 | struct sec_path *sp; | ||
229 | sp = secpath_dup(skb->sp); | ||
230 | if (!sp) | ||
231 | goto drop; | ||
232 | if (skb->sp) | ||
233 | secpath_put(skb->sp); | ||
234 | skb->sp = sp; | ||
235 | } | ||
236 | |||
237 | if (1 + skb->sp->len > XFRM_MAX_DEPTH) | ||
238 | goto drop; | ||
239 | |||
240 | skb->sp->xvec[skb->sp->len] = xfrm_vec_one; | ||
241 | skb->sp->len ++; | ||
242 | |||
243 | return 1; | ||
244 | drop: | ||
245 | if (xfrm_vec_one) | ||
246 | xfrm_state_put(xfrm_vec_one); | ||
247 | return -1; | ||
248 | } | ||
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c new file mode 100644 index 000000000000..6031c16d46ca --- /dev/null +++ b/net/ipv6/xfrm6_mode_ro.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * xfrm6_mode_ro.c - Route optimization mode for IPv6. | ||
3 | * | ||
4 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
5 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | /* | ||
22 | * Authors: | ||
23 | * Noriaki TAKAMIYA @USAGI | ||
24 | * Masahide NAKAMURA @USAGI | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/skbuff.h> | ||
31 | #include <linux/stringify.h> | ||
32 | #include <net/ipv6.h> | ||
33 | #include <net/xfrm.h> | ||
34 | |||
35 | /* Add route optimization header space. | ||
36 | * | ||
37 | * The IP header and mutable extension headers will be moved forward to make | ||
38 | * space for the route optimization header. | ||
39 | * | ||
40 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
41 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
42 | * of the extension header directly preceding the encapsulation header, or in | ||
43 | * its absence, that of the top IP header. The value of skb->data will always | ||
44 | * point to the top IP header. | ||
45 | */ | ||
46 | static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | ||
47 | { | ||
48 | struct ipv6hdr *iph; | ||
49 | u8 *prevhdr; | ||
50 | int hdr_len; | ||
51 | |||
52 | skb_push(skb, x->props.header_len); | ||
53 | iph = skb->nh.ipv6h; | ||
54 | |||
55 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
56 | skb->nh.raw = prevhdr - x->props.header_len; | ||
57 | skb->h.raw = skb->data + hdr_len; | ||
58 | memmove(skb->data, iph, hdr_len); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Do nothing about routing optimization header unlike IPsec. | ||
64 | */ | ||
65 | static int xfrm6_ro_input(struct xfrm_state *x, struct sk_buff *skb) | ||
66 | { | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static struct xfrm_mode xfrm6_ro_mode = { | ||
71 | .input = xfrm6_ro_input, | ||
72 | .output = xfrm6_ro_output, | ||
73 | .owner = THIS_MODULE, | ||
74 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, | ||
75 | }; | ||
76 | |||
77 | static int __init xfrm6_ro_init(void) | ||
78 | { | ||
79 | return xfrm_register_mode(&xfrm6_ro_mode, AF_INET6); | ||
80 | } | ||
81 | |||
82 | static void __exit xfrm6_ro_exit(void) | ||
83 | { | ||
84 | int err; | ||
85 | |||
86 | err = xfrm_unregister_mode(&xfrm6_ro_mode, AF_INET6); | ||
87 | BUG_ON(err); | ||
88 | } | ||
89 | |||
90 | module_init(xfrm6_ro_init); | ||
91 | module_exit(xfrm6_ro_exit); | ||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_ROUTEOPTIMIZATION); | ||
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index 711d713e36d8..3a4b39b12bad 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c | |||
@@ -25,9 +25,8 @@ | |||
25 | * its absence, that of the top IP header. The value of skb->data will always | 25 | * its absence, that of the top IP header. The value of skb->data will always |
26 | * point to the top IP header. | 26 | * point to the top IP header. |
27 | */ | 27 | */ |
28 | static int xfrm6_transport_output(struct sk_buff *skb) | 28 | static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) |
29 | { | 29 | { |
30 | struct xfrm_state *x = skb->dst->xfrm; | ||
31 | struct ipv6hdr *iph; | 30 | struct ipv6hdr *iph; |
32 | u8 *prevhdr; | 31 | u8 *prevhdr; |
33 | int hdr_len; | 32 | int hdr_len; |
@@ -35,7 +34,7 @@ static int xfrm6_transport_output(struct sk_buff *skb) | |||
35 | skb_push(skb, x->props.header_len); | 34 | skb_push(skb, x->props.header_len); |
36 | iph = skb->nh.ipv6h; | 35 | iph = skb->nh.ipv6h; |
37 | 36 | ||
38 | hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | 37 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); |
39 | skb->nh.raw = prevhdr - x->props.header_len; | 38 | skb->nh.raw = prevhdr - x->props.header_len; |
40 | skb->h.raw = skb->data + hdr_len; | 39 | skb->h.raw = skb->data + hdr_len; |
41 | memmove(skb->data, iph, hdr_len); | 40 | memmove(skb->data, iph, hdr_len); |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 8af79be2edca..5e7d8a7d6414 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -37,10 +37,9 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | |||
37 | * its absence, that of the top IP header. The value of skb->data will always | 37 | * its absence, that of the top IP header. The value of skb->data will always |
38 | * point to the top IP header. | 38 | * point to the top IP header. |
39 | */ | 39 | */ |
40 | static int xfrm6_tunnel_output(struct sk_buff *skb) | 40 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
41 | { | 41 | { |
42 | struct dst_entry *dst = skb->dst; | 42 | struct dst_entry *dst = skb->dst; |
43 | struct xfrm_state *x = dst->xfrm; | ||
44 | struct ipv6hdr *iph, *top_iph; | 43 | struct ipv6hdr *iph, *top_iph; |
45 | int dsfield; | 44 | int dsfield; |
46 | 45 | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index c8c8b44a0f58..c260ea104c52 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -17,6 +17,12 @@ | |||
17 | #include <net/ipv6.h> | 17 | #include <net/ipv6.h> |
18 | #include <net/xfrm.h> | 18 | #include <net/xfrm.h> |
19 | 19 | ||
20 | int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | ||
21 | u8 **prevhdr) | ||
22 | { | ||
23 | return ip6_find_1stfragopt(skb, prevhdr); | ||
24 | } | ||
25 | |||
20 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) | 26 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) |
21 | { | 27 | { |
22 | int mtu, ret = 0; | 28 | int mtu, ret = 0; |
@@ -41,13 +47,13 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
41 | struct xfrm_state *x = dst->xfrm; | 47 | struct xfrm_state *x = dst->xfrm; |
42 | int err; | 48 | int err; |
43 | 49 | ||
44 | if (skb->ip_summed == CHECKSUM_HW) { | 50 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
45 | err = skb_checksum_help(skb, 0); | 51 | err = skb_checksum_help(skb); |
46 | if (err) | 52 | if (err) |
47 | goto error_nolock; | 53 | goto error_nolock; |
48 | } | 54 | } |
49 | 55 | ||
50 | if (x->props.mode) { | 56 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
51 | err = xfrm6_tunnel_check_size(skb); | 57 | err = xfrm6_tunnel_check_size(skb); |
52 | if (err) | 58 | if (err) |
53 | goto error_nolock; | 59 | goto error_nolock; |
@@ -59,7 +65,7 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
59 | if (err) | 65 | if (err) |
60 | goto error; | 66 | goto error; |
61 | 67 | ||
62 | err = x->mode->output(skb); | 68 | err = x->mode->output(x, skb); |
63 | if (err) | 69 | if (err) |
64 | goto error; | 70 | goto error; |
65 | 71 | ||
@@ -69,6 +75,8 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
69 | 75 | ||
70 | x->curlft.bytes += skb->len; | 76 | x->curlft.bytes += skb->len; |
71 | x->curlft.packets++; | 77 | x->curlft.packets++; |
78 | if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) | ||
79 | x->lastused = (u64)xtime.tv_sec; | ||
72 | 80 | ||
73 | spin_unlock_bh(&x->lock); | 81 | spin_unlock_bh(&x->lock); |
74 | 82 | ||
@@ -80,7 +88,7 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
80 | } | 88 | } |
81 | dst = skb->dst; | 89 | dst = skb->dst; |
82 | x = dst->xfrm; | 90 | x = dst->xfrm; |
83 | } while (x && !x->props.mode); | 91 | } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); |
84 | 92 | ||
85 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | 93 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; |
86 | err = 0; | 94 | err = 0; |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 73cd250aecbb..6a252e2134d1 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <net/ip.h> | 18 | #include <net/ip.h> |
19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
20 | #include <net/ip6_route.h> | 20 | #include <net/ip6_route.h> |
21 | #ifdef CONFIG_IPV6_MIP6 | ||
22 | #include <net/mip6.h> | ||
23 | #endif | ||
21 | 24 | ||
22 | static struct dst_ops xfrm6_dst_ops; | 25 | static struct dst_ops xfrm6_dst_ops; |
23 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 26 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
@@ -31,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) | |||
31 | return err; | 34 | return err; |
32 | } | 35 | } |
33 | 36 | ||
37 | static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | ||
38 | { | ||
39 | struct rt6_info *rt; | ||
40 | struct flowi fl_tunnel = { | ||
41 | .nl_u = { | ||
42 | .ip6_u = { | ||
43 | .daddr = *(struct in6_addr *)&daddr->a6, | ||
44 | }, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { | ||
49 | ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6, | ||
50 | (struct in6_addr *)&saddr->a6); | ||
51 | dst_release(&rt->u.dst); | ||
52 | return 0; | ||
53 | } | ||
54 | return -EHOSTUNREACH; | ||
55 | } | ||
56 | |||
34 | static struct dst_entry * | 57 | static struct dst_entry * |
35 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | 58 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) |
36 | { | 59 | { |
@@ -50,7 +73,9 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
50 | xdst->u.rt6.rt6i_src.plen); | 73 | xdst->u.rt6.rt6i_src.plen); |
51 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && | 74 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && |
52 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && | 75 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && |
53 | xfrm_bundle_ok(xdst, fl, AF_INET6)) { | 76 | xfrm_bundle_ok(xdst, fl, AF_INET6, |
77 | (xdst->u.rt6.rt6i_dst.plen != 128 || | ||
78 | xdst->u.rt6.rt6i_src.plen != 128))) { | ||
54 | dst_clone(dst); | 79 | dst_clone(dst); |
55 | break; | 80 | break; |
56 | } | 81 | } |
@@ -59,6 +84,40 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
59 | return dst; | 84 | return dst; |
60 | } | 85 | } |
61 | 86 | ||
87 | static inline struct in6_addr* | ||
88 | __xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr) | ||
89 | { | ||
90 | return (x->type->remote_addr) ? | ||
91 | (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) : | ||
92 | (struct in6_addr*)&x->id.daddr; | ||
93 | } | ||
94 | |||
95 | static inline struct in6_addr* | ||
96 | __xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr) | ||
97 | { | ||
98 | return (x->type->local_addr) ? | ||
99 | (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) : | ||
100 | (struct in6_addr*)&x->props.saddr; | ||
101 | } | ||
102 | |||
103 | static inline void | ||
104 | __xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x) | ||
105 | { | ||
106 | if (x->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
107 | *nflen += x->props.header_len; | ||
108 | else | ||
109 | *len += x->props.header_len; | ||
110 | } | ||
111 | |||
112 | static inline void | ||
113 | __xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x) | ||
114 | { | ||
115 | if (x->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
116 | *nflen -= x->props.header_len; | ||
117 | else | ||
118 | *len -= x->props.header_len; | ||
119 | } | ||
120 | |||
62 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 121 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate |
63 | * all the metrics... Shortly, bundle a bundle. | 122 | * all the metrics... Shortly, bundle a bundle. |
64 | */ | 123 | */ |
@@ -83,6 +142,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
83 | int i; | 142 | int i; |
84 | int err = 0; | 143 | int err = 0; |
85 | int header_len = 0; | 144 | int header_len = 0; |
145 | int nfheader_len = 0; | ||
86 | int trailer_len = 0; | 146 | int trailer_len = 0; |
87 | 147 | ||
88 | dst = dst_prev = NULL; | 148 | dst = dst_prev = NULL; |
@@ -109,17 +169,18 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
109 | 169 | ||
110 | xdst = (struct xfrm_dst *)dst1; | 170 | xdst = (struct xfrm_dst *)dst1; |
111 | xdst->route = &rt->u.dst; | 171 | xdst->route = &rt->u.dst; |
172 | xdst->genid = xfrm[i]->genid; | ||
112 | if (rt->rt6i_node) | 173 | if (rt->rt6i_node) |
113 | xdst->route_cookie = rt->rt6i_node->fn_sernum; | 174 | xdst->route_cookie = rt->rt6i_node->fn_sernum; |
114 | 175 | ||
115 | dst1->next = dst_prev; | 176 | dst1->next = dst_prev; |
116 | dst_prev = dst1; | 177 | dst_prev = dst1; |
117 | if (xfrm[i]->props.mode) { | 178 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
118 | remote = (struct in6_addr*)&xfrm[i]->id.daddr; | 179 | remote = __xfrm6_bundle_addr_remote(xfrm[i], remote); |
119 | local = (struct in6_addr*)&xfrm[i]->props.saddr; | 180 | local = __xfrm6_bundle_addr_local(xfrm[i], local); |
120 | tunnel = 1; | 181 | tunnel = 1; |
121 | } | 182 | } |
122 | header_len += xfrm[i]->props.header_len; | 183 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); |
123 | trailer_len += xfrm[i]->props.trailer_len; | 184 | trailer_len += xfrm[i]->props.trailer_len; |
124 | 185 | ||
125 | if (tunnel) { | 186 | if (tunnel) { |
@@ -154,6 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
154 | dst_prev->flags |= DST_HOST; | 215 | dst_prev->flags |= DST_HOST; |
155 | dst_prev->lastuse = jiffies; | 216 | dst_prev->lastuse = jiffies; |
156 | dst_prev->header_len = header_len; | 217 | dst_prev->header_len = header_len; |
218 | dst_prev->nfheader_len = nfheader_len; | ||
157 | dst_prev->trailer_len = trailer_len; | 219 | dst_prev->trailer_len = trailer_len; |
158 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | 220 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); |
159 | 221 | ||
@@ -172,7 +234,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
172 | x->u.rt6.rt6i_src = rt0->rt6i_src; | 234 | x->u.rt6.rt6i_src = rt0->rt6i_src; |
173 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; | 235 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; |
174 | in6_dev_hold(rt0->rt6i_idev); | 236 | in6_dev_hold(rt0->rt6i_idev); |
175 | header_len -= x->u.dst.xfrm->props.header_len; | 237 | __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm); |
176 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | 238 | trailer_len -= x->u.dst.xfrm->props.trailer_len; |
177 | } | 239 | } |
178 | 240 | ||
@@ -232,6 +294,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) | |||
232 | fl->proto = nexthdr; | 294 | fl->proto = nexthdr; |
233 | return; | 295 | return; |
234 | 296 | ||
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | case IPPROTO_MH: | ||
299 | if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) { | ||
300 | struct ip6_mh *mh; | ||
301 | mh = (struct ip6_mh *)exthdr; | ||
302 | |||
303 | fl->fl_mh_type = mh->ip6mh_type; | ||
304 | } | ||
305 | fl->proto = nexthdr; | ||
306 | return; | ||
307 | #endif | ||
308 | |||
235 | /* XXX Why are there these headers? */ | 309 | /* XXX Why are there these headers? */ |
236 | case IPPROTO_AH: | 310 | case IPPROTO_AH: |
237 | case IPPROTO_ESP: | 311 | case IPPROTO_ESP: |
@@ -308,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
308 | .family = AF_INET6, | 382 | .family = AF_INET6, |
309 | .dst_ops = &xfrm6_dst_ops, | 383 | .dst_ops = &xfrm6_dst_ops, |
310 | .dst_lookup = xfrm6_dst_lookup, | 384 | .dst_lookup = xfrm6_dst_lookup, |
385 | .get_saddr = xfrm6_get_saddr, | ||
311 | .find_bundle = __xfrm6_find_bundle, | 386 | .find_bundle = __xfrm6_find_bundle, |
312 | .bundle_create = __xfrm6_bundle_create, | 387 | .bundle_create = __xfrm6_bundle_create, |
313 | .decode_session = _decode_session6, | 388 | .decode_session = _decode_session6, |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index b33296b3f6de..711bfafb2472 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -42,102 +42,135 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
42 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); | 42 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); |
43 | if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) | 43 | if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) |
44 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); | 44 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); |
45 | if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) { | ||
46 | struct rt6_info *rt; | ||
47 | struct flowi fl_tunnel = { | ||
48 | .nl_u = { | ||
49 | .ip6_u = { | ||
50 | .daddr = *(struct in6_addr *)daddr, | ||
51 | } | ||
52 | } | ||
53 | }; | ||
54 | if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, | ||
55 | &fl_tunnel, AF_INET6)) { | ||
56 | ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr, | ||
57 | (struct in6_addr *)&x->props.saddr); | ||
58 | dst_release(&rt->u.dst); | ||
59 | } | ||
60 | } | ||
61 | x->props.mode = tmpl->mode; | 45 | x->props.mode = tmpl->mode; |
62 | x->props.reqid = tmpl->reqid; | 46 | x->props.reqid = tmpl->reqid; |
63 | x->props.family = AF_INET6; | 47 | x->props.family = AF_INET6; |
64 | } | 48 | } |
65 | 49 | ||
66 | static struct xfrm_state * | 50 | static int |
67 | __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) | 51 | __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) |
68 | { | 52 | { |
69 | unsigned h = __xfrm6_spi_hash(daddr, spi, proto); | 53 | int i; |
70 | struct xfrm_state *x; | 54 | int j = 0; |
71 | 55 | ||
72 | list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) { | 56 | /* Rule 1: select IPsec transport except AH */ |
73 | if (x->props.family == AF_INET6 && | 57 | for (i = 0; i < n; i++) { |
74 | spi == x->id.spi && | 58 | if (src[i]->props.mode == XFRM_MODE_TRANSPORT && |
75 | ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && | 59 | src[i]->id.proto != IPPROTO_AH) { |
76 | proto == x->id.proto) { | 60 | dst[j++] = src[i]; |
77 | xfrm_state_hold(x); | 61 | src[i] = NULL; |
78 | return x; | 62 | } |
63 | } | ||
64 | if (j == n) | ||
65 | goto end; | ||
66 | |||
67 | /* Rule 2: select MIPv6 RO or inbound trigger */ | ||
68 | #ifdef CONFIG_IPV6_MIP6 | ||
69 | for (i = 0; i < n; i++) { | ||
70 | if (src[i] && | ||
71 | (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION || | ||
72 | src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) { | ||
73 | dst[j++] = src[i]; | ||
74 | src[i] = NULL; | ||
75 | } | ||
76 | } | ||
77 | if (j == n) | ||
78 | goto end; | ||
79 | #endif | ||
80 | |||
81 | /* Rule 3: select IPsec transport AH */ | ||
82 | for (i = 0; i < n; i++) { | ||
83 | if (src[i] && | ||
84 | src[i]->props.mode == XFRM_MODE_TRANSPORT && | ||
85 | src[i]->id.proto == IPPROTO_AH) { | ||
86 | dst[j++] = src[i]; | ||
87 | src[i] = NULL; | ||
79 | } | 88 | } |
80 | } | 89 | } |
81 | return NULL; | 90 | if (j == n) |
91 | goto end; | ||
92 | |||
93 | /* Rule 4: select IPsec tunnel */ | ||
94 | for (i = 0; i < n; i++) { | ||
95 | if (src[i] && | ||
96 | src[i]->props.mode == XFRM_MODE_TUNNEL) { | ||
97 | dst[j++] = src[i]; | ||
98 | src[i] = NULL; | ||
99 | } | ||
100 | } | ||
101 | if (likely(j == n)) | ||
102 | goto end; | ||
103 | |||
104 | /* Final rule */ | ||
105 | for (i = 0; i < n; i++) { | ||
106 | if (src[i]) { | ||
107 | dst[j++] = src[i]; | ||
108 | src[i] = NULL; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | end: | ||
113 | return 0; | ||
82 | } | 114 | } |
83 | 115 | ||
84 | static struct xfrm_state * | 116 | static int |
85 | __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, | 117 | __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) |
86 | xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
87 | int create) | ||
88 | { | 118 | { |
89 | struct xfrm_state *x, *x0; | 119 | int i; |
90 | unsigned h = __xfrm6_dst_hash(daddr); | 120 | int j = 0; |
91 | 121 | ||
92 | x0 = NULL; | 122 | /* Rule 1: select IPsec transport */ |
93 | 123 | for (i = 0; i < n; i++) { | |
94 | list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) { | 124 | if (src[i]->mode == XFRM_MODE_TRANSPORT) { |
95 | if (x->props.family == AF_INET6 && | 125 | dst[j++] = src[i]; |
96 | ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && | 126 | src[i] = NULL; |
97 | mode == x->props.mode && | 127 | } |
98 | proto == x->id.proto && | ||
99 | ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) && | ||
100 | reqid == x->props.reqid && | ||
101 | x->km.state == XFRM_STATE_ACQ && | ||
102 | !x->id.spi) { | ||
103 | x0 = x; | ||
104 | break; | ||
105 | } | ||
106 | } | 128 | } |
107 | if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { | 129 | if (j == n) |
108 | ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6, | 130 | goto end; |
109 | (struct in6_addr *)daddr); | 131 | |
110 | ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6, | 132 | /* Rule 2: select MIPv6 RO or inbound trigger */ |
111 | (struct in6_addr *)saddr); | 133 | #ifdef CONFIG_IPV6_MIP6 |
112 | x0->sel.prefixlen_d = 128; | 134 | for (i = 0; i < n; i++) { |
113 | x0->sel.prefixlen_s = 128; | 135 | if (src[i] && |
114 | ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6, | 136 | (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION || |
115 | (struct in6_addr *)saddr); | 137 | src[i]->mode == XFRM_MODE_IN_TRIGGER)) { |
116 | x0->km.state = XFRM_STATE_ACQ; | 138 | dst[j++] = src[i]; |
117 | ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6, | 139 | src[i] = NULL; |
118 | (struct in6_addr *)daddr); | 140 | } |
119 | x0->id.proto = proto; | ||
120 | x0->props.family = AF_INET6; | ||
121 | x0->props.mode = mode; | ||
122 | x0->props.reqid = reqid; | ||
123 | x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | ||
124 | xfrm_state_hold(x0); | ||
125 | x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | ||
126 | add_timer(&x0->timer); | ||
127 | xfrm_state_hold(x0); | ||
128 | list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); | ||
129 | wake_up(&km_waitq); | ||
130 | } | 141 | } |
131 | if (x0) | 142 | if (j == n) |
132 | xfrm_state_hold(x0); | 143 | goto end; |
133 | return x0; | 144 | #endif |
145 | |||
146 | /* Rule 3: select IPsec tunnel */ | ||
147 | for (i = 0; i < n; i++) { | ||
148 | if (src[i] && | ||
149 | src[i]->mode == XFRM_MODE_TUNNEL) { | ||
150 | dst[j++] = src[i]; | ||
151 | src[i] = NULL; | ||
152 | } | ||
153 | } | ||
154 | if (likely(j == n)) | ||
155 | goto end; | ||
156 | |||
157 | /* Final rule */ | ||
158 | for (i = 0; i < n; i++) { | ||
159 | if (src[i]) { | ||
160 | dst[j++] = src[i]; | ||
161 | src[i] = NULL; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | end: | ||
166 | return 0; | ||
134 | } | 167 | } |
135 | 168 | ||
136 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { | 169 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { |
137 | .family = AF_INET6, | 170 | .family = AF_INET6, |
138 | .init_tempsel = __xfrm6_init_tempsel, | 171 | .init_tempsel = __xfrm6_init_tempsel, |
139 | .state_lookup = __xfrm6_state_lookup, | 172 | .tmpl_sort = __xfrm6_tmpl_sort, |
140 | .find_acq = __xfrm6_find_acq, | 173 | .state_sort = __xfrm6_state_sort, |
141 | }; | 174 | }; |
142 | 175 | ||
143 | void __init xfrm6_state_init(void) | 176 | void __init xfrm6_state_init(void) |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index c8f9369c2a87..59685ee8f700 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -307,7 +307,7 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
307 | 307 | ||
308 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) | 308 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) |
309 | { | 309 | { |
310 | if (!x->props.mode) | 310 | if (x->props.mode != XFRM_MODE_TUNNEL) |
311 | return -EINVAL; | 311 | return -EINVAL; |
312 | 312 | ||
313 | if (x->encap) | 313 | if (x->encap) |