diff options
Diffstat (limited to 'net/ipv6')
60 files changed, 3864 insertions, 1680 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index e923d4dea418..a2d211da2aba 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -77,6 +77,7 @@ config INET6_ESP | |||
| 77 | select CRYPTO | 77 | select CRYPTO |
| 78 | select CRYPTO_HMAC | 78 | select CRYPTO_HMAC |
| 79 | select CRYPTO_MD5 | 79 | select CRYPTO_MD5 |
| 80 | select CRYPTO_CBC | ||
| 80 | select CRYPTO_SHA1 | 81 | select CRYPTO_SHA1 |
| 81 | select CRYPTO_DES | 82 | select CRYPTO_DES |
| 82 | ---help--- | 83 | ---help--- |
| @@ -97,6 +98,15 @@ config INET6_IPCOMP | |||
| 97 | 98 | ||
| 98 | If unsure, say Y. | 99 | If unsure, say Y. |
| 99 | 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 | |||
| 100 | config INET6_XFRM_TUNNEL | 110 | config INET6_XFRM_TUNNEL |
| 101 | tristate | 111 | tristate |
| 102 | select INET6_TUNNEL | 112 | select INET6_TUNNEL |
| @@ -126,6 +136,13 @@ config INET6_XFRM_MODE_TUNNEL | |||
| 126 | 136 | ||
| 127 | If unsure, say Y. | 137 | If unsure, say Y. |
| 128 | 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 | |||
| 129 | config IPV6_TUNNEL | 146 | config IPV6_TUNNEL |
| 130 | tristate "IPv6: IPv6-in-IPv6 tunnel" | 147 | tristate "IPv6: IPv6-in-IPv6 tunnel" |
| 131 | select INET6_TUNNEL | 148 | select INET6_TUNNEL |
| @@ -135,3 +152,31 @@ config IPV6_TUNNEL | |||
| 135 | 152 | ||
| 136 | If unsure, say N. | 153 | If unsure, say N. |
| 137 | 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 4da664538f52..e03c33b2465b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -40,7 +40,6 @@ | |||
| 40 | * status etc. | 40 | * status etc. |
| 41 | */ | 41 | */ |
| 42 | 42 | ||
| 43 | #include <linux/config.h> | ||
| 44 | #include <linux/errno.h> | 43 | #include <linux/errno.h> |
| 45 | #include <linux/types.h> | 44 | #include <linux/types.h> |
| 46 | #include <linux/socket.h> | 45 | #include <linux/socket.h> |
| @@ -49,6 +48,7 @@ | |||
| 49 | #include <linux/net.h> | 48 | #include <linux/net.h> |
| 50 | #include <linux/in6.h> | 49 | #include <linux/in6.h> |
| 51 | #include <linux/netdevice.h> | 50 | #include <linux/netdevice.h> |
| 51 | #include <linux/if_addr.h> | ||
| 52 | #include <linux/if_arp.h> | 52 | #include <linux/if_arp.h> |
| 53 | #include <linux/if_arcnet.h> | 53 | #include <linux/if_arcnet.h> |
| 54 | #include <linux/if_infiniband.h> | 54 | #include <linux/if_infiniband.h> |
| @@ -73,6 +73,7 @@ | |||
| 73 | #include <net/addrconf.h> | 73 | #include <net/addrconf.h> |
| 74 | #include <net/tcp.h> | 74 | #include <net/tcp.h> |
| 75 | #include <net/ip.h> | 75 | #include <net/ip.h> |
| 76 | #include <net/netlink.h> | ||
| 76 | #include <linux/if_tunnel.h> | 77 | #include <linux/if_tunnel.h> |
| 77 | #include <linux/rtnetlink.h> | 78 | #include <linux/rtnetlink.h> |
| 78 | 79 | ||
| @@ -118,9 +119,6 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
| 118 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 119 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; |
| 119 | static DEFINE_RWLOCK(addrconf_hash_lock); | 120 | static DEFINE_RWLOCK(addrconf_hash_lock); |
| 120 | 121 | ||
| 121 | /* Protects inet6 devices */ | ||
| 122 | DEFINE_RWLOCK(addrconf_lock); | ||
| 123 | |||
| 124 | static void addrconf_verify(unsigned long); | 122 | static void addrconf_verify(unsigned long); |
| 125 | 123 | ||
| 126 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); | 124 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); |
| @@ -145,7 +143,7 @@ static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *de | |||
| 145 | 143 | ||
| 146 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); | 144 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
| 147 | 145 | ||
| 148 | struct ipv6_devconf ipv6_devconf = { | 146 | struct ipv6_devconf ipv6_devconf __read_mostly = { |
| 149 | .forwarding = 0, | 147 | .forwarding = 0, |
| 150 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 148 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
| 151 | .mtu6 = IPV6_MIN_MTU, | 149 | .mtu6 = IPV6_MIN_MTU, |
| @@ -174,9 +172,10 @@ struct ipv6_devconf ipv6_devconf = { | |||
| 174 | .accept_ra_rt_info_max_plen = 0, | 172 | .accept_ra_rt_info_max_plen = 0, |
| 175 | #endif | 173 | #endif |
| 176 | #endif | 174 | #endif |
| 175 | .proxy_ndp = 0, | ||
| 177 | }; | 176 | }; |
| 178 | 177 | ||
| 179 | static struct ipv6_devconf ipv6_devconf_dflt = { | 178 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
| 180 | .forwarding = 0, | 179 | .forwarding = 0, |
| 181 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 180 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
| 182 | .mtu6 = IPV6_MIN_MTU, | 181 | .mtu6 = IPV6_MIN_MTU, |
| @@ -204,6 +203,7 @@ static struct ipv6_devconf ipv6_devconf_dflt = { | |||
| 204 | .accept_ra_rt_info_max_plen = 0, | 203 | .accept_ra_rt_info_max_plen = 0, |
| 205 | #endif | 204 | #endif |
| 206 | #endif | 205 | #endif |
| 206 | .proxy_ndp = 0, | ||
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
| @@ -315,6 +315,12 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
| 315 | 315 | ||
| 316 | /* Nobody refers to this device, we may destroy it. */ | 316 | /* Nobody refers to this device, we may destroy it. */ |
| 317 | 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 | |||
| 318 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 324 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
| 319 | { | 325 | { |
| 320 | struct net_device *dev = idev->dev; | 326 | struct net_device *dev = idev->dev; |
| @@ -329,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
| 329 | return; | 335 | return; |
| 330 | } | 336 | } |
| 331 | snmp6_free_dev(idev); | 337 | snmp6_free_dev(idev); |
| 332 | kfree(idev); | 338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); |
| 333 | } | 339 | } |
| 334 | 340 | ||
| 335 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | 341 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) |
| @@ -405,9 +411,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
| 405 | if (netif_carrier_ok(dev)) | 411 | if (netif_carrier_ok(dev)) |
| 406 | ndev->if_flags |= IF_READY; | 412 | ndev->if_flags |= IF_READY; |
| 407 | 413 | ||
| 408 | write_lock_bh(&addrconf_lock); | 414 | /* protected by rtnl_lock */ |
| 409 | dev->ip6_ptr = ndev; | 415 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
| 410 | write_unlock_bh(&addrconf_lock); | ||
| 411 | 416 | ||
| 412 | ipv6_mc_init_dev(ndev); | 417 | ipv6_mc_init_dev(ndev); |
| 413 | ndev->tstamp = jiffies; | 418 | ndev->tstamp = jiffies; |
| @@ -471,7 +476,7 @@ static void addrconf_forward_change(void) | |||
| 471 | 476 | ||
| 472 | read_lock(&dev_base_lock); | 477 | read_lock(&dev_base_lock); |
| 473 | for (dev=dev_base; dev; dev=dev->next) { | 478 | for (dev=dev_base; dev; dev=dev->next) { |
| 474 | read_lock(&addrconf_lock); | 479 | rcu_read_lock(); |
| 475 | idev = __in6_dev_get(dev); | 480 | idev = __in6_dev_get(dev); |
| 476 | if (idev) { | 481 | if (idev) { |
| 477 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); | 482 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); |
| @@ -479,7 +484,7 @@ static void addrconf_forward_change(void) | |||
| 479 | if (changed) | 484 | if (changed) |
| 480 | dev_forward_change(idev); | 485 | dev_forward_change(idev); |
| 481 | } | 486 | } |
| 482 | read_unlock(&addrconf_lock); | 487 | rcu_read_unlock(); |
| 483 | } | 488 | } |
| 484 | read_unlock(&dev_base_lock); | 489 | read_unlock(&dev_base_lock); |
| 485 | } | 490 | } |
| @@ -509,6 +514,26 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
| 509 | kfree(ifp); | 514 | kfree(ifp); |
| 510 | } | 515 | } |
| 511 | 516 | ||
| 517 | static void | ||
| 518 | ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) | ||
| 519 | { | ||
| 520 | struct inet6_ifaddr *ifa, **ifap; | ||
| 521 | int ifp_scope = ipv6_addr_src_scope(&ifp->addr); | ||
| 522 | |||
| 523 | /* | ||
| 524 | * Each device address list is sorted in order of scope - | ||
| 525 | * global before linklocal. | ||
| 526 | */ | ||
| 527 | for (ifap = &idev->addr_list; (ifa = *ifap) != NULL; | ||
| 528 | ifap = &ifa->if_next) { | ||
| 529 | if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | |||
| 533 | ifp->if_next = *ifap; | ||
| 534 | *ifap = ifp; | ||
| 535 | } | ||
| 536 | |||
| 512 | /* On success it returns ifp with increased reference count */ | 537 | /* On success it returns ifp with increased reference count */ |
| 513 | 538 | ||
| 514 | static struct inet6_ifaddr * | 539 | static struct inet6_ifaddr * |
| @@ -520,7 +545,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 520 | int hash; | 545 | int hash; |
| 521 | int err = 0; | 546 | int err = 0; |
| 522 | 547 | ||
| 523 | read_lock_bh(&addrconf_lock); | 548 | rcu_read_lock_bh(); |
| 524 | if (idev->dead) { | 549 | if (idev->dead) { |
| 525 | err = -ENODEV; /*XXX*/ | 550 | err = -ENODEV; /*XXX*/ |
| 526 | goto out2; | 551 | goto out2; |
| @@ -559,6 +584,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 559 | ifa->flags = flags | IFA_F_TENTATIVE; | 584 | ifa->flags = flags | IFA_F_TENTATIVE; |
| 560 | ifa->cstamp = ifa->tstamp = jiffies; | 585 | ifa->cstamp = ifa->tstamp = jiffies; |
| 561 | 586 | ||
| 587 | ifa->rt = rt; | ||
| 588 | |||
| 562 | ifa->idev = idev; | 589 | ifa->idev = idev; |
| 563 | in6_dev_hold(idev); | 590 | in6_dev_hold(idev); |
| 564 | /* For caller */ | 591 | /* For caller */ |
| @@ -574,8 +601,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 574 | 601 | ||
| 575 | write_lock(&idev->lock); | 602 | write_lock(&idev->lock); |
| 576 | /* Add to inet6_dev unicast addr list. */ | 603 | /* Add to inet6_dev unicast addr list. */ |
| 577 | ifa->if_next = idev->addr_list; | 604 | ipv6_link_dev_addr(idev, ifa); |
| 578 | idev->addr_list = ifa; | ||
| 579 | 605 | ||
| 580 | #ifdef CONFIG_IPV6_PRIVACY | 606 | #ifdef CONFIG_IPV6_PRIVACY |
| 581 | if (ifa->flags&IFA_F_TEMPORARY) { | 607 | if (ifa->flags&IFA_F_TEMPORARY) { |
| @@ -585,12 +611,10 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 585 | } | 611 | } |
| 586 | #endif | 612 | #endif |
| 587 | 613 | ||
| 588 | ifa->rt = rt; | ||
| 589 | |||
| 590 | in6_ifa_hold(ifa); | 614 | in6_ifa_hold(ifa); |
| 591 | write_unlock(&idev->lock); | 615 | write_unlock(&idev->lock); |
| 592 | out2: | 616 | out2: |
| 593 | read_unlock_bh(&addrconf_lock); | 617 | rcu_read_unlock_bh(); |
| 594 | 618 | ||
| 595 | if (likely(err == 0)) | 619 | if (likely(err == 0)) |
| 596 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); | 620 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); |
| @@ -716,7 +740,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 716 | 740 | ||
| 717 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 741 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
| 718 | if (onlink == 0) { | 742 | if (onlink == 0) { |
| 719 | ip6_del_rt(rt, NULL, NULL, NULL); | 743 | ip6_del_rt(rt); |
| 720 | rt = NULL; | 744 | rt = NULL; |
| 721 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { | 745 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { |
| 722 | rt->rt6i_expires = expires; | 746 | rt->rt6i_expires = expires; |
| @@ -893,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
| 893 | memset(&hiscore, 0, sizeof(hiscore)); | 917 | memset(&hiscore, 0, sizeof(hiscore)); |
| 894 | 918 | ||
| 895 | read_lock(&dev_base_lock); | 919 | read_lock(&dev_base_lock); |
| 896 | read_lock(&addrconf_lock); | 920 | rcu_read_lock(); |
| 897 | 921 | ||
| 898 | for (dev = dev_base; dev; dev=dev->next) { | 922 | for (dev = dev_base; dev; dev=dev->next) { |
| 899 | struct inet6_dev *idev; | 923 | struct inet6_dev *idev; |
| @@ -988,7 +1012,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
| 988 | continue; | 1012 | continue; |
| 989 | } else if (score.scope < hiscore.scope) { | 1013 | } else if (score.scope < hiscore.scope) { |
| 990 | if (score.scope < daddr_scope) | 1014 | if (score.scope < daddr_scope) |
| 991 | continue; | 1015 | break; /* addresses sorted by scope */ |
| 992 | else { | 1016 | else { |
| 993 | score.rule = 2; | 1017 | score.rule = 2; |
| 994 | goto record_it; | 1018 | goto record_it; |
| @@ -1014,9 +1038,27 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
| 1014 | continue; | 1038 | continue; |
| 1015 | } | 1039 | } |
| 1016 | 1040 | ||
| 1017 | /* 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 | ||
| 1018 | if (hiscore.rule < 4) | 1059 | if (hiscore.rule < 4) |
| 1019 | hiscore.rule++; | 1060 | hiscore.rule++; |
| 1061 | #endif | ||
| 1020 | 1062 | ||
| 1021 | /* Rule 5: Prefer outgoing interface */ | 1063 | /* Rule 5: Prefer outgoing interface */ |
| 1022 | if (hiscore.rule < 5) { | 1064 | if (hiscore.rule < 5) { |
| @@ -1105,7 +1147,7 @@ record_it: | |||
| 1105 | } | 1147 | } |
| 1106 | read_unlock_bh(&idev->lock); | 1148 | read_unlock_bh(&idev->lock); |
| 1107 | } | 1149 | } |
| 1108 | read_unlock(&addrconf_lock); | 1150 | rcu_read_unlock(); |
| 1109 | read_unlock(&dev_base_lock); | 1151 | read_unlock(&dev_base_lock); |
| 1110 | 1152 | ||
| 1111 | if (!ifa_result) | 1153 | if (!ifa_result) |
| @@ -1129,7 +1171,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
| 1129 | struct inet6_dev *idev; | 1171 | struct inet6_dev *idev; |
| 1130 | int err = -EADDRNOTAVAIL; | 1172 | int err = -EADDRNOTAVAIL; |
| 1131 | 1173 | ||
| 1132 | read_lock(&addrconf_lock); | 1174 | rcu_read_lock(); |
| 1133 | if ((idev = __in6_dev_get(dev)) != NULL) { | 1175 | if ((idev = __in6_dev_get(dev)) != NULL) { |
| 1134 | struct inet6_ifaddr *ifp; | 1176 | struct inet6_ifaddr *ifp; |
| 1135 | 1177 | ||
| @@ -1143,7 +1185,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
| 1143 | } | 1185 | } |
| 1144 | read_unlock_bh(&idev->lock); | 1186 | read_unlock_bh(&idev->lock); |
| 1145 | } | 1187 | } |
| 1146 | read_unlock(&addrconf_lock); | 1188 | rcu_read_unlock(); |
| 1147 | return err; | 1189 | return err; |
| 1148 | } | 1190 | } |
| 1149 | 1191 | ||
| @@ -1216,8 +1258,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
| 1216 | { | 1258 | { |
| 1217 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | 1259 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; |
| 1218 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 1260 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
| 1219 | u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; | 1261 | __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; |
| 1220 | u32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 1262 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); |
| 1221 | int sk_ipv6only = ipv6_only_sock(sk); | 1263 | int sk_ipv6only = ipv6_only_sock(sk); |
| 1222 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 1264 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
| 1223 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); | 1265 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); |
| @@ -1444,7 +1486,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
| 1444 | struct inet6_dev *idev = (struct inet6_dev *) data; | 1486 | struct inet6_dev *idev = (struct inet6_dev *) data; |
| 1445 | unsigned long expires; | 1487 | unsigned long expires; |
| 1446 | 1488 | ||
| 1447 | read_lock_bh(&addrconf_lock); | 1489 | rcu_read_lock_bh(); |
| 1448 | write_lock_bh(&idev->lock); | 1490 | write_lock_bh(&idev->lock); |
| 1449 | 1491 | ||
| 1450 | if (idev->dead) | 1492 | if (idev->dead) |
| @@ -1468,7 +1510,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
| 1468 | 1510 | ||
| 1469 | out: | 1511 | out: |
| 1470 | write_unlock_bh(&idev->lock); | 1512 | write_unlock_bh(&idev->lock); |
| 1471 | read_unlock_bh(&addrconf_lock); | 1513 | rcu_read_unlock_bh(); |
| 1472 | in6_dev_put(idev); | 1514 | in6_dev_put(idev); |
| 1473 | } | 1515 | } |
| 1474 | 1516 | ||
| @@ -1489,59 +1531,56 @@ static void | |||
| 1489 | 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, |
| 1490 | unsigned long expires, u32 flags) | 1532 | unsigned long expires, u32 flags) |
| 1491 | { | 1533 | { |
| 1492 | 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 | }; | ||
| 1493 | 1542 | ||
| 1494 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1543 | ipv6_addr_copy(&cfg.fc_dst, pfx); |
| 1495 | ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx); | ||
| 1496 | rtmsg.rtmsg_dst_len = plen; | ||
| 1497 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
| 1498 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
| 1499 | rtmsg.rtmsg_info = expires; | ||
| 1500 | rtmsg.rtmsg_flags = RTF_UP|flags; | ||
| 1501 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
| 1502 | 1544 | ||
| 1503 | /* Prevent useless cloning on PtP SIT. | 1545 | /* Prevent useless cloning on PtP SIT. |
| 1504 | This thing is done here expecting that the whole | 1546 | This thing is done here expecting that the whole |
| 1505 | class of non-broadcast devices need not cloning. | 1547 | class of non-broadcast devices need not cloning. |
| 1506 | */ | 1548 | */ |
| 1507 | if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) | 1549 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
| 1508 | rtmsg.rtmsg_flags |= RTF_NONEXTHOP; | 1550 | cfg.fc_flags |= RTF_NONEXTHOP; |
| 1509 | 1551 | ||
| 1510 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1552 | ip6_route_add(&cfg); |
| 1511 | } | 1553 | } |
| 1512 | 1554 | ||
| 1513 | /* Create "default" multicast route to the interface */ | 1555 | /* Create "default" multicast route to the interface */ |
| 1514 | 1556 | ||
| 1515 | static void addrconf_add_mroute(struct net_device *dev) | 1557 | static void addrconf_add_mroute(struct net_device *dev) |
| 1516 | { | 1558 | { |
| 1517 | 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); | ||
| 1518 | 1568 | ||
| 1519 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1569 | ip6_route_add(&cfg); |
| 1520 | ipv6_addr_set(&rtmsg.rtmsg_dst, | ||
| 1521 | htonl(0xFF000000), 0, 0, 0); | ||
| 1522 | rtmsg.rtmsg_dst_len = 8; | ||
| 1523 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
| 1524 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
| 1525 | rtmsg.rtmsg_flags = RTF_UP; | ||
| 1526 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
| 1527 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
| 1528 | } | 1570 | } |
| 1529 | 1571 | ||
| 1530 | static void sit_route_add(struct net_device *dev) | 1572 | static void sit_route_add(struct net_device *dev) |
| 1531 | { | 1573 | { |
| 1532 | struct in6_rtmsg rtmsg; | 1574 | struct fib6_config cfg = { |
| 1533 | 1575 | .fc_table = RT6_TABLE_MAIN, | |
| 1534 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1576 | .fc_metric = IP6_RT_PRIO_ADDRCONF, |
| 1535 | 1577 | .fc_ifindex = dev->ifindex, | |
| 1536 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1578 | .fc_dst_len = 96, |
| 1537 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | 1579 | .fc_flags = RTF_UP | RTF_NONEXTHOP, |
| 1580 | }; | ||
| 1538 | 1581 | ||
| 1539 | /* prefix length - 96 bits "::d.d.d.d" */ | 1582 | /* prefix length - 96 bits "::d.d.d.d" */ |
| 1540 | rtmsg.rtmsg_dst_len = 96; | 1583 | ip6_route_add(&cfg); |
| 1541 | rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; | ||
| 1542 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
| 1543 | |||
| 1544 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
| 1545 | } | 1584 | } |
| 1546 | 1585 | ||
| 1547 | static void addrconf_add_lroute(struct net_device *dev) | 1586 | static void addrconf_add_lroute(struct net_device *dev) |
| @@ -1642,7 +1681,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
| 1642 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 1681 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
| 1643 | if (rt->rt6i_flags&RTF_EXPIRES) { | 1682 | if (rt->rt6i_flags&RTF_EXPIRES) { |
| 1644 | if (valid_lft == 0) { | 1683 | if (valid_lft == 0) { |
| 1645 | ip6_del_rt(rt, NULL, NULL, NULL); | 1684 | ip6_del_rt(rt); |
| 1646 | rt = NULL; | 1685 | rt = NULL; |
| 1647 | } else { | 1686 | } else { |
| 1648 | rt->rt6i_expires = jiffies + rt_expires; | 1687 | rt->rt6i_expires = jiffies + rt_expires; |
| @@ -1851,7 +1890,8 @@ err_exit: | |||
| 1851 | /* | 1890 | /* |
| 1852 | * Manual configuration of address on an interface | 1891 | * Manual configuration of address on an interface |
| 1853 | */ | 1892 | */ |
| 1854 | 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, |
| 1894 | __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) | ||
| 1855 | { | 1895 | { |
| 1856 | struct inet6_ifaddr *ifp; | 1896 | struct inet6_ifaddr *ifp; |
| 1857 | struct inet6_dev *idev; | 1897 | struct inet6_dev *idev; |
| @@ -1860,21 +1900,41 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) | |||
| 1860 | 1900 | ||
| 1861 | ASSERT_RTNL(); | 1901 | ASSERT_RTNL(); |
| 1862 | 1902 | ||
| 1903 | /* check the lifetime */ | ||
| 1904 | if (!valid_lft || prefered_lft > valid_lft) | ||
| 1905 | return -EINVAL; | ||
| 1906 | |||
| 1863 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | 1907 | if ((dev = __dev_get_by_index(ifindex)) == NULL) |
| 1864 | return -ENODEV; | 1908 | return -ENODEV; |
| 1865 | 1909 | ||
| 1866 | if (!(dev->flags&IFF_UP)) | ||
| 1867 | return -ENETDOWN; | ||
| 1868 | |||
| 1869 | if ((idev = addrconf_add_dev(dev)) == NULL) | 1910 | if ((idev = addrconf_add_dev(dev)) == NULL) |
| 1870 | return -ENOBUFS; | 1911 | return -ENOBUFS; |
| 1871 | 1912 | ||
| 1872 | scope = ipv6_addr_scope(pfx); | 1913 | scope = ipv6_addr_scope(pfx); |
| 1873 | 1914 | ||
| 1874 | ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT); | 1915 | if (valid_lft == INFINITY_LIFE_TIME) |
| 1916 | ifa_flags |= IFA_F_PERMANENT; | ||
| 1917 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 1918 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 1919 | |||
| 1920 | if (prefered_lft == 0) | ||
| 1921 | ifa_flags |= IFA_F_DEPRECATED; | ||
| 1922 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
| 1923 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
| 1924 | prefered_lft = 0x7FFFFFFF/HZ; | ||
| 1925 | |||
| 1926 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | ||
| 1927 | |||
| 1875 | if (!IS_ERR(ifp)) { | 1928 | if (!IS_ERR(ifp)) { |
| 1929 | spin_lock_bh(&ifp->lock); | ||
| 1930 | ifp->valid_lft = valid_lft; | ||
| 1931 | ifp->prefered_lft = prefered_lft; | ||
| 1932 | ifp->tstamp = jiffies; | ||
| 1933 | spin_unlock_bh(&ifp->lock); | ||
| 1934 | |||
| 1876 | addrconf_dad_start(ifp, 0); | 1935 | addrconf_dad_start(ifp, 0); |
| 1877 | in6_ifa_put(ifp); | 1936 | in6_ifa_put(ifp); |
| 1937 | addrconf_verify(0); | ||
| 1878 | return 0; | 1938 | return 0; |
| 1879 | } | 1939 | } |
| 1880 | 1940 | ||
| @@ -1927,7 +1987,8 @@ int addrconf_add_ifaddr(void __user *arg) | |||
| 1927 | return -EFAULT; | 1987 | return -EFAULT; |
| 1928 | 1988 | ||
| 1929 | rtnl_lock(); | 1989 | rtnl_lock(); |
| 1930 | 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, |
| 1991 | IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | ||
| 1931 | rtnl_unlock(); | 1992 | rtnl_unlock(); |
| 1932 | return err; | 1993 | return err; |
| 1933 | } | 1994 | } |
| @@ -2300,10 +2361,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2300 | Do not dev_put! | 2361 | Do not dev_put! |
| 2301 | */ | 2362 | */ |
| 2302 | if (how == 1) { | 2363 | if (how == 1) { |
| 2303 | write_lock_bh(&addrconf_lock); | ||
| 2304 | dev->ip6_ptr = NULL; | ||
| 2305 | idev->dead = 1; | 2364 | idev->dead = 1; |
| 2306 | write_unlock_bh(&addrconf_lock); | 2365 | |
| 2366 | /* protected by rtnl_lock */ | ||
| 2367 | rcu_assign_pointer(dev->ip6_ptr, NULL); | ||
| 2307 | 2368 | ||
| 2308 | /* Step 1.5: remove snmp6 entry */ | 2369 | /* Step 1.5: remove snmp6 entry */ |
| 2309 | snmp6_unregister_dev(idev); | 2370 | snmp6_unregister_dev(idev); |
| @@ -2470,7 +2531,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
| 2470 | spin_lock_bh(&ifp->lock); | 2531 | spin_lock_bh(&ifp->lock); |
| 2471 | 2532 | ||
| 2472 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2533 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
| 2473 | !(ifp->flags&IFA_F_TENTATIVE)) { | 2534 | !(ifp->flags&IFA_F_TENTATIVE) || |
| 2535 | ifp->flags & IFA_F_NODAD) { | ||
| 2474 | ifp->flags &= ~IFA_F_TENTATIVE; | 2536 | ifp->flags &= ~IFA_F_TENTATIVE; |
| 2475 | spin_unlock_bh(&ifp->lock); | 2537 | spin_unlock_bh(&ifp->lock); |
| 2476 | read_unlock_bh(&idev->lock); | 2538 | read_unlock_bh(&idev->lock); |
| @@ -2715,6 +2777,26 @@ void if6_proc_exit(void) | |||
| 2715 | } | 2777 | } |
| 2716 | #endif /* CONFIG_PROC_FS */ | 2778 | #endif /* CONFIG_PROC_FS */ |
| 2717 | 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 | |||
| 2718 | /* | 2800 | /* |
| 2719 | * Periodic address status verification | 2801 | * Periodic address status verification |
| 2720 | */ | 2802 | */ |
| @@ -2753,12 +2835,16 @@ restart: | |||
| 2753 | ifp->idev->nd_parms->retrans_time / HZ; | 2835 | ifp->idev->nd_parms->retrans_time / HZ; |
| 2754 | #endif | 2836 | #endif |
| 2755 | 2837 | ||
| 2756 | if (age >= ifp->valid_lft) { | 2838 | if (ifp->valid_lft != INFINITY_LIFE_TIME && |
| 2839 | age >= ifp->valid_lft) { | ||
| 2757 | spin_unlock(&ifp->lock); | 2840 | spin_unlock(&ifp->lock); |
| 2758 | in6_ifa_hold(ifp); | 2841 | in6_ifa_hold(ifp); |
| 2759 | read_unlock(&addrconf_hash_lock); | 2842 | read_unlock(&addrconf_hash_lock); |
| 2760 | ipv6_del_addr(ifp); | 2843 | ipv6_del_addr(ifp); |
| 2761 | goto restart; | 2844 | goto restart; |
| 2845 | } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { | ||
| 2846 | spin_unlock(&ifp->lock); | ||
| 2847 | continue; | ||
| 2762 | } else if (age >= ifp->prefered_lft) { | 2848 | } else if (age >= ifp->prefered_lft) { |
| 2763 | /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ | 2849 | /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ |
| 2764 | int deprecate = 0; | 2850 | int deprecate = 0; |
| @@ -2821,178 +2907,267 @@ restart: | |||
| 2821 | spin_unlock_bh(&addrconf_verify_lock); | 2907 | spin_unlock_bh(&addrconf_verify_lock); |
| 2822 | } | 2908 | } |
| 2823 | 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 | |||
| 2824 | static int | 2933 | static int |
| 2825 | 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) |
| 2826 | { | 2935 | { |
| 2827 | struct rtattr **rta = arg; | 2936 | struct ifaddrmsg *ifm; |
| 2828 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2937 | struct nlattr *tb[IFA_MAX+1]; |
| 2829 | struct in6_addr *pfx; | 2938 | struct in6_addr *pfx; |
| 2939 | int err; | ||
| 2830 | 2940 | ||
| 2831 | pfx = NULL; | 2941 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
| 2832 | if (rta[IFA_ADDRESS-1]) { | 2942 | if (err < 0) |
| 2833 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2943 | return err; |
| 2834 | return -EINVAL; | 2944 | |
| 2835 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 2945 | ifm = nlmsg_data(nlh); |
| 2836 | } | 2946 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
| 2837 | if (rta[IFA_LOCAL-1]) { | ||
| 2838 | if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) | ||
| 2839 | return -EINVAL; | ||
| 2840 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
| 2841 | } | ||
| 2842 | if (pfx == NULL) | 2947 | if (pfx == NULL) |
| 2843 | return -EINVAL; | 2948 | return -EINVAL; |
| 2844 | 2949 | ||
| 2845 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2950 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
| 2846 | } | 2951 | } |
| 2847 | 2952 | ||
| 2953 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, | ||
| 2954 | u32 prefered_lft, u32 valid_lft) | ||
| 2955 | { | ||
| 2956 | if (!valid_lft || (prefered_lft > valid_lft)) | ||
| 2957 | return -EINVAL; | ||
| 2958 | |||
| 2959 | if (valid_lft == INFINITY_LIFE_TIME) | ||
| 2960 | ifa_flags |= IFA_F_PERMANENT; | ||
| 2961 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 2962 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 2963 | |||
| 2964 | if (prefered_lft == 0) | ||
| 2965 | ifa_flags |= IFA_F_DEPRECATED; | ||
| 2966 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
| 2967 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
| 2968 | prefered_lft = 0x7FFFFFFF/HZ; | ||
| 2969 | |||
| 2970 | spin_lock_bh(&ifp->lock); | ||
| 2971 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; | ||
| 2972 | ifp->tstamp = jiffies; | ||
| 2973 | ifp->valid_lft = valid_lft; | ||
| 2974 | ifp->prefered_lft = prefered_lft; | ||
| 2975 | |||
| 2976 | spin_unlock_bh(&ifp->lock); | ||
| 2977 | if (!(ifp->flags&IFA_F_TENTATIVE)) | ||
| 2978 | ipv6_ifa_notify(0, ifp); | ||
| 2979 | |||
| 2980 | addrconf_verify(0); | ||
| 2981 | |||
| 2982 | return 0; | ||
| 2983 | } | ||
| 2984 | |||
| 2848 | static int | 2985 | static int |
| 2849 | 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) |
| 2850 | { | 2987 | { |
| 2851 | struct rtattr **rta = arg; | 2988 | struct ifaddrmsg *ifm; |
| 2852 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2989 | struct nlattr *tb[IFA_MAX+1]; |
| 2853 | struct in6_addr *pfx; | 2990 | struct in6_addr *pfx; |
| 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; | ||
| 2854 | 2996 | ||
| 2855 | pfx = NULL; | 2997 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
| 2856 | if (rta[IFA_ADDRESS-1]) { | 2998 | if (err < 0) |
| 2857 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2999 | return err; |
| 2858 | return -EINVAL; | 3000 | |
| 2859 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 3001 | ifm = nlmsg_data(nlh); |
| 2860 | } | 3002 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
| 2861 | if (rta[IFA_LOCAL-1]) { | ||
| 2862 | if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) | ||
| 2863 | return -EINVAL; | ||
| 2864 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
| 2865 | } | ||
| 2866 | if (pfx == NULL) | 3003 | if (pfx == NULL) |
| 2867 | return -EINVAL; | 3004 | return -EINVAL; |
| 2868 | 3005 | ||
| 2869 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 3006 | if (tb[IFA_CACHEINFO]) { |
| 3007 | struct ifa_cacheinfo *ci; | ||
| 3008 | |||
| 3009 | ci = nla_data(tb[IFA_CACHEINFO]); | ||
| 3010 | valid_lft = ci->ifa_valid; | ||
| 3011 | preferred_lft = ci->ifa_prefered; | ||
| 3012 | } else { | ||
| 3013 | preferred_lft = INFINITY_LIFE_TIME; | ||
| 3014 | valid_lft = INFINITY_LIFE_TIME; | ||
| 3015 | } | ||
| 3016 | |||
| 3017 | dev = __dev_get_by_index(ifm->ifa_index); | ||
| 3018 | if (dev == NULL) | ||
| 3019 | return -ENODEV; | ||
| 3020 | |||
| 3021 | /* We ignore other flags so far. */ | ||
| 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); | ||
| 3032 | } | ||
| 3033 | |||
| 3034 | if (nlh->nlmsg_flags & NLM_F_EXCL || | ||
| 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; | ||
| 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; | ||
| 3056 | } | ||
| 3057 | |||
| 3058 | static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, | ||
| 3059 | unsigned long tstamp, u32 preferred, u32 valid) | ||
| 3060 | { | ||
| 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); | ||
| 2870 | } | 3071 | } |
| 2871 | 3072 | ||
| 2872 | /* Maximum length of ifa_cacheinfo attributes */ | 3073 | static inline int rt_scope(int ifa_scope) |
| 2873 | #define INET6_IFADDR_RTA_SPACE \ | 3074 | { |
| 2874 | RTA_SPACE(16) /* IFA_ADDRESS */ + \ | 3075 | if (ifa_scope & IFA_HOST) |
| 2875 | RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */ | 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 | } | ||
| 2876 | 3092 | ||
| 2877 | 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, |
| 2878 | u32 pid, u32 seq, int event, unsigned int flags) | 3094 | u32 pid, u32 seq, int event, unsigned int flags) |
| 2879 | { | 3095 | { |
| 2880 | struct ifaddrmsg *ifm; | ||
| 2881 | struct nlmsghdr *nlh; | 3096 | struct nlmsghdr *nlh; |
| 2882 | struct ifa_cacheinfo ci; | 3097 | u32 preferred, valid; |
| 2883 | 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); | ||
| 2884 | 3105 | ||
| 2885 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
| 2886 | ifm = NLMSG_DATA(nlh); | ||
| 2887 | ifm->ifa_family = AF_INET6; | ||
| 2888 | ifm->ifa_prefixlen = ifa->prefix_len; | ||
| 2889 | ifm->ifa_flags = ifa->flags; | ||
| 2890 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
| 2891 | if (ifa->scope&IFA_HOST) | ||
| 2892 | ifm->ifa_scope = RT_SCOPE_HOST; | ||
| 2893 | else if (ifa->scope&IFA_LINK) | ||
| 2894 | ifm->ifa_scope = RT_SCOPE_LINK; | ||
| 2895 | else if (ifa->scope&IFA_SITE) | ||
| 2896 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
| 2897 | ifm->ifa_index = ifa->idev->dev->ifindex; | ||
| 2898 | RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr); | ||
| 2899 | if (!(ifa->flags&IFA_F_PERMANENT)) { | 3106 | if (!(ifa->flags&IFA_F_PERMANENT)) { |
| 2900 | ci.ifa_prefered = ifa->prefered_lft; | 3107 | preferred = ifa->prefered_lft; |
| 2901 | ci.ifa_valid = ifa->valid_lft; | 3108 | valid = ifa->valid_lft; |
| 2902 | if (ci.ifa_prefered != INFINITY_LIFE_TIME) { | 3109 | if (preferred != INFINITY_LIFE_TIME) { |
| 2903 | long tval = (jiffies - ifa->tstamp)/HZ; | 3110 | long tval = (jiffies - ifa->tstamp)/HZ; |
| 2904 | ci.ifa_prefered -= tval; | 3111 | preferred -= tval; |
| 2905 | if (ci.ifa_valid != INFINITY_LIFE_TIME) | 3112 | if (valid != INFINITY_LIFE_TIME) |
| 2906 | ci.ifa_valid -= tval; | 3113 | valid -= tval; |
| 2907 | } | 3114 | } |
| 2908 | } else { | 3115 | } else { |
| 2909 | ci.ifa_prefered = INFINITY_LIFE_TIME; | 3116 | preferred = INFINITY_LIFE_TIME; |
| 2910 | ci.ifa_valid = INFINITY_LIFE_TIME; | 3117 | valid = INFINITY_LIFE_TIME; |
| 2911 | } | 3118 | } |
| 2912 | ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100 | ||
| 2913 | + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
| 2914 | ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
| 2915 | + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
| 2916 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
| 2917 | nlh->nlmsg_len = skb->tail - b; | ||
| 2918 | return skb->len; | ||
| 2919 | 3119 | ||
| 2920 | nlmsg_failure: | 3120 | if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 || |
| 2921 | rtattr_failure: | 3121 | put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) |
| 2922 | skb_trim(skb, b - skb->data); | 3122 | return nlmsg_cancel(skb, nlh); |
| 2923 | return -1; | 3123 | |
| 3124 | return nlmsg_end(skb, nlh); | ||
| 2924 | } | 3125 | } |
| 2925 | 3126 | ||
| 2926 | 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, |
| 2927 | u32 pid, u32 seq, int event, u16 flags) | 3128 | u32 pid, u32 seq, int event, u16 flags) |
| 2928 | { | 3129 | { |
| 2929 | struct ifaddrmsg *ifm; | ||
| 2930 | struct nlmsghdr *nlh; | 3130 | struct nlmsghdr *nlh; |
| 2931 | struct ifa_cacheinfo ci; | 3131 | u8 scope = RT_SCOPE_UNIVERSE; |
| 2932 | unsigned char *b = skb->tail; | 3132 | int ifindex = ifmca->idev->dev->ifindex; |
| 2933 | |||
| 2934 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
| 2935 | ifm = NLMSG_DATA(nlh); | ||
| 2936 | ifm->ifa_family = AF_INET6; | ||
| 2937 | ifm->ifa_prefixlen = 128; | ||
| 2938 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
| 2939 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
| 2940 | if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE) | ||
| 2941 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
| 2942 | ifm->ifa_index = ifmca->idev->dev->ifindex; | ||
| 2943 | RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr); | ||
| 2944 | ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ | ||
| 2945 | * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ | ||
| 2946 | * 100 / HZ); | ||
| 2947 | ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ | ||
| 2948 | * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ | ||
| 2949 | * 100 / HZ); | ||
| 2950 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
| 2951 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
| 2952 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
| 2953 | nlh->nlmsg_len = skb->tail - b; | ||
| 2954 | return skb->len; | ||
| 2955 | 3133 | ||
| 2956 | nlmsg_failure: | 3134 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) |
| 2957 | rtattr_failure: | 3135 | scope = RT_SCOPE_SITE; |
| 2958 | skb_trim(skb, b - skb->data); | 3136 | |
| 2959 | 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); | ||
| 2960 | } | 3148 | } |
| 2961 | 3149 | ||
| 2962 | 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, |
| 2963 | u32 pid, u32 seq, int event, unsigned int flags) | 3151 | u32 pid, u32 seq, int event, unsigned int flags) |
| 2964 | { | 3152 | { |
| 2965 | struct ifaddrmsg *ifm; | ||
| 2966 | struct nlmsghdr *nlh; | 3153 | struct nlmsghdr *nlh; |
| 2967 | struct ifa_cacheinfo ci; | 3154 | u8 scope = RT_SCOPE_UNIVERSE; |
| 2968 | unsigned char *b = skb->tail; | 3155 | int ifindex = ifaca->aca_idev->dev->ifindex; |
| 2969 | |||
| 2970 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
| 2971 | ifm = NLMSG_DATA(nlh); | ||
| 2972 | ifm->ifa_family = AF_INET6; | ||
| 2973 | ifm->ifa_prefixlen = 128; | ||
| 2974 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
| 2975 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
| 2976 | if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE) | ||
| 2977 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
| 2978 | ifm->ifa_index = ifaca->aca_idev->dev->ifindex; | ||
| 2979 | RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr); | ||
| 2980 | ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ | ||
| 2981 | * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ | ||
| 2982 | * 100 / HZ); | ||
| 2983 | ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ | ||
| 2984 | * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ | ||
| 2985 | * 100 / HZ); | ||
| 2986 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
| 2987 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
| 2988 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
| 2989 | nlh->nlmsg_len = skb->tail - b; | ||
| 2990 | return skb->len; | ||
| 2991 | 3156 | ||
| 2992 | nlmsg_failure: | 3157 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) |
| 2993 | rtattr_failure: | 3158 | scope = RT_SCOPE_SITE; |
| 2994 | skb_trim(skb, b - skb->data); | 3159 | |
| 2995 | 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); | ||
| 2996 | } | 3171 | } |
| 2997 | 3172 | ||
| 2998 | enum addr_type_t | 3173 | enum addr_type_t |
| @@ -3103,23 +3278,74 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 3103 | return inet6_dump_addr(skb, cb, type); | 3278 | return inet6_dump_addr(skb, cb, type); |
| 3104 | } | 3279 | } |
| 3105 | 3280 | ||
| 3106 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3281 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
| 3282 | void *arg) | ||
| 3107 | { | 3283 | { |
| 3284 | struct ifaddrmsg *ifm; | ||
| 3285 | struct nlattr *tb[IFA_MAX+1]; | ||
| 3286 | struct in6_addr *addr = NULL; | ||
| 3287 | struct net_device *dev = NULL; | ||
| 3288 | struct inet6_ifaddr *ifa; | ||
| 3108 | struct sk_buff *skb; | 3289 | struct sk_buff *skb; |
| 3109 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | 3290 | int err; |
| 3110 | 3291 | ||
| 3111 | skb = alloc_skb(size, GFP_ATOMIC); | 3292 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
| 3112 | if (!skb) { | 3293 | if (err < 0) |
| 3113 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, ENOBUFS); | 3294 | goto errout; |
| 3114 | return; | 3295 | |
| 3296 | addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); | ||
| 3297 | if (addr == NULL) { | ||
| 3298 | err = -EINVAL; | ||
| 3299 | goto errout; | ||
| 3300 | } | ||
| 3301 | |||
| 3302 | ifm = nlmsg_data(nlh); | ||
| 3303 | if (ifm->ifa_index) | ||
| 3304 | dev = __dev_get_by_index(ifm->ifa_index); | ||
| 3305 | |||
| 3306 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { | ||
| 3307 | err = -EADDRNOTAVAIL; | ||
| 3308 | goto errout; | ||
| 3115 | } | 3309 | } |
| 3116 | if (inet6_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) { | 3310 | |
| 3311 | if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) { | ||
| 3312 | err = -ENOBUFS; | ||
| 3313 | goto errout_ifa; | ||
| 3314 | } | ||
| 3315 | |||
| 3316 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | ||
| 3317 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | ||
| 3318 | if (err < 0) { | ||
| 3117 | kfree_skb(skb); | 3319 | kfree_skb(skb); |
| 3118 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, EINVAL); | 3320 | goto errout_ifa; |
| 3119 | return; | 3321 | } |
| 3322 | |||
| 3323 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | ||
| 3324 | errout_ifa: | ||
| 3325 | in6_ifa_put(ifa); | ||
| 3326 | errout: | ||
| 3327 | return err; | ||
| 3328 | } | ||
| 3329 | |||
| 3330 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | ||
| 3331 | { | ||
| 3332 | struct sk_buff *skb; | ||
| 3333 | int err = -ENOBUFS; | ||
| 3334 | |||
| 3335 | skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); | ||
| 3336 | if (skb == NULL) | ||
| 3337 | goto errout; | ||
| 3338 | |||
| 3339 | err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); | ||
| 3340 | if (err < 0) { | ||
| 3341 | kfree_skb(skb); | ||
| 3342 | goto errout; | ||
| 3120 | } | 3343 | } |
| 3121 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR; | 3344 | |
| 3122 | 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); | ||
| 3123 | } | 3349 | } |
| 3124 | 3350 | ||
| 3125 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | 3351 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, |
| @@ -3154,6 +3380,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
| 3154 | 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; |
| 3155 | #endif | 3381 | #endif |
| 3156 | #endif | 3382 | #endif |
| 3383 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | ||
| 3157 | } | 3384 | } |
| 3158 | 3385 | ||
| 3159 | /* Maximum length of ifinfomsg attributes */ | 3386 | /* Maximum length of ifinfomsg attributes */ |
| @@ -3260,20 +3487,23 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 3260 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | 3487 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) |
| 3261 | { | 3488 | { |
| 3262 | struct sk_buff *skb; | 3489 | struct sk_buff *skb; |
| 3263 | 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; | ||
| 3264 | 3492 | ||
| 3265 | skb = alloc_skb(size, GFP_ATOMIC); | 3493 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
| 3266 | if (!skb) { | 3494 | if (skb == NULL) |
| 3267 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, ENOBUFS); | 3495 | goto errout; |
| 3268 | return; | 3496 | |
| 3269 | } | 3497 | err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); |
| 3270 | if (inet6_fill_ifinfo(skb, idev, current->pid, 0, event, 0) < 0) { | 3498 | if (err < 0) { |
| 3271 | kfree_skb(skb); | 3499 | kfree_skb(skb); |
| 3272 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, EINVAL); | 3500 | goto errout; |
| 3273 | return; | ||
| 3274 | } | 3501 | } |
| 3275 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO; | 3502 | |
| 3276 | 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); | ||
| 3277 | } | 3507 | } |
| 3278 | 3508 | ||
| 3279 | /* Maximum length of prefix_cacheinfo attributes */ | 3509 | /* Maximum length of prefix_cacheinfo attributes */ |
| @@ -3325,33 +3555,40 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |||
| 3325 | struct prefix_info *pinfo) | 3555 | struct prefix_info *pinfo) |
| 3326 | { | 3556 | { |
| 3327 | struct sk_buff *skb; | 3557 | struct sk_buff *skb; |
| 3328 | 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; | ||
| 3329 | 3560 | ||
| 3330 | skb = alloc_skb(size, GFP_ATOMIC); | 3561 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
| 3331 | if (!skb) { | 3562 | if (skb == NULL) |
| 3332 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, ENOBUFS); | 3563 | goto errout; |
| 3333 | return; | 3564 | |
| 3334 | } | 3565 | err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); |
| 3335 | if (inet6_fill_prefix(skb, idev, pinfo, current->pid, 0, event, 0) < 0) { | 3566 | if (err < 0) { |
| 3336 | kfree_skb(skb); | 3567 | kfree_skb(skb); |
| 3337 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, EINVAL); | 3568 | goto errout; |
| 3338 | return; | ||
| 3339 | } | 3569 | } |
| 3340 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX; | 3570 | |
| 3341 | 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); | ||
| 3342 | } | 3575 | } |
| 3343 | 3576 | ||
| 3344 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | 3577 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { |
| 3345 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, | 3578 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, |
| 3346 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, | 3579 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, |
| 3347 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, | 3580 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, |
| 3348 | [RTM_GETADDR - RTM_BASE] = { .dumpit = inet6_dump_ifaddr, }, | 3581 | [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr, |
| 3582 | .dumpit = inet6_dump_ifaddr, }, | ||
| 3349 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, | 3583 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, |
| 3350 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, | 3584 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, |
| 3351 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, | 3585 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, |
| 3352 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, | 3586 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, |
| 3353 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, | 3587 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, |
| 3354 | .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 | ||
| 3355 | }; | 3592 | }; |
| 3356 | 3593 | ||
| 3357 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3594 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
| @@ -3360,7 +3597,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
| 3360 | 3597 | ||
| 3361 | switch (event) { | 3598 | switch (event) { |
| 3362 | case RTM_NEWADDR: | 3599 | case RTM_NEWADDR: |
| 3363 | ip6_ins_rt(ifp->rt, NULL, NULL, NULL); | 3600 | ip6_ins_rt(ifp->rt); |
| 3364 | if (ifp->idev->cnf.forwarding) | 3601 | if (ifp->idev->cnf.forwarding) |
| 3365 | addrconf_join_anycast(ifp); | 3602 | addrconf_join_anycast(ifp); |
| 3366 | break; | 3603 | break; |
| @@ -3369,7 +3606,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
| 3369 | addrconf_leave_anycast(ifp); | 3606 | addrconf_leave_anycast(ifp); |
| 3370 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 3607 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
| 3371 | dst_hold(&ifp->rt->u.dst); | 3608 | dst_hold(&ifp->rt->u.dst); |
| 3372 | if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) | 3609 | if (ip6_del_rt(ifp->rt)) |
| 3373 | dst_free(&ifp->rt->u.dst); | 3610 | dst_free(&ifp->rt->u.dst); |
| 3374 | break; | 3611 | break; |
| 3375 | } | 3612 | } |
| @@ -3377,10 +3614,10 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
| 3377 | 3614 | ||
| 3378 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3615 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
| 3379 | { | 3616 | { |
| 3380 | read_lock_bh(&addrconf_lock); | 3617 | rcu_read_lock_bh(); |
| 3381 | if (likely(ifp->idev->dead == 0)) | 3618 | if (likely(ifp->idev->dead == 0)) |
| 3382 | __ipv6_ifa_notify(event, ifp); | 3619 | __ipv6_ifa_notify(event, ifp); |
| 3383 | read_unlock_bh(&addrconf_lock); | 3620 | rcu_read_unlock_bh(); |
| 3384 | } | 3621 | } |
| 3385 | 3622 | ||
| 3386 | #ifdef CONFIG_SYSCTL | 3623 | #ifdef CONFIG_SYSCTL |
| @@ -3477,7 +3714,7 @@ static struct addrconf_sysctl_table | |||
| 3477 | ctl_table addrconf_conf_dir[2]; | 3714 | ctl_table addrconf_conf_dir[2]; |
| 3478 | ctl_table addrconf_proto_dir[2]; | 3715 | ctl_table addrconf_proto_dir[2]; |
| 3479 | ctl_table addrconf_root_dir[2]; | 3716 | ctl_table addrconf_root_dir[2]; |
| 3480 | } addrconf_sysctl = { | 3717 | } addrconf_sysctl __read_mostly = { |
| 3481 | .sysctl_header = NULL, | 3718 | .sysctl_header = NULL, |
| 3482 | .addrconf_vars = { | 3719 | .addrconf_vars = { |
| 3483 | { | 3720 | { |
| @@ -3667,6 +3904,14 @@ static struct addrconf_sysctl_table | |||
| 3667 | #endif | 3904 | #endif |
| 3668 | #endif | 3905 | #endif |
| 3669 | { | 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 | { | ||
| 3670 | .ctl_name = 0, /* sentinel */ | 3915 | .ctl_name = 0, /* sentinel */ |
| 3671 | } | 3916 | } |
| 3672 | }, | 3917 | }, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e19457fe4f6e..e94eccb99707 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | 23 | ||
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
| 26 | #include <linux/config.h> | ||
| 27 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
| 28 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 29 | #include <linux/socket.h> | 28 | #include <linux/socket.h> |
| @@ -60,6 +59,9 @@ | |||
| 60 | #ifdef CONFIG_IPV6_TUNNEL | 59 | #ifdef CONFIG_IPV6_TUNNEL |
| 61 | #include <net/ip6_tunnel.h> | 60 | #include <net/ip6_tunnel.h> |
| 62 | #endif | 61 | #endif |
| 62 | #ifdef CONFIG_IPV6_MIP6 | ||
| 63 | #include <net/mip6.h> | ||
| 64 | #endif | ||
| 63 | 65 | ||
| 64 | #include <asm/uaccess.h> | 66 | #include <asm/uaccess.h> |
| 65 | #include <asm/system.h> | 67 | #include <asm/system.h> |
| @@ -68,7 +70,7 @@ MODULE_AUTHOR("Cast of dozens"); | |||
| 68 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); | 70 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); |
| 69 | MODULE_LICENSE("GPL"); | 71 | MODULE_LICENSE("GPL"); |
| 70 | 72 | ||
| 71 | int sysctl_ipv6_bindv6only; | 73 | int sysctl_ipv6_bindv6only __read_mostly; |
| 72 | 74 | ||
| 73 | /* The inetsw table contains everything that inet_create needs to | 75 | /* The inetsw table contains everything that inet_create needs to |
| 74 | * build a new socket. | 76 | * build a new socket. |
| @@ -244,7 +246,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 244 | struct sock *sk = sock->sk; | 246 | struct sock *sk = sock->sk; |
| 245 | struct inet_sock *inet = inet_sk(sk); | 247 | struct inet_sock *inet = inet_sk(sk); |
| 246 | struct ipv6_pinfo *np = inet6_sk(sk); | 248 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 247 | __u32 v4addr = 0; | 249 | __be32 v4addr = 0; |
| 248 | unsigned short snum; | 250 | unsigned short snum; |
| 249 | int addr_type = 0; | 251 | int addr_type = 0; |
| 250 | int err = 0; | 252 | int err = 0; |
| @@ -638,6 +640,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 638 | fl.oif = sk->sk_bound_dev_if; | 640 | fl.oif = sk->sk_bound_dev_if; |
| 639 | fl.fl_ip_dport = inet->dport; | 641 | fl.fl_ip_dport = inet->dport; |
| 640 | fl.fl_ip_sport = inet->sport; | 642 | fl.fl_ip_sport = inet->sport; |
| 643 | security_sk_classify_flow(sk, &fl); | ||
| 641 | 644 | ||
| 642 | if (np->opt && np->opt->srcrt) { | 645 | if (np->opt && np->opt->srcrt) { |
| 643 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | 646 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; |
| @@ -659,9 +662,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 659 | return err; | 662 | return err; |
| 660 | } | 663 | } |
| 661 | 664 | ||
| 662 | ip6_dst_store(sk, dst, NULL); | 665 | __ip6_dst_store(sk, dst, NULL, NULL); |
| 663 | sk->sk_route_caps = dst->dev->features & | ||
| 664 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 665 | } | 666 | } |
| 666 | 667 | ||
| 667 | return 0; | 668 | return 0; |
| @@ -760,6 +761,8 @@ static int __init inet6_init(void) | |||
| 760 | struct list_head *r; | 761 | struct list_head *r; |
| 761 | int err; | 762 | int err; |
| 762 | 763 | ||
| 764 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); | ||
| 765 | |||
| 763 | #ifdef MODULE | 766 | #ifdef MODULE |
| 764 | #if 0 /* FIXME --RR */ | 767 | #if 0 /* FIXME --RR */ |
| 765 | if (!mod_member_present(&__this_module, can_unload)) | 768 | if (!mod_member_present(&__this_module, can_unload)) |
| @@ -769,11 +772,6 @@ static int __init inet6_init(void) | |||
| 769 | #endif | 772 | #endif |
| 770 | #endif | 773 | #endif |
| 771 | 774 | ||
| 772 | if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) { | ||
| 773 | printk(KERN_CRIT "inet6_proto_init: size fault\n"); | ||
| 774 | return -EINVAL; | ||
| 775 | } | ||
| 776 | |||
| 777 | err = proto_register(&tcpv6_prot, 1); | 775 | err = proto_register(&tcpv6_prot, 1); |
| 778 | if (err) | 776 | if (err) |
| 779 | goto out; | 777 | goto out; |
| @@ -859,6 +857,9 @@ static int __init inet6_init(void) | |||
| 859 | ipv6_frag_init(); | 857 | ipv6_frag_init(); |
| 860 | ipv6_nodata_init(); | 858 | ipv6_nodata_init(); |
| 861 | ipv6_destopt_init(); | 859 | ipv6_destopt_init(); |
| 860 | #ifdef CONFIG_IPV6_MIP6 | ||
| 861 | mip6_init(); | ||
| 862 | #endif | ||
| 862 | 863 | ||
| 863 | /* Init v6 transport protocols. */ | 864 | /* Init v6 transport protocols. */ |
| 864 | udpv6_init(); | 865 | udpv6_init(); |
| @@ -922,6 +923,9 @@ static void __exit inet6_exit(void) | |||
| 922 | tcp6_proc_exit(); | 923 | tcp6_proc_exit(); |
| 923 | raw6_proc_exit(); | 924 | raw6_proc_exit(); |
| 924 | #endif | 925 | #endif |
| 926 | #ifdef CONFIG_IPV6_MIP6 | ||
| 927 | mip6_fini(); | ||
| 928 | #endif | ||
| 925 | /* Cleanup code parts. */ | 929 | /* Cleanup code parts. */ |
| 926 | sit_cleanup(); | 930 | sit_cleanup(); |
| 927 | ip6_flowlabel_cleanup(); | 931 | ip6_flowlabel_cleanup(); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index d31c0d6c0448..b0d83e8e4252 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | * This file is derived from net/ipv4/ah.c. | 24 | * This file is derived from net/ipv4/ah.c. |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/config.h> | ||
| 28 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 29 | #include <net/ip.h> | 28 | #include <net/ip.h> |
| 30 | #include <net/ah.h> | 29 | #include <net/ah.h> |
| @@ -75,6 +74,66 @@ bad: | |||
| 75 | return 0; | 74 | return 0; |
| 76 | } | 75 | } |
| 77 | 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 | |||
| 78 | /** | 137 | /** |
| 79 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header | 138 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header |
| 80 | * @iph: IPv6 header | 139 | * @iph: IPv6 header |
| @@ -114,7 +173,7 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) | |||
| 114 | ipv6_addr_copy(&iph->daddr, &final_addr); | 173 | ipv6_addr_copy(&iph->daddr, &final_addr); |
| 115 | } | 174 | } |
| 116 | 175 | ||
| 117 | 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) |
| 118 | { | 177 | { |
| 119 | union { | 178 | union { |
| 120 | struct ipv6hdr *iph; | 179 | struct ipv6hdr *iph; |
| @@ -129,8 +188,12 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) | |||
| 129 | 188 | ||
| 130 | while (exthdr.raw < end) { | 189 | while (exthdr.raw < end) { |
| 131 | switch (nexthdr) { | 190 | switch (nexthdr) { |
| 132 | case NEXTHDR_HOP: | ||
| 133 | 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: | ||
| 134 | if (!zero_out_mutable_opts(exthdr.opth)) { | 197 | if (!zero_out_mutable_opts(exthdr.opth)) { |
| 135 | LIMIT_NETDEBUG( | 198 | LIMIT_NETDEBUG( |
| 136 | KERN_WARNING "overrun %sopts\n", | 199 | KERN_WARNING "overrun %sopts\n", |
| @@ -165,6 +228,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 165 | u8 nexthdr; | 228 | u8 nexthdr; |
| 166 | char tmp_base[8]; | 229 | char tmp_base[8]; |
| 167 | struct { | 230 | struct { |
| 231 | #ifdef CONFIG_IPV6_MIP6 | ||
| 232 | struct in6_addr saddr; | ||
| 233 | #endif | ||
| 168 | struct in6_addr daddr; | 234 | struct in6_addr daddr; |
| 169 | char hdrs[0]; | 235 | char hdrs[0]; |
| 170 | } *tmp_ext; | 236 | } *tmp_ext; |
| @@ -189,10 +255,15 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 189 | err = -ENOMEM; | 255 | err = -ENOMEM; |
| 190 | goto error; | 256 | goto error; |
| 191 | } | 257 | } |
| 258 | #ifdef CONFIG_IPV6_MIP6 | ||
| 259 | memcpy(tmp_ext, &top_iph->saddr, extlen); | ||
| 260 | #else | ||
| 192 | memcpy(tmp_ext, &top_iph->daddr, extlen); | 261 | memcpy(tmp_ext, &top_iph->daddr, extlen); |
| 262 | #endif | ||
| 193 | err = ipv6_clear_mutable_options(top_iph, | 263 | err = ipv6_clear_mutable_options(top_iph, |
| 194 | extlen - sizeof(*tmp_ext) + | 264 | extlen - sizeof(*tmp_ext) + |
| 195 | sizeof(*top_iph)); | 265 | sizeof(*top_iph), |
| 266 | XFRM_POLICY_OUT); | ||
| 196 | if (err) | 267 | if (err) |
| 197 | goto error_free_iph; | 268 | goto error_free_iph; |
| 198 | } | 269 | } |
| @@ -214,13 +285,20 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 214 | ah->spi = x->id.spi; | 285 | ah->spi = x->id.spi; |
| 215 | ah->seq_no = htonl(++x->replay.oseq); | 286 | ah->seq_no = htonl(++x->replay.oseq); |
| 216 | xfrm_aevent_doreplay(x); | 287 | xfrm_aevent_doreplay(x); |
| 217 | ahp->icv(ahp, skb, ah->auth_data); | 288 | err = ah_mac_digest(ahp, skb, ah->auth_data); |
| 289 | if (err) | ||
| 290 | goto error_free_iph; | ||
| 291 | memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); | ||
| 218 | 292 | ||
| 219 | err = 0; | 293 | err = 0; |
| 220 | 294 | ||
| 221 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); | 295 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); |
| 222 | if (tmp_ext) { | 296 | if (tmp_ext) { |
| 297 | #ifdef CONFIG_IPV6_MIP6 | ||
| 298 | memcpy(&top_iph->saddr, tmp_ext, extlen); | ||
| 299 | #else | ||
| 223 | memcpy(&top_iph->daddr, tmp_ext, extlen); | 300 | memcpy(&top_iph->daddr, tmp_ext, extlen); |
| 301 | #endif | ||
| 224 | error_free_iph: | 302 | error_free_iph: |
| 225 | kfree(tmp_ext); | 303 | kfree(tmp_ext); |
| 226 | } | 304 | } |
| @@ -252,6 +330,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 252 | u16 hdr_len; | 330 | u16 hdr_len; |
| 253 | u16 ah_hlen; | 331 | u16 ah_hlen; |
| 254 | int nexthdr; | 332 | int nexthdr; |
| 333 | int err = -EINVAL; | ||
| 255 | 334 | ||
| 256 | if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) | 335 | if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) |
| 257 | goto out; | 336 | goto out; |
| @@ -279,7 +358,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 279 | if (!tmp_hdr) | 358 | if (!tmp_hdr) |
| 280 | goto out; | 359 | goto out; |
| 281 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); | 360 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); |
| 282 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len)) | 361 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN)) |
| 283 | goto free_out; | 362 | goto free_out; |
| 284 | skb->nh.ipv6h->priority = 0; | 363 | skb->nh.ipv6h->priority = 0; |
| 285 | skb->nh.ipv6h->flow_lbl[0] = 0; | 364 | skb->nh.ipv6h->flow_lbl[0] = 0; |
| @@ -293,8 +372,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 293 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); | 372 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); |
| 294 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | 373 | memset(ah->auth_data, 0, ahp->icv_trunc_len); |
| 295 | skb_push(skb, hdr_len); | 374 | skb_push(skb, hdr_len); |
| 296 | ahp->icv(ahp, skb, ah->auth_data); | 375 | err = ah_mac_digest(ahp, skb, ah->auth_data); |
| 297 | if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { | 376 | if (err) |
| 377 | goto free_out; | ||
| 378 | err = -EINVAL; | ||
| 379 | if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { | ||
| 298 | LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); | 380 | LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); |
| 299 | x->stats.integrity_failed++; | 381 | x->stats.integrity_failed++; |
| 300 | goto free_out; | 382 | goto free_out; |
| @@ -311,7 +393,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 311 | free_out: | 393 | free_out: |
| 312 | kfree(tmp_hdr); | 394 | kfree(tmp_hdr); |
| 313 | out: | 395 | out: |
| 314 | return -EINVAL; | 396 | return err; |
| 315 | } | 397 | } |
| 316 | 398 | ||
| 317 | static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 399 | static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| @@ -339,6 +421,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
| 339 | { | 421 | { |
| 340 | struct ah_data *ahp = NULL; | 422 | struct ah_data *ahp = NULL; |
| 341 | struct xfrm_algo_desc *aalg_desc; | 423 | struct xfrm_algo_desc *aalg_desc; |
| 424 | struct crypto_hash *tfm; | ||
| 342 | 425 | ||
| 343 | if (!x->aalg) | 426 | if (!x->aalg) |
| 344 | goto error; | 427 | goto error; |
| @@ -356,24 +439,27 @@ static int ah6_init_state(struct xfrm_state *x) | |||
| 356 | 439 | ||
| 357 | ahp->key = x->aalg->alg_key; | 440 | ahp->key = x->aalg->alg_key; |
| 358 | ahp->key_len = (x->aalg->alg_key_len+7)/8; | 441 | ahp->key_len = (x->aalg->alg_key_len+7)/8; |
| 359 | ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); | 442 | tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); |
| 360 | if (!ahp->tfm) | 443 | if (IS_ERR(tfm)) |
| 444 | goto error; | ||
| 445 | |||
| 446 | ahp->tfm = tfm; | ||
| 447 | if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len)) | ||
| 361 | goto error; | 448 | goto error; |
| 362 | ahp->icv = ah_hmac_digest; | ||
| 363 | 449 | ||
| 364 | /* | 450 | /* |
| 365 | * Lookup the algorithm description maintained by xfrm_algo, | 451 | * Lookup the algorithm description maintained by xfrm_algo, |
| 366 | * verify crypto transform properties, and store information | 452 | * verify crypto transform properties, and store information |
| 367 | * we need for AH processing. This lookup cannot fail here | 453 | * we need for AH processing. This lookup cannot fail here |
| 368 | * after a successful crypto_alloc_tfm(). | 454 | * after a successful crypto_alloc_hash(). |
| 369 | */ | 455 | */ |
| 370 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); | 456 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); |
| 371 | BUG_ON(!aalg_desc); | 457 | BUG_ON(!aalg_desc); |
| 372 | 458 | ||
| 373 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != | 459 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != |
| 374 | crypto_tfm_alg_digestsize(ahp->tfm)) { | 460 | crypto_hash_digestsize(tfm)) { |
| 375 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", | 461 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", |
| 376 | x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), | 462 | x->aalg->alg_name, crypto_hash_digestsize(tfm), |
| 377 | aalg_desc->uinfo.auth.icv_fullbits/8); | 463 | aalg_desc->uinfo.auth.icv_fullbits/8); |
| 378 | goto error; | 464 | goto error; |
| 379 | } | 465 | } |
| @@ -388,7 +474,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
| 388 | goto error; | 474 | goto error; |
| 389 | 475 | ||
| 390 | 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); |
| 391 | if (x->props.mode) | 477 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 392 | x->props.header_len += sizeof(struct ipv6hdr); | 478 | x->props.header_len += sizeof(struct ipv6hdr); |
| 393 | x->data = ahp; | 479 | x->data = ahp; |
| 394 | 480 | ||
| @@ -397,7 +483,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
| 397 | error: | 483 | error: |
| 398 | if (ahp) { | 484 | if (ahp) { |
| 399 | kfree(ahp->work_icv); | 485 | kfree(ahp->work_icv); |
| 400 | crypto_free_tfm(ahp->tfm); | 486 | crypto_free_hash(ahp->tfm); |
| 401 | kfree(ahp); | 487 | kfree(ahp); |
| 402 | } | 488 | } |
| 403 | return -EINVAL; | 489 | return -EINVAL; |
| @@ -412,7 +498,7 @@ static void ah6_destroy(struct xfrm_state *x) | |||
| 412 | 498 | ||
| 413 | kfree(ahp->work_icv); | 499 | kfree(ahp->work_icv); |
| 414 | ahp->work_icv = NULL; | 500 | ahp->work_icv = NULL; |
| 415 | crypto_free_tfm(ahp->tfm); | 501 | crypto_free_hash(ahp->tfm); |
| 416 | ahp->tfm = NULL; | 502 | ahp->tfm = NULL; |
| 417 | kfree(ahp); | 503 | kfree(ahp); |
| 418 | } | 504 | } |
| @@ -425,7 +511,8 @@ static struct xfrm_type ah6_type = | |||
| 425 | .init_state = ah6_init_state, | 511 | .init_state = ah6_init_state, |
| 426 | .destructor = ah6_destroy, | 512 | .destructor = ah6_destroy, |
| 427 | .input = ah6_input, | 513 | .input = ah6_input, |
| 428 | .output = ah6_output | 514 | .output = ah6_output, |
| 515 | .hdr_offset = xfrm6_find_1stfragopt, | ||
| 429 | }; | 516 | }; |
| 430 | 517 | ||
| 431 | 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 39ec528923f6..a9604764e015 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
| 17 | #include <linux/config.h> | ||
| 18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 19 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
| 20 | #include <linux/types.h> | 19 | #include <linux/types.h> |
| @@ -57,7 +56,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
| 57 | int onlink; | 56 | int onlink; |
| 58 | 57 | ||
| 59 | onlink = 0; | 58 | onlink = 0; |
| 60 | read_lock(&addrconf_lock); | 59 | rcu_read_lock(); |
| 61 | idev = __in6_dev_get(dev); | 60 | idev = __in6_dev_get(dev); |
| 62 | if (idev) { | 61 | if (idev) { |
| 63 | read_lock_bh(&idev->lock); | 62 | read_lock_bh(&idev->lock); |
| @@ -69,7 +68,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
| 69 | } | 68 | } |
| 70 | read_unlock_bh(&idev->lock); | 69 | read_unlock_bh(&idev->lock); |
| 71 | } | 70 | } |
| 72 | read_unlock(&addrconf_lock); | 71 | rcu_read_unlock(); |
| 73 | return onlink; | 72 | return onlink; |
| 74 | } | 73 | } |
| 75 | 74 | ||
| @@ -336,7 +335,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
| 336 | write_unlock_bh(&idev->lock); | 335 | write_unlock_bh(&idev->lock); |
| 337 | 336 | ||
| 338 | dst_hold(&rt->u.dst); | 337 | dst_hold(&rt->u.dst); |
| 339 | if (ip6_ins_rt(rt, NULL, NULL, NULL)) | 338 | if (ip6_ins_rt(rt)) |
| 340 | dst_release(&rt->u.dst); | 339 | dst_release(&rt->u.dst); |
| 341 | 340 | ||
| 342 | addrconf_join_solict(dev, &aca->aca_addr); | 341 | addrconf_join_solict(dev, &aca->aca_addr); |
| @@ -379,7 +378,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
| 379 | addrconf_leave_solict(idev, &aca->aca_addr); | 378 | addrconf_leave_solict(idev, &aca->aca_addr); |
| 380 | 379 | ||
| 381 | dst_hold(&aca->aca_rt->u.dst); | 380 | dst_hold(&aca->aca_rt->u.dst); |
| 382 | if (ip6_del_rt(aca->aca_rt, NULL, NULL, NULL)) | 381 | if (ip6_del_rt(aca->aca_rt)) |
| 383 | dst_free(&aca->aca_rt->u.dst); | 382 | dst_free(&aca->aca_rt->u.dst); |
| 384 | else | 383 | else |
| 385 | 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 99a6eb23378b..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 | } |
| @@ -696,7 +706,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
| 696 | } | 706 | } |
| 697 | 707 | ||
| 698 | tc = *(int *)CMSG_DATA(cmsg); | 708 | tc = *(int *)CMSG_DATA(cmsg); |
| 699 | if (tc < 0 || tc > 0xff) | 709 | if (tc < -1 || tc > 0xff) |
| 700 | goto exit_f; | 710 | goto exit_f; |
| 701 | 711 | ||
| 702 | err = 0; | 712 | err = 0; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a15a6f320f70..e78680a9985b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | * This file is derived from net/ipv4/esp.c | 24 | * This file is derived from net/ipv4/esp.c |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/config.h> | 27 | #include <linux/err.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <net/ip.h> | 29 | #include <net/ip.h> |
| 30 | #include <net/xfrm.h> | 30 | #include <net/xfrm.h> |
| @@ -45,7 +45,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 45 | int hdr_len; | 45 | int hdr_len; |
| 46 | struct ipv6hdr *top_iph; | 46 | struct ipv6hdr *top_iph; |
| 47 | struct ipv6_esp_hdr *esph; | 47 | struct ipv6_esp_hdr *esph; |
| 48 | struct crypto_tfm *tfm; | 48 | struct crypto_blkcipher *tfm; |
| 49 | struct blkcipher_desc desc; | ||
| 49 | struct esp_data *esp; | 50 | struct esp_data *esp; |
| 50 | struct sk_buff *trailer; | 51 | struct sk_buff *trailer; |
| 51 | int blksize; | 52 | int blksize; |
| @@ -68,7 +69,9 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 68 | 69 | ||
| 69 | alen = esp->auth.icv_trunc_len; | 70 | alen = esp->auth.icv_trunc_len; |
| 70 | tfm = esp->conf.tfm; | 71 | tfm = esp->conf.tfm; |
| 71 | blksize = ALIGN(crypto_tfm_alg_blocksize(tfm), 4); | 72 | desc.tfm = tfm; |
| 73 | desc.flags = 0; | ||
| 74 | blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); | ||
| 72 | clen = ALIGN(clen + 2, blksize); | 75 | clen = ALIGN(clen + 2, blksize); |
| 73 | if (esp->conf.padlen) | 76 | if (esp->conf.padlen) |
| 74 | clen = ALIGN(clen, esp->conf.padlen); | 77 | clen = ALIGN(clen, esp->conf.padlen); |
| @@ -96,8 +99,13 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 96 | esph->seq_no = htonl(++x->replay.oseq); | 99 | esph->seq_no = htonl(++x->replay.oseq); |
| 97 | xfrm_aevent_doreplay(x); | 100 | xfrm_aevent_doreplay(x); |
| 98 | 101 | ||
| 99 | if (esp->conf.ivlen) | 102 | if (esp->conf.ivlen) { |
| 100 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 103 | if (unlikely(!esp->conf.ivinitted)) { |
| 104 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | ||
| 105 | esp->conf.ivinitted = 1; | ||
| 106 | } | ||
| 107 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); | ||
| 108 | } | ||
| 101 | 109 | ||
| 102 | do { | 110 | do { |
| 103 | struct scatterlist *sg = &esp->sgbuf[0]; | 111 | struct scatterlist *sg = &esp->sgbuf[0]; |
| @@ -108,24 +116,25 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 108 | goto error; | 116 | goto error; |
| 109 | } | 117 | } |
| 110 | skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); | 118 | skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); |
| 111 | crypto_cipher_encrypt(tfm, sg, sg, clen); | 119 | err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); |
| 112 | if (unlikely(sg != &esp->sgbuf[0])) | 120 | if (unlikely(sg != &esp->sgbuf[0])) |
| 113 | kfree(sg); | 121 | kfree(sg); |
| 114 | } while (0); | 122 | } while (0); |
| 115 | 123 | ||
| 124 | if (unlikely(err)) | ||
| 125 | goto error; | ||
| 126 | |||
| 116 | if (esp->conf.ivlen) { | 127 | if (esp->conf.ivlen) { |
| 117 | memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 128 | memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); |
| 118 | crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 129 | crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen); |
| 119 | } | 130 | } |
| 120 | 131 | ||
| 121 | if (esp->auth.icv_full_len) { | 132 | if (esp->auth.icv_full_len) { |
| 122 | esp->auth.icv(esp, skb, (u8*)esph-skb->data, | 133 | err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, |
| 123 | sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); | 134 | sizeof(*esph) + esp->conf.ivlen + clen); |
| 124 | pskb_put(skb, trailer, alen); | 135 | memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); |
| 125 | } | 136 | } |
| 126 | 137 | ||
| 127 | err = 0; | ||
| 128 | |||
| 129 | error: | 138 | error: |
| 130 | return err; | 139 | return err; |
| 131 | } | 140 | } |
| @@ -135,8 +144,10 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 135 | struct ipv6hdr *iph; | 144 | struct ipv6hdr *iph; |
| 136 | struct ipv6_esp_hdr *esph; | 145 | struct ipv6_esp_hdr *esph; |
| 137 | struct esp_data *esp = x->data; | 146 | struct esp_data *esp = x->data; |
| 147 | struct crypto_blkcipher *tfm = esp->conf.tfm; | ||
| 148 | struct blkcipher_desc desc = { .tfm = tfm }; | ||
| 138 | struct sk_buff *trailer; | 149 | struct sk_buff *trailer; |
| 139 | int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); | 150 | int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); |
| 140 | int alen = esp->auth.icv_trunc_len; | 151 | int alen = esp->auth.icv_trunc_len; |
| 141 | int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; | 152 | int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; |
| 142 | 153 | ||
| @@ -156,15 +167,16 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 156 | 167 | ||
| 157 | /* If integrity check is required, do this. */ | 168 | /* If integrity check is required, do this. */ |
| 158 | if (esp->auth.icv_full_len) { | 169 | if (esp->auth.icv_full_len) { |
| 159 | u8 sum[esp->auth.icv_full_len]; | 170 | u8 sum[alen]; |
| 160 | u8 sum1[alen]; | ||
| 161 | 171 | ||
| 162 | esp->auth.icv(esp, skb, 0, skb->len-alen, sum); | 172 | ret = esp_mac_digest(esp, skb, 0, skb->len - alen); |
| 173 | if (ret) | ||
| 174 | goto out; | ||
| 163 | 175 | ||
| 164 | if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) | 176 | if (skb_copy_bits(skb, skb->len - alen, sum, alen)) |
| 165 | BUG(); | 177 | BUG(); |
| 166 | 178 | ||
| 167 | if (unlikely(memcmp(sum, sum1, alen))) { | 179 | if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { |
| 168 | x->stats.integrity_failed++; | 180 | x->stats.integrity_failed++; |
| 169 | ret = -EINVAL; | 181 | ret = -EINVAL; |
| 170 | goto out; | 182 | goto out; |
| @@ -183,7 +195,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 183 | 195 | ||
| 184 | /* Get ivec. This can be wrong, check against another impls. */ | 196 | /* Get ivec. This can be wrong, check against another impls. */ |
| 185 | if (esp->conf.ivlen) | 197 | if (esp->conf.ivlen) |
| 186 | crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); | 198 | crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); |
| 187 | 199 | ||
| 188 | { | 200 | { |
| 189 | u8 nexthdr[2]; | 201 | u8 nexthdr[2]; |
| @@ -198,9 +210,11 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 198 | } | 210 | } |
| 199 | } | 211 | } |
| 200 | skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); | 212 | skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); |
| 201 | crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); | 213 | ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); |
| 202 | if (unlikely(sg != &esp->sgbuf[0])) | 214 | if (unlikely(sg != &esp->sgbuf[0])) |
| 203 | kfree(sg); | 215 | kfree(sg); |
| 216 | if (unlikely(ret)) | ||
| 217 | goto out; | ||
| 204 | 218 | ||
| 205 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) | 219 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) |
| 206 | BUG(); | 220 | BUG(); |
| @@ -226,9 +240,9 @@ out: | |||
| 226 | static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) | 240 | static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) |
| 227 | { | 241 | { |
| 228 | struct esp_data *esp = x->data; | 242 | struct esp_data *esp = x->data; |
| 229 | u32 blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); | 243 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
| 230 | 244 | ||
| 231 | if (x->props.mode) { | 245 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
| 232 | mtu = ALIGN(mtu + 2, blksize); | 246 | mtu = ALIGN(mtu + 2, blksize); |
| 233 | } else { | 247 | } else { |
| 234 | /* The worst case. */ | 248 | /* The worst case. */ |
| @@ -267,11 +281,11 @@ static void esp6_destroy(struct xfrm_state *x) | |||
| 267 | if (!esp) | 281 | if (!esp) |
| 268 | return; | 282 | return; |
| 269 | 283 | ||
| 270 | crypto_free_tfm(esp->conf.tfm); | 284 | crypto_free_blkcipher(esp->conf.tfm); |
| 271 | esp->conf.tfm = NULL; | 285 | esp->conf.tfm = NULL; |
| 272 | kfree(esp->conf.ivec); | 286 | kfree(esp->conf.ivec); |
| 273 | esp->conf.ivec = NULL; | 287 | esp->conf.ivec = NULL; |
| 274 | crypto_free_tfm(esp->auth.tfm); | 288 | crypto_free_hash(esp->auth.tfm); |
| 275 | esp->auth.tfm = NULL; | 289 | esp->auth.tfm = NULL; |
| 276 | kfree(esp->auth.work_icv); | 290 | kfree(esp->auth.work_icv); |
| 277 | esp->auth.work_icv = NULL; | 291 | esp->auth.work_icv = NULL; |
| @@ -281,6 +295,7 @@ static void esp6_destroy(struct xfrm_state *x) | |||
| 281 | static int esp6_init_state(struct xfrm_state *x) | 295 | static int esp6_init_state(struct xfrm_state *x) |
| 282 | { | 296 | { |
| 283 | struct esp_data *esp = NULL; | 297 | struct esp_data *esp = NULL; |
| 298 | struct crypto_blkcipher *tfm; | ||
| 284 | 299 | ||
| 285 | /* null auth and encryption can have zero length keys */ | 300 | /* null auth and encryption can have zero length keys */ |
| 286 | if (x->aalg) { | 301 | if (x->aalg) { |
| @@ -299,24 +314,29 @@ static int esp6_init_state(struct xfrm_state *x) | |||
| 299 | 314 | ||
| 300 | if (x->aalg) { | 315 | if (x->aalg) { |
| 301 | struct xfrm_algo_desc *aalg_desc; | 316 | struct xfrm_algo_desc *aalg_desc; |
| 317 | struct crypto_hash *hash; | ||
| 302 | 318 | ||
| 303 | esp->auth.key = x->aalg->alg_key; | 319 | esp->auth.key = x->aalg->alg_key; |
| 304 | esp->auth.key_len = (x->aalg->alg_key_len+7)/8; | 320 | esp->auth.key_len = (x->aalg->alg_key_len+7)/8; |
| 305 | esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); | 321 | hash = crypto_alloc_hash(x->aalg->alg_name, 0, |
| 306 | if (esp->auth.tfm == NULL) | 322 | CRYPTO_ALG_ASYNC); |
| 323 | if (IS_ERR(hash)) | ||
| 324 | goto error; | ||
| 325 | |||
| 326 | esp->auth.tfm = hash; | ||
| 327 | if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len)) | ||
| 307 | goto error; | 328 | goto error; |
| 308 | esp->auth.icv = esp_hmac_digest; | ||
| 309 | 329 | ||
| 310 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); | 330 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); |
| 311 | BUG_ON(!aalg_desc); | 331 | BUG_ON(!aalg_desc); |
| 312 | 332 | ||
| 313 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != | 333 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != |
| 314 | crypto_tfm_alg_digestsize(esp->auth.tfm)) { | 334 | crypto_hash_digestsize(hash)) { |
| 315 | printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", | 335 | NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", |
| 316 | x->aalg->alg_name, | 336 | x->aalg->alg_name, |
| 317 | crypto_tfm_alg_digestsize(esp->auth.tfm), | 337 | crypto_hash_digestsize(hash), |
| 318 | aalg_desc->uinfo.auth.icv_fullbits/8); | 338 | aalg_desc->uinfo.auth.icv_fullbits/8); |
| 319 | goto error; | 339 | goto error; |
| 320 | } | 340 | } |
| 321 | 341 | ||
| 322 | esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 342 | esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
| @@ -328,24 +348,22 @@ static int esp6_init_state(struct xfrm_state *x) | |||
| 328 | } | 348 | } |
| 329 | esp->conf.key = x->ealg->alg_key; | 349 | esp->conf.key = x->ealg->alg_key; |
| 330 | esp->conf.key_len = (x->ealg->alg_key_len+7)/8; | 350 | esp->conf.key_len = (x->ealg->alg_key_len+7)/8; |
| 331 | if (x->props.ealgo == SADB_EALG_NULL) | 351 | tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC); |
| 332 | esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB); | 352 | if (IS_ERR(tfm)) |
| 333 | else | ||
| 334 | esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); | ||
| 335 | if (esp->conf.tfm == NULL) | ||
| 336 | goto error; | 353 | goto error; |
| 337 | esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); | 354 | esp->conf.tfm = tfm; |
| 355 | esp->conf.ivlen = crypto_blkcipher_ivsize(tfm); | ||
| 338 | esp->conf.padlen = 0; | 356 | esp->conf.padlen = 0; |
| 339 | if (esp->conf.ivlen) { | 357 | if (esp->conf.ivlen) { |
| 340 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); | 358 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); |
| 341 | if (unlikely(esp->conf.ivec == NULL)) | 359 | if (unlikely(esp->conf.ivec == NULL)) |
| 342 | goto error; | 360 | goto error; |
| 343 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | 361 | esp->conf.ivinitted = 0; |
| 344 | } | 362 | } |
| 345 | if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len)) | 363 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) |
| 346 | goto error; | 364 | goto error; |
| 347 | 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; |
| 348 | if (x->props.mode) | 366 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 349 | x->props.header_len += sizeof(struct ipv6hdr); | 367 | x->props.header_len += sizeof(struct ipv6hdr); |
| 350 | x->data = esp; | 368 | x->data = esp; |
| 351 | return 0; | 369 | return 0; |
| @@ -366,7 +384,8 @@ static struct xfrm_type esp6_type = | |||
| 366 | .destructor = esp6_destroy, | 384 | .destructor = esp6_destroy, |
| 367 | .get_max_size = esp6_get_max_size, | 385 | .get_max_size = esp6_get_max_size, |
| 368 | .input = esp6_input, | 386 | .input = esp6_input, |
| 369 | .output = esp6_output | 387 | .output = esp6_output, |
| 388 | .hdr_offset = xfrm6_find_1stfragopt, | ||
| 370 | }; | 389 | }; |
| 371 | 390 | ||
| 372 | 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 a18d4256372c..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 | ||
| @@ -179,7 +316,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
| 179 | 316 | ||
| 180 | static struct inet6_protocol destopt_protocol = { | 317 | static struct inet6_protocol destopt_protocol = { |
| 181 | .handler = ipv6_destopt_rcv, | 318 | .handler = ipv6_destopt_rcv, |
| 182 | .flags = INET6_PROTO_NOPOLICY, | 319 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, |
| 183 | }; | 320 | }; |
| 184 | 321 | ||
| 185 | void __init ipv6_destopt_init(void) | 322 | void __init ipv6_destopt_init(void) |
| @@ -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); |
| @@ -340,7 +527,7 @@ looped_back: | |||
| 340 | 527 | ||
| 341 | static struct inet6_protocol rthdr_protocol = { | 528 | static struct inet6_protocol rthdr_protocol = { |
| 342 | .handler = ipv6_rthdr_rcv, | 529 | .handler = ipv6_rthdr_rcv, |
| 343 | .flags = INET6_PROTO_NOPOLICY, | 530 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, |
| 344 | }; | 531 | }; |
| 345 | 532 | ||
| 346 | void __init ipv6_rthdr_init(void) | 533 | void __init ipv6_rthdr_init(void) |
| @@ -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 | } |
| @@ -635,14 +828,17 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
| 635 | struct ipv6_txoptions *opt2; | 828 | struct ipv6_txoptions *opt2; |
| 636 | int err; | 829 | int err; |
| 637 | 830 | ||
| 638 | if (newtype != IPV6_HOPOPTS && opt->hopopt) | 831 | if (opt) { |
| 639 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); | 832 | if (newtype != IPV6_HOPOPTS && opt->hopopt) |
| 640 | if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) | 833 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); |
| 641 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); | 834 | if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) |
| 642 | if (newtype != IPV6_RTHDR && opt->srcrt) | 835 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); |
| 643 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); | 836 | if (newtype != IPV6_RTHDR && opt->srcrt) |
| 644 | if (newtype != IPV6_DSTOPTS && opt->dst1opt) | 837 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); |
| 645 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); | 838 | if (newtype != IPV6_DSTOPTS && opt->dst1opt) |
| 839 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); | ||
| 840 | } | ||
| 841 | |||
| 646 | if (newopt && newoptlen) | 842 | if (newopt && newoptlen) |
| 647 | tot_len += CMSG_ALIGN(newoptlen); | 843 | tot_len += CMSG_ALIGN(newoptlen); |
| 648 | 844 | ||
| @@ -659,25 +855,25 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
| 659 | opt2->tot_len = tot_len; | 855 | opt2->tot_len = tot_len; |
| 660 | p = (char *)(opt2 + 1); | 856 | p = (char *)(opt2 + 1); |
| 661 | 857 | ||
| 662 | err = ipv6_renew_option(opt->hopopt, newopt, newoptlen, | 858 | err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen, |
| 663 | newtype != IPV6_HOPOPTS, | 859 | newtype != IPV6_HOPOPTS, |
| 664 | &opt2->hopopt, &p); | 860 | &opt2->hopopt, &p); |
| 665 | if (err) | 861 | if (err) |
| 666 | goto out; | 862 | goto out; |
| 667 | 863 | ||
| 668 | err = ipv6_renew_option(opt->dst0opt, newopt, newoptlen, | 864 | err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen, |
| 669 | newtype != IPV6_RTHDRDSTOPTS, | 865 | newtype != IPV6_RTHDRDSTOPTS, |
| 670 | &opt2->dst0opt, &p); | 866 | &opt2->dst0opt, &p); |
| 671 | if (err) | 867 | if (err) |
| 672 | goto out; | 868 | goto out; |
| 673 | 869 | ||
| 674 | err = ipv6_renew_option(opt->srcrt, newopt, newoptlen, | 870 | err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen, |
| 675 | newtype != IPV6_RTHDR, | 871 | newtype != IPV6_RTHDR, |
| 676 | (struct ipv6_opt_hdr **)opt2->srcrt, &p); | 872 | (struct ipv6_opt_hdr **)&opt2->srcrt, &p); |
| 677 | if (err) | 873 | if (err) |
| 678 | goto out; | 874 | goto out; |
| 679 | 875 | ||
| 680 | err = ipv6_renew_option(opt->dst1opt, newopt, newoptlen, | 876 | err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen, |
| 681 | newtype != IPV6_DSTOPTS, | 877 | newtype != IPV6_DSTOPTS, |
| 682 | &opt2->dst1opt, &p); | 878 | &opt2->dst1opt, &p); |
| 683 | if (err) | 879 | if (err) |
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 1044b6fce0d5..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; |
| @@ -401,7 +427,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
| 401 | if (hlimit < 0) | 427 | if (hlimit < 0) |
| 402 | hlimit = ipv6_get_hoplimit(dst->dev); | 428 | hlimit = ipv6_get_hoplimit(dst->dev); |
| 403 | 429 | ||
| 404 | tclass = np->cork.tclass; | 430 | tclass = np->tclass; |
| 405 | if (tclass < 0) | 431 | if (tclass < 0) |
| 406 | tclass = 0; | 432 | tclass = 0; |
| 407 | 433 | ||
| @@ -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; |
| @@ -497,7 +524,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 497 | if (hlimit < 0) | 524 | if (hlimit < 0) |
| 498 | hlimit = ipv6_get_hoplimit(dst->dev); | 525 | hlimit = ipv6_get_hoplimit(dst->dev); |
| 499 | 526 | ||
| 500 | tclass = np->cork.tclass; | 527 | tclass = np->tclass; |
| 501 | if (tclass < 0) | 528 | if (tclass < 0) |
| 502 | tclass = 0; | 529 | tclass = 0; |
| 503 | 530 | ||
| @@ -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; |
| @@ -712,6 +739,11 @@ discard_it: | |||
| 712 | return 0; | 739 | return 0; |
| 713 | } | 740 | } |
| 714 | 741 | ||
| 742 | /* | ||
| 743 | * Special lock-class for __icmpv6_socket: | ||
| 744 | */ | ||
| 745 | static struct lock_class_key icmpv6_socket_sk_dst_lock_key; | ||
| 746 | |||
| 715 | int __init icmpv6_init(struct net_proto_family *ops) | 747 | int __init icmpv6_init(struct net_proto_family *ops) |
| 716 | { | 748 | { |
| 717 | struct sock *sk; | 749 | struct sock *sk; |
| @@ -730,6 +762,14 @@ int __init icmpv6_init(struct net_proto_family *ops) | |||
| 730 | 762 | ||
| 731 | sk = per_cpu(__icmpv6_socket, i)->sk; | 763 | sk = per_cpu(__icmpv6_socket, i)->sk; |
| 732 | sk->sk_allocation = GFP_ATOMIC; | 764 | sk->sk_allocation = GFP_ATOMIC; |
| 765 | /* | ||
| 766 | * Split off their lock-class, because sk->sk_dst_lock | ||
| 767 | * gets used from softirqs, which is safe for | ||
| 768 | * __icmpv6_socket (because those never get directly used | ||
| 769 | * via userspace syscalls), but unsafe for normal sockets. | ||
| 770 | */ | ||
| 771 | lockdep_set_class(&sk->sk_dst_lock, | ||
| 772 | &icmpv6_socket_sk_dst_lock_key); | ||
| 733 | 773 | ||
| 734 | /* Enough space for 2 64K ICMP packets, including | 774 | /* Enough space for 2 64K ICMP packets, including |
| 735 | * sk_buff struct overhead. | 775 | * sk_buff struct overhead. |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index eb2865d5ae28..827f41d1478b 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | * 2 of the License, or(at your option) any later version. | 13 | * 2 of the License, or(at your option) any later version. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/config.h> | ||
| 17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 18 | #include <linux/in6.h> | 17 | #include <linux/in6.h> |
| 19 | #include <linux/ipv6.h> | 18 | #include <linux/ipv6.h> |
| @@ -158,6 +157,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
| 158 | fl.oif = sk->sk_bound_dev_if; | 157 | fl.oif = sk->sk_bound_dev_if; |
| 159 | fl.fl_ip_sport = inet->sport; | 158 | fl.fl_ip_sport = inet->sport; |
| 160 | fl.fl_ip_dport = inet->dport; | 159 | fl.fl_ip_dport = inet->dport; |
| 160 | security_sk_classify_flow(sk, &fl); | ||
| 161 | 161 | ||
| 162 | if (np->opt && np->opt->srcrt) { | 162 | if (np->opt && np->opt->srcrt) { |
| 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
| @@ -186,9 +186,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
| 186 | return err; | 186 | return err; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | ip6_dst_store(sk, dst, NULL); | 189 | __ip6_dst_store(sk, dst, NULL, NULL); |
| 190 | sk->sk_route_caps = dst->dev->features & | ||
| 191 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 192 | } | 190 | } |
| 193 | 191 | ||
| 194 | skb->dst = dst_clone(dst); | 192 | skb->dst = dst_clone(dst); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 2ae84c961678..8accd1fbeeda 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | * 2 of the License, or (at your option) any later version. | 14 | * 2 of the License, or (at your option) any later version. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/config.h> | ||
| 18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 19 | #include <linux/random.h> | 18 | #include <linux/random.h> |
| 20 | 19 | ||
| @@ -65,7 +64,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, | |||
| 65 | { | 64 | { |
| 66 | struct sock *sk; | 65 | struct sock *sk; |
| 67 | const struct hlist_node *node; | 66 | const struct hlist_node *node; |
| 68 | const __u32 ports = INET_COMBINED_PORTS(sport, hnum); | 67 | const __portpair ports = INET_COMBINED_PORTS(sport, hnum); |
| 69 | /* Optimize here for direct hit, only listening connections can | 68 | /* Optimize here for direct hit, only listening connections can |
| 70 | * have wildcards anyways. | 69 | * have wildcards anyways. |
| 71 | */ | 70 | */ |
| @@ -83,7 +82,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, | |||
| 83 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | 82 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { |
| 84 | const struct inet_timewait_sock *tw = inet_twsk(sk); | 83 | const struct inet_timewait_sock *tw = inet_twsk(sk); |
| 85 | 84 | ||
| 86 | if(*((__u32 *)&(tw->tw_dport)) == ports && | 85 | if(*((__portpair *)&(tw->tw_dport)) == ports && |
| 87 | sk->sk_family == PF_INET6) { | 86 | sk->sk_family == PF_INET6) { |
| 88 | const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | 87 | const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); |
| 89 | 88 | ||
| @@ -172,7 +171,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 172 | const struct in6_addr *daddr = &np->rcv_saddr; | 171 | const struct in6_addr *daddr = &np->rcv_saddr; |
| 173 | const struct in6_addr *saddr = &np->daddr; | 172 | const struct in6_addr *saddr = &np->daddr; |
| 174 | const int dif = sk->sk_bound_dev_if; | 173 | const int dif = sk->sk_bound_dev_if; |
| 175 | const u32 ports = INET_COMBINED_PORTS(inet->dport, lport); | 174 | const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); |
| 176 | const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, | 175 | const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, |
| 177 | inet->dport); | 176 | inet->dport); |
| 178 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); | 177 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); |
| @@ -189,7 +188,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
| 189 | 188 | ||
| 190 | tw = inet_twsk(sk2); | 189 | tw = inet_twsk(sk2); |
| 191 | 190 | ||
| 192 | if(*((__u32 *)&(tw->tw_dport)) == ports && | 191 | if(*((__portpair *)&(tw->tw_dport)) == ports && |
| 193 | sk2->sk_family == PF_INET6 && | 192 | sk2->sk_family == PF_INET6 && |
| 194 | ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && | 193 | ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && |
| 195 | ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && | 194 | ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 2cb6149349bf..8fcae7a6510b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -18,8 +18,8 @@ | |||
| 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/config.h> | ||
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
| 25 | #include <linux/net.h> | 25 | #include <linux/net.h> |
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/netdevice.h> | 27 | #include <linux/netdevice.h> |
| 28 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
| 29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
| 30 | #include <linux/list.h> | ||
| 30 | 31 | ||
| 31 | #ifdef CONFIG_PROC_FS | 32 | #ifdef CONFIG_PROC_FS |
| 32 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
| @@ -69,19 +70,19 @@ struct fib6_cleaner_t | |||
| 69 | void *arg; | 70 | void *arg; |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | DEFINE_RWLOCK(fib6_walker_lock); | 73 | static DEFINE_RWLOCK(fib6_walker_lock); |
| 73 | |||
| 74 | 74 | ||
| 75 | #ifdef CONFIG_IPV6_SUBTREES | 75 | #ifdef CONFIG_IPV6_SUBTREES |
| 76 | #define FWS_INIT FWS_S | 76 | #define FWS_INIT FWS_S |
| 77 | #define SUBTREE(fn) ((fn)->subtree) | ||
| 78 | #else | 77 | #else |
| 79 | #define FWS_INIT FWS_L | 78 | #define FWS_INIT FWS_L |
| 80 | #define SUBTREE(fn) NULL | ||
| 81 | #endif | 79 | #endif |
| 82 | 80 | ||
| 83 | 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); | ||
| 84 | 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); | ||
| 85 | 86 | ||
| 86 | /* | 87 | /* |
| 87 | * 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 |
| @@ -94,13 +95,31 @@ static __u32 rt_sernum; | |||
| 94 | 95 | ||
| 95 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); | 96 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); |
| 96 | 97 | ||
| 97 | struct fib6_walker_t fib6_walker_list = { | 98 | static struct fib6_walker_t fib6_walker_list = { |
| 98 | .prev = &fib6_walker_list, | 99 | .prev = &fib6_walker_list, |
| 99 | .next = &fib6_walker_list, | 100 | .next = &fib6_walker_list, |
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 102 | #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) |
| 103 | 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 | } | ||
| 104 | static __inline__ u32 fib6_new_sernum(void) | 123 | static __inline__ u32 fib6_new_sernum(void) |
| 105 | { | 124 | { |
| 106 | u32 n = ++rt_sernum; | 125 | u32 n = ++rt_sernum; |
| @@ -148,6 +167,253 @@ static __inline__ void rt6_release(struct rt6_info *rt) | |||
| 148 | dst_free(&rt->u.dst); | 167 | dst_free(&rt->u.dst); |
| 149 | } | 168 | } |
| 150 | 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 | } | ||
| 151 | 417 | ||
| 152 | /* | 418 | /* |
| 153 | * Routing Table | 419 | * Routing Table |
| @@ -344,7 +610,7 @@ insert_above: | |||
| 344 | */ | 610 | */ |
| 345 | 611 | ||
| 346 | 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, |
| 347 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) | 613 | struct nl_info *info) |
| 348 | { | 614 | { |
| 349 | struct rt6_info *iter = NULL; | 615 | struct rt6_info *iter = NULL; |
| 350 | struct rt6_info **ins; | 616 | struct rt6_info **ins; |
| @@ -399,7 +665,7 @@ out: | |||
| 399 | *ins = rt; | 665 | *ins = rt; |
| 400 | rt->rt6i_node = fn; | 666 | rt->rt6i_node = fn; |
| 401 | atomic_inc(&rt->rt6i_ref); | 667 | atomic_inc(&rt->rt6i_ref); |
| 402 | inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); | 668 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
| 403 | rt6_stats.fib_rt_entries++; | 669 | rt6_stats.fib_rt_entries++; |
| 404 | 670 | ||
| 405 | if ((fn->fn_flags & RTN_RTINFO) == 0) { | 671 | if ((fn->fn_flags & RTN_RTINFO) == 0) { |
| @@ -429,10 +695,9 @@ void fib6_force_start_gc(void) | |||
| 429 | * with source addr info in sub-trees | 695 | * with source addr info in sub-trees |
| 430 | */ | 696 | */ |
| 431 | 697 | ||
| 432 | 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) |
| 433 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | ||
| 434 | { | 699 | { |
| 435 | struct fib6_node *fn; | 700 | struct fib6_node *fn, *pn = NULL; |
| 436 | int err = -ENOMEM; | 701 | int err = -ENOMEM; |
| 437 | 702 | ||
| 438 | 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), |
| @@ -441,6 +706,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
| 441 | if (fn == NULL) | 706 | if (fn == NULL) |
| 442 | goto out; | 707 | goto out; |
| 443 | 708 | ||
| 709 | pn = fn; | ||
| 710 | |||
| 444 | #ifdef CONFIG_IPV6_SUBTREES | 711 | #ifdef CONFIG_IPV6_SUBTREES |
| 445 | if (rt->rt6i_src.plen) { | 712 | if (rt->rt6i_src.plen) { |
| 446 | struct fib6_node *sn; | 713 | struct fib6_node *sn; |
| @@ -486,10 +753,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
| 486 | /* Now link new subtree to main tree */ | 753 | /* Now link new subtree to main tree */ |
| 487 | sfn->parent = fn; | 754 | sfn->parent = fn; |
| 488 | fn->subtree = sfn; | 755 | fn->subtree = sfn; |
| 489 | if (fn->leaf == NULL) { | ||
| 490 | fn->leaf = rt; | ||
| 491 | atomic_inc(&rt->rt6i_ref); | ||
| 492 | } | ||
| 493 | } else { | 756 | } else { |
| 494 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, | 757 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, |
| 495 | sizeof(struct in6_addr), rt->rt6i_src.plen, | 758 | sizeof(struct in6_addr), rt->rt6i_src.plen, |
| @@ -499,21 +762,42 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
| 499 | goto st_failure; | 762 | goto st_failure; |
| 500 | } | 763 | } |
| 501 | 764 | ||
| 765 | if (fn->leaf == NULL) { | ||
| 766 | fn->leaf = rt; | ||
| 767 | atomic_inc(&rt->rt6i_ref); | ||
| 768 | } | ||
| 502 | fn = sn; | 769 | fn = sn; |
| 503 | } | 770 | } |
| 504 | #endif | 771 | #endif |
| 505 | 772 | ||
| 506 | err = fib6_add_rt2node(fn, rt, nlh, req); | 773 | err = fib6_add_rt2node(fn, rt, info); |
| 507 | 774 | ||
| 508 | if (err == 0) { | 775 | if (err == 0) { |
| 509 | fib6_start_gc(rt); | 776 | fib6_start_gc(rt); |
| 510 | if (!(rt->rt6i_flags&RTF_CACHE)) | 777 | if (!(rt->rt6i_flags&RTF_CACHE)) |
| 511 | fib6_prune_clones(fn, rt); | 778 | fib6_prune_clones(pn, rt); |
| 512 | } | 779 | } |
| 513 | 780 | ||
| 514 | out: | 781 | out: |
| 515 | 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 | ||
| 516 | dst_free(&rt->u.dst); | 799 | dst_free(&rt->u.dst); |
| 800 | } | ||
| 517 | return err; | 801 | return err; |
| 518 | 802 | ||
| 519 | #ifdef CONFIG_IPV6_SUBTREES | 803 | #ifdef CONFIG_IPV6_SUBTREES |
| @@ -544,6 +828,9 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
| 544 | struct fib6_node *fn; | 828 | struct fib6_node *fn; |
| 545 | int dir; | 829 | int dir; |
| 546 | 830 | ||
| 831 | if (unlikely(args->offset == 0)) | ||
| 832 | return NULL; | ||
| 833 | |||
| 547 | /* | 834 | /* |
| 548 | * Descend on a tree | 835 | * Descend on a tree |
| 549 | */ | 836 | */ |
| @@ -565,33 +852,26 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
| 565 | break; | 852 | break; |
| 566 | } | 853 | } |
| 567 | 854 | ||
| 568 | while ((fn->fn_flags & RTN_ROOT) == 0) { | 855 | while(fn) { |
| 569 | #ifdef CONFIG_IPV6_SUBTREES | 856 | if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) { |
| 570 | if (fn->subtree) { | ||
| 571 | struct fib6_node *st; | ||
| 572 | struct lookup_args *narg; | ||
| 573 | |||
| 574 | narg = args + 1; | ||
| 575 | |||
| 576 | if (narg->addr) { | ||
| 577 | st = fib6_lookup_1(fn->subtree, narg); | ||
| 578 | |||
| 579 | if (st && !(st->fn_flags & RTN_ROOT)) | ||
| 580 | return st; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | #endif | ||
| 584 | |||
| 585 | if (fn->fn_flags & RTN_RTINFO) { | ||
| 586 | struct rt6key *key; | 857 | struct rt6key *key; |
| 587 | 858 | ||
| 588 | key = (struct rt6key *) ((u8 *) fn->leaf + | 859 | key = (struct rt6key *) ((u8 *) fn->leaf + |
| 589 | args->offset); | 860 | args->offset); |
| 590 | 861 | ||
| 591 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) | 862 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) { |
| 592 | 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 | } | ||
| 593 | } | 870 | } |
| 594 | 871 | ||
| 872 | if (fn->fn_flags & RTN_ROOT) | ||
| 873 | break; | ||
| 874 | |||
| 595 | fn = fn->parent; | 875 | fn = fn->parent; |
| 596 | } | 876 | } |
| 597 | 877 | ||
| @@ -601,18 +881,24 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
| 601 | 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, |
| 602 | struct in6_addr *saddr) | 882 | struct in6_addr *saddr) |
| 603 | { | 883 | { |
| 604 | struct lookup_args args[2]; | ||
| 605 | struct fib6_node *fn; | 884 | struct fib6_node *fn; |
| 606 | 885 | struct lookup_args args[] = { | |
| 607 | args[0].offset = offsetof(struct rt6_info, rt6i_dst); | 886 | { |
| 608 | args[0].addr = daddr; | 887 | .offset = offsetof(struct rt6_info, rt6i_dst), |
| 609 | 888 | .addr = daddr, | |
| 889 | }, | ||
| 610 | #ifdef CONFIG_IPV6_SUBTREES | 890 | #ifdef CONFIG_IPV6_SUBTREES |
| 611 | args[1].offset = offsetof(struct rt6_info, rt6i_src); | 891 | { |
| 612 | args[1].addr = saddr; | 892 | .offset = offsetof(struct rt6_info, rt6i_src), |
| 893 | .addr = saddr, | ||
| 894 | }, | ||
| 613 | #endif | 895 | #endif |
| 896 | { | ||
| 897 | .offset = 0, /* sentinel */ | ||
| 898 | } | ||
| 899 | }; | ||
| 614 | 900 | ||
| 615 | fn = fib6_lookup_1(root, args); | 901 | fn = fib6_lookup_1(root, daddr ? args : args + 1); |
| 616 | 902 | ||
| 617 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) | 903 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) |
| 618 | fn = root; | 904 | fn = root; |
| @@ -668,10 +954,8 @@ struct fib6_node * fib6_locate(struct fib6_node *root, | |||
| 668 | #ifdef CONFIG_IPV6_SUBTREES | 954 | #ifdef CONFIG_IPV6_SUBTREES |
| 669 | if (src_len) { | 955 | if (src_len) { |
| 670 | BUG_TRAP(saddr!=NULL); | 956 | BUG_TRAP(saddr!=NULL); |
| 671 | if (fn == NULL) | 957 | if (fn && fn->subtree) |
| 672 | fn = fn->subtree; | 958 | fn = fib6_locate_1(fn->subtree, saddr, src_len, |
| 673 | if (fn) | ||
| 674 | fn = fib6_locate_1(fn, saddr, src_len, | ||
| 675 | offsetof(struct rt6_info, rt6i_src)); | 959 | offsetof(struct rt6_info, rt6i_src)); |
| 676 | } | 960 | } |
| 677 | #endif | 961 | #endif |
| @@ -700,7 +984,7 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) | |||
| 700 | if(fn->right) | 984 | if(fn->right) |
| 701 | return fn->right->leaf; | 985 | return fn->right->leaf; |
| 702 | 986 | ||
| 703 | fn = SUBTREE(fn); | 987 | fn = FIB6_SUBTREE(fn); |
| 704 | } | 988 | } |
| 705 | return NULL; | 989 | return NULL; |
| 706 | } | 990 | } |
| @@ -731,7 +1015,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
| 731 | if (fn->right) child = fn->right, children |= 1; | 1015 | if (fn->right) child = fn->right, children |= 1; |
| 732 | if (fn->left) child = fn->left, children |= 2; | 1016 | if (fn->left) child = fn->left, children |= 2; |
| 733 | 1017 | ||
| 734 | if (children == 3 || SUBTREE(fn) | 1018 | if (children == 3 || FIB6_SUBTREE(fn) |
| 735 | #ifdef CONFIG_IPV6_SUBTREES | 1019 | #ifdef CONFIG_IPV6_SUBTREES |
| 736 | /* Subtree root (i.e. fn) may have one child */ | 1020 | /* Subtree root (i.e. fn) may have one child */ |
| 737 | || (children && fn->fn_flags&RTN_ROOT) | 1021 | || (children && fn->fn_flags&RTN_ROOT) |
| @@ -750,9 +1034,9 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
| 750 | 1034 | ||
| 751 | pn = fn->parent; | 1035 | pn = fn->parent; |
| 752 | #ifdef CONFIG_IPV6_SUBTREES | 1036 | #ifdef CONFIG_IPV6_SUBTREES |
| 753 | if (SUBTREE(pn) == fn) { | 1037 | if (FIB6_SUBTREE(pn) == fn) { |
| 754 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1038 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
| 755 | SUBTREE(pn) = NULL; | 1039 | FIB6_SUBTREE(pn) = NULL; |
| 756 | nstate = FWS_L; | 1040 | nstate = FWS_L; |
| 757 | } else { | 1041 | } else { |
| 758 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); | 1042 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); |
| @@ -800,7 +1084,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
| 800 | read_unlock(&fib6_walker_lock); | 1084 | read_unlock(&fib6_walker_lock); |
| 801 | 1085 | ||
| 802 | node_free(fn); | 1086 | node_free(fn); |
| 803 | if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) | 1087 | if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn)) |
| 804 | return pn; | 1088 | return pn; |
| 805 | 1089 | ||
| 806 | rt6_release(pn->leaf); | 1090 | rt6_release(pn->leaf); |
| @@ -810,7 +1094,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
| 810 | } | 1094 | } |
| 811 | 1095 | ||
| 812 | 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, |
| 813 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1097 | struct nl_info *info) |
| 814 | { | 1098 | { |
| 815 | struct fib6_walker_t *w; | 1099 | struct fib6_walker_t *w; |
| 816 | struct rt6_info *rt = *rtp; | 1100 | struct rt6_info *rt = *rtp; |
| @@ -866,11 +1150,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 866 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); | 1150 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); |
| 867 | } | 1151 | } |
| 868 | 1152 | ||
| 869 | inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); | 1153 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
| 870 | rt6_release(rt); | 1154 | rt6_release(rt); |
| 871 | } | 1155 | } |
| 872 | 1156 | ||
| 873 | 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) |
| 874 | { | 1158 | { |
| 875 | struct fib6_node *fn = rt->rt6i_node; | 1159 | struct fib6_node *fn = rt->rt6i_node; |
| 876 | struct rt6_info **rtp; | 1160 | struct rt6_info **rtp; |
| @@ -886,8 +1170,18 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
| 886 | 1170 | ||
| 887 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); | 1171 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); |
| 888 | 1172 | ||
| 889 | if (!(rt->rt6i_flags&RTF_CACHE)) | 1173 | if (!(rt->rt6i_flags&RTF_CACHE)) { |
| 890 | 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 | } | ||
| 891 | 1185 | ||
| 892 | /* | 1186 | /* |
| 893 | * Walk the leaf entries looking for ourself | 1187 | * Walk the leaf entries looking for ourself |
| @@ -895,7 +1189,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
| 895 | 1189 | ||
| 896 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { | 1190 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { |
| 897 | if (*rtp == rt) { | 1191 | if (*rtp == rt) { |
| 898 | fib6_del_route(fn, rtp, nlh, _rtattr, req); | 1192 | fib6_del_route(fn, rtp, info); |
| 899 | return 0; | 1193 | return 0; |
| 900 | } | 1194 | } |
| 901 | } | 1195 | } |
| @@ -926,7 +1220,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
| 926 | * <0 -> walk is terminated by an error. | 1220 | * <0 -> walk is terminated by an error. |
| 927 | */ | 1221 | */ |
| 928 | 1222 | ||
| 929 | int fib6_walk_continue(struct fib6_walker_t *w) | 1223 | static int fib6_walk_continue(struct fib6_walker_t *w) |
| 930 | { | 1224 | { |
| 931 | struct fib6_node *fn, *pn; | 1225 | struct fib6_node *fn, *pn; |
| 932 | 1226 | ||
| @@ -943,8 +1237,8 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
| 943 | switch (w->state) { | 1237 | switch (w->state) { |
| 944 | #ifdef CONFIG_IPV6_SUBTREES | 1238 | #ifdef CONFIG_IPV6_SUBTREES |
| 945 | case FWS_S: | 1239 | case FWS_S: |
| 946 | if (SUBTREE(fn)) { | 1240 | if (FIB6_SUBTREE(fn)) { |
| 947 | w->node = SUBTREE(fn); | 1241 | w->node = FIB6_SUBTREE(fn); |
| 948 | continue; | 1242 | continue; |
| 949 | } | 1243 | } |
| 950 | w->state = FWS_L; | 1244 | w->state = FWS_L; |
| @@ -978,7 +1272,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
| 978 | pn = fn->parent; | 1272 | pn = fn->parent; |
| 979 | w->node = pn; | 1273 | w->node = pn; |
| 980 | #ifdef CONFIG_IPV6_SUBTREES | 1274 | #ifdef CONFIG_IPV6_SUBTREES |
| 981 | if (SUBTREE(pn) == fn) { | 1275 | if (FIB6_SUBTREE(pn) == fn) { |
| 982 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1276 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
| 983 | w->state = FWS_L; | 1277 | w->state = FWS_L; |
| 984 | continue; | 1278 | continue; |
| @@ -1000,7 +1294,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
| 1000 | } | 1294 | } |
| 1001 | } | 1295 | } |
| 1002 | 1296 | ||
| 1003 | int fib6_walk(struct fib6_walker_t *w) | 1297 | static int fib6_walk(struct fib6_walker_t *w) |
| 1004 | { | 1298 | { |
| 1005 | int res; | 1299 | int res; |
| 1006 | 1300 | ||
| @@ -1024,7 +1318,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
| 1024 | res = c->func(rt, c->arg); | 1318 | res = c->func(rt, c->arg); |
| 1025 | if (res < 0) { | 1319 | if (res < 0) { |
| 1026 | w->leaf = rt; | 1320 | w->leaf = rt; |
| 1027 | res = fib6_del(rt, NULL, NULL, NULL); | 1321 | res = fib6_del(rt, NULL); |
| 1028 | if (res) { | 1322 | if (res) { |
| 1029 | #if RT6_DEBUG >= 2 | 1323 | #if RT6_DEBUG >= 2 |
| 1030 | 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); |
| @@ -1050,9 +1344,9 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
| 1050 | * ignoring pure split nodes) will be scanned. | 1344 | * ignoring pure split nodes) will be scanned. |
| 1051 | */ | 1345 | */ |
| 1052 | 1346 | ||
| 1053 | void fib6_clean_tree(struct fib6_node *root, | 1347 | static void fib6_clean_tree(struct fib6_node *root, |
| 1054 | int (*func)(struct rt6_info *, void *arg), | 1348 | int (*func)(struct rt6_info *, void *arg), |
| 1055 | int prune, void *arg) | 1349 | int prune, void *arg) |
| 1056 | { | 1350 | { |
| 1057 | struct fib6_cleaner_t c; | 1351 | struct fib6_cleaner_t c; |
| 1058 | 1352 | ||
| @@ -1065,6 +1359,25 @@ void fib6_clean_tree(struct fib6_node *root, | |||
| 1065 | fib6_walk(&c.w); | 1359 | fib6_walk(&c.w); |
| 1066 | } | 1360 | } |
| 1067 | 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 | |||
| 1068 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) | 1381 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) |
| 1069 | { | 1382 | { |
| 1070 | if (rt->rt6i_flags & RTF_CACHE) { | 1383 | if (rt->rt6i_flags & RTF_CACHE) { |
| @@ -1143,11 +1456,8 @@ void fib6_run_gc(unsigned long dummy) | |||
| 1143 | } | 1456 | } |
| 1144 | gc_args.more = 0; | 1457 | gc_args.more = 0; |
| 1145 | 1458 | ||
| 1146 | |||
| 1147 | write_lock_bh(&rt6_lock); | ||
| 1148 | ndisc_dst_gc(&gc_args.more); | 1459 | ndisc_dst_gc(&gc_args.more); |
| 1149 | fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); | 1460 | fib6_clean_all(fib6_age, 0, NULL); |
| 1150 | write_unlock_bh(&rt6_lock); | ||
| 1151 | 1461 | ||
| 1152 | if (gc_args.more) | 1462 | if (gc_args.more) |
| 1153 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); | 1463 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); |
| @@ -1162,10 +1472,10 @@ void __init fib6_init(void) | |||
| 1162 | { | 1472 | { |
| 1163 | fib6_node_kmem = kmem_cache_create("fib6_nodes", | 1473 | fib6_node_kmem = kmem_cache_create("fib6_nodes", |
| 1164 | sizeof(struct fib6_node), | 1474 | sizeof(struct fib6_node), |
| 1165 | 0, SLAB_HWCACHE_ALIGN, | 1475 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
| 1166 | NULL, NULL); | 1476 | NULL, NULL); |
| 1167 | if (!fib6_node_kmem) | 1477 | |
| 1168 | panic("cannot create fib6_nodes cache"); | 1478 | fib6_tables_init(); |
| 1169 | } | 1479 | } |
| 1170 | 1480 | ||
| 1171 | void fib6_gc_cleanup(void) | 1481 | void fib6_gc_cleanup(void) |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index f9ca63912fbf..1d672b0547f2 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/capability.h> | 12 | #include <linux/capability.h> |
| 13 | #include <linux/config.h> | ||
| 14 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 15 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 16 | #include <linux/socket.h> | 15 | #include <linux/socket.h> |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index aceee252503d..6b8e6d76a58b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
| @@ -71,6 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 71 | goto out; | 71 | goto out; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); | ||
| 75 | |||
| 74 | /* | 76 | /* |
| 75 | * Store incoming device index. When the packet will | 77 | * Store incoming device index. When the packet will |
| 76 | * be queued, we cannot refer to skb->dev anymore. | 78 | * be queued, we cannot refer to skb->dev anymore. |
| @@ -84,14 +86,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 84 | */ | 86 | */ |
| 85 | IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex; | 87 | IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex; |
| 86 | 88 | ||
| 87 | if (skb->len < sizeof(struct ipv6hdr)) | 89 | if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) |
| 88 | goto err; | 90 | goto err; |
| 89 | 91 | ||
| 90 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) { | ||
| 91 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
| 92 | goto drop; | ||
| 93 | } | ||
| 94 | |||
| 95 | hdr = skb->nh.ipv6h; | 92 | hdr = skb->nh.ipv6h; |
| 96 | 93 | ||
| 97 | if (hdr->version != 6) | 94 | if (hdr->version != 6) |
| @@ -114,7 +111,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 114 | } | 111 | } |
| 115 | 112 | ||
| 116 | if (hdr->nexthdr == NEXTHDR_HOP) { | 113 | if (hdr->nexthdr == NEXTHDR_HOP) { |
| 117 | if (ipv6_parse_hopopts(skb) < 0) { | 114 | if (ipv6_parse_hopopts(&skb) < 0) { |
| 118 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
| 119 | return 0; | 116 | return 0; |
| 120 | } | 117 | } |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index abb94de33768..66716911962e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | * for datagram xmit | 28 | * for datagram xmit |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include <linux/config.h> | ||
| 32 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
| 33 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 34 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| @@ -148,7 +147,7 @@ static int ip6_output2(struct sk_buff *skb) | |||
| 148 | 147 | ||
| 149 | int ip6_output(struct sk_buff *skb) | 148 | int ip6_output(struct sk_buff *skb) |
| 150 | { | 149 | { |
| 151 | if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) || | 150 | if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) || |
| 152 | dst_allfrag(skb->dst)) | 151 | dst_allfrag(skb->dst)) |
| 153 | return ip6_fragment(skb, ip6_output2); | 152 | return ip6_fragment(skb, ip6_output2); |
| 154 | else | 153 | else |
| @@ -230,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
| 230 | skb->priority = sk->sk_priority; | 229 | skb->priority = sk->sk_priority; |
| 231 | 230 | ||
| 232 | mtu = dst_mtu(dst); | 231 | mtu = dst_mtu(dst); |
| 233 | if ((skb->len <= mtu) || ipfragok) { | 232 | if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { |
| 234 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 233 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); |
| 235 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, | 234 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, |
| 236 | dst_output); | 235 | dst_output); |
| @@ -309,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | |||
| 309 | return 0; | 308 | return 0; |
| 310 | } | 309 | } |
| 311 | 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 | |||
| 312 | static inline int ip6_forward_finish(struct sk_buff *skb) | 361 | static inline int ip6_forward_finish(struct sk_buff *skb) |
| 313 | { | 362 | { |
| 314 | return dst_output(skb); | 363 | return dst_output(skb); |
| @@ -357,11 +406,24 @@ int ip6_forward(struct sk_buff *skb) | |||
| 357 | skb->dev = dst->dev; | 406 | skb->dev = dst->dev; |
| 358 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 407 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
| 359 | 0, skb->dev); | 408 | 0, skb->dev); |
| 409 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
| 360 | 410 | ||
| 361 | kfree_skb(skb); | 411 | kfree_skb(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; |
| @@ -596,6 +666,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 596 | } | 666 | } |
| 597 | 667 | ||
| 598 | err = output(skb); | 668 | err = output(skb); |
| 669 | if(!err) | ||
| 670 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 671 | |||
| 599 | if (err || !frag) | 672 | if (err || !frag) |
| 600 | break; | 673 | break; |
| 601 | 674 | ||
| @@ -707,12 +780,11 @@ slow_path: | |||
| 707 | /* | 780 | /* |
| 708 | * Put this fragment into the sending queue. | 781 | * Put this fragment into the sending queue. |
| 709 | */ | 782 | */ |
| 710 | |||
| 711 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 712 | |||
| 713 | err = output(frag); | 783 | err = output(frag); |
| 714 | if (err) | 784 | if (err) |
| 715 | goto fail; | 785 | goto fail; |
| 786 | |||
| 787 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 716 | } | 788 | } |
| 717 | kfree_skb(skb); | 789 | kfree_skb(skb); |
| 718 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | 790 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); |
| @@ -724,48 +796,59 @@ fail: | |||
| 724 | return err; | 796 | return err; |
| 725 | } | 797 | } |
| 726 | 798 | ||
| 727 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 799 | static inline int ip6_rt_check(struct rt6key *rt_key, |
| 800 | struct in6_addr *fl_addr, | ||
| 801 | struct in6_addr *addr_cache) | ||
| 728 | { | 802 | { |
| 729 | int err = 0; | 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 | } | ||
| 730 | 806 | ||
| 731 | *dst = NULL; | 807 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
| 732 | if (sk) { | 808 | struct dst_entry *dst, |
| 733 | struct ipv6_pinfo *np = inet6_sk(sk); | 809 | struct flowi *fl) |
| 734 | 810 | { | |
| 735 | *dst = sk_dst_check(sk, np->dst_cookie); | 811 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 736 | if (*dst) { | 812 | struct rt6_info *rt = (struct rt6_info *)dst; |
| 737 | struct rt6_info *rt = (struct rt6_info*)*dst; | 813 | |
| 738 | 814 | if (!dst) | |
| 739 | /* Yes, checking route validity in not connected | 815 | goto out; |
| 740 | * case is not very simple. Take into account, | 816 | |
| 741 | * that we do not support routing by source, TOS, | 817 | /* Yes, checking route validity in not connected |
| 742 | * and MSG_DONTROUTE --ANK (980726) | 818 | * case is not very simple. Take into account, |
| 743 | * | 819 | * that we do not support routing by source, TOS, |
| 744 | * 1. If route was host route, check that | 820 | * and MSG_DONTROUTE --ANK (980726) |
| 745 | * cached destination is current. | 821 | * |
| 746 | * If it is network route, we still may | 822 | * 1. ip6_rt_check(): If route was host route, |
| 747 | * check its validity using saved pointer | 823 | * check that cached destination is current. |
| 748 | * to the last used address: daddr_cache. | 824 | * If it is network route, we still may |
| 749 | * We do not want to save whole address now, | 825 | * check its validity using saved pointer |
| 750 | * (because main consumer of this service | 826 | * to the last used address: daddr_cache. |
| 751 | * is tcp, which has not this problem), | 827 | * We do not want to save whole address now, |
| 752 | * so that the last trick works only on connected | 828 | * (because main consumer of this service |
| 753 | * sockets. | 829 | * is tcp, which has not this problem), |
| 754 | * 2. oif also should be the same. | 830 | * so that the last trick works only on connected |
| 755 | */ | 831 | * sockets. |
| 756 | if (((rt->rt6i_dst.plen != 128 || | 832 | * 2. oif also should be the same. |
| 757 | !ipv6_addr_equal(&fl->fl6_dst, | 833 | */ |
| 758 | &rt->rt6i_dst.addr)) | 834 | if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) || |
| 759 | && (np->daddr_cache == NULL || | 835 | #ifdef CONFIG_IPV6_SUBTREES |
| 760 | !ipv6_addr_equal(&fl->fl6_dst, | 836 | ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) || |
| 761 | np->daddr_cache))) | 837 | #endif |
| 762 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { | 838 | (fl->oif && fl->oif != dst->dev->ifindex)) { |
| 763 | dst_release(*dst); | 839 | dst_release(dst); |
| 764 | *dst = NULL; | 840 | dst = NULL; |
| 765 | } | ||
| 766 | } | ||
| 767 | } | 841 | } |
| 768 | 842 | ||
| 843 | out: | ||
| 844 | return dst; | ||
| 845 | } | ||
| 846 | |||
| 847 | static int ip6_dst_lookup_tail(struct sock *sk, | ||
| 848 | struct dst_entry **dst, struct flowi *fl) | ||
| 849 | { | ||
| 850 | int err; | ||
| 851 | |||
| 769 | if (*dst == NULL) | 852 | if (*dst == NULL) |
| 770 | *dst = ip6_route_output(sk, fl); | 853 | *dst = ip6_route_output(sk, fl); |
| 771 | 854 | ||
| @@ -774,7 +857,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | |||
| 774 | 857 | ||
| 775 | if (ipv6_addr_any(&fl->fl6_src)) { | 858 | if (ipv6_addr_any(&fl->fl6_src)) { |
| 776 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); | 859 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); |
| 777 | |||
| 778 | if (err) | 860 | if (err) |
| 779 | goto out_err_release; | 861 | goto out_err_release; |
| 780 | } | 862 | } |
| @@ -787,8 +869,48 @@ out_err_release: | |||
| 787 | return err; | 869 | return err; |
| 788 | } | 870 | } |
| 789 | 871 | ||
| 872 | /** | ||
| 873 | * ip6_dst_lookup - perform route lookup on flow | ||
| 874 | * @sk: socket which provides route info | ||
| 875 | * @dst: pointer to dst_entry * for result | ||
| 876 | * @fl: flow to lookup | ||
| 877 | * | ||
| 878 | * This function performs a route lookup on the given flow. | ||
| 879 | * | ||
| 880 | * It returns zero on success, or a standard errno code on error. | ||
| 881 | */ | ||
| 882 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 883 | { | ||
| 884 | *dst = NULL; | ||
| 885 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 886 | } | ||
| 790 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 887 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
| 791 | 888 | ||
| 889 | /** | ||
| 890 | * ip6_sk_dst_lookup - perform socket cached route lookup on flow | ||
| 891 | * @sk: socket which provides the dst cache and route info | ||
| 892 | * @dst: pointer to dst_entry * for result | ||
| 893 | * @fl: flow to lookup | ||
| 894 | * | ||
| 895 | * This function performs a route lookup on the given flow with the | ||
| 896 | * possibility of using the cached route in the socket if it is valid. | ||
| 897 | * It will take the socket dst lock when operating on the dst cache. | ||
| 898 | * As a result, this function can only be used in process context. | ||
| 899 | * | ||
| 900 | * It returns zero on success, or a standard errno code on error. | ||
| 901 | */ | ||
| 902 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 903 | { | ||
| 904 | *dst = NULL; | ||
| 905 | if (sk) { | ||
| 906 | *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | ||
| 907 | *dst = ip6_sk_dst_check(sk, *dst, fl); | ||
| 908 | } | ||
| 909 | |||
| 910 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 911 | } | ||
| 912 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | ||
| 913 | |||
| 792 | static inline int ip6_ufo_append_data(struct sock *sk, | 914 | static inline int ip6_ufo_append_data(struct sock *sk, |
| 793 | int getfrag(void *from, char *to, int offset, int len, | 915 | int getfrag(void *from, char *to, int offset, int len, |
| 794 | int odd, struct sk_buff *skb), | 916 | int odd, struct sk_buff *skb), |
| @@ -822,7 +944,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
| 822 | /* initialize protocol header pointer */ | 944 | /* initialize protocol header pointer */ |
| 823 | skb->h.raw = skb->data + fragheaderlen; | 945 | skb->h.raw = skb->data + fragheaderlen; |
| 824 | 946 | ||
| 825 | skb->ip_summed = CHECKSUM_HW; | 947 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 826 | skb->csum = 0; | 948 | skb->csum = 0; |
| 827 | sk->sk_sndmsg_off = 0; | 949 | sk->sk_sndmsg_off = 0; |
| 828 | } | 950 | } |
| @@ -835,7 +957,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
| 835 | /* specify the length of each IP datagram fragment*/ | 957 | /* specify the length of each IP datagram fragment*/ |
| 836 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen - | 958 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen - |
| 837 | sizeof(struct frag_hdr); | 959 | sizeof(struct frag_hdr); |
| 838 | skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; | 960 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
| 839 | ipv6_select_ident(skb, &fhdr); | 961 | ipv6_select_ident(skb, &fhdr); |
| 840 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; | 962 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; |
| 841 | __skb_queue_tail(&sk->sk_write_queue, skb); | 963 | __skb_queue_tail(&sk->sk_write_queue, skb); |
| @@ -919,7 +1041,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 919 | 1041 | ||
| 920 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | 1042 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); |
| 921 | 1043 | ||
| 922 | fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0); | 1044 | fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0); |
| 923 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1045 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
| 924 | 1046 | ||
| 925 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1047 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
| @@ -1051,7 +1173,7 @@ alloc_new_skb: | |||
| 1051 | skb_prev->csum = csum_sub(skb_prev->csum, | 1173 | skb_prev->csum = csum_sub(skb_prev->csum, |
| 1052 | skb->csum); | 1174 | skb->csum); |
| 1053 | data += fraggap; | 1175 | data += fraggap; |
| 1054 | skb_trim(skb_prev, maxfraglen); | 1176 | pskb_trim_unique(skb_prev, maxfraglen); |
| 1055 | } | 1177 | } |
| 1056 | copy = datalen - transhdrlen - fraggap; | 1178 | copy = datalen - transhdrlen - fraggap; |
| 1057 | if (copy < 0) { | 1179 | if (copy < 0) { |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a995796b5a57..84d7ebdb9d21 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | * | 19 | * |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <linux/config.h> | ||
| 23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 24 | #include <linux/capability.h> | 23 | #include <linux/capability.h> |
| 25 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
| @@ -568,10 +567,9 @@ static inline struct ipv6_txoptions *create_tel(__u8 encap_limit) | |||
| 568 | 567 | ||
| 569 | int opt_len = sizeof(*opt) + 8; | 568 | int opt_len = sizeof(*opt) + 8; |
| 570 | 569 | ||
| 571 | if (!(opt = kmalloc(opt_len, GFP_ATOMIC))) { | 570 | if (!(opt = kzalloc(opt_len, GFP_ATOMIC))) { |
| 572 | return NULL; | 571 | return NULL; |
| 573 | } | 572 | } |
| 574 | memset(opt, 0, opt_len); | ||
| 575 | opt->tot_len = opt_len; | 573 | opt->tot_len = opt_len; |
| 576 | opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1); | 574 | opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1); |
| 577 | opt->opt_nflen = 8; | 575 | opt->opt_nflen = 8; |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index f28cd37feed3..a2860e35efd7 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | * The decompression of IP datagram MUST be done after the reassembly, | 30 | * The decompression of IP datagram MUST be done after the reassembly, |
| 31 | * AH/ESP processing. | 31 | * AH/ESP processing. |
| 32 | */ | 32 | */ |
| 33 | #include <linux/config.h> | ||
| 34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 35 | #include <net/ip.h> | 34 | #include <net/ip.h> |
| 36 | #include <net/xfrm.h> | 35 | #include <net/xfrm.h> |
| @@ -54,7 +53,7 @@ | |||
| 54 | 53 | ||
| 55 | struct ipcomp6_tfms { | 54 | struct ipcomp6_tfms { |
| 56 | struct list_head list; | 55 | struct list_head list; |
| 57 | struct crypto_tfm **tfms; | 56 | struct crypto_comp **tfms; |
| 58 | int users; | 57 | int users; |
| 59 | }; | 58 | }; |
| 60 | 59 | ||
| @@ -71,7 +70,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 71 | int plen, dlen; | 70 | int plen, dlen; |
| 72 | struct ipcomp_data *ipcd = x->data; | 71 | struct ipcomp_data *ipcd = x->data; |
| 73 | u8 *start, *scratch; | 72 | u8 *start, *scratch; |
| 74 | struct crypto_tfm *tfm; | 73 | struct crypto_comp *tfm; |
| 75 | int cpu; | 74 | int cpu; |
| 76 | 75 | ||
| 77 | if (skb_linearize_cow(skb)) | 76 | if (skb_linearize_cow(skb)) |
| @@ -110,7 +109,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 110 | goto out_put_cpu; | 109 | goto out_put_cpu; |
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | skb_put(skb, dlen - plen); | 112 | skb->truesize += dlen - plen; |
| 113 | __skb_put(skb, dlen - plen); | ||
| 114 | memcpy(skb->data, scratch, dlen); | 114 | memcpy(skb->data, scratch, dlen); |
| 115 | err = ipch->nexthdr; | 115 | err = ipch->nexthdr; |
| 116 | 116 | ||
| @@ -129,7 +129,7 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 129 | struct ipcomp_data *ipcd = x->data; | 129 | struct ipcomp_data *ipcd = x->data; |
| 130 | int plen, dlen; | 130 | int plen, dlen; |
| 131 | u8 *start, *scratch; | 131 | u8 *start, *scratch; |
| 132 | struct crypto_tfm *tfm; | 132 | struct crypto_comp *tfm; |
| 133 | int cpu; | 133 | int cpu; |
| 134 | 134 | ||
| 135 | hdr_len = skb->h.raw - skb->data; | 135 | hdr_len = skb->h.raw - skb->data; |
| @@ -178,7 +178,7 @@ out_ok: | |||
| 178 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 178 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 179 | int type, int code, int offset, __u32 info) | 179 | int type, int code, int offset, __u32 info) |
| 180 | { | 180 | { |
| 181 | u32 spi; | 181 | __be32 spi; |
| 182 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 182 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; |
| 183 | struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset); | 183 | struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset); |
| 184 | struct xfrm_state *x; | 184 | struct xfrm_state *x; |
| @@ -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)) |
| @@ -234,7 +234,7 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x) | |||
| 234 | { | 234 | { |
| 235 | int err = 0; | 235 | int err = 0; |
| 236 | struct xfrm_state *t = NULL; | 236 | struct xfrm_state *t = NULL; |
| 237 | u32 spi; | 237 | __be32 spi; |
| 238 | 238 | ||
| 239 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); | 239 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); |
| 240 | if (spi) | 240 | if (spi) |
| @@ -301,7 +301,7 @@ static void **ipcomp6_alloc_scratches(void) | |||
| 301 | return scratches; | 301 | return scratches; |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | static void ipcomp6_free_tfms(struct crypto_tfm **tfms) | 304 | static void ipcomp6_free_tfms(struct crypto_comp **tfms) |
| 305 | { | 305 | { |
| 306 | struct ipcomp6_tfms *pos; | 306 | struct ipcomp6_tfms *pos; |
| 307 | int cpu; | 307 | int cpu; |
| @@ -323,28 +323,28 @@ static void ipcomp6_free_tfms(struct crypto_tfm **tfms) | |||
| 323 | return; | 323 | return; |
| 324 | 324 | ||
| 325 | for_each_possible_cpu(cpu) { | 325 | for_each_possible_cpu(cpu) { |
| 326 | struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); | 326 | struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu); |
| 327 | crypto_free_tfm(tfm); | 327 | crypto_free_comp(tfm); |
| 328 | } | 328 | } |
| 329 | free_percpu(tfms); | 329 | free_percpu(tfms); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | static struct crypto_tfm **ipcomp6_alloc_tfms(const char *alg_name) | 332 | static struct crypto_comp **ipcomp6_alloc_tfms(const char *alg_name) |
| 333 | { | 333 | { |
| 334 | struct ipcomp6_tfms *pos; | 334 | struct ipcomp6_tfms *pos; |
| 335 | struct crypto_tfm **tfms; | 335 | struct crypto_comp **tfms; |
| 336 | int cpu; | 336 | int cpu; |
| 337 | 337 | ||
| 338 | /* This can be any valid CPU ID so we don't need locking. */ | 338 | /* This can be any valid CPU ID so we don't need locking. */ |
| 339 | cpu = raw_smp_processor_id(); | 339 | cpu = raw_smp_processor_id(); |
| 340 | 340 | ||
| 341 | list_for_each_entry(pos, &ipcomp6_tfms_list, list) { | 341 | list_for_each_entry(pos, &ipcomp6_tfms_list, list) { |
| 342 | struct crypto_tfm *tfm; | 342 | struct crypto_comp *tfm; |
| 343 | 343 | ||
| 344 | tfms = pos->tfms; | 344 | tfms = pos->tfms; |
| 345 | tfm = *per_cpu_ptr(tfms, cpu); | 345 | tfm = *per_cpu_ptr(tfms, cpu); |
| 346 | 346 | ||
| 347 | if (!strcmp(crypto_tfm_alg_name(tfm), alg_name)) { | 347 | if (!strcmp(crypto_comp_name(tfm), alg_name)) { |
| 348 | pos->users++; | 348 | pos->users++; |
| 349 | return tfms; | 349 | return tfms; |
| 350 | } | 350 | } |
| @@ -358,12 +358,13 @@ static struct crypto_tfm **ipcomp6_alloc_tfms(const char *alg_name) | |||
| 358 | INIT_LIST_HEAD(&pos->list); | 358 | INIT_LIST_HEAD(&pos->list); |
| 359 | list_add(&pos->list, &ipcomp6_tfms_list); | 359 | list_add(&pos->list, &ipcomp6_tfms_list); |
| 360 | 360 | ||
| 361 | pos->tfms = tfms = alloc_percpu(struct crypto_tfm *); | 361 | pos->tfms = tfms = alloc_percpu(struct crypto_comp *); |
| 362 | if (!tfms) | 362 | if (!tfms) |
| 363 | goto error; | 363 | goto error; |
| 364 | 364 | ||
| 365 | for_each_possible_cpu(cpu) { | 365 | for_each_possible_cpu(cpu) { |
| 366 | struct crypto_tfm *tfm = crypto_alloc_tfm(alg_name, 0); | 366 | struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0, |
| 367 | CRYPTO_ALG_ASYNC); | ||
| 367 | if (!tfm) | 368 | if (!tfm) |
| 368 | goto error; | 369 | goto error; |
| 369 | *per_cpu_ptr(tfms, cpu) = tfm; | 370 | *per_cpu_ptr(tfms, cpu) = tfm; |
| @@ -416,7 +417,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
| 416 | goto out; | 417 | goto out; |
| 417 | 418 | ||
| 418 | x->props.header_len = 0; | 419 | x->props.header_len = 0; |
| 419 | if (x->props.mode) | 420 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 420 | x->props.header_len += sizeof(struct ipv6hdr); | 421 | x->props.header_len += sizeof(struct ipv6hdr); |
| 421 | 422 | ||
| 422 | mutex_lock(&ipcomp6_resource_mutex); | 423 | mutex_lock(&ipcomp6_resource_mutex); |
| @@ -428,7 +429,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
| 428 | goto error; | 429 | goto error; |
| 429 | mutex_unlock(&ipcomp6_resource_mutex); | 430 | mutex_unlock(&ipcomp6_resource_mutex); |
| 430 | 431 | ||
| 431 | if (x->props.mode) { | 432 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
| 432 | err = ipcomp6_tunnel_attach(x); | 433 | err = ipcomp6_tunnel_attach(x); |
| 433 | if (err) | 434 | if (err) |
| 434 | goto error_tunnel; | 435 | goto error_tunnel; |
| @@ -460,6 +461,7 @@ static struct xfrm_type ipcomp6_type = | |||
| 460 | .destructor = ipcomp6_destroy, | 461 | .destructor = ipcomp6_destroy, |
| 461 | .input = ipcomp6_input, | 462 | .input = ipcomp6_input, |
| 462 | .output = ipcomp6_output, | 463 | .output = ipcomp6_output, |
| 464 | .hdr_offset = xfrm6_find_1stfragopt, | ||
| 463 | }; | 465 | }; |
| 464 | 466 | ||
| 465 | 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 4c20eeb3d568..de6b91981b30 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/capability.h> | 29 | #include <linux/capability.h> |
| 30 | #include <linux/config.h> | ||
| 31 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 32 | #include <linux/types.h> | 31 | #include <linux/types.h> |
| 33 | #include <linux/socket.h> | 32 | #include <linux/socket.h> |
| @@ -58,9 +57,116 @@ | |||
| 58 | 57 | ||
| 59 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | 58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; |
| 60 | 59 | ||
| 60 | static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | ||
| 61 | int proto) | ||
| 62 | { | ||
| 63 | struct inet6_protocol *ops = NULL; | ||
| 64 | |||
| 65 | for (;;) { | ||
| 66 | struct ipv6_opt_hdr *opth; | ||
| 67 | int len; | ||
| 68 | |||
| 69 | if (proto != NEXTHDR_HOP) { | ||
| 70 | ops = rcu_dereference(inet6_protos[proto]); | ||
| 71 | |||
| 72 | if (unlikely(!ops)) | ||
| 73 | break; | ||
| 74 | |||
| 75 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | |||
| 79 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
| 80 | break; | ||
| 81 | |||
| 82 | opth = (void *)skb->data; | ||
| 83 | len = opth->hdrlen * 8 + 8; | ||
| 84 | |||
| 85 | if (unlikely(!pskb_may_pull(skb, len))) | ||
| 86 | break; | ||
| 87 | |||
| 88 | proto = opth->nexthdr; | ||
| 89 | __skb_pull(skb, len); | ||
| 90 | } | ||
| 91 | |||
| 92 | return ops; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
| 96 | { | ||
| 97 | struct ipv6hdr *ipv6h; | ||
| 98 | struct inet6_protocol *ops; | ||
| 99 | int err = -EINVAL; | ||
| 100 | |||
| 101 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 102 | goto out; | ||
| 103 | |||
| 104 | ipv6h = skb->nh.ipv6h; | ||
| 105 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 106 | err = -EPROTONOSUPPORT; | ||
| 107 | |||
| 108 | rcu_read_lock(); | ||
| 109 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
| 110 | if (likely(ops && ops->gso_send_check)) { | ||
| 111 | skb->h.raw = skb->data; | ||
| 112 | err = ops->gso_send_check(skb); | ||
| 113 | } | ||
| 114 | rcu_read_unlock(); | ||
| 115 | |||
| 116 | out: | ||
| 117 | return err; | ||
| 118 | } | ||
| 119 | |||
| 120 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | ||
| 121 | { | ||
| 122 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 123 | struct ipv6hdr *ipv6h; | ||
| 124 | struct inet6_protocol *ops; | ||
| 125 | |||
| 126 | if (!(features & NETIF_F_HW_CSUM)) | ||
| 127 | features &= ~NETIF_F_SG; | ||
| 128 | |||
| 129 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 130 | ~(SKB_GSO_UDP | | ||
| 131 | SKB_GSO_DODGY | | ||
| 132 | SKB_GSO_TCP_ECN | | ||
| 133 | SKB_GSO_TCPV6 | | ||
| 134 | 0))) | ||
| 135 | goto out; | ||
| 136 | |||
| 137 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
| 138 | goto out; | ||
| 139 | |||
| 140 | ipv6h = skb->nh.ipv6h; | ||
| 141 | __skb_pull(skb, sizeof(*ipv6h)); | ||
| 142 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
| 143 | |||
| 144 | rcu_read_lock(); | ||
| 145 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
| 146 | if (likely(ops && ops->gso_segment)) { | ||
| 147 | skb->h.raw = skb->data; | ||
| 148 | segs = ops->gso_segment(skb, features); | ||
| 149 | } | ||
| 150 | rcu_read_unlock(); | ||
| 151 | |||
| 152 | if (unlikely(IS_ERR(segs))) | ||
| 153 | goto out; | ||
| 154 | |||
| 155 | for (skb = segs; skb; skb = skb->next) { | ||
| 156 | ipv6h = skb->nh.ipv6h; | ||
| 157 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
| 158 | sizeof(*ipv6h)); | ||
| 159 | } | ||
| 160 | |||
| 161 | out: | ||
| 162 | return segs; | ||
| 163 | } | ||
| 164 | |||
| 61 | static struct packet_type ipv6_packet_type = { | 165 | static struct packet_type ipv6_packet_type = { |
| 62 | .type = __constant_htons(ETH_P_IPV6), | 166 | .type = __constant_htons(ETH_P_IPV6), |
| 63 | .func = ipv6_rcv, | 167 | .func = ipv6_rcv, |
| 168 | .gso_send_check = ipv6_gso_send_check, | ||
| 169 | .gso_segment = ipv6_gso_segment, | ||
| 64 | }; | 170 | }; |
| 65 | 171 | ||
| 66 | struct ip6_ra_chain *ip6_ra_chain; | 172 | struct ip6_ra_chain *ip6_ra_chain; |
| @@ -259,7 +365,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 259 | break; | 365 | break; |
| 260 | 366 | ||
| 261 | case IPV6_TCLASS: | 367 | case IPV6_TCLASS: |
| 262 | if (val < 0 || val > 0xff) | 368 | if (val < -1 || val > 0xff) |
| 263 | goto e_inval; | 369 | goto e_inval; |
| 264 | np->tclass = val; | 370 | np->tclass = val; |
| 265 | retv = 0; | 371 | retv = 0; |
| @@ -304,8 +410,16 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 304 | /* routing header option needs extra check */ | 410 | /* routing header option needs extra check */ |
| 305 | if (optname == IPV6_RTHDR && opt->srcrt) { | 411 | if (optname == IPV6_RTHDR && opt->srcrt) { |
| 306 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | 412 | struct ipv6_rt_hdr *rthdr = opt->srcrt; |
| 307 | if (rthdr->type) | 413 | switch (rthdr->type) { |
| 414 | case IPV6_SRCRT_TYPE_0: | ||
| 415 | #ifdef CONFIG_IPV6_MIP6 | ||
| 416 | case IPV6_SRCRT_TYPE_2: | ||
| 417 | #endif | ||
| 418 | break; | ||
| 419 | default: | ||
| 308 | goto sticky_done; | 420 | goto sticky_done; |
| 421 | } | ||
| 422 | |||
| 309 | if ((rthdr->hdrlen & 1) || | 423 | if ((rthdr->hdrlen & 1) || |
| 310 | (rthdr->hdrlen >> 1) != rthdr->segments_left) | 424 | (rthdr->hdrlen >> 1) != rthdr->segments_left) |
| 311 | goto sticky_done; | 425 | goto sticky_done; |
| @@ -844,6 +958,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 844 | 958 | ||
| 845 | case IPV6_TCLASS: | 959 | case IPV6_TCLASS: |
| 846 | val = np->tclass; | 960 | val = np->tclass; |
| 961 | if (val < 0) | ||
| 962 | val = 0; | ||
| 847 | break; | 963 | break; |
| 848 | 964 | ||
| 849 | case IPV6_RECVTCLASS: | 965 | case IPV6_RECVTCLASS: |
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 16482785bdfd..0e8e0676a033 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | 1 | ||
| 2 | #include <linux/config.h> | ||
| 3 | #include <linux/module.h> | 2 | #include <linux/module.h> |
| 4 | #include <net/protocol.h> | 3 | #include <net/protocol.h> |
| 5 | #include <net/ipv6.h> | 4 | #include <net/ipv6.h> |
| @@ -15,7 +14,6 @@ EXPORT_SYMBOL(ndisc_mc_map); | |||
| 15 | EXPORT_SYMBOL(register_inet6addr_notifier); | 14 | EXPORT_SYMBOL(register_inet6addr_notifier); |
| 16 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 15 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
| 17 | EXPORT_SYMBOL(ip6_route_output); | 16 | EXPORT_SYMBOL(ip6_route_output); |
| 18 | EXPORT_SYMBOL(addrconf_lock); | ||
| 19 | EXPORT_SYMBOL(ipv6_setsockopt); | 17 | EXPORT_SYMBOL(ipv6_setsockopt); |
| 20 | EXPORT_SYMBOL(ipv6_getsockopt); | 18 | EXPORT_SYMBOL(ipv6_getsockopt); |
| 21 | EXPORT_SYMBOL(inet6_register_protosw); | 19 | EXPORT_SYMBOL(inet6_register_protosw); |
| @@ -32,6 +30,8 @@ EXPORT_SYMBOL(ipv6_chk_addr); | |||
| 32 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 30 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
| 33 | #ifdef CONFIG_XFRM | 31 | #ifdef CONFIG_XFRM |
| 34 | EXPORT_SYMBOL(xfrm6_rcv); | 32 | EXPORT_SYMBOL(xfrm6_rcv); |
| 33 | EXPORT_SYMBOL(xfrm6_input_addr); | ||
| 34 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); | ||
| 35 | #endif | 35 | #endif |
| 36 | EXPORT_SYMBOL(rt6_lookup); | 36 | EXPORT_SYMBOL(rt6_lookup); |
| 37 | 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 6e871afbb2c7..3b114e3fa2f8 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | * - MLDv2 support | 28 | * - MLDv2 support |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include <linux/config.h> | ||
| 32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 33 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
| 34 | #include <linux/types.h> | 33 | #include <linux/types.h> |
| @@ -172,7 +171,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
| 172 | 171 | ||
| 173 | #define IPV6_MLD_MAX_MSF 64 | 172 | #define IPV6_MLD_MAX_MSF 64 |
| 174 | 173 | ||
| 175 | int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF; | 174 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; |
| 176 | 175 | ||
| 177 | /* | 176 | /* |
| 178 | * socket join on multicast group | 177 | * socket join on multicast group |
| @@ -269,13 +268,14 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
| 269 | if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { | 268 | if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { |
| 270 | struct inet6_dev *idev = in6_dev_get(dev); | 269 | struct inet6_dev *idev = in6_dev_get(dev); |
| 271 | 270 | ||
| 271 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | ||
| 272 | if (idev) { | 272 | if (idev) { |
| 273 | (void) ip6_mc_leave_src(sk,mc_lst,idev); | ||
| 274 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 273 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
| 275 | in6_dev_put(idev); | 274 | in6_dev_put(idev); |
| 276 | } | 275 | } |
| 277 | dev_put(dev); | 276 | dev_put(dev); |
| 278 | } | 277 | } else |
| 278 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | ||
| 279 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 279 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 280 | return 0; | 280 | return 0; |
| 281 | } | 281 | } |
| @@ -335,13 +335,14 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
| 335 | if (dev) { | 335 | if (dev) { |
| 336 | struct inet6_dev *idev = in6_dev_get(dev); | 336 | struct inet6_dev *idev = in6_dev_get(dev); |
| 337 | 337 | ||
| 338 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | ||
| 338 | if (idev) { | 339 | if (idev) { |
| 339 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | ||
| 340 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 340 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
| 341 | in6_dev_put(idev); | 341 | in6_dev_put(idev); |
| 342 | } | 342 | } |
| 343 | dev_put(dev); | 343 | dev_put(dev); |
| 344 | } | 344 | } else |
| 345 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | ||
| 345 | 346 | ||
| 346 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 347 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 347 | 348 | ||
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 dfa20d3be9b6..0304b5fe8d6a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -48,7 +48,6 @@ | |||
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | #include <linux/module.h> | 50 | #include <linux/module.h> |
| 51 | #include <linux/config.h> | ||
| 52 | #include <linux/errno.h> | 51 | #include <linux/errno.h> |
| 53 | #include <linux/types.h> | 52 | #include <linux/types.h> |
| 54 | #include <linux/socket.h> | 53 | #include <linux/socket.h> |
| @@ -63,6 +62,7 @@ | |||
| 63 | #include <linux/sysctl.h> | 62 | #include <linux/sysctl.h> |
| 64 | #endif | 63 | #endif |
| 65 | 64 | ||
| 65 | #include <linux/if_addr.h> | ||
| 66 | #include <linux/if_arp.h> | 66 | #include <linux/if_arp.h> |
| 67 | #include <linux/ipv6.h> | 67 | #include <linux/ipv6.h> |
| 68 | #include <linux/icmpv6.h> | 68 | #include <linux/icmpv6.h> |
| @@ -412,7 +412,8 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
| 412 | */ | 412 | */ |
| 413 | 413 | ||
| 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, |
| 415 | struct in6_addr *saddr, struct in6_addr *daddr) | 415 | struct in6_addr *saddr, struct in6_addr *daddr, |
| 416 | int oif) | ||
| 416 | { | 417 | { |
| 417 | memset(fl, 0, sizeof(*fl)); | 418 | memset(fl, 0, sizeof(*fl)); |
| 418 | ipv6_addr_copy(&fl->fl6_src, saddr); | 419 | ipv6_addr_copy(&fl->fl6_src, saddr); |
| @@ -420,6 +421,8 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type, | |||
| 420 | fl->proto = IPPROTO_ICMPV6; | 421 | fl->proto = IPPROTO_ICMPV6; |
| 421 | fl->fl_icmp_type = type; | 422 | fl->fl_icmp_type = type; |
| 422 | fl->fl_icmp_code = 0; | 423 | fl->fl_icmp_code = 0; |
| 424 | fl->oif = oif; | ||
| 425 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
| 423 | } | 426 | } |
| 424 | 427 | ||
| 425 | 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, |
| @@ -451,7 +454,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 451 | src_addr = &tmpaddr; | 454 | src_addr = &tmpaddr; |
| 452 | } | 455 | } |
| 453 | 456 | ||
| 454 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); | 457 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr, |
| 458 | dev->ifindex); | ||
| 455 | 459 | ||
| 456 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 460 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
| 457 | if (!dst) | 461 | if (!dst) |
| @@ -492,7 +496,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 492 | msg->icmph.icmp6_unused = 0; | 496 | msg->icmph.icmp6_unused = 0; |
| 493 | msg->icmph.icmp6_router = router; | 497 | msg->icmph.icmp6_router = router; |
| 494 | msg->icmph.icmp6_solicited = solicited; | 498 | msg->icmph.icmp6_solicited = solicited; |
| 495 | msg->icmph.icmp6_override = !!override; | 499 | msg->icmph.icmp6_override = override; |
| 496 | 500 | ||
| 497 | /* Set the target address. */ | 501 | /* Set the target address. */ |
| 498 | ipv6_addr_copy(&msg->target, solicited_addr); | 502 | ipv6_addr_copy(&msg->target, solicited_addr); |
| @@ -541,7 +545,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
| 541 | saddr = &addr_buf; | 545 | saddr = &addr_buf; |
| 542 | } | 546 | } |
| 543 | 547 | ||
| 544 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); | 548 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr, |
| 549 | dev->ifindex); | ||
| 545 | 550 | ||
| 546 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 551 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
| 547 | if (!dst) | 552 | if (!dst) |
| @@ -616,7 +621,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
| 616 | int len; | 621 | int len; |
| 617 | int err; | 622 | int err; |
| 618 | 623 | ||
| 619 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); | 624 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, |
| 625 | dev->ifindex); | ||
| 620 | 626 | ||
| 621 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); | 627 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); |
| 622 | if (!dst) | 628 | if (!dst) |
| @@ -730,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 730 | struct inet6_ifaddr *ifp; | 736 | struct inet6_ifaddr *ifp; |
| 731 | struct inet6_dev *idev = NULL; | 737 | struct inet6_dev *idev = NULL; |
| 732 | struct neighbour *neigh; | 738 | struct neighbour *neigh; |
| 739 | struct pneigh_entry *pneigh = NULL; | ||
| 733 | int dad = ipv6_addr_any(saddr); | 740 | int dad = ipv6_addr_any(saddr); |
| 734 | int inc; | 741 | int inc; |
| 742 | int is_router; | ||
| 735 | 743 | ||
| 736 | if (ipv6_addr_is_multicast(&msg->target)) { | 744 | if (ipv6_addr_is_multicast(&msg->target)) { |
| 737 | ND_PRINTK2(KERN_WARNING | 745 | ND_PRINTK2(KERN_WARNING |
| @@ -816,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 816 | 824 | ||
| 817 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 825 | if (ipv6_chk_acast_addr(dev, &msg->target) || |
| 818 | (idev->cnf.forwarding && | 826 | (idev->cnf.forwarding && |
| 819 | 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)) { | ||
| 820 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 830 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
| 821 | skb->pkt_type != PACKET_HOST && | 831 | skb->pkt_type != PACKET_HOST && |
| 822 | inc != 0 && | 832 | inc != 0 && |
| @@ -837,12 +847,14 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 837 | goto out; | 847 | goto out; |
| 838 | } | 848 | } |
| 839 | 849 | ||
| 850 | is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding); | ||
| 851 | |||
| 840 | if (dad) { | 852 | if (dad) { |
| 841 | struct in6_addr maddr; | 853 | struct in6_addr maddr; |
| 842 | 854 | ||
| 843 | ipv6_addr_all_nodes(&maddr); | 855 | ipv6_addr_all_nodes(&maddr); |
| 844 | ndisc_send_na(dev, NULL, &maddr, &msg->target, | 856 | ndisc_send_na(dev, NULL, &maddr, &msg->target, |
| 845 | idev->cnf.forwarding, 0, (ifp != NULL), 1); | 857 | is_router, 0, (ifp != NULL), 1); |
| 846 | goto out; | 858 | goto out; |
| 847 | } | 859 | } |
| 848 | 860 | ||
| @@ -863,7 +875,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
| 863 | NEIGH_UPDATE_F_OVERRIDE); | 875 | NEIGH_UPDATE_F_OVERRIDE); |
| 864 | if (neigh || !dev->hard_header) { | 876 | if (neigh || !dev->hard_header) { |
| 865 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 877 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
| 866 | idev->cnf.forwarding, | 878 | is_router, |
| 867 | 1, (ifp != NULL && inc), inc); | 879 | 1, (ifp != NULL && inc), inc); |
| 868 | if (neigh) | 880 | if (neigh) |
| 869 | neigh_release(neigh); | 881 | neigh_release(neigh); |
| @@ -946,6 +958,20 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
| 946 | if (neigh->nud_state & NUD_FAILED) | 958 | if (neigh->nud_state & NUD_FAILED) |
| 947 | goto out; | 959 | goto out; |
| 948 | 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 | |||
| 949 | neigh_update(neigh, lladdr, | 975 | neigh_update(neigh, lladdr, |
| 950 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, | 976 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, |
| 951 | NEIGH_UPDATE_F_WEAK_OVERRIDE| | 977 | NEIGH_UPDATE_F_WEAK_OVERRIDE| |
| @@ -960,7 +986,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
| 960 | struct rt6_info *rt; | 986 | struct rt6_info *rt; |
| 961 | rt = rt6_get_dflt_router(saddr, dev); | 987 | rt = rt6_get_dflt_router(saddr, dev); |
| 962 | if (rt) | 988 | if (rt) |
| 963 | ip6_del_rt(rt, NULL, NULL, NULL); | 989 | ip6_del_rt(rt); |
| 964 | } | 990 | } |
| 965 | 991 | ||
| 966 | out: | 992 | out: |
| @@ -1113,7 +1139,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1113 | 1139 | ||
| 1114 | if (rt && lifetime == 0) { | 1140 | if (rt && lifetime == 0) { |
| 1115 | neigh_clone(neigh); | 1141 | neigh_clone(neigh); |
| 1116 | ip6_del_rt(rt, NULL, NULL, NULL); | 1142 | ip6_del_rt(rt); |
| 1117 | rt = NULL; | 1143 | rt = NULL; |
| 1118 | } | 1144 | } |
| 1119 | 1145 | ||
| @@ -1345,7 +1371,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
| 1345 | 1371 | ||
| 1346 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1372 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
| 1347 | if (neigh) { | 1373 | if (neigh) { |
| 1348 | rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, lladdr, | 1374 | rt6_redirect(dest, &skb->nh.ipv6h->daddr, |
| 1375 | &skb->nh.ipv6h->saddr, neigh, lladdr, | ||
| 1349 | on_link); | 1376 | on_link); |
| 1350 | neigh_release(neigh); | 1377 | neigh_release(neigh); |
| 1351 | } | 1378 | } |
| @@ -1381,7 +1408,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
| 1381 | return; | 1408 | return; |
| 1382 | } | 1409 | } |
| 1383 | 1410 | ||
| 1384 | 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); | ||
| 1385 | 1413 | ||
| 1386 | dst = ip6_route_output(NULL, &fl); | 1414 | dst = ip6_route_output(NULL, &fl); |
| 1387 | 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 b4b7d441af25..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 | } |
| @@ -505,7 +505,7 @@ ipq_rcv_skb(struct sk_buff *skb) | |||
| 505 | if (type <= IPQM_BASE) | 505 | if (type <= IPQM_BASE) |
| 506 | return; | 506 | return; |
| 507 | 507 | ||
| 508 | if (security_netlink_recv(skb)) | 508 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) |
| 509 | RCV_SKB_FAIL(-EPERM); | 509 | RCV_SKB_FAIL(-EPERM); |
| 510 | 510 | ||
| 511 | write_lock_bh(&queue_lock); | 511 | write_lock_bh(&queue_lock); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 2e72f89a7019..4ab368fa0b8f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -19,13 +19,13 @@ | |||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/capability.h> | 21 | #include <linux/capability.h> |
| 22 | #include <linux/config.h> | ||
| 23 | #include <linux/in.h> | 22 | #include <linux/in.h> |
| 24 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
| 25 | #include <linux/kmod.h> | 24 | #include <linux/kmod.h> |
| 26 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
| 27 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
| 28 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 28 | #include <linux/poison.h> | ||
| 29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
| 30 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
| 31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| @@ -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 |
| @@ -377,7 +371,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
| 377 | } while (!hotdrop); | 371 | } while (!hotdrop); |
| 378 | 372 | ||
| 379 | #ifdef CONFIG_NETFILTER_DEBUG | 373 | #ifdef CONFIG_NETFILTER_DEBUG |
| 380 | ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac; | 374 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; |
| 381 | #endif | 375 | #endif |
| 382 | read_unlock_bh(&table->lock); | 376 | read_unlock_bh(&table->lock); |
| 383 | 377 | ||
| @@ -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 | } |
| @@ -1281,7 +1270,8 @@ int ip6t_register_table(struct xt_table *table, | |||
| 1281 | return ret; | 1270 | return ret; |
| 1282 | } | 1271 | } |
| 1283 | 1272 | ||
| 1284 | if (xt_register_table(table, &bootstrap, newinfo) != 0) { | 1273 | ret = xt_register_table(table, &bootstrap, newinfo); |
| 1274 | if (ret != 0) { | ||
| 1285 | xt_free_table_info(newinfo); | 1275 | xt_free_table_info(newinfo); |
| 1286 | return ret; | 1276 | return ret; |
| 1287 | } | 1277 | } |
| @@ -1351,7 +1341,6 @@ icmp6_checkentry(const char *tablename, | |||
| 1351 | const void *entry, | 1341 | const void *entry, |
| 1352 | const struct xt_match *match, | 1342 | const struct xt_match *match, |
| 1353 | void *matchinfo, | 1343 | void *matchinfo, |
| 1354 | unsigned int matchsize, | ||
| 1355 | unsigned int hook_mask) | 1344 | unsigned int hook_mask) |
| 1356 | { | 1345 | { |
| 1357 | const struct ip6t_icmp *icmpinfo = matchinfo; | 1346 | const struct ip6t_icmp *icmpinfo = matchinfo; |
| @@ -1397,23 +1386,39 @@ static int __init ip6_tables_init(void) | |||
| 1397 | { | 1386 | { |
| 1398 | int ret; | 1387 | int ret; |
| 1399 | 1388 | ||
| 1400 | xt_proto_init(AF_INET6); | 1389 | ret = xt_proto_init(AF_INET6); |
| 1390 | if (ret < 0) | ||
| 1391 | goto err1; | ||
| 1401 | 1392 | ||
| 1402 | /* Noone else will be downing sem now, so we won't sleep */ | 1393 | /* Noone else will be downing sem now, so we won't sleep */ |
| 1403 | xt_register_target(&ip6t_standard_target); | 1394 | ret = xt_register_target(&ip6t_standard_target); |
| 1404 | xt_register_target(&ip6t_error_target); | 1395 | if (ret < 0) |
| 1405 | xt_register_match(&icmp6_matchstruct); | 1396 | goto err2; |
| 1397 | ret = xt_register_target(&ip6t_error_target); | ||
| 1398 | if (ret < 0) | ||
| 1399 | goto err3; | ||
| 1400 | ret = xt_register_match(&icmp6_matchstruct); | ||
| 1401 | if (ret < 0) | ||
| 1402 | goto err4; | ||
| 1406 | 1403 | ||
| 1407 | /* Register setsockopt */ | 1404 | /* Register setsockopt */ |
| 1408 | ret = nf_register_sockopt(&ip6t_sockopts); | 1405 | ret = nf_register_sockopt(&ip6t_sockopts); |
| 1409 | if (ret < 0) { | 1406 | if (ret < 0) |
| 1410 | duprintf("Unable to register sockopts.\n"); | 1407 | goto err5; |
| 1411 | xt_proto_fini(AF_INET6); | ||
| 1412 | return ret; | ||
| 1413 | } | ||
| 1414 | 1408 | ||
| 1415 | printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n"); | 1409 | printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n"); |
| 1416 | return 0; | 1410 | return 0; |
| 1411 | |||
| 1412 | err5: | ||
| 1413 | xt_unregister_match(&icmp6_matchstruct); | ||
| 1414 | err4: | ||
| 1415 | xt_unregister_target(&ip6t_error_target); | ||
| 1416 | err3: | ||
| 1417 | xt_unregister_target(&ip6t_standard_target); | ||
| 1418 | err2: | ||
| 1419 | xt_proto_fini(AF_INET6); | ||
| 1420 | err1: | ||
| 1421 | return ret; | ||
| 1417 | } | 1422 | } |
| 1418 | 1423 | ||
| 1419 | static void __exit ip6_tables_fini(void) | 1424 | static void __exit ip6_tables_fini(void) |
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 de1175c27f6d..311eae82feb3 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | * 2 of the License, or (at your option) any later version. | 15 | * 2 of the License, or (at your option) any later version. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/config.h> | ||
| 19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 20 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
| 21 | #include <linux/icmpv6.h> | 20 | #include <linux/icmpv6.h> |
| @@ -97,6 +96,7 @@ static void send_reset(struct sk_buff *oldskb) | |||
| 97 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); | 96 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); |
| 98 | fl.fl_ip_sport = otcph.dest; | 97 | fl.fl_ip_sport = otcph.dest; |
| 99 | fl.fl_ip_dport = otcph.source; | 98 | fl.fl_ip_dport = otcph.source; |
| 99 | security_skb_classify_flow(oldskb, &fl); | ||
| 100 | dst = ip6_route_output(NULL, &fl); | 100 | dst = ip6_route_output(NULL, &fl); |
| 101 | if (dst == NULL) | 101 | if (dst == NULL) |
| 102 | return; | 102 | return; |
| @@ -180,8 +180,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
| 180 | const struct net_device *out, | 180 | const struct net_device *out, |
| 181 | unsigned int hooknum, | 181 | unsigned int hooknum, |
| 182 | const struct xt_target *target, | 182 | const struct xt_target *target, |
| 183 | const void *targinfo, | 183 | const void *targinfo) |
| 184 | void *userinfo) | ||
| 185 | { | 184 | { |
| 186 | const struct ip6t_reject_info *reject = targinfo; | 185 | const struct ip6t_reject_info *reject = targinfo; |
| 187 | 186 | ||
| @@ -224,7 +223,6 @@ static int check(const char *tablename, | |||
| 224 | const void *entry, | 223 | const void *entry, |
| 225 | const struct xt_target *target, | 224 | const struct xt_target *target, |
| 226 | void *targinfo, | 225 | void *targinfo, |
| 227 | unsigned int targinfosize, | ||
| 228 | unsigned int hook_mask) | 226 | unsigned int hook_mask) |
| 229 | { | 227 | { |
| 230 | const struct ip6t_reject_info *rejinfo = targinfo; | 228 | const struct ip6t_reject_info *rejinfo = targinfo; |
| @@ -257,9 +255,7 @@ static struct ip6t_target ip6t_reject_reg = { | |||
| 257 | 255 | ||
| 258 | static int __init ip6t_reject_init(void) | 256 | static int __init ip6t_reject_init(void) |
| 259 | { | 257 | { |
| 260 | if (ip6t_register_target(&ip6t_reject_reg)) | 258 | return ip6t_register_target(&ip6t_reject_reg); |
| 261 | return -EINVAL; | ||
| 262 | return 0; | ||
| 263 | } | 259 | } |
| 264 | 260 | ||
| 265 | 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 2a71c3b669f1..e5e53fff9e38 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | * structures. | 20 | * structures. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/config.h> | ||
| 24 | #include <linux/types.h> | 23 | #include <linux/types.h> |
| 25 | #include <linux/ipv6.h> | 24 | #include <linux/ipv6.h> |
| 26 | #include <linux/in6.h> | 25 | #include <linux/in6.h> |
| @@ -336,7 +335,7 @@ static struct nf_hook_ops ipv6_conntrack_ops[] = { | |||
| 336 | /* From nf_conntrack_proto_icmpv6.c */ | 335 | /* From nf_conntrack_proto_icmpv6.c */ |
| 337 | extern unsigned int nf_ct_icmpv6_timeout; | 336 | extern unsigned int nf_ct_icmpv6_timeout; |
| 338 | 337 | ||
| 339 | /* From nf_conntrack_frag6.c */ | 338 | /* From nf_conntrack_reasm.c */ |
| 340 | extern unsigned int nf_ct_frag6_timeout; | 339 | extern unsigned int nf_ct_frag6_timeout; |
| 341 | extern unsigned int nf_ct_frag6_low_thresh; | 340 | extern unsigned int nf_ct_frag6_low_thresh; |
| 342 | 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 c32a029e43f0..bf93c1ea6be9 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | * 2 of the License, or (at your option) any later version. | 14 | * 2 of the License, or (at your option) any later version. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/config.h> | ||
| 18 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
| 19 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 20 | #include <linux/string.h> | 19 | #include <linux/string.h> |
| @@ -55,9 +54,9 @@ | |||
| 55 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | 54 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ |
| 56 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | 55 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT |
| 57 | 56 | ||
| 58 | unsigned int nf_ct_frag6_high_thresh = 256*1024; | 57 | unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024; |
| 59 | unsigned int nf_ct_frag6_low_thresh = 192*1024; | 58 | unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024; |
| 60 | unsigned long nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT; | 59 | unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT; |
| 61 | 60 | ||
| 62 | struct nf_ct_frag6_skb_cb | 61 | struct nf_ct_frag6_skb_cb |
| 63 | { | 62 | { |
| @@ -409,7 +408,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
| 409 | return -1; | 408 | return -1; |
| 410 | } | 409 | } |
| 411 | 410 | ||
| 412 | if (skb->ip_summed == CHECKSUM_HW) | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
| 413 | skb->csum = csum_sub(skb->csum, | 412 | skb->csum = csum_sub(skb->csum, |
| 414 | csum_partial(skb->nh.raw, | 413 | csum_partial(skb->nh.raw, |
| 415 | (u8*)(fhdr + 1) - skb->nh.raw, | 414 | (u8*)(fhdr + 1) - skb->nh.raw, |
| @@ -641,7 +640,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 641 | head->len += fp->len; | 640 | head->len += fp->len; |
| 642 | if (head->ip_summed != fp->ip_summed) | 641 | if (head->ip_summed != fp->ip_summed) |
| 643 | head->ip_summed = CHECKSUM_NONE; | 642 | head->ip_summed = CHECKSUM_NONE; |
| 644 | else if (head->ip_summed == CHECKSUM_HW) | 643 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
| 645 | head->csum = csum_add(head->csum, fp->csum); | 644 | head->csum = csum_add(head->csum, fp->csum); |
| 646 | head->truesize += fp->truesize; | 645 | head->truesize += fp->truesize; |
| 647 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); | 646 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); |
| @@ -653,7 +652,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 653 | head->nh.ipv6h->payload_len = htons(payload_len); | 652 | head->nh.ipv6h->payload_len = htons(payload_len); |
| 654 | 653 | ||
| 655 | /* Yes, and fold redundant checksum back. 8) */ | 654 | /* Yes, and fold redundant checksum back. 8) */ |
| 656 | if (head->ip_summed == CHECKSUM_HW) | 655 | if (head->ip_summed == CHECKSUM_COMPLETE) |
| 657 | 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); |
| 658 | 657 | ||
| 659 | fq->fragments = NULL; | 658 | fq->fragments = NULL; |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 779ddf77f4d4..efee7a6301a8 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | * as published by the Free Software Foundation; either version | 17 | * as published by the Free Software Foundation; either version |
| 18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
| 19 | */ | 19 | */ |
| 20 | #include <linux/config.h> | ||
| 21 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 22 | #include <linux/socket.h> | 21 | #include <linux/socket.h> |
| 23 | #include <linux/net.h> | 22 | #include <linux/net.h> |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index fa1ce0ae123e..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, |
| @@ -411,6 +438,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 411 | /* Copy the address. */ | 438 | /* Copy the address. */ |
| 412 | if (sin6) { | 439 | if (sin6) { |
| 413 | sin6->sin6_family = AF_INET6; | 440 | sin6->sin6_family = AF_INET6; |
| 441 | sin6->sin6_port = 0; | ||
| 414 | ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); | 442 | ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); |
| 415 | sin6->sin6_flowinfo = 0; | 443 | sin6->sin6_flowinfo = 0; |
| 416 | sin6->sin6_scope_id = 0; | 444 | sin6->sin6_scope_id = 0; |
| @@ -581,6 +609,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
| 581 | struct iovec *iov; | 609 | struct iovec *iov; |
| 582 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
| 583 | u8 __user *code = NULL; | 611 | u8 __user *code = NULL; |
| 612 | #ifdef CONFIG_IPV6_MIP6 | ||
| 613 | u8 len = 0; | ||
| 614 | #endif | ||
| 584 | int probed = 0; | 615 | int probed = 0; |
| 585 | int i; | 616 | int i; |
| 586 | 617 | ||
| @@ -612,6 +643,20 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
| 612 | probed = 1; | 643 | probed = 1; |
| 613 | } | 644 | } |
| 614 | 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 | ||
| 615 | default: | 660 | default: |
| 616 | probed = 1; | 661 | probed = 1; |
| 617 | break; | 662 | break; |
| @@ -758,6 +803,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 758 | 803 | ||
| 759 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 804 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
| 760 | fl.oif = np->mcast_oif; | 805 | fl.oif = np->mcast_oif; |
| 806 | security_sk_classify_flow(sk, &fl); | ||
| 761 | 807 | ||
| 762 | err = ip6_dst_lookup(sk, &dst, &fl); | 808 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 763 | if (err) | 809 | if (err) |
| @@ -780,7 +826,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 780 | } | 826 | } |
| 781 | 827 | ||
| 782 | if (tclass < 0) { | 828 | if (tclass < 0) { |
| 783 | tclass = np->cork.tclass; | 829 | tclass = np->tclass; |
| 784 | if (tclass < 0) | 830 | if (tclass < 0) |
| 785 | tclass = 0; | 831 | tclass = 0; |
| 786 | } | 832 | } |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index eef985e010ea..f39bbedd1327 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | * YOSHIFUJI,H. @USAGI Always remove fragment header to | 28 | * YOSHIFUJI,H. @USAGI Always remove fragment header to |
| 29 | * calculate ICV correctly. | 29 | * calculate ICV correctly. |
| 30 | */ | 30 | */ |
| 31 | #include <linux/config.h> | ||
| 32 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
| 33 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 34 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| @@ -54,10 +53,10 @@ | |||
| 54 | #include <net/ndisc.h> | 53 | #include <net/ndisc.h> |
| 55 | #include <net/addrconf.h> | 54 | #include <net/addrconf.h> |
| 56 | 55 | ||
| 57 | int sysctl_ip6frag_high_thresh = 256*1024; | 56 | int sysctl_ip6frag_high_thresh __read_mostly = 256*1024; |
| 58 | int sysctl_ip6frag_low_thresh = 192*1024; | 57 | int sysctl_ip6frag_low_thresh __read_mostly = 192*1024; |
| 59 | 58 | ||
| 60 | int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT; | 59 | int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT; |
| 61 | 60 | ||
| 62 | struct ip6frag_skb_cb | 61 | struct ip6frag_skb_cb |
| 63 | { | 62 | { |
| @@ -153,7 +152,7 @@ static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | |||
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | static struct timer_list ip6_frag_secret_timer; | 154 | static struct timer_list ip6_frag_secret_timer; |
| 156 | int sysctl_ip6frag_secret_interval = 10 * 60 * HZ; | 155 | int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ; |
| 157 | 156 | ||
| 158 | static void ip6_frag_secret_rebuild(unsigned long dummy) | 157 | static void ip6_frag_secret_rebuild(unsigned long dummy) |
| 159 | { | 158 | { |
| @@ -434,7 +433,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 434 | return; | 433 | return; |
| 435 | } | 434 | } |
| 436 | 435 | ||
| 437 | if (skb->ip_summed == CHECKSUM_HW) | 436 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
| 438 | skb->csum = csum_sub(skb->csum, | 437 | skb->csum = csum_sub(skb->csum, |
| 439 | 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)); |
| 440 | 439 | ||
| @@ -648,7 +647,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
| 648 | head->len += fp->len; | 647 | head->len += fp->len; |
| 649 | if (head->ip_summed != fp->ip_summed) | 648 | if (head->ip_summed != fp->ip_summed) |
| 650 | head->ip_summed = CHECKSUM_NONE; | 649 | head->ip_summed = CHECKSUM_NONE; |
| 651 | else if (head->ip_summed == CHECKSUM_HW) | 650 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
| 652 | head->csum = csum_add(head->csum, fp->csum); | 651 | head->csum = csum_add(head->csum, fp->csum); |
| 653 | head->truesize += fp->truesize; | 652 | head->truesize += fp->truesize; |
| 654 | atomic_sub(fp->truesize, &ip6_frag_mem); | 653 | atomic_sub(fp->truesize, &ip6_frag_mem); |
| @@ -663,7 +662,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
| 663 | *skb_in = head; | 662 | *skb_in = head; |
| 664 | 663 | ||
| 665 | /* Yes, and fold redundant checksum back. 8) */ | 664 | /* Yes, and fold redundant checksum back. 8) */ |
| 666 | if (head->ip_summed == CHECKSUM_HW) | 665 | if (head->ip_summed == CHECKSUM_COMPLETE) |
| 667 | 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); |
| 668 | 667 | ||
| 669 | 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 8a777932786d..d6b4b4f48d18 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -22,10 +22,11 @@ | |||
| 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> |
| 28 | #include <linux/config.h> | ||
| 29 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 30 | #include <linux/types.h> | 31 | #include <linux/types.h> |
| 31 | #include <linux/times.h> | 32 | #include <linux/times.h> |
| @@ -36,7 +37,6 @@ | |||
| 36 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
| 37 | #include <linux/in6.h> | 38 | #include <linux/in6.h> |
| 38 | #include <linux/init.h> | 39 | #include <linux/init.h> |
| 39 | #include <linux/netlink.h> | ||
| 40 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
| 41 | 41 | ||
| 42 | #ifdef CONFIG_PROC_FS | 42 | #ifdef CONFIG_PROC_FS |
| @@ -54,6 +54,8 @@ | |||
| 54 | #include <linux/rtnetlink.h> | 54 | #include <linux/rtnetlink.h> |
| 55 | #include <net/dst.h> | 55 | #include <net/dst.h> |
| 56 | #include <net/xfrm.h> | 56 | #include <net/xfrm.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,10 +385,10 @@ 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 spinlock_t lock = SPIN_LOCK_UNLOCKED; | 391 | static DEFINE_SPINLOCK(lock); |
| 353 | spin_lock(&lock); | 392 | spin_lock(&lock); |
| 354 | *head = rt0->u.next; | 393 | *head = rt0->u.next; |
| 355 | rt0->u.next = last->u.next; | 394 | rt0->u.next = last->u.next; |
| @@ -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 | } |
| @@ -743,11 +854,10 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
| 743 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 854 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
| 744 | } | 855 | } |
| 745 | dst->metrics[RTAX_MTU-1] = mtu; | 856 | dst->metrics[RTAX_MTU-1] = mtu; |
| 857 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | ||
| 746 | } | 858 | } |
| 747 | } | 859 | } |
| 748 | 860 | ||
| 749 | /* Protected by rt6_lock. */ | ||
| 750 | static struct dst_entry *ndisc_dst_gc_list; | ||
| 751 | static int ipv6_get_mtu(struct net_device *dev); | 861 | static int ipv6_get_mtu(struct net_device *dev); |
| 752 | 862 | ||
| 753 | static inline unsigned int ipv6_advmss(unsigned int mtu) | 863 | static inline unsigned int ipv6_advmss(unsigned int mtu) |
| @@ -768,6 +878,9 @@ static inline unsigned int ipv6_advmss(unsigned int mtu) | |||
| 768 | return mtu; | 878 | return mtu; |
| 769 | } | 879 | } |
| 770 | 880 | ||
| 881 | static struct dst_entry *ndisc_dst_gc_list; | ||
| 882 | static DEFINE_SPINLOCK(ndisc_lock); | ||
| 883 | |||
| 771 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | 884 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, |
| 772 | struct neighbour *neigh, | 885 | struct neighbour *neigh, |
| 773 | struct in6_addr *addr, | 886 | struct in6_addr *addr, |
| @@ -808,10 +921,10 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | |||
| 808 | rt->rt6i_dst.plen = 128; | 921 | rt->rt6i_dst.plen = 128; |
| 809 | #endif | 922 | #endif |
| 810 | 923 | ||
| 811 | write_lock_bh(&rt6_lock); | 924 | spin_lock_bh(&ndisc_lock); |
| 812 | rt->u.dst.next = ndisc_dst_gc_list; | 925 | rt->u.dst.next = ndisc_dst_gc_list; |
| 813 | ndisc_dst_gc_list = &rt->u.dst; | 926 | ndisc_dst_gc_list = &rt->u.dst; |
| 814 | write_unlock_bh(&rt6_lock); | 927 | spin_unlock_bh(&ndisc_lock); |
| 815 | 928 | ||
| 816 | fib6_force_start_gc(); | 929 | fib6_force_start_gc(); |
| 817 | 930 | ||
| @@ -825,8 +938,11 @@ int ndisc_dst_gc(int *more) | |||
| 825 | int freed; | 938 | int freed; |
| 826 | 939 | ||
| 827 | next = NULL; | 940 | next = NULL; |
| 941 | freed = 0; | ||
| 942 | |||
| 943 | spin_lock_bh(&ndisc_lock); | ||
| 828 | pprev = &ndisc_dst_gc_list; | 944 | pprev = &ndisc_dst_gc_list; |
| 829 | freed = 0; | 945 | |
| 830 | while ((dst = *pprev) != NULL) { | 946 | while ((dst = *pprev) != NULL) { |
| 831 | if (!atomic_read(&dst->__refcnt)) { | 947 | if (!atomic_read(&dst->__refcnt)) { |
| 832 | *pprev = dst->next; | 948 | *pprev = dst->next; |
| @@ -838,6 +954,8 @@ int ndisc_dst_gc(int *more) | |||
| 838 | } | 954 | } |
| 839 | } | 955 | } |
| 840 | 956 | ||
| 957 | spin_unlock_bh(&ndisc_lock); | ||
| 958 | |||
| 841 | return freed; | 959 | return freed; |
| 842 | } | 960 | } |
| 843 | 961 | ||
| @@ -898,28 +1016,24 @@ int ipv6_get_hoplimit(struct net_device *dev) | |||
| 898 | * | 1016 | * |
| 899 | */ | 1017 | */ |
| 900 | 1018 | ||
| 901 | int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 1019 | int ip6_route_add(struct fib6_config *cfg) |
| 902 | void *_rtattr, struct netlink_skb_parms *req) | ||
| 903 | { | 1020 | { |
| 904 | int err; | 1021 | int err; |
| 905 | struct rtmsg *r; | ||
| 906 | struct rtattr **rta; | ||
| 907 | struct rt6_info *rt = NULL; | 1022 | struct rt6_info *rt = NULL; |
| 908 | struct net_device *dev = NULL; | 1023 | struct net_device *dev = NULL; |
| 909 | struct inet6_dev *idev = NULL; | 1024 | struct inet6_dev *idev = NULL; |
| 1025 | struct fib6_table *table; | ||
| 910 | int addr_type; | 1026 | int addr_type; |
| 911 | 1027 | ||
| 912 | rta = (struct rtattr **) _rtattr; | 1028 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
| 913 | |||
| 914 | if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128) | ||
| 915 | return -EINVAL; | 1029 | return -EINVAL; |
| 916 | #ifndef CONFIG_IPV6_SUBTREES | 1030 | #ifndef CONFIG_IPV6_SUBTREES |
| 917 | if (rtmsg->rtmsg_src_len) | 1031 | if (cfg->fc_src_len) |
| 918 | return -EINVAL; | 1032 | return -EINVAL; |
| 919 | #endif | 1033 | #endif |
| 920 | if (rtmsg->rtmsg_ifindex) { | 1034 | if (cfg->fc_ifindex) { |
| 921 | err = -ENODEV; | 1035 | err = -ENODEV; |
| 922 | dev = dev_get_by_index(rtmsg->rtmsg_ifindex); | 1036 | dev = dev_get_by_index(cfg->fc_ifindex); |
| 923 | if (!dev) | 1037 | if (!dev) |
| 924 | goto out; | 1038 | goto out; |
| 925 | idev = in6_dev_get(dev); | 1039 | idev = in6_dev_get(dev); |
| @@ -927,8 +1041,14 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 927 | goto out; | 1041 | goto out; |
| 928 | } | 1042 | } |
| 929 | 1043 | ||
| 930 | if (rtmsg->rtmsg_metric == 0) | 1044 | if (cfg->fc_metric == 0) |
| 931 | 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 | } | ||
| 932 | 1052 | ||
| 933 | rt = ip6_dst_alloc(); | 1053 | rt = ip6_dst_alloc(); |
| 934 | 1054 | ||
| @@ -938,14 +1058,13 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 938 | } | 1058 | } |
| 939 | 1059 | ||
| 940 | rt->u.dst.obsolete = -1; | 1060 | rt->u.dst.obsolete = -1; |
| 941 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(rtmsg->rtmsg_info); | 1061 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires); |
| 942 | if (nlh && (r = NLMSG_DATA(nlh))) { | ||
| 943 | rt->rt6i_protocol = r->rtm_protocol; | ||
| 944 | } else { | ||
| 945 | rt->rt6i_protocol = RTPROT_BOOT; | ||
| 946 | } | ||
| 947 | 1062 | ||
| 948 | 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); | ||
| 949 | 1068 | ||
| 950 | if (addr_type & IPV6_ADDR_MULTICAST) | 1069 | if (addr_type & IPV6_ADDR_MULTICAST) |
| 951 | rt->u.dst.input = ip6_mc_input; | 1070 | rt->u.dst.input = ip6_mc_input; |
| @@ -954,24 +1073,22 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 954 | 1073 | ||
| 955 | rt->u.dst.output = ip6_output; | 1074 | rt->u.dst.output = ip6_output; |
| 956 | 1075 | ||
| 957 | ipv6_addr_prefix(&rt->rt6i_dst.addr, | 1076 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
| 958 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len); | 1077 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
| 959 | rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len; | ||
| 960 | if (rt->rt6i_dst.plen == 128) | 1078 | if (rt->rt6i_dst.plen == 128) |
| 961 | rt->u.dst.flags = DST_HOST; | 1079 | rt->u.dst.flags = DST_HOST; |
| 962 | 1080 | ||
| 963 | #ifdef CONFIG_IPV6_SUBTREES | 1081 | #ifdef CONFIG_IPV6_SUBTREES |
| 964 | ipv6_addr_prefix(&rt->rt6i_src.addr, | 1082 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
| 965 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1083 | rt->rt6i_src.plen = cfg->fc_src_len; |
| 966 | rt->rt6i_src.plen = rtmsg->rtmsg_src_len; | ||
| 967 | #endif | 1084 | #endif |
| 968 | 1085 | ||
| 969 | rt->rt6i_metric = rtmsg->rtmsg_metric; | 1086 | rt->rt6i_metric = cfg->fc_metric; |
| 970 | 1087 | ||
| 971 | /* We cannot add true routes via loopback here, | 1088 | /* We cannot add true routes via loopback here, |
| 972 | they would result in kernel looping; promote them to reject routes | 1089 | they would result in kernel looping; promote them to reject routes |
| 973 | */ | 1090 | */ |
| 974 | if ((rtmsg->rtmsg_flags&RTF_REJECT) || | 1091 | if ((cfg->fc_flags & RTF_REJECT) || |
| 975 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1092 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { |
| 976 | /* hold loopback dev/idev if we haven't done so. */ | 1093 | /* hold loopback dev/idev if we haven't done so. */ |
| 977 | if (dev != &loopback_dev) { | 1094 | if (dev != &loopback_dev) { |
| @@ -994,12 +1111,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 994 | goto install_route; | 1111 | goto install_route; |
| 995 | } | 1112 | } |
| 996 | 1113 | ||
| 997 | if (rtmsg->rtmsg_flags & RTF_GATEWAY) { | 1114 | if (cfg->fc_flags & RTF_GATEWAY) { |
| 998 | struct in6_addr *gw_addr; | 1115 | struct in6_addr *gw_addr; |
| 999 | int gwa_type; | 1116 | int gwa_type; |
| 1000 | 1117 | ||
| 1001 | gw_addr = &rtmsg->rtmsg_gateway; | 1118 | gw_addr = &cfg->fc_gateway; |
| 1002 | ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway); | 1119 | ipv6_addr_copy(&rt->rt6i_gateway, gw_addr); |
| 1003 | gwa_type = ipv6_addr_type(gw_addr); | 1120 | gwa_type = ipv6_addr_type(gw_addr); |
| 1004 | 1121 | ||
| 1005 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { | 1122 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { |
| @@ -1016,7 +1133,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 1016 | if (!(gwa_type&IPV6_ADDR_UNICAST)) | 1133 | if (!(gwa_type&IPV6_ADDR_UNICAST)) |
| 1017 | goto out; | 1134 | goto out; |
| 1018 | 1135 | ||
| 1019 | grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1); | 1136 | grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1); |
| 1020 | 1137 | ||
| 1021 | err = -EHOSTUNREACH; | 1138 | err = -EHOSTUNREACH; |
| 1022 | if (grt == NULL) | 1139 | if (grt == NULL) |
| @@ -1048,7 +1165,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 1048 | if (dev == NULL) | 1165 | if (dev == NULL) |
| 1049 | goto out; | 1166 | goto out; |
| 1050 | 1167 | ||
| 1051 | if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) { | 1168 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
| 1052 | 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); |
| 1053 | if (IS_ERR(rt->rt6i_nexthop)) { | 1170 | if (IS_ERR(rt->rt6i_nexthop)) { |
| 1054 | err = PTR_ERR(rt->rt6i_nexthop); | 1171 | err = PTR_ERR(rt->rt6i_nexthop); |
| @@ -1057,24 +1174,24 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
| 1057 | } | 1174 | } |
| 1058 | } | 1175 | } |
| 1059 | 1176 | ||
| 1060 | rt->rt6i_flags = rtmsg->rtmsg_flags; | 1177 | rt->rt6i_flags = cfg->fc_flags; |
| 1061 | 1178 | ||
| 1062 | install_route: | 1179 | install_route: |
| 1063 | if (rta && rta[RTA_METRICS-1]) { | 1180 | if (cfg->fc_mx) { |
| 1064 | int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); | 1181 | struct nlattr *nla; |
| 1065 | struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]); | 1182 | int remaining; |
| 1066 | 1183 | ||
| 1067 | while (RTA_OK(attr, attrlen)) { | 1184 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
| 1068 | unsigned flavor = attr->rta_type; | 1185 | int type = nla->nla_type; |
| 1069 | if (flavor) { | 1186 | |
| 1070 | if (flavor > RTAX_MAX) { | 1187 | if (type) { |
| 1188 | if (type > RTAX_MAX) { | ||
| 1071 | err = -EINVAL; | 1189 | err = -EINVAL; |
| 1072 | goto out; | 1190 | goto out; |
| 1073 | } | 1191 | } |
| 1074 | rt->u.dst.metrics[flavor-1] = | 1192 | |
| 1075 | *(u32 *)RTA_DATA(attr); | 1193 | rt->u.dst.metrics[type - 1] = nla_get_u32(nla); |
| 1076 | } | 1194 | } |
| 1077 | attr = RTA_NEXT(attr, attrlen); | ||
| 1078 | } | 1195 | } |
| 1079 | } | 1196 | } |
| 1080 | 1197 | ||
| @@ -1086,7 +1203,8 @@ install_route: | |||
| 1086 | 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)); |
| 1087 | rt->u.dst.dev = dev; | 1204 | rt->u.dst.dev = dev; |
| 1088 | rt->rt6i_idev = idev; | 1205 | rt->rt6i_idev = idev; |
| 1089 | return ip6_ins_rt(rt, nlh, _rtattr, req); | 1206 | rt->rt6i_table = table; |
| 1207 | return __ip6_ins_rt(rt, &cfg->fc_nlinfo); | ||
| 1090 | 1208 | ||
| 1091 | out: | 1209 | out: |
| 1092 | if (dev) | 1210 | if (dev) |
| @@ -1098,51 +1216,65 @@ out: | |||
| 1098 | return err; | 1216 | return err; |
| 1099 | } | 1217 | } |
| 1100 | 1218 | ||
| 1101 | 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) |
| 1102 | { | 1220 | { |
| 1103 | int err; | 1221 | int err; |
| 1222 | struct fib6_table *table; | ||
| 1104 | 1223 | ||
| 1105 | write_lock_bh(&rt6_lock); | 1224 | if (rt == &ip6_null_entry) |
| 1225 | return -ENOENT; | ||
| 1106 | 1226 | ||
| 1107 | 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); | ||
| 1108 | dst_release(&rt->u.dst); | 1231 | dst_release(&rt->u.dst); |
| 1109 | 1232 | ||
| 1110 | write_unlock_bh(&rt6_lock); | 1233 | write_unlock_bh(&table->tb6_lock); |
| 1111 | 1234 | ||
| 1112 | return err; | 1235 | return err; |
| 1113 | } | 1236 | } |
| 1114 | 1237 | ||
| 1115 | 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) |
| 1116 | { | 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; | ||
| 1117 | struct fib6_node *fn; | 1246 | struct fib6_node *fn; |
| 1118 | struct rt6_info *rt; | 1247 | struct rt6_info *rt; |
| 1119 | int err = -ESRCH; | 1248 | int err = -ESRCH; |
| 1120 | 1249 | ||
| 1121 | read_lock_bh(&rt6_lock); | 1250 | table = fib6_get_table(cfg->fc_table); |
| 1251 | if (table == NULL) | ||
| 1252 | return err; | ||
| 1122 | 1253 | ||
| 1123 | fn = fib6_locate(&ip6_routing_table, | 1254 | read_lock_bh(&table->tb6_lock); |
| 1124 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, | 1255 | |
| 1125 | &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); | ||
| 1126 | 1259 | ||
| 1127 | if (fn) { | 1260 | if (fn) { |
| 1128 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1261 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
| 1129 | if (rtmsg->rtmsg_ifindex && | 1262 | if (cfg->fc_ifindex && |
| 1130 | (rt->rt6i_dev == NULL || | 1263 | (rt->rt6i_dev == NULL || |
| 1131 | rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex)) | 1264 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) |
| 1132 | continue; | 1265 | continue; |
| 1133 | if (rtmsg->rtmsg_flags&RTF_GATEWAY && | 1266 | if (cfg->fc_flags & RTF_GATEWAY && |
| 1134 | !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway)) | 1267 | !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) |
| 1135 | continue; | 1268 | continue; |
| 1136 | if (rtmsg->rtmsg_metric && | 1269 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
| 1137 | rtmsg->rtmsg_metric != rt->rt6i_metric) | ||
| 1138 | continue; | 1270 | continue; |
| 1139 | dst_hold(&rt->u.dst); | 1271 | dst_hold(&rt->u.dst); |
| 1140 | read_unlock_bh(&rt6_lock); | 1272 | read_unlock_bh(&table->tb6_lock); |
| 1141 | 1273 | ||
| 1142 | return ip6_del_rt(rt, nlh, _rtattr, req); | 1274 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); |
| 1143 | } | 1275 | } |
| 1144 | } | 1276 | } |
| 1145 | read_unlock_bh(&rt6_lock); | 1277 | read_unlock_bh(&table->tb6_lock); |
| 1146 | 1278 | ||
| 1147 | return err; | 1279 | return err; |
| 1148 | } | 1280 | } |
| @@ -1150,11 +1282,17 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r | |||
| 1150 | /* | 1282 | /* |
| 1151 | * Handle redirects | 1283 | * Handle redirects |
| 1152 | */ | 1284 | */ |
| 1153 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1285 | struct ip6rd_flowi { |
| 1154 | 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) | ||
| 1155 | { | 1293 | { |
| 1156 | struct rt6_info *rt, *nrt = NULL; | 1294 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; |
| 1157 | int strict; | 1295 | struct rt6_info *rt; |
| 1158 | struct fib6_node *fn; | 1296 | struct fib6_node *fn; |
| 1159 | 1297 | ||
| 1160 | /* | 1298 | /* |
| @@ -1167,10 +1305,9 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | |||
| 1167 | * 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 |
| 1168 | * routes. | 1306 | * routes. |
| 1169 | */ | 1307 | */ |
| 1170 | strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); | ||
| 1171 | 1308 | ||
| 1172 | read_lock_bh(&rt6_lock); | 1309 | read_lock_bh(&table->tb6_lock); |
| 1173 | fn = fib6_lookup(&ip6_routing_table, dest, NULL); | 1310 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
| 1174 | restart: | 1311 | restart: |
| 1175 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1312 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
| 1176 | /* | 1313 | /* |
| @@ -1185,29 +1322,60 @@ restart: | |||
| 1185 | continue; | 1322 | continue; |
| 1186 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1323 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
| 1187 | continue; | 1324 | continue; |
| 1188 | if (neigh->dev != rt->rt6i_dev) | 1325 | if (fl->oif != rt->rt6i_dev->ifindex) |
| 1189 | continue; | 1326 | continue; |
| 1190 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) | 1327 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
| 1191 | continue; | 1328 | continue; |
| 1192 | break; | 1329 | break; |
| 1193 | } | 1330 | } |
| 1194 | if (rt) | ||
| 1195 | dst_hold(&rt->u.dst); | ||
| 1196 | else if (strict) { | ||
| 1197 | while ((fn = fn->parent) != NULL) { | ||
| 1198 | if (fn->fn_flags & RTN_ROOT) | ||
| 1199 | break; | ||
| 1200 | if (fn->fn_flags & RTN_RTINFO) | ||
| 1201 | goto restart; | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | read_unlock_bh(&rt6_lock); | ||
| 1205 | 1331 | ||
| 1206 | 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) { | ||
| 1207 | if (net_ratelimit()) | 1375 | if (net_ratelimit()) |
| 1208 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1376 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
| 1209 | "for redirect target\n"); | 1377 | "for redirect target\n"); |
| 1210 | return; | 1378 | goto out; |
| 1211 | } | 1379 | } |
| 1212 | 1380 | ||
| 1213 | /* | 1381 | /* |
| @@ -1250,11 +1418,15 @@ restart: | |||
| 1250 | 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); |
| 1251 | 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)); |
| 1252 | 1420 | ||
| 1253 | if (ip6_ins_rt(nrt, NULL, NULL, NULL)) | 1421 | if (ip6_ins_rt(nrt)) |
| 1254 | goto out; | 1422 | goto out; |
| 1255 | 1423 | ||
| 1424 | netevent.old = &rt->u.dst; | ||
| 1425 | netevent.new = &nrt->u.dst; | ||
| 1426 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | ||
| 1427 | |||
| 1256 | if (rt->rt6i_flags&RTF_CACHE) { | 1428 | if (rt->rt6i_flags&RTF_CACHE) { |
| 1257 | ip6_del_rt(rt, NULL, NULL, NULL); | 1429 | ip6_del_rt(rt); |
| 1258 | return; | 1430 | return; |
| 1259 | } | 1431 | } |
| 1260 | 1432 | ||
| @@ -1336,7 +1508,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1336 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | 1508 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); |
| 1337 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | 1509 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; |
| 1338 | 1510 | ||
| 1339 | ip6_ins_rt(nrt, NULL, NULL, NULL); | 1511 | ip6_ins_rt(nrt); |
| 1340 | } | 1512 | } |
| 1341 | out: | 1513 | out: |
| 1342 | dst_release(&rt->u.dst); | 1514 | dst_release(&rt->u.dst); |
| @@ -1372,6 +1544,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
| 1372 | #ifdef CONFIG_IPV6_SUBTREES | 1544 | #ifdef CONFIG_IPV6_SUBTREES |
| 1373 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1545 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
| 1374 | #endif | 1546 | #endif |
| 1547 | rt->rt6i_table = ort->rt6i_table; | ||
| 1375 | } | 1548 | } |
| 1376 | return rt; | 1549 | return rt; |
| 1377 | } | 1550 | } |
| @@ -1382,9 +1555,14 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
| 1382 | { | 1555 | { |
| 1383 | struct fib6_node *fn; | 1556 | struct fib6_node *fn; |
| 1384 | struct rt6_info *rt = NULL; | 1557 | struct rt6_info *rt = NULL; |
| 1558 | struct fib6_table *table; | ||
| 1385 | 1559 | ||
| 1386 | write_lock_bh(&rt6_lock); | 1560 | table = fib6_get_table(RT6_TABLE_INFO); |
| 1387 | fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); | 1561 | if (table == NULL) |
| 1562 | return NULL; | ||
| 1563 | |||
| 1564 | write_lock_bh(&table->tb6_lock); | ||
| 1565 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); | ||
| 1388 | if (!fn) | 1566 | if (!fn) |
| 1389 | goto out; | 1567 | goto out; |
| 1390 | 1568 | ||
| @@ -1399,7 +1577,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
| 1399 | break; | 1577 | break; |
| 1400 | } | 1578 | } |
| 1401 | out: | 1579 | out: |
| 1402 | write_unlock_bh(&rt6_lock); | 1580 | write_unlock_bh(&table->tb6_lock); |
| 1403 | return rt; | 1581 | return rt; |
| 1404 | } | 1582 | } |
| 1405 | 1583 | ||
| @@ -1407,21 +1585,23 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
| 1407 | struct in6_addr *gwaddr, int ifindex, | 1585 | struct in6_addr *gwaddr, int ifindex, |
| 1408 | unsigned pref) | 1586 | unsigned pref) |
| 1409 | { | 1587 | { |
| 1410 | 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); | ||
| 1411 | 1599 | ||
| 1412 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
| 1413 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
| 1414 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
| 1415 | rtmsg.rtmsg_dst_len = prefixlen; | ||
| 1416 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
| 1417 | rtmsg.rtmsg_metric = 1024; | ||
| 1418 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
| 1419 | /* 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. */ |
| 1420 | if (!prefixlen) | 1601 | if (!prefixlen) |
| 1421 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | 1602 | cfg.fc_flags |= RTF_DEFAULT; |
| 1422 | rtmsg.rtmsg_ifindex = ifindex; | ||
| 1423 | 1603 | ||
| 1424 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1604 | ip6_route_add(&cfg); |
| 1425 | 1605 | ||
| 1426 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | 1606 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); |
| 1427 | } | 1607 | } |
| @@ -1430,12 +1610,14 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
| 1430 | 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) |
| 1431 | { | 1611 | { |
| 1432 | struct rt6_info *rt; | 1612 | struct rt6_info *rt; |
| 1433 | struct fib6_node *fn; | 1613 | struct fib6_table *table; |
| 1434 | 1614 | ||
| 1435 | fn = &ip6_routing_table; | 1615 | table = fib6_get_table(RT6_TABLE_DFLT); |
| 1616 | if (table == NULL) | ||
| 1617 | return NULL; | ||
| 1436 | 1618 | ||
| 1437 | write_lock_bh(&rt6_lock); | 1619 | write_lock_bh(&table->tb6_lock); |
| 1438 | for (rt = fn->leaf; rt; rt=rt->u.next) { | 1620 | for (rt = table->tb6_root.leaf; rt; rt=rt->u.next) { |
| 1439 | if (dev == rt->rt6i_dev && | 1621 | if (dev == rt->rt6i_dev && |
| 1440 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1622 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
| 1441 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1623 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
| @@ -1443,7 +1625,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
| 1443 | } | 1625 | } |
| 1444 | if (rt) | 1626 | if (rt) |
| 1445 | dst_hold(&rt->u.dst); | 1627 | dst_hold(&rt->u.dst); |
| 1446 | write_unlock_bh(&rt6_lock); | 1628 | write_unlock_bh(&table->tb6_lock); |
| 1447 | return rt; | 1629 | return rt; |
| 1448 | } | 1630 | } |
| 1449 | 1631 | ||
| @@ -1451,43 +1633,65 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
| 1451 | struct net_device *dev, | 1633 | struct net_device *dev, |
| 1452 | unsigned int pref) | 1634 | unsigned int pref) |
| 1453 | { | 1635 | { |
| 1454 | 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 | }; | ||
| 1455 | 1643 | ||
| 1456 | memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); | 1644 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); |
| 1457 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
| 1458 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
| 1459 | rtmsg.rtmsg_metric = 1024; | ||
| 1460 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | | ||
| 1461 | RTF_PREF(pref); | ||
| 1462 | 1645 | ||
| 1463 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1646 | ip6_route_add(&cfg); |
| 1464 | 1647 | ||
| 1465 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
| 1466 | return rt6_get_dflt_router(gwaddr, dev); | 1648 | return rt6_get_dflt_router(gwaddr, dev); |
| 1467 | } | 1649 | } |
| 1468 | 1650 | ||
| 1469 | void rt6_purge_dflt_routers(void) | 1651 | void rt6_purge_dflt_routers(void) |
| 1470 | { | 1652 | { |
| 1471 | 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; | ||
| 1472 | 1660 | ||
| 1473 | restart: | 1661 | restart: |
| 1474 | read_lock_bh(&rt6_lock); | 1662 | read_lock_bh(&table->tb6_lock); |
| 1475 | for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { | 1663 | for (rt = table->tb6_root.leaf; rt; rt = rt->u.next) { |
| 1476 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1664 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
| 1477 | dst_hold(&rt->u.dst); | 1665 | dst_hold(&rt->u.dst); |
| 1478 | 1666 | read_unlock_bh(&table->tb6_lock); | |
| 1479 | read_unlock_bh(&rt6_lock); | 1667 | ip6_del_rt(rt); |
| 1480 | |||
| 1481 | ip6_del_rt(rt, NULL, NULL, NULL); | ||
| 1482 | |||
| 1483 | goto restart; | 1668 | goto restart; |
| 1484 | } | 1669 | } |
| 1485 | } | 1670 | } |
| 1486 | 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); | ||
| 1487 | } | 1690 | } |
| 1488 | 1691 | ||
| 1489 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | 1692 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) |
| 1490 | { | 1693 | { |
| 1694 | struct fib6_config cfg; | ||
| 1491 | struct in6_rtmsg rtmsg; | 1695 | struct in6_rtmsg rtmsg; |
| 1492 | int err; | 1696 | int err; |
| 1493 | 1697 | ||
| @@ -1500,14 +1704,16 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
| 1500 | sizeof(struct in6_rtmsg)); | 1704 | sizeof(struct in6_rtmsg)); |
| 1501 | if (err) | 1705 | if (err) |
| 1502 | return -EFAULT; | 1706 | return -EFAULT; |
| 1503 | 1707 | ||
| 1708 | rtmsg_to_fib6_config(&rtmsg, &cfg); | ||
| 1709 | |||
| 1504 | rtnl_lock(); | 1710 | rtnl_lock(); |
| 1505 | switch (cmd) { | 1711 | switch (cmd) { |
| 1506 | case SIOCADDRT: | 1712 | case SIOCADDRT: |
| 1507 | err = ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1713 | err = ip6_route_add(&cfg); |
| 1508 | break; | 1714 | break; |
| 1509 | case SIOCDELRT: | 1715 | case SIOCDELRT: |
| 1510 | err = ip6_route_del(&rtmsg, NULL, NULL, NULL); | 1716 | err = ip6_route_del(&cfg); |
| 1511 | break; | 1717 | break; |
| 1512 | default: | 1718 | default: |
| 1513 | err = -EINVAL; | 1719 | err = -EINVAL; |
| @@ -1526,6 +1732,10 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
| 1526 | 1732 | ||
| 1527 | static int ip6_pkt_discard(struct sk_buff *skb) | 1733 | static int ip6_pkt_discard(struct sk_buff *skb) |
| 1528 | { | 1734 | { |
| 1735 | int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); | ||
| 1736 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) | ||
| 1737 | IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS); | ||
| 1738 | |||
| 1529 | IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); | 1739 | IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); |
| 1530 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); | 1740 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); |
| 1531 | kfree_skb(skb); | 1741 | kfree_skb(skb); |
| @@ -1577,6 +1787,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
| 1577 | 1787 | ||
| 1578 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 1788 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
| 1579 | rt->rt6i_dst.plen = 128; | 1789 | rt->rt6i_dst.plen = 128; |
| 1790 | rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL); | ||
| 1580 | 1791 | ||
| 1581 | atomic_set(&rt->u.dst.__refcnt, 1); | 1792 | atomic_set(&rt->u.dst.__refcnt, 1); |
| 1582 | 1793 | ||
| @@ -1595,9 +1806,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) | |||
| 1595 | 1806 | ||
| 1596 | void rt6_ifdown(struct net_device *dev) | 1807 | void rt6_ifdown(struct net_device *dev) |
| 1597 | { | 1808 | { |
| 1598 | write_lock_bh(&rt6_lock); | 1809 | fib6_clean_all(fib6_ifdown, 0, dev); |
| 1599 | fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); | ||
| 1600 | write_unlock_bh(&rt6_lock); | ||
| 1601 | } | 1810 | } |
| 1602 | 1811 | ||
| 1603 | struct rt6_mtu_change_arg | 1812 | struct rt6_mtu_change_arg |
| @@ -1647,80 +1856,114 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
| 1647 | 1856 | ||
| 1648 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) | 1857 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) |
| 1649 | { | 1858 | { |
| 1650 | struct rt6_mtu_change_arg arg; | 1859 | struct rt6_mtu_change_arg arg = { |
| 1860 | .dev = dev, | ||
| 1861 | .mtu = mtu, | ||
| 1862 | }; | ||
| 1651 | 1863 | ||
| 1652 | arg.dev = dev; | 1864 | fib6_clean_all(rt6_mtu_change_route, 0, &arg); |
| 1653 | arg.mtu = mtu; | ||
| 1654 | read_lock_bh(&rt6_lock); | ||
| 1655 | fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg); | ||
| 1656 | read_unlock_bh(&rt6_lock); | ||
| 1657 | } | 1865 | } |
| 1658 | 1866 | ||
| 1659 | 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 = { |
| 1660 | 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) | ||
| 1661 | { | 1877 | { |
| 1662 | memset(rtmsg, 0, sizeof(*rtmsg)); | 1878 | struct rtmsg *rtm; |
| 1879 | struct nlattr *tb[RTA_MAX+1]; | ||
| 1880 | int err; | ||
| 1663 | 1881 | ||
| 1664 | rtmsg->rtmsg_dst_len = r->rtm_dst_len; | 1882 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
| 1665 | rtmsg->rtmsg_src_len = r->rtm_src_len; | 1883 | if (err < 0) |
| 1666 | rtmsg->rtmsg_flags = RTF_UP; | 1884 | goto errout; |
| 1667 | if (r->rtm_type == RTN_UNREACHABLE) | ||
| 1668 | rtmsg->rtmsg_flags |= RTF_REJECT; | ||
| 1669 | 1885 | ||
| 1670 | if (rta[RTA_GATEWAY-1]) { | 1886 | err = -EINVAL; |
| 1671 | if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) | 1887 | rtm = nlmsg_data(nlh); |
| 1672 | return -EINVAL; | 1888 | memset(cfg, 0, sizeof(*cfg)); |
| 1673 | memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16); | 1889 | |
| 1674 | rtmsg->rtmsg_flags |= RTF_GATEWAY; | 1890 | cfg->fc_table = rtm->rtm_table; |
| 1675 | } | 1891 | cfg->fc_dst_len = rtm->rtm_dst_len; |
| 1676 | if (rta[RTA_DST-1]) { | 1892 | cfg->fc_src_len = rtm->rtm_src_len; |
| 1677 | if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3)) | 1893 | cfg->fc_flags = RTF_UP; |
| 1678 | return -EINVAL; | 1894 | cfg->fc_protocol = rtm->rtm_protocol; |
| 1679 | 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; | ||
| 1680 | } | 1905 | } |
| 1681 | if (rta[RTA_SRC-1]) { | 1906 | |
| 1682 | if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3)) | 1907 | if (tb[RTA_DST]) { |
| 1683 | return -EINVAL; | 1908 | int plen = (rtm->rtm_dst_len + 7) >> 3; |
| 1684 | 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); | ||
| 1685 | } | 1914 | } |
| 1686 | if (rta[RTA_OIF-1]) { | 1915 | |
| 1687 | if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int))) | 1916 | if (tb[RTA_SRC]) { |
| 1688 | return -EINVAL; | 1917 | int plen = (rtm->rtm_src_len + 7) >> 3; |
| 1689 | 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); | ||
| 1690 | } | 1923 | } |
| 1691 | if (rta[RTA_PRIORITY-1]) { | 1924 | |
| 1692 | if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4)) | 1925 | if (tb[RTA_OIF]) |
| 1693 | return -EINVAL; | 1926 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
| 1694 | 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]); | ||
| 1695 | } | 1934 | } |
| 1696 | 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; | ||
| 1697 | } | 1942 | } |
| 1698 | 1943 | ||
| 1699 | 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) |
| 1700 | { | 1945 | { |
| 1701 | struct rtmsg *r = NLMSG_DATA(nlh); | 1946 | struct fib6_config cfg; |
| 1702 | struct in6_rtmsg rtmsg; | 1947 | int err; |
| 1703 | 1948 | ||
| 1704 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1949 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
| 1705 | return -EINVAL; | 1950 | if (err < 0) |
| 1706 | return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1951 | return err; |
| 1952 | |||
| 1953 | return ip6_route_del(&cfg); | ||
| 1707 | } | 1954 | } |
| 1708 | 1955 | ||
| 1709 | 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) |
| 1710 | { | 1957 | { |
| 1711 | struct rtmsg *r = NLMSG_DATA(nlh); | 1958 | struct fib6_config cfg; |
| 1712 | struct in6_rtmsg rtmsg; | 1959 | int err; |
| 1713 | 1960 | ||
| 1714 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1961 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
| 1715 | return -EINVAL; | 1962 | if (err < 0) |
| 1716 | return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1963 | return err; |
| 1717 | } | ||
| 1718 | 1964 | ||
| 1719 | struct rt6_rtnl_dump_arg | 1965 | return ip6_route_add(&cfg); |
| 1720 | { | 1966 | } |
| 1721 | struct sk_buff *skb; | ||
| 1722 | struct netlink_callback *cb; | ||
| 1723 | }; | ||
| 1724 | 1967 | ||
| 1725 | 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, |
| 1726 | struct in6_addr *dst, struct in6_addr *src, | 1969 | struct in6_addr *dst, struct in6_addr *src, |
| @@ -1728,9 +1971,9 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
| 1728 | int prefix, unsigned int flags) | 1971 | int prefix, unsigned int flags) |
| 1729 | { | 1972 | { |
| 1730 | struct rtmsg *rtm; | 1973 | struct rtmsg *rtm; |
| 1731 | struct nlmsghdr *nlh; | 1974 | struct nlmsghdr *nlh; |
| 1732 | unsigned char *b = skb->tail; | ||
| 1733 | struct rta_cacheinfo ci; | 1975 | struct rta_cacheinfo ci; |
| 1976 | u32 table; | ||
| 1734 | 1977 | ||
| 1735 | if (prefix) { /* user wants prefix routes only */ | 1978 | if (prefix) { /* user wants prefix routes only */ |
| 1736 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 1979 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
| @@ -1739,13 +1982,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
| 1739 | } | 1982 | } |
| 1740 | } | 1983 | } |
| 1741 | 1984 | ||
| 1742 | nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*rtm), flags); | 1985 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); |
| 1743 | rtm = NLMSG_DATA(nlh); | 1986 | if (nlh == NULL) |
| 1987 | return -ENOBUFS; | ||
| 1988 | |||
| 1989 | rtm = nlmsg_data(nlh); | ||
| 1744 | rtm->rtm_family = AF_INET6; | 1990 | rtm->rtm_family = AF_INET6; |
| 1745 | rtm->rtm_dst_len = rt->rt6i_dst.plen; | 1991 | rtm->rtm_dst_len = rt->rt6i_dst.plen; |
| 1746 | rtm->rtm_src_len = rt->rt6i_src.plen; | 1992 | rtm->rtm_src_len = rt->rt6i_src.plen; |
| 1747 | rtm->rtm_tos = 0; | 1993 | rtm->rtm_tos = 0; |
| 1748 | 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); | ||
| 1749 | if (rt->rt6i_flags&RTF_REJECT) | 2000 | if (rt->rt6i_flags&RTF_REJECT) |
| 1750 | rtm->rtm_type = RTN_UNREACHABLE; | 2001 | rtm->rtm_type = RTN_UNREACHABLE; |
| 1751 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) | 2002 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) |
| @@ -1766,31 +2017,35 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
| 1766 | rtm->rtm_flags |= RTM_F_CLONED; | 2017 | rtm->rtm_flags |= RTM_F_CLONED; |
| 1767 | 2018 | ||
| 1768 | if (dst) { | 2019 | if (dst) { |
| 1769 | RTA_PUT(skb, RTA_DST, 16, dst); | 2020 | NLA_PUT(skb, RTA_DST, 16, dst); |
| 1770 | rtm->rtm_dst_len = 128; | 2021 | rtm->rtm_dst_len = 128; |
| 1771 | } else if (rtm->rtm_dst_len) | 2022 | } else if (rtm->rtm_dst_len) |
| 1772 | RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); | 2023 | NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); |
| 1773 | #ifdef CONFIG_IPV6_SUBTREES | 2024 | #ifdef CONFIG_IPV6_SUBTREES |
| 1774 | if (src) { | 2025 | if (src) { |
| 1775 | RTA_PUT(skb, RTA_SRC, 16, src); | 2026 | NLA_PUT(skb, RTA_SRC, 16, src); |
| 1776 | rtm->rtm_src_len = 128; | 2027 | rtm->rtm_src_len = 128; |
| 1777 | } else if (rtm->rtm_src_len) | 2028 | } else if (rtm->rtm_src_len) |
| 1778 | RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); | 2029 | NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); |
| 1779 | #endif | 2030 | #endif |
| 1780 | if (iif) | 2031 | if (iif) |
| 1781 | RTA_PUT(skb, RTA_IIF, 4, &iif); | 2032 | NLA_PUT_U32(skb, RTA_IIF, iif); |
| 1782 | else if (dst) { | 2033 | else if (dst) { |
| 1783 | struct in6_addr saddr_buf; | 2034 | struct in6_addr saddr_buf; |
| 1784 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) | 2035 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) |
| 1785 | RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2036 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
| 1786 | } | 2037 | } |
| 2038 | |||
| 1787 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2039 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
| 1788 | goto rtattr_failure; | 2040 | goto nla_put_failure; |
| 2041 | |||
| 1789 | if (rt->u.dst.neighbour) | 2042 | if (rt->u.dst.neighbour) |
| 1790 | 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 | |||
| 1791 | if (rt->u.dst.dev) | 2045 | if (rt->u.dst.dev) |
| 1792 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex); | 2046 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
| 1793 | RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric); | 2047 | |
| 2048 | NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); | ||
| 1794 | 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); |
| 1795 | if (rt->rt6i_expires) | 2050 | if (rt->rt6i_expires) |
| 1796 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); | 2051 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); |
| @@ -1802,23 +2057,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
| 1802 | ci.rta_id = 0; | 2057 | ci.rta_id = 0; |
| 1803 | ci.rta_ts = 0; | 2058 | ci.rta_ts = 0; |
| 1804 | ci.rta_tsage = 0; | 2059 | ci.rta_tsage = 0; |
| 1805 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 2060 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
| 1806 | nlh->nlmsg_len = skb->tail - b; | ||
| 1807 | return skb->len; | ||
| 1808 | 2061 | ||
| 1809 | nlmsg_failure: | 2062 | return nlmsg_end(skb, nlh); |
| 1810 | rtattr_failure: | 2063 | |
| 1811 | skb_trim(skb, b - skb->data); | 2064 | nla_put_failure: |
| 1812 | return -1; | 2065 | return nlmsg_cancel(skb, nlh); |
| 1813 | } | 2066 | } |
| 1814 | 2067 | ||
| 1815 | static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | 2068 | int rt6_dump_route(struct rt6_info *rt, void *p_arg) |
| 1816 | { | 2069 | { |
| 1817 | 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; |
| 1818 | int prefix; | 2071 | int prefix; |
| 1819 | 2072 | ||
| 1820 | if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) { | 2073 | if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { |
| 1821 | struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh); | 2074 | struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); |
| 1822 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; | 2075 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; |
| 1823 | } else | 2076 | } else |
| 1824 | prefix = 0; | 2077 | prefix = 0; |
| @@ -1828,189 +2081,108 @@ static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
| 1828 | prefix, NLM_F_MULTI); | 2081 | prefix, NLM_F_MULTI); |
| 1829 | } | 2082 | } |
| 1830 | 2083 | ||
| 1831 | 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) |
| 1832 | { | 2085 | { |
| 1833 | int res; | 2086 | struct nlattr *tb[RTA_MAX+1]; |
| 1834 | 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; | ||
| 1835 | 2092 | ||
| 1836 | for (rt = w->leaf; rt; rt = rt->u.next) { | 2093 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
| 1837 | res = rt6_dump_route(rt, w->args); | 2094 | if (err < 0) |
| 1838 | if (res < 0) { | 2095 | goto errout; |
| 1839 | /* Frame is full, suspend walking */ | ||
| 1840 | w->leaf = rt; | ||
| 1841 | return 1; | ||
| 1842 | } | ||
| 1843 | BUG_TRAP(res!=0); | ||
| 1844 | } | ||
| 1845 | w->leaf = NULL; | ||
| 1846 | return 0; | ||
| 1847 | } | ||
| 1848 | |||
| 1849 | static void fib6_dump_end(struct netlink_callback *cb) | ||
| 1850 | { | ||
| 1851 | struct fib6_walker_t *w = (void*)cb->args[0]; | ||
| 1852 | |||
| 1853 | if (w) { | ||
| 1854 | cb->args[0] = 0; | ||
| 1855 | fib6_walker_unlink(w); | ||
| 1856 | kfree(w); | ||
| 1857 | } | ||
| 1858 | cb->done = (void*)cb->args[1]; | ||
| 1859 | cb->args[1] = 0; | ||
| 1860 | } | ||
| 1861 | |||
| 1862 | static int fib6_dump_done(struct netlink_callback *cb) | ||
| 1863 | { | ||
| 1864 | fib6_dump_end(cb); | ||
| 1865 | return cb->done ? cb->done(cb) : 0; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 1869 | { | ||
| 1870 | struct rt6_rtnl_dump_arg arg; | ||
| 1871 | struct fib6_walker_t *w; | ||
| 1872 | int res; | ||
| 1873 | 2096 | ||
| 1874 | arg.skb = skb; | 2097 | err = -EINVAL; |
| 1875 | arg.cb = cb; | 2098 | memset(&fl, 0, sizeof(fl)); |
| 1876 | 2099 | ||
| 1877 | w = (void*)cb->args[0]; | 2100 | if (tb[RTA_SRC]) { |
| 1878 | if (w == NULL) { | 2101 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
| 1879 | /* New dump: | 2102 | goto errout; |
| 1880 | * | ||
| 1881 | * 1. hook callback destructor. | ||
| 1882 | */ | ||
| 1883 | cb->args[1] = (long)cb->done; | ||
| 1884 | cb->done = fib6_dump_done; | ||
| 1885 | 2103 | ||
| 1886 | /* | 2104 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); |
| 1887 | * 2. allocate and initialize walker. | ||
| 1888 | */ | ||
| 1889 | w = kzalloc(sizeof(*w), GFP_ATOMIC); | ||
| 1890 | if (w == NULL) | ||
| 1891 | return -ENOMEM; | ||
| 1892 | RT6_TRACE("dump<%p", w); | ||
| 1893 | w->root = &ip6_routing_table; | ||
| 1894 | w->func = fib6_dump_node; | ||
| 1895 | w->args = &arg; | ||
| 1896 | cb->args[0] = (long)w; | ||
| 1897 | read_lock_bh(&rt6_lock); | ||
| 1898 | res = fib6_walk(w); | ||
| 1899 | read_unlock_bh(&rt6_lock); | ||
| 1900 | } else { | ||
| 1901 | w->args = &arg; | ||
| 1902 | read_lock_bh(&rt6_lock); | ||
| 1903 | res = fib6_walk_continue(w); | ||
| 1904 | read_unlock_bh(&rt6_lock); | ||
| 1905 | } | 2105 | } |
| 1906 | #if RT6_DEBUG >= 3 | ||
| 1907 | if (res <= 0 && skb->len == 0) | ||
| 1908 | RT6_TRACE("%p>dump end\n", w); | ||
| 1909 | #endif | ||
| 1910 | res = res < 0 ? res : skb->len; | ||
| 1911 | /* res < 0 is an error. (really, impossible) | ||
| 1912 | res == 0 means that dump is complete, but skb still can contain data. | ||
| 1913 | res > 0 dump is not complete, but frame is full. | ||
| 1914 | */ | ||
| 1915 | /* Destroy walker, if dump of this table is complete. */ | ||
| 1916 | if (res <= 0) | ||
| 1917 | fib6_dump_end(cb); | ||
| 1918 | return res; | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | ||
| 1922 | { | ||
| 1923 | struct rtattr **rta = arg; | ||
| 1924 | int iif = 0; | ||
| 1925 | int err = -ENOBUFS; | ||
| 1926 | struct sk_buff *skb; | ||
| 1927 | struct flowi fl; | ||
| 1928 | struct rt6_info *rt; | ||
| 1929 | 2106 | ||
| 1930 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2107 | if (tb[RTA_DST]) { |
| 1931 | if (skb == NULL) | 2108 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
| 1932 | goto out; | 2109 | goto errout; |
| 1933 | 2110 | ||
| 1934 | /* Reserve room for dummy headers, this skb can pass | 2111 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); |
| 1935 | through good chunk of routing engine. | 2112 | } |
| 1936 | */ | ||
| 1937 | skb->mac.raw = skb->data; | ||
| 1938 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
| 1939 | 2113 | ||
| 1940 | memset(&fl, 0, sizeof(fl)); | 2114 | if (tb[RTA_IIF]) |
| 1941 | if (rta[RTA_SRC-1]) | 2115 | iif = nla_get_u32(tb[RTA_IIF]); |
| 1942 | ipv6_addr_copy(&fl.fl6_src, | ||
| 1943 | (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); | ||
| 1944 | if (rta[RTA_DST-1]) | ||
| 1945 | ipv6_addr_copy(&fl.fl6_dst, | ||
| 1946 | (struct in6_addr*)RTA_DATA(rta[RTA_DST-1])); | ||
| 1947 | 2116 | ||
| 1948 | if (rta[RTA_IIF-1]) | 2117 | if (tb[RTA_OIF]) |
| 1949 | memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 2118 | fl.oif = nla_get_u32(tb[RTA_OIF]); |
| 1950 | 2119 | ||
| 1951 | if (iif) { | 2120 | if (iif) { |
| 1952 | struct net_device *dev; | 2121 | struct net_device *dev; |
| 1953 | dev = __dev_get_by_index(iif); | 2122 | dev = __dev_get_by_index(iif); |
| 1954 | if (!dev) { | 2123 | if (!dev) { |
| 1955 | err = -ENODEV; | 2124 | err = -ENODEV; |
| 1956 | goto out_free; | 2125 | goto errout; |
| 1957 | } | 2126 | } |
| 1958 | } | 2127 | } |
| 1959 | 2128 | ||
| 1960 | fl.oif = 0; | 2129 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
| 1961 | if (rta[RTA_OIF-1]) | 2130 | if (skb == NULL) { |
| 1962 | memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 2131 | err = -ENOBUFS; |
| 2132 | goto errout; | ||
| 2133 | } | ||
| 1963 | 2134 | ||
| 1964 | 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)); | ||
| 1965 | 2140 | ||
| 2141 | rt = (struct rt6_info*) ip6_route_output(NULL, &fl); | ||
| 1966 | skb->dst = &rt->u.dst; | 2142 | skb->dst = &rt->u.dst; |
| 1967 | 2143 | ||
| 1968 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | 2144 | err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, |
| 1969 | err = rt6_fill_node(skb, rt, | ||
| 1970 | &fl.fl6_dst, &fl.fl6_src, | ||
| 1971 | iif, | ||
| 1972 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2145 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
| 1973 | nlh->nlmsg_seq, 0, 0); | 2146 | nlh->nlmsg_seq, 0, 0); |
| 1974 | if (err < 0) { | 2147 | if (err < 0) { |
| 1975 | err = -EMSGSIZE; | 2148 | kfree_skb(skb); |
| 1976 | goto out_free; | 2149 | goto errout; |
| 1977 | } | 2150 | } |
| 1978 | 2151 | ||
| 1979 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 2152 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
| 1980 | if (err > 0) | 2153 | errout: |
| 1981 | err = 0; | ||
| 1982 | out: | ||
| 1983 | return err; | 2154 | return err; |
| 1984 | out_free: | ||
| 1985 | kfree_skb(skb); | ||
| 1986 | goto out; | ||
| 1987 | } | 2155 | } |
| 1988 | 2156 | ||
| 1989 | 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) |
| 1990 | struct netlink_skb_parms *req) | ||
| 1991 | { | 2158 | { |
| 1992 | struct sk_buff *skb; | 2159 | struct sk_buff *skb; |
| 1993 | int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); | 2160 | u32 pid = 0, seq = 0; |
| 1994 | u32 pid = current->pid; | 2161 | struct nlmsghdr *nlh = NULL; |
| 1995 | u32 seq = 0; | 2162 | int payload = sizeof(struct rtmsg) + 256; |
| 1996 | 2163 | int err = -ENOBUFS; | |
| 1997 | if (req) | 2164 | |
| 1998 | pid = req->pid; | 2165 | if (info) { |
| 1999 | if (nlh) | 2166 | pid = info->pid; |
| 2000 | seq = nlh->nlmsg_seq; | 2167 | nlh = info->nlh; |
| 2001 | 2168 | if (nlh) | |
| 2002 | skb = alloc_skb(size, gfp_any()); | 2169 | seq = nlh->nlmsg_seq; |
| 2003 | if (!skb) { | ||
| 2004 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, ENOBUFS); | ||
| 2005 | return; | ||
| 2006 | } | 2170 | } |
| 2007 | 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) { | ||
| 2008 | kfree_skb(skb); | 2178 | kfree_skb(skb); |
| 2009 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, EINVAL); | 2179 | goto errout; |
| 2010 | return; | ||
| 2011 | } | 2180 | } |
| 2012 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE; | 2181 | |
| 2013 | 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); | ||
| 2014 | } | 2186 | } |
| 2015 | 2187 | ||
| 2016 | /* | 2188 | /* |
| @@ -2086,16 +2258,13 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
| 2086 | 2258 | ||
| 2087 | 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) |
| 2088 | { | 2260 | { |
| 2089 | struct rt6_proc_arg arg; | 2261 | struct rt6_proc_arg arg = { |
| 2090 | arg.buffer = buffer; | 2262 | .buffer = buffer, |
| 2091 | arg.offset = offset; | 2263 | .offset = offset, |
| 2092 | arg.length = length; | 2264 | .length = length, |
| 2093 | arg.skip = 0; | 2265 | }; |
| 2094 | arg.len = 0; | ||
| 2095 | 2266 | ||
| 2096 | read_lock_bh(&rt6_lock); | 2267 | fib6_clean_all(rt6_info_route, 0, &arg); |
| 2097 | fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg); | ||
| 2098 | read_unlock_bh(&rt6_lock); | ||
| 2099 | 2268 | ||
| 2100 | *start = buffer; | 2269 | *start = buffer; |
| 2101 | if (offset) | 2270 | if (offset) |
| @@ -2250,13 +2419,9 @@ void __init ip6_route_init(void) | |||
| 2250 | { | 2419 | { |
| 2251 | struct proc_dir_entry *p; | 2420 | struct proc_dir_entry *p; |
| 2252 | 2421 | ||
| 2253 | ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", | 2422 | ip6_dst_ops.kmem_cachep = |
| 2254 | sizeof(struct rt6_info), | 2423 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, |
| 2255 | 0, SLAB_HWCACHE_ALIGN, | 2424 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
| 2256 | NULL, NULL); | ||
| 2257 | if (!ip6_dst_ops.kmem_cachep) | ||
| 2258 | panic("cannot create ip6_dst_cache"); | ||
| 2259 | |||
| 2260 | fib6_init(); | 2425 | fib6_init(); |
| 2261 | #ifdef CONFIG_PROC_FS | 2426 | #ifdef CONFIG_PROC_FS |
| 2262 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); | 2427 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); |
| @@ -2268,10 +2433,16 @@ void __init ip6_route_init(void) | |||
| 2268 | #ifdef CONFIG_XFRM | 2433 | #ifdef CONFIG_XFRM |
| 2269 | xfrm6_init(); | 2434 | xfrm6_init(); |
| 2270 | #endif | 2435 | #endif |
| 2436 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
| 2437 | fib6_rules_init(); | ||
| 2438 | #endif | ||
| 2271 | } | 2439 | } |
| 2272 | 2440 | ||
| 2273 | void ip6_route_cleanup(void) | 2441 | void ip6_route_cleanup(void) |
| 2274 | { | 2442 | { |
| 2443 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
| 2444 | fib6_rules_cleanup(); | ||
| 2445 | #endif | ||
| 2275 | #ifdef CONFIG_PROC_FS | 2446 | #ifdef CONFIG_PROC_FS |
| 2276 | proc_net_remove("ipv6_route"); | 2447 | proc_net_remove("ipv6_route"); |
| 2277 | proc_net_remove("rt6_stats"); | 2448 | proc_net_remove("rt6_stats"); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 6578c3080f47..836eecd7e62b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | * Nate Thompson <nate@thebog.net>: 6to4 support | 18 | * Nate Thompson <nate@thebog.net>: 6to4 support |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/config.h> | ||
| 22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 23 | #include <linux/capability.h> | 22 | #include <linux/capability.h> |
| 24 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| @@ -381,7 +380,6 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 381 | secpath_reset(skb); | 380 | secpath_reset(skb); |
| 382 | skb->mac.raw = skb->nh.raw; | 381 | skb->mac.raw = skb->nh.raw; |
| 383 | skb->nh.raw = skb->data; | 382 | skb->nh.raw = skb->data; |
| 384 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
| 385 | IPCB(skb)->flags = 0; | 383 | IPCB(skb)->flags = 0; |
| 386 | skb->protocol = htons(ETH_P_IPV6); | 384 | skb->protocol = htons(ETH_P_IPV6); |
| 387 | skb->pkt_type = PACKET_HOST; | 385 | skb->pkt_type = PACKET_HOST; |
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 8eff9fa1e983..7a4639db1346 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | 7 | ||
| 8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
| 9 | #include <linux/sysctl.h> | 9 | #include <linux/sysctl.h> |
| 10 | #include <linux/config.h> | ||
| 11 | #include <linux/in6.h> | 10 | #include <linux/in6.h> |
| 12 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
| 13 | #include <net/ndisc.h> | 12 | #include <net/ndisc.h> |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a50eb306e9e2..3b6575478fcc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/config.h> | ||
| 30 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| 31 | #include <linux/types.h> | 30 | #include <linux/types.h> |
| 32 | #include <linux/socket.h> | 31 | #include <linux/socket.h> |
| @@ -252,6 +251,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 252 | final_p = &final; | 251 | final_p = &final; |
| 253 | } | 252 | } |
| 254 | 253 | ||
| 254 | security_sk_classify_flow(sk, &fl); | ||
| 255 | |||
| 255 | err = ip6_dst_lookup(sk, &dst, &fl); | 256 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 256 | if (err) | 257 | if (err) |
| 257 | goto failure; | 258 | goto failure; |
| @@ -270,9 +271,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 270 | ipv6_addr_copy(&np->saddr, saddr); | 271 | ipv6_addr_copy(&np->saddr, saddr); |
| 271 | inet->rcv_saddr = LOOPBACK4_IPV6; | 272 | inet->rcv_saddr = LOOPBACK4_IPV6; |
| 272 | 273 | ||
| 273 | ip6_dst_store(sk, dst, NULL); | 274 | sk->sk_gso_type = SKB_GSO_TCPV6; |
| 274 | sk->sk_route_caps = dst->dev->features & | 275 | __ip6_dst_store(sk, dst, NULL, NULL); |
| 275 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 276 | 276 | ||
| 277 | icsk->icsk_ext_hdr_len = 0; | 277 | icsk->icsk_ext_hdr_len = 0; |
| 278 | if (np->opt) | 278 | if (np->opt) |
| @@ -376,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 376 | fl.oif = sk->sk_bound_dev_if; | 376 | fl.oif = sk->sk_bound_dev_if; |
| 377 | fl.fl_ip_dport = inet->dport; | 377 | fl.fl_ip_dport = inet->dport; |
| 378 | fl.fl_ip_sport = inet->sport; | 378 | fl.fl_ip_sport = inet->sport; |
| 379 | security_skb_classify_flow(skb, &fl); | ||
| 379 | 380 | ||
| 380 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 381 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { |
| 381 | sk->sk_err_soft = -err; | 382 | sk->sk_err_soft = -err; |
| @@ -429,7 +430,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 429 | case TCP_SYN_RECV: /* Cannot happen. | 430 | case TCP_SYN_RECV: /* Cannot happen. |
| 430 | It can, it SYNs are crossed. --ANK */ | 431 | It can, it SYNs are crossed. --ANK */ |
| 431 | if (!sock_owned_by_user(sk)) { | 432 | if (!sock_owned_by_user(sk)) { |
| 432 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 433 | sk->sk_err = err; | 433 | sk->sk_err = err; |
| 434 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ | 434 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ |
| 435 | 435 | ||
| @@ -470,6 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 470 | fl.oif = treq->iif; | 470 | fl.oif = treq->iif; |
| 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
| 472 | fl.fl_ip_sport = inet_sk(sk)->sport; | 472 | fl.fl_ip_sport = inet_sk(sk)->sport; |
| 473 | security_req_classify_flow(req, &fl); | ||
| 473 | 474 | ||
| 474 | if (dst == NULL) { | 475 | if (dst == NULL) { |
| 475 | opt = np->opt; | 476 | opt = np->opt; |
| @@ -544,7 +545,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 544 | struct ipv6_pinfo *np = inet6_sk(sk); | 545 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 545 | struct tcphdr *th = skb->h.th; | 546 | struct tcphdr *th = skb->h.th; |
| 546 | 547 | ||
| 547 | if (skb->ip_summed == CHECKSUM_HW) { | 548 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 548 | 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); |
| 549 | skb->csum = offsetof(struct tcphdr, check); | 550 | skb->csum = offsetof(struct tcphdr, check); |
| 550 | } else { | 551 | } else { |
| @@ -554,6 +555,24 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 554 | } | 555 | } |
| 555 | } | 556 | } |
| 556 | 557 | ||
| 558 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | ||
| 559 | { | ||
| 560 | struct ipv6hdr *ipv6h; | ||
| 561 | struct tcphdr *th; | ||
| 562 | |||
| 563 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
| 564 | return -EINVAL; | ||
| 565 | |||
| 566 | ipv6h = skb->nh.ipv6h; | ||
| 567 | th = skb->h.th; | ||
| 568 | |||
| 569 | th->check = 0; | ||
| 570 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 571 | IPPROTO_TCP, 0); | ||
| 572 | skb->csum = offsetof(struct tcphdr, check); | ||
| 573 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 574 | return 0; | ||
| 575 | } | ||
| 557 | 576 | ||
| 558 | static void tcp_v6_send_reset(struct sk_buff *skb) | 577 | static void tcp_v6_send_reset(struct sk_buff *skb) |
| 559 | { | 578 | { |
| @@ -610,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) | |||
| 610 | fl.oif = inet6_iif(skb); | 629 | fl.oif = inet6_iif(skb); |
| 611 | fl.fl_ip_dport = t1->dest; | 630 | fl.fl_ip_dport = t1->dest; |
| 612 | fl.fl_ip_sport = t1->source; | 631 | fl.fl_ip_sport = t1->source; |
| 632 | security_skb_classify_flow(skb, &fl); | ||
| 613 | 633 | ||
| 614 | /* sk = NULL, but it is safe for now. RST socket required. */ | 634 | /* sk = NULL, but it is safe for now. RST socket required. */ |
| 615 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 635 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
| @@ -676,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
| 676 | fl.oif = inet6_iif(skb); | 696 | fl.oif = inet6_iif(skb); |
| 677 | fl.fl_ip_dport = t1->dest; | 697 | fl.fl_ip_dport = t1->dest; |
| 678 | fl.fl_ip_sport = t1->source; | 698 | fl.fl_ip_sport = t1->source; |
| 699 | security_skb_classify_flow(skb, &fl); | ||
| 679 | 700 | ||
| 680 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 701 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
| 681 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 702 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
| @@ -805,6 +826,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 805 | 826 | ||
| 806 | tcp_rsk(req)->snt_isn = isn; | 827 | tcp_rsk(req)->snt_isn = isn; |
| 807 | 828 | ||
| 829 | security_inet_conn_request(sk, skb, req); | ||
| 830 | |||
| 808 | if (tcp_v6_send_synack(sk, req, NULL)) | 831 | if (tcp_v6_send_synack(sk, req, NULL)) |
| 809 | goto drop; | 832 | goto drop; |
| 810 | 833 | ||
| @@ -815,7 +838,6 @@ drop: | |||
| 815 | if (req) | 838 | if (req) |
| 816 | reqsk_free(req); | 839 | reqsk_free(req); |
| 817 | 840 | ||
| 818 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 819 | return 0; /* don't send reset */ | 841 | return 0; /* don't send reset */ |
| 820 | } | 842 | } |
| 821 | 843 | ||
| @@ -909,6 +931,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 909 | fl.oif = sk->sk_bound_dev_if; | 931 | fl.oif = sk->sk_bound_dev_if; |
| 910 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 932 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
| 911 | fl.fl_ip_sport = inet_sk(sk)->sport; | 933 | fl.fl_ip_sport = inet_sk(sk)->sport; |
| 934 | security_req_classify_flow(req, &fl); | ||
| 912 | 935 | ||
| 913 | if (ip6_dst_lookup(sk, &dst, &fl)) | 936 | if (ip6_dst_lookup(sk, &dst, &fl)) |
| 914 | goto out; | 937 | goto out; |
| @@ -930,9 +953,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 930 | * comment in that function for the gory details. -acme | 953 | * comment in that function for the gory details. -acme |
| 931 | */ | 954 | */ |
| 932 | 955 | ||
| 933 | ip6_dst_store(newsk, dst, NULL); | 956 | newsk->sk_gso_type = SKB_GSO_TCPV6; |
| 934 | newsk->sk_route_caps = dst->dev->features & | 957 | __ip6_dst_store(newsk, dst, NULL, NULL); |
| 935 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | ||
| 936 | 958 | ||
| 937 | newtcp6sk = (struct tcp6_sock *)newsk; | 959 | newtcp6sk = (struct tcp6_sock *)newsk; |
| 938 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 960 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
| @@ -1011,7 +1033,7 @@ out: | |||
| 1011 | 1033 | ||
| 1012 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1034 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
| 1013 | { | 1035 | { |
| 1014 | if (skb->ip_summed == CHECKSUM_HW) { | 1036 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| 1015 | 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, |
| 1016 | &skb->nh.ipv6h->daddr,skb->csum)) { | 1038 | &skb->nh.ipv6h->daddr,skb->csum)) { |
| 1017 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1039 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| @@ -1053,7 +1075,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 1053 | if (skb->protocol == htons(ETH_P_IP)) | 1075 | if (skb->protocol == htons(ETH_P_IP)) |
| 1054 | return tcp_v4_do_rcv(sk, skb); | 1076 | return tcp_v4_do_rcv(sk, skb); |
| 1055 | 1077 | ||
| 1056 | if (sk_filter(sk, skb, 0)) | 1078 | if (sk_filter(sk, skb)) |
| 1057 | goto discard; | 1079 | goto discard; |
| 1058 | 1080 | ||
| 1059 | /* | 1081 | /* |
| @@ -1210,12 +1232,12 @@ process: | |||
| 1210 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1232 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1211 | goto discard_and_relse; | 1233 | goto discard_and_relse; |
| 1212 | 1234 | ||
| 1213 | if (sk_filter(sk, skb, 0)) | 1235 | if (sk_filter(sk, skb)) |
| 1214 | goto discard_and_relse; | 1236 | goto discard_and_relse; |
| 1215 | 1237 | ||
| 1216 | skb->dev = NULL; | 1238 | skb->dev = NULL; |
| 1217 | 1239 | ||
| 1218 | bh_lock_sock(sk); | 1240 | bh_lock_sock_nested(sk); |
| 1219 | ret = 0; | 1241 | ret = 0; |
| 1220 | if (!sock_owned_by_user(sk)) { | 1242 | if (!sock_owned_by_user(sk)) { |
| 1221 | #ifdef CONFIG_NET_DMA | 1243 | #ifdef CONFIG_NET_DMA |
| @@ -1469,7 +1491,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
| 1469 | dest->s6_addr32[0], dest->s6_addr32[1], | 1491 | dest->s6_addr32[0], dest->s6_addr32[1], |
| 1470 | dest->s6_addr32[2], dest->s6_addr32[3], destp, | 1492 | dest->s6_addr32[2], dest->s6_addr32[3], destp, |
| 1471 | sp->sk_state, | 1493 | sp->sk_state, |
| 1472 | tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, | 1494 | tp->write_seq-tp->snd_una, |
| 1495 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), | ||
| 1473 | timer_active, | 1496 | timer_active, |
| 1474 | jiffies_to_clock_t(timer_expires - jiffies), | 1497 | jiffies_to_clock_t(timer_expires - jiffies), |
| 1475 | icsk->icsk_retransmits, | 1498 | icsk->icsk_retransmits, |
| @@ -1605,6 +1628,8 @@ struct proto tcpv6_prot = { | |||
| 1605 | static struct inet6_protocol tcpv6_protocol = { | 1628 | static struct inet6_protocol tcpv6_protocol = { |
| 1606 | .handler = tcp_v6_rcv, | 1629 | .handler = tcp_v6_rcv, |
| 1607 | .err_handler = tcp_v6_err, | 1630 | .err_handler = tcp_v6_err, |
| 1631 | .gso_send_check = tcp_v6_gso_send_check, | ||
| 1632 | .gso_segment = tcp_tso_segment, | ||
| 1608 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 1633 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
| 1609 | }; | 1634 | }; |
| 1610 | 1635 | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8d3432a70f3a..9662561701d1 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | * 2 of the License, or (at your option) any later version. | 23 | * 2 of the License, or (at your option) any later version. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/config.h> | ||
| 27 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
| 28 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 29 | #include <linux/socket.h> | 28 | #include <linux/socket.h> |
| @@ -62,81 +61,9 @@ | |||
| 62 | 61 | ||
| 63 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
| 64 | 63 | ||
| 65 | /* 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) |
| 66 | * to add some silly "cookie" argument to this method just for that. | ||
| 67 | */ | ||
| 68 | static int udp_v6_get_port(struct sock *sk, unsigned short snum) | ||
| 69 | { | 65 | { |
| 70 | struct sock *sk2; | 66 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
| 71 | struct hlist_node *node; | ||
| 72 | |||
| 73 | write_lock_bh(&udp_hash_lock); | ||
| 74 | if (snum == 0) { | ||
| 75 | int best_size_so_far, best, result, i; | ||
| 76 | |||
| 77 | if (udp_port_rover > sysctl_local_port_range[1] || | ||
| 78 | udp_port_rover < sysctl_local_port_range[0]) | ||
| 79 | udp_port_rover = sysctl_local_port_range[0]; | ||
| 80 | best_size_so_far = 32767; | ||
| 81 | best = result = udp_port_rover; | ||
| 82 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | ||
| 83 | int size; | ||
| 84 | struct hlist_head *list; | ||
| 85 | |||
| 86 | list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | ||
| 87 | if (hlist_empty(list)) { | ||
| 88 | if (result > sysctl_local_port_range[1]) | ||
| 89 | result = sysctl_local_port_range[0] + | ||
| 90 | ((result - sysctl_local_port_range[0]) & | ||
| 91 | (UDP_HTABLE_SIZE - 1)); | ||
| 92 | goto gotit; | ||
| 93 | } | ||
| 94 | size = 0; | ||
| 95 | sk_for_each(sk2, node, list) | ||
| 96 | if (++size >= best_size_so_far) | ||
| 97 | goto next; | ||
| 98 | best_size_so_far = size; | ||
| 99 | best = result; | ||
| 100 | next:; | ||
| 101 | } | ||
| 102 | result = best; | ||
| 103 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { | ||
| 104 | if (result > sysctl_local_port_range[1]) | ||
| 105 | result = sysctl_local_port_range[0] | ||
| 106 | + ((result - sysctl_local_port_range[0]) & | ||
| 107 | (UDP_HTABLE_SIZE - 1)); | ||
| 108 | if (!udp_lport_inuse(result)) | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | ||
| 112 | goto fail; | ||
| 113 | gotit: | ||
| 114 | udp_port_rover = snum = result; | ||
| 115 | } else { | ||
| 116 | sk_for_each(sk2, node, | ||
| 117 | &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) { | ||
| 118 | if (inet_sk(sk2)->num == snum && | ||
| 119 | sk2 != sk && | ||
| 120 | (!sk2->sk_bound_dev_if || | ||
| 121 | !sk->sk_bound_dev_if || | ||
| 122 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | ||
| 123 | (!sk2->sk_reuse || !sk->sk_reuse) && | ||
| 124 | ipv6_rcv_saddr_equal(sk, sk2)) | ||
| 125 | goto fail; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | inet_sk(sk)->num = snum; | ||
| 130 | if (sk_unhashed(sk)) { | ||
| 131 | sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]); | ||
| 132 | sock_prot_inc_use(sk->sk_prot); | ||
| 133 | } | ||
| 134 | write_unlock_bh(&udp_hash_lock); | ||
| 135 | return 0; | ||
| 136 | |||
| 137 | fail: | ||
| 138 | write_unlock_bh(&udp_hash_lock); | ||
| 139 | return 1; | ||
| 140 | } | 67 | } |
| 141 | 68 | ||
| 142 | static void udp_v6_hash(struct sock *sk) | 69 | static void udp_v6_hash(struct sock *sk) |
| @@ -346,6 +273,8 @@ out: | |||
| 346 | 273 | ||
| 347 | 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) |
| 348 | { | 275 | { |
| 276 | int rc; | ||
| 277 | |||
| 349 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { | 278 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { |
| 350 | kfree_skb(skb); | 279 | kfree_skb(skb); |
| 351 | return -1; | 280 | return -1; |
| @@ -357,7 +286,10 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
| 357 | return 0; | 286 | return 0; |
| 358 | } | 287 | } |
| 359 | 288 | ||
| 360 | 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); | ||
| 361 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 293 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); |
| 362 | kfree_skb(skb); | 294 | kfree_skb(skb); |
| 363 | return 0; | 295 | return 0; |
| @@ -476,7 +408,7 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
| 476 | uh = skb->h.uh; | 408 | uh = skb->h.uh; |
| 477 | } | 409 | } |
| 478 | 410 | ||
| 479 | if (skb->ip_summed == CHECKSUM_HW && | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE && |
| 480 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | 412 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) |
| 481 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 413 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 482 | 414 | ||
| @@ -783,7 +715,9 @@ do_udp_sendmsg: | |||
| 783 | connected = 0; | 715 | connected = 0; |
| 784 | } | 716 | } |
| 785 | 717 | ||
| 786 | err = ip6_dst_lookup(sk, &dst, fl); | 718 | security_sk_classify_flow(sk, fl); |
| 719 | |||
| 720 | err = ip6_sk_dst_lookup(sk, &dst, fl); | ||
| 787 | if (err) | 721 | if (err) |
| 788 | goto out; | 722 | goto out; |
| 789 | if (final_p) | 723 | if (final_p) |
| @@ -841,7 +775,12 @@ do_append_data: | |||
| 841 | if (connected) { | 775 | if (connected) { |
| 842 | ip6_dst_store(sk, dst, | 776 | ip6_dst_store(sk, dst, |
| 843 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? | 777 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? |
| 844 | &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); | ||
| 845 | } else { | 784 | } else { |
| 846 | dst_release(dst); | 785 | dst_release(dst); |
| 847 | } | 786 | } |
| @@ -856,6 +795,16 @@ out: | |||
| 856 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 795 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); |
| 857 | return len; | 796 | return len; |
| 858 | } | 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 | } | ||
| 859 | return err; | 808 | return err; |
| 860 | 809 | ||
| 861 | do_confirm: | 810 | do_confirm: |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 0405d74ff910..5c8b7a568800 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
| @@ -16,10 +16,10 @@ | |||
| 16 | #include <net/ipv6.h> | 16 | #include <net/ipv6.h> |
| 17 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
| 18 | 18 | ||
| 19 | int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | 19 | int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) |
| 20 | { | 20 | { |
| 21 | int err; | 21 | int err; |
| 22 | u32 seq; | 22 | __be32 seq; |
| 23 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | 23 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; |
| 24 | struct xfrm_state *x; | 24 | struct xfrm_state *x; |
| 25 | int xfrm_nr = 0; | 25 | int xfrm_nr = 0; |
| @@ -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 48fccb1eca08..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; |
| @@ -122,10 +130,10 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
| 122 | { | 130 | { |
| 123 | struct sk_buff *segs; | 131 | struct sk_buff *segs; |
| 124 | 132 | ||
| 125 | if (!skb_shinfo(skb)->gso_size) | 133 | if (!skb_is_gso(skb)) |
| 126 | return xfrm6_output_finish2(skb); | 134 | return xfrm6_output_finish2(skb); |
| 127 | 135 | ||
| 128 | skb->protocol = htons(ETH_P_IP); | 136 | skb->protocol = htons(ETH_P_IPV6); |
| 129 | segs = skb_gso_segment(skb, 0); | 137 | segs = skb_gso_segment(skb, 0); |
| 130 | kfree_skb(skb); | 138 | kfree_skb(skb); |
| 131 | if (unlikely(IS_ERR(segs))) | 139 | if (unlikely(IS_ERR(segs))) |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index ee715f2691e9..6a252e2134d1 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -12,13 +12,15 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/compiler.h> | 14 | #include <linux/compiler.h> |
| 15 | #include <linux/config.h> | ||
| 16 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 17 | #include <net/addrconf.h> | 16 | #include <net/addrconf.h> |
| 18 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
| 19 | #include <net/ip.h> | 18 | #include <net/ip.h> |
| 20 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
| 21 | #include <net/ip6_route.h> | 20 | #include <net/ip6_route.h> |
| 21 | #ifdef CONFIG_IPV6_MIP6 | ||
| 22 | #include <net/mip6.h> | ||
| 23 | #endif | ||
| 22 | 24 | ||
| 23 | static struct dst_ops xfrm6_dst_ops; | 25 | static struct dst_ops xfrm6_dst_ops; |
| 24 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 26 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
| @@ -32,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) | |||
| 32 | return err; | 34 | return err; |
| 33 | } | 35 | } |
| 34 | 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 | |||
| 35 | static struct dst_entry * | 57 | static struct dst_entry * |
| 36 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | 58 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) |
| 37 | { | 59 | { |
| @@ -51,7 +73,9 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
| 51 | xdst->u.rt6.rt6i_src.plen); | 73 | xdst->u.rt6.rt6i_src.plen); |
| 52 | 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) && |
| 53 | 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) && |
| 54 | 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))) { | ||
| 55 | dst_clone(dst); | 79 | dst_clone(dst); |
| 56 | break; | 80 | break; |
| 57 | } | 81 | } |
| @@ -60,6 +84,40 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
| 60 | return dst; | 84 | return dst; |
| 61 | } | 85 | } |
| 62 | 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 | |||
| 63 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 121 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate |
| 64 | * all the metrics... Shortly, bundle a bundle. | 122 | * all the metrics... Shortly, bundle a bundle. |
| 65 | */ | 123 | */ |
| @@ -84,6 +142,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
| 84 | int i; | 142 | int i; |
| 85 | int err = 0; | 143 | int err = 0; |
| 86 | int header_len = 0; | 144 | int header_len = 0; |
| 145 | int nfheader_len = 0; | ||
| 87 | int trailer_len = 0; | 146 | int trailer_len = 0; |
| 88 | 147 | ||
| 89 | dst = dst_prev = NULL; | 148 | dst = dst_prev = NULL; |
| @@ -110,17 +169,18 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
| 110 | 169 | ||
| 111 | xdst = (struct xfrm_dst *)dst1; | 170 | xdst = (struct xfrm_dst *)dst1; |
| 112 | xdst->route = &rt->u.dst; | 171 | xdst->route = &rt->u.dst; |
| 172 | xdst->genid = xfrm[i]->genid; | ||
| 113 | if (rt->rt6i_node) | 173 | if (rt->rt6i_node) |
| 114 | xdst->route_cookie = rt->rt6i_node->fn_sernum; | 174 | xdst->route_cookie = rt->rt6i_node->fn_sernum; |
| 115 | 175 | ||
| 116 | dst1->next = dst_prev; | 176 | dst1->next = dst_prev; |
| 117 | dst_prev = dst1; | 177 | dst_prev = dst1; |
| 118 | if (xfrm[i]->props.mode) { | 178 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
| 119 | remote = (struct in6_addr*)&xfrm[i]->id.daddr; | 179 | remote = __xfrm6_bundle_addr_remote(xfrm[i], remote); |
| 120 | local = (struct in6_addr*)&xfrm[i]->props.saddr; | 180 | local = __xfrm6_bundle_addr_local(xfrm[i], local); |
| 121 | tunnel = 1; | 181 | tunnel = 1; |
| 122 | } | 182 | } |
| 123 | header_len += xfrm[i]->props.header_len; | 183 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); |
| 124 | trailer_len += xfrm[i]->props.trailer_len; | 184 | trailer_len += xfrm[i]->props.trailer_len; |
| 125 | 185 | ||
| 126 | if (tunnel) { | 186 | if (tunnel) { |
| @@ -155,6 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
| 155 | dst_prev->flags |= DST_HOST; | 215 | dst_prev->flags |= DST_HOST; |
| 156 | dst_prev->lastuse = jiffies; | 216 | dst_prev->lastuse = jiffies; |
| 157 | dst_prev->header_len = header_len; | 217 | dst_prev->header_len = header_len; |
| 218 | dst_prev->nfheader_len = nfheader_len; | ||
| 158 | dst_prev->trailer_len = trailer_len; | 219 | dst_prev->trailer_len = trailer_len; |
| 159 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | 220 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); |
| 160 | 221 | ||
| @@ -173,7 +234,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
| 173 | x->u.rt6.rt6i_src = rt0->rt6i_src; | 234 | x->u.rt6.rt6i_src = rt0->rt6i_src; |
| 174 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; | 235 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; |
| 175 | in6_dev_hold(rt0->rt6i_idev); | 236 | in6_dev_hold(rt0->rt6i_idev); |
| 176 | header_len -= x->u.dst.xfrm->props.header_len; | 237 | __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm); |
| 177 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | 238 | trailer_len -= x->u.dst.xfrm->props.trailer_len; |
| 178 | } | 239 | } |
| 179 | 240 | ||
| @@ -233,6 +294,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) | |||
| 233 | fl->proto = nexthdr; | 294 | fl->proto = nexthdr; |
| 234 | return; | 295 | return; |
| 235 | 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 | |||
| 236 | /* XXX Why are there these headers? */ | 309 | /* XXX Why are there these headers? */ |
| 237 | case IPPROTO_AH: | 310 | case IPPROTO_AH: |
| 238 | case IPPROTO_ESP: | 311 | case IPPROTO_ESP: |
| @@ -309,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
| 309 | .family = AF_INET6, | 382 | .family = AF_INET6, |
| 310 | .dst_ops = &xfrm6_dst_ops, | 383 | .dst_ops = &xfrm6_dst_ops, |
| 311 | .dst_lookup = xfrm6_dst_lookup, | 384 | .dst_lookup = xfrm6_dst_lookup, |
| 385 | .get_saddr = xfrm6_get_saddr, | ||
| 312 | .find_bundle = __xfrm6_find_bundle, | 386 | .find_bundle = __xfrm6_find_bundle, |
| 313 | .bundle_create = __xfrm6_bundle_create, | 387 | .bundle_create = __xfrm6_bundle_create, |
| 314 | .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..9ddaa9d41539 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
| @@ -29,9 +29,9 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
| 29 | ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); | 29 | ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); |
| 30 | ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); | 30 | ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); |
| 31 | x->sel.dport = xfrm_flowi_dport(fl); | 31 | x->sel.dport = xfrm_flowi_dport(fl); |
| 32 | x->sel.dport_mask = ~0; | 32 | x->sel.dport_mask = htons(0xffff); |
| 33 | x->sel.sport = xfrm_flowi_sport(fl); | 33 | x->sel.sport = xfrm_flowi_sport(fl); |
| 34 | x->sel.sport_mask = ~0; | 34 | x->sel.sport_mask = htons(0xffff); |
| 35 | x->sel.prefixlen_d = 128; | 35 | x->sel.prefixlen_d = 128; |
| 36 | x->sel.prefixlen_s = 128; | 36 | x->sel.prefixlen_s = 128; |
| 37 | x->sel.proto = fl->proto; | 37 | x->sel.proto = fl->proto; |
| @@ -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 d37768e5064f..7af227bb1551 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | * Based on net/ipv4/xfrm4_tunnel.c | 21 | * Based on net/ipv4/xfrm4_tunnel.c |
| 22 | * | 22 | * |
| 23 | */ | 23 | */ |
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 26 | #include <linux/xfrm.h> | 25 | #include <linux/xfrm.h> |
| 27 | #include <linux/list.h> | 26 | #include <linux/list.h> |
| @@ -32,27 +31,6 @@ | |||
| 32 | #include <linux/icmpv6.h> | 31 | #include <linux/icmpv6.h> |
| 33 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
| 34 | 33 | ||
| 35 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG | ||
| 36 | # define X6TDEBUG 3 | ||
| 37 | #else | ||
| 38 | # define X6TDEBUG 1 | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #define X6TPRINTK(fmt, args...) printk(fmt, ## args) | ||
| 42 | #define X6TNOPRINTK(fmt, args...) do { ; } while(0) | ||
| 43 | |||
| 44 | #if X6TDEBUG >= 1 | ||
| 45 | # define X6TPRINTK1 X6TPRINTK | ||
| 46 | #else | ||
| 47 | # define X6TPRINTK1 X6TNOPRINTK | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #if X6TDEBUG >= 3 | ||
| 51 | # define X6TPRINTK3 X6TPRINTK | ||
| 52 | #else | ||
| 53 | # define X6TPRINTK3 X6TNOPRINTK | ||
| 54 | #endif | ||
| 55 | |||
| 56 | /* | 34 | /* |
| 57 | * xfrm_tunnel_spi things are for allocating unique id ("spi") | 35 | * xfrm_tunnel_spi things are for allocating unique id ("spi") |
| 58 | * per xfrm_address_t. | 36 | * per xfrm_address_t. |
| @@ -63,15 +41,8 @@ struct xfrm6_tunnel_spi { | |||
| 63 | xfrm_address_t addr; | 41 | xfrm_address_t addr; |
| 64 | u32 spi; | 42 | u32 spi; |
| 65 | atomic_t refcnt; | 43 | atomic_t refcnt; |
| 66 | #ifdef XFRM6_TUNNEL_SPI_MAGIC | ||
| 67 | u32 magic; | ||
| 68 | #endif | ||
| 69 | }; | 44 | }; |
| 70 | 45 | ||
| 71 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG | ||
| 72 | # define XFRM6_TUNNEL_SPI_MAGIC 0xdeadbeef | ||
| 73 | #endif | ||
| 74 | |||
| 75 | static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); | 46 | static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); |
| 76 | 47 | ||
| 77 | static u32 xfrm6_tunnel_spi; | 48 | static u32 xfrm6_tunnel_spi; |
| @@ -87,43 +58,15 @@ static kmem_cache_t *xfrm6_tunnel_spi_kmem __read_mostly; | |||
| 87 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | 58 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; |
| 88 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | 59 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; |
| 89 | 60 | ||
| 90 | #ifdef XFRM6_TUNNEL_SPI_MAGIC | ||
| 91 | static int x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi, | ||
| 92 | const char *name) | ||
| 93 | { | ||
| 94 | if (unlikely(x6spi->magic != XFRM6_TUNNEL_SPI_MAGIC)) { | ||
| 95 | X6TPRINTK3(KERN_DEBUG "%s(): x6spi object " | ||
| 96 | "at %p has corrupted magic %08x " | ||
| 97 | "(should be %08x)\n", | ||
| 98 | name, x6spi, x6spi->magic, XFRM6_TUNNEL_SPI_MAGIC); | ||
| 99 | return -1; | ||
| 100 | } | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | #else | ||
| 104 | static int inline x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi, | ||
| 105 | const char *name) | ||
| 106 | { | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | #endif | ||
| 110 | |||
| 111 | #define X6SPI_CHECK_MAGIC(x6spi) x6spi_check_magic((x6spi), __FUNCTION__) | ||
| 112 | |||
| 113 | |||
| 114 | static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 61 | static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
| 115 | { | 62 | { |
| 116 | unsigned h; | 63 | unsigned h; |
| 117 | 64 | ||
| 118 | X6TPRINTK3(KERN_DEBUG "%s(addr=%p)\n", __FUNCTION__, addr); | ||
| 119 | |||
| 120 | h = addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]; | 65 | h = addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]; |
| 121 | h ^= h >> 16; | 66 | h ^= h >> 16; |
| 122 | h ^= h >> 8; | 67 | h ^= h >> 8; |
| 123 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; | 68 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; |
| 124 | 69 | ||
| 125 | X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, h); | ||
| 126 | |||
| 127 | return h; | 70 | return h; |
| 128 | } | 71 | } |
| 129 | 72 | ||
| @@ -137,19 +80,13 @@ static int xfrm6_tunnel_spi_init(void) | |||
| 137 | { | 80 | { |
| 138 | int i; | 81 | int i; |
| 139 | 82 | ||
| 140 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); | ||
| 141 | |||
| 142 | xfrm6_tunnel_spi = 0; | 83 | xfrm6_tunnel_spi = 0; |
| 143 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", | 84 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", |
| 144 | sizeof(struct xfrm6_tunnel_spi), | 85 | sizeof(struct xfrm6_tunnel_spi), |
| 145 | 0, SLAB_HWCACHE_ALIGN, | 86 | 0, SLAB_HWCACHE_ALIGN, |
| 146 | NULL, NULL); | 87 | NULL, NULL); |
| 147 | if (!xfrm6_tunnel_spi_kmem) { | 88 | if (!xfrm6_tunnel_spi_kmem) |
| 148 | X6TPRINTK1(KERN_ERR | ||
| 149 | "%s(): failed to allocate xfrm6_tunnel_spi_kmem\n", | ||
| 150 | __FUNCTION__); | ||
| 151 | return -ENOMEM; | 89 | return -ENOMEM; |
| 152 | } | ||
| 153 | 90 | ||
| 154 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | 91 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) |
| 155 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); | 92 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); |
| @@ -162,22 +99,16 @@ static void xfrm6_tunnel_spi_fini(void) | |||
| 162 | { | 99 | { |
| 163 | int i; | 100 | int i; |
| 164 | 101 | ||
| 165 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); | ||
| 166 | |||
| 167 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { | 102 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { |
| 168 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) | 103 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) |
| 169 | goto err; | 104 | return; |
| 170 | } | 105 | } |
| 171 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { | 106 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { |
| 172 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | 107 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) |
| 173 | goto err; | 108 | return; |
| 174 | } | 109 | } |
| 175 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | 110 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); |
| 176 | xfrm6_tunnel_spi_kmem = NULL; | 111 | xfrm6_tunnel_spi_kmem = NULL; |
| 177 | return; | ||
| 178 | err: | ||
| 179 | X6TPRINTK1(KERN_ERR "%s(): table is not empty\n", __FUNCTION__); | ||
| 180 | return; | ||
| 181 | } | 112 | } |
| 182 | 113 | ||
| 183 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | 114 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) |
| @@ -185,19 +116,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 185 | struct xfrm6_tunnel_spi *x6spi; | 116 | struct xfrm6_tunnel_spi *x6spi; |
| 186 | struct hlist_node *pos; | 117 | struct hlist_node *pos; |
| 187 | 118 | ||
| 188 | X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); | ||
| 189 | |||
| 190 | hlist_for_each_entry(x6spi, pos, | 119 | hlist_for_each_entry(x6spi, pos, |
| 191 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 120 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
| 192 | list_byaddr) { | 121 | list_byaddr) { |
| 193 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 122 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
| 194 | X6SPI_CHECK_MAGIC(x6spi); | ||
| 195 | X6TPRINTK3(KERN_DEBUG "%s() = %p(%u)\n", __FUNCTION__, x6spi, x6spi->spi); | ||
| 196 | return x6spi; | 123 | return x6spi; |
| 197 | } | ||
| 198 | } | 124 | } |
| 199 | 125 | ||
| 200 | X6TPRINTK3(KERN_DEBUG "%s() = NULL(0)\n", __FUNCTION__); | ||
| 201 | return NULL; | 126 | return NULL; |
| 202 | } | 127 | } |
| 203 | 128 | ||
| @@ -206,8 +131,6 @@ u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 206 | struct xfrm6_tunnel_spi *x6spi; | 131 | struct xfrm6_tunnel_spi *x6spi; |
| 207 | u32 spi; | 132 | u32 spi; |
| 208 | 133 | ||
| 209 | X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); | ||
| 210 | |||
| 211 | read_lock_bh(&xfrm6_tunnel_spi_lock); | 134 | read_lock_bh(&xfrm6_tunnel_spi_lock); |
| 212 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 135 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); |
| 213 | spi = x6spi ? x6spi->spi : 0; | 136 | spi = x6spi ? x6spi->spi : 0; |
| @@ -224,8 +147,6 @@ static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | |||
| 224 | struct hlist_node *pos; | 147 | struct hlist_node *pos; |
| 225 | unsigned index; | 148 | unsigned index; |
| 226 | 149 | ||
| 227 | X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); | ||
| 228 | |||
| 229 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || | 150 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || |
| 230 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) | 151 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) |
| 231 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; | 152 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; |
| @@ -259,18 +180,10 @@ try_next_2:; | |||
| 259 | spi = 0; | 180 | spi = 0; |
| 260 | goto out; | 181 | goto out; |
| 261 | alloc_spi: | 182 | alloc_spi: |
| 262 | X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for " NIP6_FMT "\n", | ||
| 263 | __FUNCTION__, | ||
| 264 | NIP6(*(struct in6_addr *)saddr)); | ||
| 265 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC); | 183 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC); |
| 266 | if (!x6spi) { | 184 | if (!x6spi) |
| 267 | X6TPRINTK1(KERN_ERR "%s(): kmem_cache_alloc() failed\n", | ||
| 268 | __FUNCTION__); | ||
| 269 | goto out; | 185 | goto out; |
| 270 | } | 186 | |
| 271 | #ifdef XFRM6_TUNNEL_SPI_MAGIC | ||
| 272 | x6spi->magic = XFRM6_TUNNEL_SPI_MAGIC; | ||
| 273 | #endif | ||
| 274 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); | 187 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); |
| 275 | x6spi->spi = spi; | 188 | x6spi->spi = spi; |
| 276 | atomic_set(&x6spi->refcnt, 1); | 189 | atomic_set(&x6spi->refcnt, 1); |
| @@ -279,9 +192,7 @@ alloc_spi: | |||
| 279 | 192 | ||
| 280 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 193 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
| 281 | hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 194 | hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); |
| 282 | X6SPI_CHECK_MAGIC(x6spi); | ||
| 283 | out: | 195 | out: |
| 284 | X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi); | ||
| 285 | return spi; | 196 | return spi; |
| 286 | } | 197 | } |
| 287 | 198 | ||
| @@ -290,8 +201,6 @@ u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | |||
| 290 | struct xfrm6_tunnel_spi *x6spi; | 201 | struct xfrm6_tunnel_spi *x6spi; |
| 291 | u32 spi; | 202 | u32 spi; |
| 292 | 203 | ||
| 293 | X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); | ||
| 294 | |||
| 295 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 204 | write_lock_bh(&xfrm6_tunnel_spi_lock); |
| 296 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 205 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); |
| 297 | if (x6spi) { | 206 | if (x6spi) { |
| @@ -301,8 +210,6 @@ u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | |||
| 301 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 210 | spi = __xfrm6_tunnel_alloc_spi(saddr); |
| 302 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 211 | write_unlock_bh(&xfrm6_tunnel_spi_lock); |
| 303 | 212 | ||
| 304 | X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi); | ||
| 305 | |||
| 306 | return spi; | 213 | return spi; |
| 307 | } | 214 | } |
| 308 | 215 | ||
| @@ -313,8 +220,6 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | |||
| 313 | struct xfrm6_tunnel_spi *x6spi; | 220 | struct xfrm6_tunnel_spi *x6spi; |
| 314 | struct hlist_node *pos, *n; | 221 | struct hlist_node *pos, *n; |
| 315 | 222 | ||
| 316 | X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); | ||
| 317 | |||
| 318 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 223 | write_lock_bh(&xfrm6_tunnel_spi_lock); |
| 319 | 224 | ||
| 320 | hlist_for_each_entry_safe(x6spi, pos, n, | 225 | hlist_for_each_entry_safe(x6spi, pos, n, |
| @@ -322,12 +227,6 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | |||
| 322 | list_byaddr) | 227 | list_byaddr) |
| 323 | { | 228 | { |
| 324 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 229 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
| 325 | X6TPRINTK3(KERN_DEBUG "%s(): x6spi object for " NIP6_FMT | ||
| 326 | " found at %p\n", | ||
| 327 | __FUNCTION__, | ||
| 328 | NIP6(*(struct in6_addr *)saddr), | ||
| 329 | x6spi); | ||
| 330 | X6SPI_CHECK_MAGIC(x6spi); | ||
| 331 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 230 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
| 332 | hlist_del(&x6spi->list_byaddr); | 231 | hlist_del(&x6spi->list_byaddr); |
| 333 | hlist_del(&x6spi->list_byspi); | 232 | hlist_del(&x6spi->list_byspi); |
| @@ -359,7 +258,7 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 359 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 258 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
| 360 | { | 259 | { |
| 361 | struct ipv6hdr *iph = skb->nh.ipv6h; | 260 | struct ipv6hdr *iph = skb->nh.ipv6h; |
| 362 | u32 spi; | 261 | __be32 spi; |
| 363 | 262 | ||
| 364 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 263 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); |
| 365 | return xfrm6_rcv_spi(skb, spi); | 264 | return xfrm6_rcv_spi(skb, spi); |
| @@ -378,20 +277,14 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 378 | case ICMPV6_ADDR_UNREACH: | 277 | case ICMPV6_ADDR_UNREACH: |
| 379 | case ICMPV6_PORT_UNREACH: | 278 | case ICMPV6_PORT_UNREACH: |
| 380 | default: | 279 | default: |
| 381 | X6TPRINTK3(KERN_DEBUG | ||
| 382 | "xfrm6_tunnel: Destination Unreach.\n"); | ||
| 383 | break; | 280 | break; |
| 384 | } | 281 | } |
| 385 | break; | 282 | break; |
| 386 | case ICMPV6_PKT_TOOBIG: | 283 | case ICMPV6_PKT_TOOBIG: |
| 387 | X6TPRINTK3(KERN_DEBUG | ||
| 388 | "xfrm6_tunnel: Packet Too Big.\n"); | ||
| 389 | break; | 284 | break; |
| 390 | case ICMPV6_TIME_EXCEED: | 285 | case ICMPV6_TIME_EXCEED: |
| 391 | switch (code) { | 286 | switch (code) { |
| 392 | case ICMPV6_EXC_HOPLIMIT: | 287 | case ICMPV6_EXC_HOPLIMIT: |
| 393 | X6TPRINTK3(KERN_DEBUG | ||
| 394 | "xfrm6_tunnel: Too small Hoplimit.\n"); | ||
| 395 | break; | 288 | break; |
| 396 | case ICMPV6_EXC_FRAGTIME: | 289 | case ICMPV6_EXC_FRAGTIME: |
| 397 | default: | 290 | default: |
| @@ -414,7 +307,7 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 414 | 307 | ||
| 415 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) | 308 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) |
| 416 | { | 309 | { |
| 417 | if (!x->props.mode) | 310 | if (x->props.mode != XFRM_MODE_TUNNEL) |
| 418 | return -EINVAL; | 311 | return -EINVAL; |
| 419 | 312 | ||
| 420 | if (x->encap) | 313 | if (x->encap) |
| @@ -448,22 +341,14 @@ static struct xfrm6_tunnel xfrm6_tunnel_handler = { | |||
| 448 | 341 | ||
| 449 | static int __init xfrm6_tunnel_init(void) | 342 | static int __init xfrm6_tunnel_init(void) |
| 450 | { | 343 | { |
| 451 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); | 344 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) |
| 452 | |||
| 453 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) { | ||
| 454 | X6TPRINTK1(KERN_ERR | ||
| 455 | "xfrm6_tunnel init: can't add xfrm type\n"); | ||
| 456 | return -EAGAIN; | 345 | return -EAGAIN; |
| 457 | } | 346 | |
| 458 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { | 347 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { |
| 459 | X6TPRINTK1(KERN_ERR | ||
| 460 | "xfrm6_tunnel init(): can't add handler\n"); | ||
| 461 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 348 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 462 | return -EAGAIN; | 349 | return -EAGAIN; |
| 463 | } | 350 | } |
| 464 | if (xfrm6_tunnel_spi_init() < 0) { | 351 | if (xfrm6_tunnel_spi_init() < 0) { |
| 465 | X6TPRINTK1(KERN_ERR | ||
| 466 | "xfrm6_tunnel init: failed to initialize spi\n"); | ||
| 467 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); | 352 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); |
| 468 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 353 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 469 | return -EAGAIN; | 354 | return -EAGAIN; |
| @@ -473,15 +358,9 @@ static int __init xfrm6_tunnel_init(void) | |||
| 473 | 358 | ||
| 474 | static void __exit xfrm6_tunnel_fini(void) | 359 | static void __exit xfrm6_tunnel_fini(void) |
| 475 | { | 360 | { |
| 476 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); | ||
| 477 | |||
| 478 | xfrm6_tunnel_spi_fini(); | 361 | xfrm6_tunnel_spi_fini(); |
| 479 | if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler)) | 362 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); |
| 480 | X6TPRINTK1(KERN_ERR | 363 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 481 | "xfrm6_tunnel close: can't remove handler\n"); | ||
| 482 | if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0) | ||
| 483 | X6TPRINTK1(KERN_ERR | ||
| 484 | "xfrm6_tunnel close: can't remove xfrm type\n"); | ||
| 485 | } | 364 | } |
| 486 | 365 | ||
| 487 | module_init(xfrm6_tunnel_init); | 366 | module_init(xfrm6_tunnel_init); |
