diff options
Diffstat (limited to 'net/ipv6')
44 files changed, 1109 insertions, 890 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 4f7fe7270e37..ed0b9e2e797a 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -11,7 +11,7 @@ menuconfig IPV6 | |||
11 | You will still be able to do traditional IPv4 networking as well. | 11 | You will still be able to do traditional IPv4 networking as well. |
12 | 12 | ||
13 | For general information about IPv6, see | 13 | For general information about IPv6, see |
14 | <http://playground.sun.com/pub/ipng/html/ipng-main.html>. | 14 | <https://en.wikipedia.org/wiki/IPv6>. |
15 | For Linux IPv6 development information, see <http://www.linux-ipv6.org>. | 15 | For Linux IPv6 development information, see <http://www.linux-ipv6.org>. |
16 | For specific information about IPv6 under Linux, read the HOWTO at | 16 | For specific information about IPv6 under Linux, read the HOWTO at |
17 | <http://www.bieringer.de/linux/IPv6/>. | 17 | <http://www.bieringer.de/linux/IPv6/>. |
@@ -50,16 +50,15 @@ config IPV6_ROUTER_PREF | |||
50 | If unsure, say N. | 50 | If unsure, say N. |
51 | 51 | ||
52 | config IPV6_ROUTE_INFO | 52 | config IPV6_ROUTE_INFO |
53 | bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)" | 53 | bool "IPv6: Route Information (RFC 4191) support" |
54 | depends on IPV6_ROUTER_PREF && EXPERIMENTAL | 54 | depends on IPV6_ROUTER_PREF |
55 | ---help--- | 55 | ---help--- |
56 | This is experimental support of Route Information. | 56 | This is experimental support of Route Information. |
57 | 57 | ||
58 | If unsure, say N. | 58 | If unsure, say N. |
59 | 59 | ||
60 | config IPV6_OPTIMISTIC_DAD | 60 | config IPV6_OPTIMISTIC_DAD |
61 | bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)" | 61 | bool "IPv6: Enable RFC 4429 Optimistic DAD" |
62 | depends on EXPERIMENTAL | ||
63 | ---help--- | 62 | ---help--- |
64 | This is experimental support for optimistic Duplicate | 63 | This is experimental support for optimistic Duplicate |
65 | Address Detection. It allows for autoconfigured addresses | 64 | Address Detection. It allows for autoconfigured addresses |
@@ -105,8 +104,7 @@ config INET6_IPCOMP | |||
105 | If unsure, say Y. | 104 | If unsure, say Y. |
106 | 105 | ||
107 | config IPV6_MIP6 | 106 | config IPV6_MIP6 |
108 | tristate "IPv6: Mobility (EXPERIMENTAL)" | 107 | tristate "IPv6: Mobility" |
109 | depends on EXPERIMENTAL | ||
110 | select XFRM | 108 | select XFRM |
111 | ---help--- | 109 | ---help--- |
112 | Support for IPv6 Mobility described in RFC 3775. | 110 | Support for IPv6 Mobility described in RFC 3775. |
@@ -150,8 +148,7 @@ config INET6_XFRM_MODE_BEET | |||
150 | If unsure, say Y. | 148 | If unsure, say Y. |
151 | 149 | ||
152 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION | 150 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION |
153 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" | 151 | tristate "IPv6: MIPv6 route optimization mode" |
154 | depends on EXPERIMENTAL | ||
155 | select XFRM | 152 | select XFRM |
156 | ---help--- | 153 | ---help--- |
157 | Support for MIPv6 route optimization mode. | 154 | Support for MIPv6 route optimization mode. |
@@ -171,8 +168,8 @@ config IPV6_SIT | |||
171 | Saying M here will produce a module called sit. If unsure, say Y. | 168 | Saying M here will produce a module called sit. If unsure, say Y. |
172 | 169 | ||
173 | config IPV6_SIT_6RD | 170 | config IPV6_SIT_6RD |
174 | bool "IPv6: IPv6 Rapid Deployment (6RD) (EXPERIMENTAL)" | 171 | bool "IPv6: IPv6 Rapid Deployment (6RD)" |
175 | depends on IPV6_SIT && EXPERIMENTAL | 172 | depends on IPV6_SIT |
176 | default n | 173 | default n |
177 | ---help--- | 174 | ---help--- |
178 | IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon | 175 | IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon |
@@ -219,7 +216,6 @@ config IPV6_GRE | |||
219 | 216 | ||
220 | config IPV6_MULTIPLE_TABLES | 217 | config IPV6_MULTIPLE_TABLES |
221 | bool "IPv6: Multiple Routing Tables" | 218 | bool "IPv6: Multiple Routing Tables" |
222 | depends on EXPERIMENTAL | ||
223 | select FIB_RULES | 219 | select FIB_RULES |
224 | ---help--- | 220 | ---help--- |
225 | Support multiple routing tables. | 221 | Support multiple routing tables. |
@@ -239,8 +235,8 @@ config IPV6_SUBTREES | |||
239 | If unsure, say N. | 235 | If unsure, say N. |
240 | 236 | ||
241 | config IPV6_MROUTE | 237 | config IPV6_MROUTE |
242 | bool "IPv6: multicast routing (EXPERIMENTAL)" | 238 | bool "IPv6: multicast routing" |
243 | depends on IPV6 && EXPERIMENTAL | 239 | depends on IPV6 |
244 | ---help--- | 240 | ---help--- |
245 | Experimental support for IPv6 multicast forwarding. | 241 | Experimental support for IPv6 multicast forwarding. |
246 | If unsure, say N. | 242 | If unsure, say N. |
@@ -260,7 +256,7 @@ config IPV6_MROUTE_MULTIPLE_TABLES | |||
260 | If unsure, say N. | 256 | If unsure, say N. |
261 | 257 | ||
262 | config IPV6_PIMSM_V2 | 258 | config IPV6_PIMSM_V2 |
263 | bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" | 259 | bool "IPv6: PIM-SM version 2 support" |
264 | depends on IPV6_MROUTE | 260 | depends on IPV6_MROUTE |
265 | ---help--- | 261 | ---help--- |
266 | Support for IPv6 PIM multicast routing protocol PIM-SMv2. | 262 | Support for IPv6 PIM multicast routing protocol PIM-SMv2. |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 4ea244891b58..309af19a0a0a 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o | |||
40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
42 | 42 | ||
43 | obj-y += addrconf_core.o exthdrs_core.o | 43 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o |
44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) | 44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) |
45 | 45 | ||
46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 408cac4ae00a..f2c7e615f902 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -110,10 +110,6 @@ static inline u32 cstamp_delta(unsigned long cstamp) | |||
110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | 110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; |
111 | } | 111 | } |
112 | 112 | ||
113 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | ||
114 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | ||
115 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | ||
116 | |||
117 | #ifdef CONFIG_SYSCTL | 113 | #ifdef CONFIG_SYSCTL |
118 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 114 | static void addrconf_sysctl_register(struct inet6_dev *idev); |
119 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 115 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); |
@@ -154,6 +150,11 @@ static void addrconf_type_change(struct net_device *dev, | |||
154 | unsigned long event); | 150 | unsigned long event); |
155 | static int addrconf_ifdown(struct net_device *dev, int how); | 151 | static int addrconf_ifdown(struct net_device *dev, int how); |
156 | 152 | ||
153 | static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | ||
154 | int plen, | ||
155 | const struct net_device *dev, | ||
156 | u32 flags, u32 noflags); | ||
157 | |||
157 | static void addrconf_dad_start(struct inet6_ifaddr *ifp); | 158 | static void addrconf_dad_start(struct inet6_ifaddr *ifp); |
158 | static void addrconf_dad_timer(unsigned long data); | 159 | static void addrconf_dad_timer(unsigned long data); |
159 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | 160 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); |
@@ -243,6 +244,9 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |||
243 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | 244 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; |
244 | const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | 245 | const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
245 | const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; | 246 | const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; |
247 | const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; | ||
248 | const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; | ||
249 | const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; | ||
246 | 250 | ||
247 | /* Check if a valid qdisc is available */ | 251 | /* Check if a valid qdisc is available */ |
248 | static inline bool addrconf_qdisc_ok(const struct net_device *dev) | 252 | static inline bool addrconf_qdisc_ok(const struct net_device *dev) |
@@ -250,12 +254,6 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
250 | return !qdisc_tx_is_noop(dev); | 254 | return !qdisc_tx_is_noop(dev); |
251 | } | 255 | } |
252 | 256 | ||
253 | /* Check if a route is valid prefix route */ | ||
254 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | ||
255 | { | ||
256 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; | ||
257 | } | ||
258 | |||
259 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 257 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
260 | { | 258 | { |
261 | if (del_timer(&ifp->timer)) | 259 | if (del_timer(&ifp->timer)) |
@@ -433,6 +431,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
433 | /* protected by rtnl_lock */ | 431 | /* protected by rtnl_lock */ |
434 | rcu_assign_pointer(dev->ip6_ptr, ndev); | 432 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
435 | 433 | ||
434 | /* Join interface-local all-node multicast group */ | ||
435 | ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes); | ||
436 | |||
436 | /* Join all-node multicast group */ | 437 | /* Join all-node multicast group */ |
437 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); | 438 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); |
438 | 439 | ||
@@ -616,10 +617,15 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
616 | if (idev->cnf.forwarding) | 617 | if (idev->cnf.forwarding) |
617 | dev_disable_lro(dev); | 618 | dev_disable_lro(dev); |
618 | if (dev->flags & IFF_MULTICAST) { | 619 | if (dev->flags & IFF_MULTICAST) { |
619 | if (idev->cnf.forwarding) | 620 | if (idev->cnf.forwarding) { |
620 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); | 621 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); |
621 | else | 622 | ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters); |
623 | ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters); | ||
624 | } else { | ||
622 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); | 625 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); |
626 | ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters); | ||
627 | ipv6_dev_mc_dec(dev, &in6addr_sitelocal_allrouters); | ||
628 | } | ||
623 | } | 629 | } |
624 | 630 | ||
625 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 631 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
@@ -941,17 +947,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
941 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { | 947 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { |
942 | struct in6_addr prefix; | 948 | struct in6_addr prefix; |
943 | struct rt6_info *rt; | 949 | struct rt6_info *rt; |
944 | struct net *net = dev_net(ifp->idev->dev); | ||
945 | struct flowi6 fl6 = {}; | ||
946 | 950 | ||
947 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); | 951 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); |
948 | fl6.flowi6_oif = ifp->idev->dev->ifindex; | ||
949 | fl6.daddr = prefix; | ||
950 | rt = (struct rt6_info *)ip6_route_lookup(net, &fl6, | ||
951 | RT6_LOOKUP_F_IFACE); | ||
952 | 952 | ||
953 | if (rt != net->ipv6.ip6_null_entry && | 953 | rt = addrconf_get_prefix_route(&prefix, |
954 | addrconf_is_prefix_route(rt)) { | 954 | ifp->prefix_len, |
955 | ifp->idev->dev, | ||
956 | 0, RTF_GATEWAY | RTF_DEFAULT); | ||
957 | |||
958 | if (rt) { | ||
955 | if (onlink == 0) { | 959 | if (onlink == 0) { |
956 | ip6_del_rt(rt); | 960 | ip6_del_rt(rt); |
957 | rt = NULL; | 961 | rt = NULL; |
@@ -1054,7 +1058,7 @@ retry: | |||
1054 | ipv6_add_addr(idev, &addr, tmp_plen, | 1058 | ipv6_add_addr(idev, &addr, tmp_plen, |
1055 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, | 1059 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, |
1056 | addr_flags) : NULL; | 1060 | addr_flags) : NULL; |
1057 | if (!ift || IS_ERR(ift)) { | 1061 | if (IS_ERR_OR_NULL(ift)) { |
1058 | in6_ifa_put(ifp); | 1062 | in6_ifa_put(ifp); |
1059 | in6_dev_put(idev); | 1063 | in6_dev_put(idev); |
1060 | pr_info("%s: retry temporary address regeneration\n", __func__); | 1064 | pr_info("%s: retry temporary address regeneration\n", __func__); |
@@ -1415,11 +1419,10 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | |||
1415 | struct net_device *dev, int strict) | 1419 | struct net_device *dev, int strict) |
1416 | { | 1420 | { |
1417 | struct inet6_ifaddr *ifp; | 1421 | struct inet6_ifaddr *ifp; |
1418 | struct hlist_node *node; | ||
1419 | unsigned int hash = inet6_addr_hash(addr); | 1422 | unsigned int hash = inet6_addr_hash(addr); |
1420 | 1423 | ||
1421 | rcu_read_lock_bh(); | 1424 | rcu_read_lock_bh(); |
1422 | hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1425 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
1423 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1426 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1424 | continue; | 1427 | continue; |
1425 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1428 | if (ipv6_addr_equal(&ifp->addr, addr) && |
@@ -1441,9 +1444,8 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | |||
1441 | { | 1444 | { |
1442 | unsigned int hash = inet6_addr_hash(addr); | 1445 | unsigned int hash = inet6_addr_hash(addr); |
1443 | struct inet6_ifaddr *ifp; | 1446 | struct inet6_ifaddr *ifp; |
1444 | struct hlist_node *node; | ||
1445 | 1447 | ||
1446 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1448 | hlist_for_each_entry(ifp, &inet6_addr_lst[hash], addr_lst) { |
1447 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1449 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1448 | continue; | 1450 | continue; |
1449 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1451 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
@@ -1483,10 +1485,9 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add | |||
1483 | { | 1485 | { |
1484 | struct inet6_ifaddr *ifp, *result = NULL; | 1486 | struct inet6_ifaddr *ifp, *result = NULL; |
1485 | unsigned int hash = inet6_addr_hash(addr); | 1487 | unsigned int hash = inet6_addr_hash(addr); |
1486 | struct hlist_node *node; | ||
1487 | 1488 | ||
1488 | rcu_read_lock_bh(); | 1489 | rcu_read_lock_bh(); |
1489 | hlist_for_each_entry_rcu_bh(ifp, node, &inet6_addr_lst[hash], addr_lst) { | 1490 | hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { |
1490 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1491 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1491 | continue; | 1492 | continue; |
1492 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1493 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
@@ -1663,6 +1664,7 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) | |||
1663 | if (dev->addr_len != IEEE802154_ADDR_LEN) | 1664 | if (dev->addr_len != IEEE802154_ADDR_LEN) |
1664 | return -1; | 1665 | return -1; |
1665 | memcpy(eui, dev->dev_addr, 8); | 1666 | memcpy(eui, dev->dev_addr, 8); |
1667 | eui[0] ^= 2; | ||
1666 | return 0; | 1668 | return 0; |
1667 | } | 1669 | } |
1668 | 1670 | ||
@@ -1877,7 +1879,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | |||
1877 | continue; | 1879 | continue; |
1878 | if ((rt->rt6i_flags & flags) != flags) | 1880 | if ((rt->rt6i_flags & flags) != flags) |
1879 | continue; | 1881 | continue; |
1880 | if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0)) | 1882 | if ((rt->rt6i_flags & noflags) != 0) |
1881 | continue; | 1883 | continue; |
1882 | dst_hold(&rt->dst); | 1884 | dst_hold(&rt->dst); |
1883 | break; | 1885 | break; |
@@ -2082,7 +2084,7 @@ ok: | |||
2082 | addr_type&IPV6_ADDR_SCOPE_MASK, | 2084 | addr_type&IPV6_ADDR_SCOPE_MASK, |
2083 | addr_flags); | 2085 | addr_flags); |
2084 | 2086 | ||
2085 | if (!ifp || IS_ERR(ifp)) { | 2087 | if (IS_ERR_OR_NULL(ifp)) { |
2086 | in6_dev_put(in6_dev); | 2088 | in6_dev_put(in6_dev); |
2087 | return; | 2089 | return; |
2088 | } | 2090 | } |
@@ -2902,11 +2904,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2902 | /* Step 2: clear hash table */ | 2904 | /* Step 2: clear hash table */ |
2903 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | 2905 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
2904 | struct hlist_head *h = &inet6_addr_lst[i]; | 2906 | struct hlist_head *h = &inet6_addr_lst[i]; |
2905 | struct hlist_node *n; | ||
2906 | 2907 | ||
2907 | spin_lock_bh(&addrconf_hash_lock); | 2908 | spin_lock_bh(&addrconf_hash_lock); |
2908 | restart: | 2909 | restart: |
2909 | hlist_for_each_entry_rcu(ifa, n, h, addr_lst) { | 2910 | hlist_for_each_entry_rcu(ifa, h, addr_lst) { |
2910 | if (ifa->idev == idev) { | 2911 | if (ifa->idev == idev) { |
2911 | hlist_del_init_rcu(&ifa->addr_lst); | 2912 | hlist_del_init_rcu(&ifa->addr_lst); |
2912 | addrconf_del_timer(ifa); | 2913 | addrconf_del_timer(ifa); |
@@ -3213,8 +3214,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos) | |||
3213 | } | 3214 | } |
3214 | 3215 | ||
3215 | for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { | 3216 | for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { |
3216 | struct hlist_node *n; | 3217 | hlist_for_each_entry_rcu_bh(ifa, &inet6_addr_lst[state->bucket], |
3217 | hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], | ||
3218 | addr_lst) { | 3218 | addr_lst) { |
3219 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3219 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3220 | continue; | 3220 | continue; |
@@ -3239,9 +3239,8 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, | |||
3239 | { | 3239 | { |
3240 | struct if6_iter_state *state = seq->private; | 3240 | struct if6_iter_state *state = seq->private; |
3241 | struct net *net = seq_file_net(seq); | 3241 | struct net *net = seq_file_net(seq); |
3242 | struct hlist_node *n = &ifa->addr_lst; | ||
3243 | 3242 | ||
3244 | hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { | 3243 | hlist_for_each_entry_continue_rcu_bh(ifa, addr_lst) { |
3245 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3244 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3246 | continue; | 3245 | continue; |
3247 | state->offset++; | 3246 | state->offset++; |
@@ -3250,7 +3249,7 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, | |||
3250 | 3249 | ||
3251 | while (++state->bucket < IN6_ADDR_HSIZE) { | 3250 | while (++state->bucket < IN6_ADDR_HSIZE) { |
3252 | state->offset = 0; | 3251 | state->offset = 0; |
3253 | hlist_for_each_entry_rcu_bh(ifa, n, | 3252 | hlist_for_each_entry_rcu_bh(ifa, |
3254 | &inet6_addr_lst[state->bucket], addr_lst) { | 3253 | &inet6_addr_lst[state->bucket], addr_lst) { |
3255 | if (!net_eq(dev_net(ifa->idev->dev), net)) | 3254 | if (!net_eq(dev_net(ifa->idev->dev), net)) |
3256 | continue; | 3255 | continue; |
@@ -3320,14 +3319,14 @@ static const struct file_operations if6_fops = { | |||
3320 | 3319 | ||
3321 | static int __net_init if6_proc_net_init(struct net *net) | 3320 | static int __net_init if6_proc_net_init(struct net *net) |
3322 | { | 3321 | { |
3323 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3322 | if (!proc_create("if_inet6", S_IRUGO, net->proc_net, &if6_fops)) |
3324 | return -ENOMEM; | 3323 | return -ENOMEM; |
3325 | return 0; | 3324 | return 0; |
3326 | } | 3325 | } |
3327 | 3326 | ||
3328 | static void __net_exit if6_proc_net_exit(struct net *net) | 3327 | static void __net_exit if6_proc_net_exit(struct net *net) |
3329 | { | 3328 | { |
3330 | proc_net_remove(net, "if_inet6"); | 3329 | remove_proc_entry("if_inet6", net->proc_net); |
3331 | } | 3330 | } |
3332 | 3331 | ||
3333 | static struct pernet_operations if6_proc_net_ops = { | 3332 | static struct pernet_operations if6_proc_net_ops = { |
@@ -3352,11 +3351,10 @@ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) | |||
3352 | { | 3351 | { |
3353 | int ret = 0; | 3352 | int ret = 0; |
3354 | struct inet6_ifaddr *ifp = NULL; | 3353 | struct inet6_ifaddr *ifp = NULL; |
3355 | struct hlist_node *n; | ||
3356 | unsigned int hash = inet6_addr_hash(addr); | 3354 | unsigned int hash = inet6_addr_hash(addr); |
3357 | 3355 | ||
3358 | rcu_read_lock_bh(); | 3356 | rcu_read_lock_bh(); |
3359 | hlist_for_each_entry_rcu_bh(ifp, n, &inet6_addr_lst[hash], addr_lst) { | 3357 | hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { |
3360 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 3358 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
3361 | continue; | 3359 | continue; |
3362 | if (ipv6_addr_equal(&ifp->addr, addr) && | 3360 | if (ipv6_addr_equal(&ifp->addr, addr) && |
@@ -3378,7 +3376,6 @@ static void addrconf_verify(unsigned long foo) | |||
3378 | { | 3376 | { |
3379 | unsigned long now, next, next_sec, next_sched; | 3377 | unsigned long now, next, next_sec, next_sched; |
3380 | struct inet6_ifaddr *ifp; | 3378 | struct inet6_ifaddr *ifp; |
3381 | struct hlist_node *node; | ||
3382 | int i; | 3379 | int i; |
3383 | 3380 | ||
3384 | rcu_read_lock_bh(); | 3381 | rcu_read_lock_bh(); |
@@ -3390,7 +3387,7 @@ static void addrconf_verify(unsigned long foo) | |||
3390 | 3387 | ||
3391 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | 3388 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
3392 | restart: | 3389 | restart: |
3393 | hlist_for_each_entry_rcu_bh(ifp, node, | 3390 | hlist_for_each_entry_rcu_bh(ifp, |
3394 | &inet6_addr_lst[i], addr_lst) { | 3391 | &inet6_addr_lst[i], addr_lst) { |
3395 | unsigned long age; | 3392 | unsigned long age; |
3396 | 3393 | ||
@@ -3861,7 +3858,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3861 | struct net_device *dev; | 3858 | struct net_device *dev; |
3862 | struct inet6_dev *idev; | 3859 | struct inet6_dev *idev; |
3863 | struct hlist_head *head; | 3860 | struct hlist_head *head; |
3864 | struct hlist_node *node; | ||
3865 | 3861 | ||
3866 | s_h = cb->args[0]; | 3862 | s_h = cb->args[0]; |
3867 | s_idx = idx = cb->args[1]; | 3863 | s_idx = idx = cb->args[1]; |
@@ -3871,7 +3867,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
3871 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 3867 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3872 | idx = 0; | 3868 | idx = 0; |
3873 | head = &net->dev_index_head[h]; | 3869 | head = &net->dev_index_head[h]; |
3874 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { | 3870 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
3875 | if (idx < s_idx) | 3871 | if (idx < s_idx) |
3876 | goto cont; | 3872 | goto cont; |
3877 | if (h > s_h || idx > s_idx) | 3873 | if (h > s_h || idx > s_idx) |
@@ -4217,7 +4213,6 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4217 | struct net_device *dev; | 4213 | struct net_device *dev; |
4218 | struct inet6_dev *idev; | 4214 | struct inet6_dev *idev; |
4219 | struct hlist_head *head; | 4215 | struct hlist_head *head; |
4220 | struct hlist_node *node; | ||
4221 | 4216 | ||
4222 | s_h = cb->args[0]; | 4217 | s_h = cb->args[0]; |
4223 | s_idx = cb->args[1]; | 4218 | s_idx = cb->args[1]; |
@@ -4226,7 +4221,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4226 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 4221 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
4227 | idx = 0; | 4222 | idx = 0; |
4228 | head = &net->dev_index_head[h]; | 4223 | head = &net->dev_index_head[h]; |
4229 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { | 4224 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
4230 | if (idx < s_idx) | 4225 | if (idx < s_idx) |
4231 | goto cont; | 4226 | goto cont; |
4232 | idev = __in6_dev_get(dev); | 4227 | idev = __in6_dev_get(dev); |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index ff76eecfd622..aad64352cb60 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -173,9 +173,8 @@ static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net, | |||
173 | const struct in6_addr *addr, | 173 | const struct in6_addr *addr, |
174 | int type, int ifindex) | 174 | int type, int ifindex) |
175 | { | 175 | { |
176 | struct hlist_node *pos; | ||
177 | struct ip6addrlbl_entry *p; | 176 | struct ip6addrlbl_entry *p; |
178 | hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { | 177 | hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { |
179 | if (__ip6addrlbl_match(net, p, addr, type, ifindex)) | 178 | if (__ip6addrlbl_match(net, p, addr, type, ifindex)) |
180 | return p; | 179 | return p; |
181 | } | 180 | } |
@@ -261,9 +260,9 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) | |||
261 | if (hlist_empty(&ip6addrlbl_table.head)) { | 260 | if (hlist_empty(&ip6addrlbl_table.head)) { |
262 | hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); | 261 | hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); |
263 | } else { | 262 | } else { |
264 | struct hlist_node *pos, *n; | 263 | struct hlist_node *n; |
265 | struct ip6addrlbl_entry *p = NULL; | 264 | struct ip6addrlbl_entry *p = NULL; |
266 | hlist_for_each_entry_safe(p, pos, n, | 265 | hlist_for_each_entry_safe(p, n, |
267 | &ip6addrlbl_table.head, list) { | 266 | &ip6addrlbl_table.head, list) { |
268 | if (p->prefixlen == newp->prefixlen && | 267 | if (p->prefixlen == newp->prefixlen && |
269 | net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) && | 268 | net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) && |
@@ -319,13 +318,13 @@ static int __ip6addrlbl_del(struct net *net, | |||
319 | int ifindex) | 318 | int ifindex) |
320 | { | 319 | { |
321 | struct ip6addrlbl_entry *p = NULL; | 320 | struct ip6addrlbl_entry *p = NULL; |
322 | struct hlist_node *pos, *n; | 321 | struct hlist_node *n; |
323 | int ret = -ESRCH; | 322 | int ret = -ESRCH; |
324 | 323 | ||
325 | ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", | 324 | ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", |
326 | __func__, prefix, prefixlen, ifindex); | 325 | __func__, prefix, prefixlen, ifindex); |
327 | 326 | ||
328 | hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { | 327 | hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { |
329 | if (p->prefixlen == prefixlen && | 328 | if (p->prefixlen == prefixlen && |
330 | net_eq(ip6addrlbl_net(p), net) && | 329 | net_eq(ip6addrlbl_net(p), net) && |
331 | p->ifindex == ifindex && | 330 | p->ifindex == ifindex && |
@@ -380,11 +379,11 @@ static int __net_init ip6addrlbl_net_init(struct net *net) | |||
380 | static void __net_exit ip6addrlbl_net_exit(struct net *net) | 379 | static void __net_exit ip6addrlbl_net_exit(struct net *net) |
381 | { | 380 | { |
382 | struct ip6addrlbl_entry *p = NULL; | 381 | struct ip6addrlbl_entry *p = NULL; |
383 | struct hlist_node *pos, *n; | 382 | struct hlist_node *n; |
384 | 383 | ||
385 | /* Remove all labels belonging to the exiting net */ | 384 | /* Remove all labels belonging to the exiting net */ |
386 | spin_lock(&ip6addrlbl_table.lock); | 385 | spin_lock(&ip6addrlbl_table.lock); |
387 | hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { | 386 | hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { |
388 | if (net_eq(ip6addrlbl_net(p), net)) { | 387 | if (net_eq(ip6addrlbl_net(p), net)) { |
389 | hlist_del_rcu(&p->list); | 388 | hlist_del_rcu(&p->list); |
390 | ip6addrlbl_put(p); | 389 | ip6addrlbl_put(p); |
@@ -505,12 +504,11 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
505 | { | 504 | { |
506 | struct net *net = sock_net(skb->sk); | 505 | struct net *net = sock_net(skb->sk); |
507 | struct ip6addrlbl_entry *p; | 506 | struct ip6addrlbl_entry *p; |
508 | struct hlist_node *pos; | ||
509 | int idx = 0, s_idx = cb->args[0]; | 507 | int idx = 0, s_idx = cb->args[0]; |
510 | int err; | 508 | int err; |
511 | 509 | ||
512 | rcu_read_lock(); | 510 | rcu_read_lock(); |
513 | hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { | 511 | hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { |
514 | if (idx >= s_idx && | 512 | if (idx >= s_idx && |
515 | net_eq(ip6addrlbl_net(p), net)) { | 513 | net_eq(ip6addrlbl_net(p), net)) { |
516 | if ((err = ip6addrlbl_fill(skb, p, | 514 | if ((err = ip6addrlbl_fill(skb, p, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b043c60429bd..6b793bfc0e10 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -811,11 +811,10 @@ static struct pernet_operations inet6_net_ops = { | |||
811 | 811 | ||
812 | static int __init inet6_init(void) | 812 | static int __init inet6_init(void) |
813 | { | 813 | { |
814 | struct sk_buff *dummy_skb; | ||
815 | struct list_head *r; | 814 | struct list_head *r; |
816 | int err = 0; | 815 | int err = 0; |
817 | 816 | ||
818 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); | 817 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > FIELD_SIZEOF(struct sk_buff, cb)); |
819 | 818 | ||
820 | /* Register the socket-side information for inet6_create. */ | 819 | /* Register the socket-side information for inet6_create. */ |
821 | for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) | 820 | for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ecc35b93314b..bb02e176cb70 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -472,7 +472,10 @@ static void ah6_input_done(struct crypto_async_request *base, int err) | |||
472 | skb->network_header += ah_hlen; | 472 | skb->network_header += ah_hlen; |
473 | memcpy(skb_network_header(skb), work_iph, hdr_len); | 473 | memcpy(skb_network_header(skb), work_iph, hdr_len); |
474 | __skb_pull(skb, ah_hlen + hdr_len); | 474 | __skb_pull(skb, ah_hlen + hdr_len); |
475 | skb_set_transport_header(skb, -hdr_len); | 475 | if (x->props.mode == XFRM_MODE_TUNNEL) |
476 | skb_reset_transport_header(skb); | ||
477 | else | ||
478 | skb_set_transport_header(skb, -hdr_len); | ||
476 | out: | 479 | out: |
477 | kfree(AH_SKB_CB(skb)->tmp); | 480 | kfree(AH_SKB_CB(skb)->tmp); |
478 | xfrm_input_resume(skb, err); | 481 | xfrm_input_resume(skb, err); |
@@ -518,8 +521,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
518 | 521 | ||
519 | /* We are going to _remove_ AH header to keep sockets happy, | 522 | /* We are going to _remove_ AH header to keep sockets happy, |
520 | * so... Later this can change. */ | 523 | * so... Later this can change. */ |
521 | if (skb_cloned(skb) && | 524 | if (skb_unclone(skb, GFP_ATOMIC)) |
522 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | ||
523 | goto out; | 525 | goto out; |
524 | 526 | ||
525 | skb->ip_summed = CHECKSUM_NONE; | 527 | skb->ip_summed = CHECKSUM_NONE; |
@@ -593,9 +595,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
593 | 595 | ||
594 | skb->network_header += ah_hlen; | 596 | skb->network_header += ah_hlen; |
595 | memcpy(skb_network_header(skb), work_iph, hdr_len); | 597 | memcpy(skb_network_header(skb), work_iph, hdr_len); |
596 | skb->transport_header = skb->network_header; | ||
597 | __skb_pull(skb, ah_hlen + hdr_len); | 598 | __skb_pull(skb, ah_hlen + hdr_len); |
598 | 599 | ||
600 | if (x->props.mode == XFRM_MODE_TUNNEL) | ||
601 | skb_reset_transport_header(skb); | ||
602 | else | ||
603 | skb_set_transport_header(skb, -hdr_len); | ||
604 | |||
599 | err = nexthdr; | 605 | err = nexthdr; |
600 | 606 | ||
601 | out_free: | 607 | out_free: |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 757a810d8f15..5a80f15a9de2 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -47,7 +47,7 @@ | |||
47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); | 47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); |
48 | 48 | ||
49 | /* Big ac list lock for all the sockets */ | 49 | /* Big ac list lock for all the sockets */ |
50 | static DEFINE_RWLOCK(ipv6_sk_ac_lock); | 50 | static DEFINE_SPINLOCK(ipv6_sk_ac_lock); |
51 | 51 | ||
52 | 52 | ||
53 | /* | 53 | /* |
@@ -128,10 +128,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
128 | 128 | ||
129 | err = ipv6_dev_ac_inc(dev, addr); | 129 | err = ipv6_dev_ac_inc(dev, addr); |
130 | if (!err) { | 130 | if (!err) { |
131 | write_lock_bh(&ipv6_sk_ac_lock); | 131 | spin_lock_bh(&ipv6_sk_ac_lock); |
132 | pac->acl_next = np->ipv6_ac_list; | 132 | pac->acl_next = np->ipv6_ac_list; |
133 | np->ipv6_ac_list = pac; | 133 | np->ipv6_ac_list = pac; |
134 | write_unlock_bh(&ipv6_sk_ac_lock); | 134 | spin_unlock_bh(&ipv6_sk_ac_lock); |
135 | pac = NULL; | 135 | pac = NULL; |
136 | } | 136 | } |
137 | 137 | ||
@@ -152,7 +152,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
152 | struct ipv6_ac_socklist *pac, *prev_pac; | 152 | struct ipv6_ac_socklist *pac, *prev_pac; |
153 | struct net *net = sock_net(sk); | 153 | struct net *net = sock_net(sk); |
154 | 154 | ||
155 | write_lock_bh(&ipv6_sk_ac_lock); | 155 | spin_lock_bh(&ipv6_sk_ac_lock); |
156 | prev_pac = NULL; | 156 | prev_pac = NULL; |
157 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { | 157 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { |
158 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && | 158 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && |
@@ -161,7 +161,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
161 | prev_pac = pac; | 161 | prev_pac = pac; |
162 | } | 162 | } |
163 | if (!pac) { | 163 | if (!pac) { |
164 | write_unlock_bh(&ipv6_sk_ac_lock); | 164 | spin_unlock_bh(&ipv6_sk_ac_lock); |
165 | return -ENOENT; | 165 | return -ENOENT; |
166 | } | 166 | } |
167 | if (prev_pac) | 167 | if (prev_pac) |
@@ -169,7 +169,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
169 | else | 169 | else |
170 | np->ipv6_ac_list = pac->acl_next; | 170 | np->ipv6_ac_list = pac->acl_next; |
171 | 171 | ||
172 | write_unlock_bh(&ipv6_sk_ac_lock); | 172 | spin_unlock_bh(&ipv6_sk_ac_lock); |
173 | 173 | ||
174 | rcu_read_lock(); | 174 | rcu_read_lock(); |
175 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); | 175 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); |
@@ -192,10 +192,10 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
192 | if (!np->ipv6_ac_list) | 192 | if (!np->ipv6_ac_list) |
193 | return; | 193 | return; |
194 | 194 | ||
195 | write_lock_bh(&ipv6_sk_ac_lock); | 195 | spin_lock_bh(&ipv6_sk_ac_lock); |
196 | pac = np->ipv6_ac_list; | 196 | pac = np->ipv6_ac_list; |
197 | np->ipv6_ac_list = NULL; | 197 | np->ipv6_ac_list = NULL; |
198 | write_unlock_bh(&ipv6_sk_ac_lock); | 198 | spin_unlock_bh(&ipv6_sk_ac_lock); |
199 | 199 | ||
200 | prev_index = 0; | 200 | prev_index = 0; |
201 | rcu_read_lock(); | 201 | rcu_read_lock(); |
@@ -509,7 +509,7 @@ static const struct file_operations ac6_seq_fops = { | |||
509 | 509 | ||
510 | int __net_init ac6_proc_init(struct net *net) | 510 | int __net_init ac6_proc_init(struct net *net) |
511 | { | 511 | { |
512 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) | 512 | if (!proc_create("anycast6", S_IRUGO, net->proc_net, &ac6_seq_fops)) |
513 | return -ENOMEM; | 513 | return -ENOMEM; |
514 | 514 | ||
515 | return 0; | 515 | return 0; |
@@ -517,7 +517,7 @@ int __net_init ac6_proc_init(struct net *net) | |||
517 | 517 | ||
518 | void ac6_proc_exit(struct net *net) | 518 | void ac6_proc_exit(struct net *net) |
519 | { | 519 | { |
520 | proc_net_remove(net, "anycast6"); | 520 | remove_proc_entry("anycast6", net->proc_net); |
521 | } | 521 | } |
522 | #endif | 522 | #endif |
523 | 523 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 8edf2601065a..f5a54782a340 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/transp_v6.h> | 30 | #include <net/transp_v6.h> |
31 | #include <net/ip6_route.h> | 31 | #include <net/ip6_route.h> |
32 | #include <net/tcp_states.h> | 32 | #include <net/tcp_states.h> |
33 | #include <net/dsfield.h> | ||
33 | 34 | ||
34 | #include <linux/errqueue.h> | 35 | #include <linux/errqueue.h> |
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
@@ -356,12 +357,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
356 | sin->sin6_port = serr->port; | 357 | sin->sin6_port = serr->port; |
357 | sin->sin6_scope_id = 0; | 358 | sin->sin6_scope_id = 0; |
358 | if (skb->protocol == htons(ETH_P_IPV6)) { | 359 | if (skb->protocol == htons(ETH_P_IPV6)) { |
359 | sin->sin6_addr = | 360 | const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset), |
360 | *(struct in6_addr *)(nh + serr->addr_offset); | 361 | struct ipv6hdr, daddr); |
362 | sin->sin6_addr = ip6h->daddr; | ||
361 | if (np->sndflow) | 363 | if (np->sndflow) |
362 | sin->sin6_flowinfo = | 364 | sin->sin6_flowinfo = ip6_flowinfo(ip6h); |
363 | (*(__be32 *)(nh + serr->addr_offset - 24) & | ||
364 | IPV6_FLOWINFO_MASK); | ||
365 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 365 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
366 | sin->sin6_scope_id = IP6CB(skb)->iif; | 366 | sin->sin6_scope_id = IP6CB(skb)->iif; |
367 | } else { | 367 | } else { |
@@ -380,7 +380,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
380 | if (skb->protocol == htons(ETH_P_IPV6)) { | 380 | if (skb->protocol == htons(ETH_P_IPV6)) { |
381 | sin->sin6_addr = ipv6_hdr(skb)->saddr; | 381 | sin->sin6_addr = ipv6_hdr(skb)->saddr; |
382 | if (np->rxopt.all) | 382 | if (np->rxopt.all) |
383 | datagram_recv_ctl(sk, msg, skb); | 383 | ip6_datagram_recv_ctl(sk, msg, skb); |
384 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 384 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
385 | sin->sin6_scope_id = IP6CB(skb)->iif; | 385 | sin->sin6_scope_id = IP6CB(skb)->iif; |
386 | } else { | 386 | } else { |
@@ -468,7 +468,8 @@ out: | |||
468 | } | 468 | } |
469 | 469 | ||
470 | 470 | ||
471 | int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | 471 | int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, |
472 | struct sk_buff *skb) | ||
472 | { | 473 | { |
473 | struct ipv6_pinfo *np = inet6_sk(sk); | 474 | struct ipv6_pinfo *np = inet6_sk(sk); |
474 | struct inet6_skb_parm *opt = IP6CB(skb); | 475 | struct inet6_skb_parm *opt = IP6CB(skb); |
@@ -488,13 +489,14 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
488 | } | 489 | } |
489 | 490 | ||
490 | if (np->rxopt.bits.rxtclass) { | 491 | if (np->rxopt.bits.rxtclass) { |
491 | int tclass = ipv6_tclass(ipv6_hdr(skb)); | 492 | int tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
492 | put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); | 493 | put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); |
493 | } | 494 | } |
494 | 495 | ||
495 | if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) { | 496 | if (np->rxopt.bits.rxflow) { |
496 | __be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK; | 497 | __be32 flowinfo = ip6_flowinfo((struct ipv6hdr *)nh); |
497 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | 498 | if (flowinfo) |
499 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | ||
498 | } | 500 | } |
499 | 501 | ||
500 | /* HbH is allowed only once */ | 502 | /* HbH is allowed only once */ |
@@ -597,11 +599,12 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
597 | } | 599 | } |
598 | return 0; | 600 | return 0; |
599 | } | 601 | } |
602 | EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); | ||
600 | 603 | ||
601 | int datagram_send_ctl(struct net *net, struct sock *sk, | 604 | int ip6_datagram_send_ctl(struct net *net, struct sock *sk, |
602 | struct msghdr *msg, struct flowi6 *fl6, | 605 | struct msghdr *msg, struct flowi6 *fl6, |
603 | struct ipv6_txoptions *opt, | 606 | struct ipv6_txoptions *opt, |
604 | int *hlimit, int *tclass, int *dontfrag) | 607 | int *hlimit, int *tclass, int *dontfrag) |
605 | { | 608 | { |
606 | struct in6_pktinfo *src_info; | 609 | struct in6_pktinfo *src_info; |
607 | struct cmsghdr *cmsg; | 610 | struct cmsghdr *cmsg; |
@@ -871,4 +874,4 @@ int datagram_send_ctl(struct net *net, struct sock *sk, | |||
871 | exit_f: | 874 | exit_f: |
872 | return err; | 875 | return err; |
873 | } | 876 | } |
874 | EXPORT_SYMBOL_GPL(datagram_send_ctl); | 877 | EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl); |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 282f3723ee19..40ffd72243a4 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -300,7 +300,10 @@ static int esp_input_done2(struct sk_buff *skb, int err) | |||
300 | 300 | ||
301 | pskb_trim(skb, skb->len - alen - padlen - 2); | 301 | pskb_trim(skb, skb->len - alen - padlen - 2); |
302 | __skb_pull(skb, hlen); | 302 | __skb_pull(skb, hlen); |
303 | skb_set_transport_header(skb, -hdr_len); | 303 | if (x->props.mode == XFRM_MODE_TUNNEL) |
304 | skb_reset_transport_header(skb); | ||
305 | else | ||
306 | skb_set_transport_header(skb, -hdr_len); | ||
304 | 307 | ||
305 | err = nexthdr[1]; | 308 | err = nexthdr[1]; |
306 | 309 | ||
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 473f628f9f20..07a7d65a7cb6 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -553,7 +553,8 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
553 | const unsigned char *nh = skb_network_header(skb); | 553 | const unsigned char *nh = skb_network_header(skb); |
554 | 554 | ||
555 | if (nh[optoff + 1] == 2) { | 555 | if (nh[optoff + 1] == 2) { |
556 | IP6CB(skb)->ra = optoff; | 556 | IP6CB(skb)->flags |= IP6SKB_ROUTERALERT; |
557 | memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra)); | ||
557 | return true; | 558 | return true; |
558 | } | 559 | } |
559 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", | 560 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index b4a9fd51dae7..fff5bdd8b680 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -81,10 +81,22 @@ static inline struct sock *icmpv6_sk(struct net *net) | |||
81 | return net->ipv6.icmp_sk[smp_processor_id()]; | 81 | return net->ipv6.icmp_sk[smp_processor_id()]; |
82 | } | 82 | } |
83 | 83 | ||
84 | static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
85 | u8 type, u8 code, int offset, __be32 info) | ||
86 | { | ||
87 | struct net *net = dev_net(skb->dev); | ||
88 | |||
89 | if (type == ICMPV6_PKT_TOOBIG) | ||
90 | ip6_update_pmtu(skb, net, info, 0, 0); | ||
91 | else if (type == NDISC_REDIRECT) | ||
92 | ip6_redirect(skb, net, 0, 0); | ||
93 | } | ||
94 | |||
84 | static int icmpv6_rcv(struct sk_buff *skb); | 95 | static int icmpv6_rcv(struct sk_buff *skb); |
85 | 96 | ||
86 | static const struct inet6_protocol icmpv6_protocol = { | 97 | static const struct inet6_protocol icmpv6_protocol = { |
87 | .handler = icmpv6_rcv, | 98 | .handler = icmpv6_rcv, |
99 | .err_handler = icmpv6_err, | ||
88 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 100 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
89 | }; | 101 | }; |
90 | 102 | ||
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 30647857a375..9bfab19ff3c0 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -31,25 +31,33 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
31 | const struct inet_bind_bucket *tb, bool relax) | 31 | const struct inet_bind_bucket *tb, bool relax) |
32 | { | 32 | { |
33 | const struct sock *sk2; | 33 | const struct sock *sk2; |
34 | const struct hlist_node *node; | 34 | int reuse = sk->sk_reuse; |
35 | int reuseport = sk->sk_reuseport; | ||
36 | kuid_t uid = sock_i_uid((struct sock *)sk); | ||
35 | 37 | ||
36 | /* We must walk the whole port owner list in this case. -DaveM */ | 38 | /* We must walk the whole port owner list in this case. -DaveM */ |
37 | /* | 39 | /* |
38 | * See comment in inet_csk_bind_conflict about sock lookup | 40 | * See comment in inet_csk_bind_conflict about sock lookup |
39 | * vs net namespaces issues. | 41 | * vs net namespaces issues. |
40 | */ | 42 | */ |
41 | sk_for_each_bound(sk2, node, &tb->owners) { | 43 | sk_for_each_bound(sk2, &tb->owners) { |
42 | if (sk != sk2 && | 44 | if (sk != sk2 && |
43 | (!sk->sk_bound_dev_if || | 45 | (!sk->sk_bound_dev_if || |
44 | !sk2->sk_bound_dev_if || | 46 | !sk2->sk_bound_dev_if || |
45 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && | 47 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
46 | (!sk->sk_reuse || !sk2->sk_reuse || | 48 | if ((!reuse || !sk2->sk_reuse || |
47 | sk2->sk_state == TCP_LISTEN) && | 49 | sk2->sk_state == TCP_LISTEN) && |
48 | ipv6_rcv_saddr_equal(sk, sk2)) | 50 | (!reuseport || !sk2->sk_reuseport || |
49 | break; | 51 | (sk2->sk_state != TCP_TIME_WAIT && |
52 | !uid_eq(uid, | ||
53 | sock_i_uid((struct sock *)sk2))))) { | ||
54 | if (ipv6_rcv_saddr_equal(sk, sk2)) | ||
55 | break; | ||
56 | } | ||
57 | } | ||
50 | } | 58 | } |
51 | 59 | ||
52 | return node != NULL; | 60 | return sk2 != NULL; |
53 | } | 61 | } |
54 | 62 | ||
55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); | 63 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index dea17fd28e50..32b4a1675d82 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -158,25 +158,38 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
158 | } | 158 | } |
159 | 159 | ||
160 | struct sock *inet6_lookup_listener(struct net *net, | 160 | struct sock *inet6_lookup_listener(struct net *net, |
161 | struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, | 161 | struct inet_hashinfo *hashinfo, const struct in6_addr *saddr, |
162 | const __be16 sport, const struct in6_addr *daddr, | ||
162 | const unsigned short hnum, const int dif) | 163 | const unsigned short hnum, const int dif) |
163 | { | 164 | { |
164 | struct sock *sk; | 165 | struct sock *sk; |
165 | const struct hlist_nulls_node *node; | 166 | const struct hlist_nulls_node *node; |
166 | struct sock *result; | 167 | struct sock *result; |
167 | int score, hiscore; | 168 | int score, hiscore, matches = 0, reuseport = 0; |
169 | u32 phash = 0; | ||
168 | unsigned int hash = inet_lhashfn(net, hnum); | 170 | unsigned int hash = inet_lhashfn(net, hnum); |
169 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; | 171 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; |
170 | 172 | ||
171 | rcu_read_lock(); | 173 | rcu_read_lock(); |
172 | begin: | 174 | begin: |
173 | result = NULL; | 175 | result = NULL; |
174 | hiscore = -1; | 176 | hiscore = 0; |
175 | sk_nulls_for_each(sk, node, &ilb->head) { | 177 | sk_nulls_for_each(sk, node, &ilb->head) { |
176 | score = compute_score(sk, net, hnum, daddr, dif); | 178 | score = compute_score(sk, net, hnum, daddr, dif); |
177 | if (score > hiscore) { | 179 | if (score > hiscore) { |
178 | hiscore = score; | 180 | hiscore = score; |
179 | result = sk; | 181 | result = sk; |
182 | reuseport = sk->sk_reuseport; | ||
183 | if (reuseport) { | ||
184 | phash = inet6_ehashfn(net, daddr, hnum, | ||
185 | saddr, sport); | ||
186 | matches = 1; | ||
187 | } | ||
188 | } else if (score == hiscore && reuseport) { | ||
189 | matches++; | ||
190 | if (((u64)phash * matches) >> 32 == 0) | ||
191 | result = sk; | ||
192 | phash = next_pseudo_random32(phash); | ||
180 | } | 193 | } |
181 | } | 194 | } |
182 | /* | 195 | /* |
diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c new file mode 100644 index 000000000000..72d198b8e4d2 --- /dev/null +++ b/net/ipv6/ip6_checksum.c | |||
@@ -0,0 +1,97 @@ | |||
1 | #include <net/ip.h> | ||
2 | #include <net/udp.h> | ||
3 | #include <net/udplite.h> | ||
4 | #include <asm/checksum.h> | ||
5 | |||
6 | #ifndef _HAVE_ARCH_IPV6_CSUM | ||
7 | __sum16 csum_ipv6_magic(const struct in6_addr *saddr, | ||
8 | const struct in6_addr *daddr, | ||
9 | __u32 len, unsigned short proto, | ||
10 | __wsum csum) | ||
11 | { | ||
12 | |||
13 | int carry; | ||
14 | __u32 ulen; | ||
15 | __u32 uproto; | ||
16 | __u32 sum = (__force u32)csum; | ||
17 | |||
18 | sum += (__force u32)saddr->s6_addr32[0]; | ||
19 | carry = (sum < (__force u32)saddr->s6_addr32[0]); | ||
20 | sum += carry; | ||
21 | |||
22 | sum += (__force u32)saddr->s6_addr32[1]; | ||
23 | carry = (sum < (__force u32)saddr->s6_addr32[1]); | ||
24 | sum += carry; | ||
25 | |||
26 | sum += (__force u32)saddr->s6_addr32[2]; | ||
27 | carry = (sum < (__force u32)saddr->s6_addr32[2]); | ||
28 | sum += carry; | ||
29 | |||
30 | sum += (__force u32)saddr->s6_addr32[3]; | ||
31 | carry = (sum < (__force u32)saddr->s6_addr32[3]); | ||
32 | sum += carry; | ||
33 | |||
34 | sum += (__force u32)daddr->s6_addr32[0]; | ||
35 | carry = (sum < (__force u32)daddr->s6_addr32[0]); | ||
36 | sum += carry; | ||
37 | |||
38 | sum += (__force u32)daddr->s6_addr32[1]; | ||
39 | carry = (sum < (__force u32)daddr->s6_addr32[1]); | ||
40 | sum += carry; | ||
41 | |||
42 | sum += (__force u32)daddr->s6_addr32[2]; | ||
43 | carry = (sum < (__force u32)daddr->s6_addr32[2]); | ||
44 | sum += carry; | ||
45 | |||
46 | sum += (__force u32)daddr->s6_addr32[3]; | ||
47 | carry = (sum < (__force u32)daddr->s6_addr32[3]); | ||
48 | sum += carry; | ||
49 | |||
50 | ulen = (__force u32)htonl((__u32) len); | ||
51 | sum += ulen; | ||
52 | carry = (sum < ulen); | ||
53 | sum += carry; | ||
54 | |||
55 | uproto = (__force u32)htonl(proto); | ||
56 | sum += uproto; | ||
57 | carry = (sum < uproto); | ||
58 | sum += carry; | ||
59 | |||
60 | return csum_fold((__force __wsum)sum); | ||
61 | } | ||
62 | EXPORT_SYMBOL(csum_ipv6_magic); | ||
63 | #endif | ||
64 | |||
65 | int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) | ||
66 | { | ||
67 | int err; | ||
68 | |||
69 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
70 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
71 | |||
72 | if (proto == IPPROTO_UDPLITE) { | ||
73 | err = udplite_checksum_init(skb, uh); | ||
74 | if (err) | ||
75 | return err; | ||
76 | } | ||
77 | |||
78 | if (uh->check == 0) { | ||
79 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
80 | this error. Well, it is reasonable. | ||
81 | */ | ||
82 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
83 | return 1; | ||
84 | } | ||
85 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
86 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
87 | skb->len, proto, skb->csum)) | ||
88 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
89 | |||
90 | if (!skb_csum_unnecessary(skb)) | ||
91 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
92 | &ipv6_hdr(skb)->daddr, | ||
93 | skb->len, proto, 0)); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | EXPORT_SYMBOL(udp6_csum_init); | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 710cafd2e1a9..192dd1a0e188 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -224,7 +224,6 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
224 | { | 224 | { |
225 | struct fib6_table *tb; | 225 | struct fib6_table *tb; |
226 | struct hlist_head *head; | 226 | struct hlist_head *head; |
227 | struct hlist_node *node; | ||
228 | unsigned int h; | 227 | unsigned int h; |
229 | 228 | ||
230 | if (id == 0) | 229 | if (id == 0) |
@@ -232,7 +231,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
232 | h = id & (FIB6_TABLE_HASHSZ - 1); | 231 | h = id & (FIB6_TABLE_HASHSZ - 1); |
233 | rcu_read_lock(); | 232 | rcu_read_lock(); |
234 | head = &net->ipv6.fib_table_hash[h]; | 233 | head = &net->ipv6.fib_table_hash[h]; |
235 | hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { | 234 | hlist_for_each_entry_rcu(tb, head, tb6_hlist) { |
236 | if (tb->tb6_id == id) { | 235 | if (tb->tb6_id == id) { |
237 | rcu_read_unlock(); | 236 | rcu_read_unlock(); |
238 | return tb; | 237 | return tb; |
@@ -363,7 +362,6 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
363 | struct rt6_rtnl_dump_arg arg; | 362 | struct rt6_rtnl_dump_arg arg; |
364 | struct fib6_walker_t *w; | 363 | struct fib6_walker_t *w; |
365 | struct fib6_table *tb; | 364 | struct fib6_table *tb; |
366 | struct hlist_node *node; | ||
367 | struct hlist_head *head; | 365 | struct hlist_head *head; |
368 | int res = 0; | 366 | int res = 0; |
369 | 367 | ||
@@ -398,7 +396,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
398 | for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { | 396 | for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { |
399 | e = 0; | 397 | e = 0; |
400 | head = &net->ipv6.fib_table_hash[h]; | 398 | head = &net->ipv6.fib_table_hash[h]; |
401 | hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { | 399 | hlist_for_each_entry_rcu(tb, head, tb6_hlist) { |
402 | if (e < s_e) | 400 | if (e < s_e) |
403 | goto next; | 401 | goto next; |
404 | res = fib6_dump_table(tb, skb, cb); | 402 | res = fib6_dump_table(tb, skb, cb); |
@@ -1520,14 +1518,13 @@ void fib6_clean_all_ro(struct net *net, int (*func)(struct rt6_info *, void *arg | |||
1520 | int prune, void *arg) | 1518 | int prune, void *arg) |
1521 | { | 1519 | { |
1522 | struct fib6_table *table; | 1520 | struct fib6_table *table; |
1523 | struct hlist_node *node; | ||
1524 | struct hlist_head *head; | 1521 | struct hlist_head *head; |
1525 | unsigned int h; | 1522 | unsigned int h; |
1526 | 1523 | ||
1527 | rcu_read_lock(); | 1524 | rcu_read_lock(); |
1528 | for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { | 1525 | for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { |
1529 | head = &net->ipv6.fib_table_hash[h]; | 1526 | head = &net->ipv6.fib_table_hash[h]; |
1530 | hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { | 1527 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { |
1531 | read_lock_bh(&table->tb6_lock); | 1528 | read_lock_bh(&table->tb6_lock); |
1532 | fib6_clean_tree(net, &table->tb6_root, | 1529 | fib6_clean_tree(net, &table->tb6_root, |
1533 | func, prune, arg); | 1530 | func, prune, arg); |
@@ -1540,14 +1537,13 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | |||
1540 | int prune, void *arg) | 1537 | int prune, void *arg) |
1541 | { | 1538 | { |
1542 | struct fib6_table *table; | 1539 | struct fib6_table *table; |
1543 | struct hlist_node *node; | ||
1544 | struct hlist_head *head; | 1540 | struct hlist_head *head; |
1545 | unsigned int h; | 1541 | unsigned int h; |
1546 | 1542 | ||
1547 | rcu_read_lock(); | 1543 | rcu_read_lock(); |
1548 | for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { | 1544 | for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { |
1549 | head = &net->ipv6.fib_table_hash[h]; | 1545 | head = &net->ipv6.fib_table_hash[h]; |
1550 | hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { | 1546 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { |
1551 | write_lock_bh(&table->tb6_lock); | 1547 | write_lock_bh(&table->tb6_lock); |
1552 | fib6_clean_tree(net, &table->tb6_root, | 1548 | fib6_clean_tree(net, &table->tb6_root, |
1553 | func, prune, arg); | 1549 | func, prune, arg); |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 29124b7a04c8..b973ed3d06cf 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -51,25 +51,38 @@ | |||
51 | #define FL_HASH(l) (ntohl(l)&FL_HASH_MASK) | 51 | #define FL_HASH(l) (ntohl(l)&FL_HASH_MASK) |
52 | 52 | ||
53 | static atomic_t fl_size = ATOMIC_INIT(0); | 53 | static atomic_t fl_size = ATOMIC_INIT(0); |
54 | static struct ip6_flowlabel *fl_ht[FL_HASH_MASK+1]; | 54 | static struct ip6_flowlabel __rcu *fl_ht[FL_HASH_MASK+1]; |
55 | 55 | ||
56 | static void ip6_fl_gc(unsigned long dummy); | 56 | static void ip6_fl_gc(unsigned long dummy); |
57 | static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); | 57 | static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); |
58 | 58 | ||
59 | /* FL hash table lock: it protects only of GC */ | 59 | /* FL hash table lock: it protects only of GC */ |
60 | 60 | ||
61 | static DEFINE_RWLOCK(ip6_fl_lock); | 61 | static DEFINE_SPINLOCK(ip6_fl_lock); |
62 | 62 | ||
63 | /* Big socket sock */ | 63 | /* Big socket sock */ |
64 | 64 | ||
65 | static DEFINE_RWLOCK(ip6_sk_fl_lock); | 65 | static DEFINE_SPINLOCK(ip6_sk_fl_lock); |
66 | 66 | ||
67 | #define for_each_fl_rcu(hash, fl) \ | ||
68 | for (fl = rcu_dereference_bh(fl_ht[(hash)]); \ | ||
69 | fl != NULL; \ | ||
70 | fl = rcu_dereference_bh(fl->next)) | ||
71 | #define for_each_fl_continue_rcu(fl) \ | ||
72 | for (fl = rcu_dereference_bh(fl->next); \ | ||
73 | fl != NULL; \ | ||
74 | fl = rcu_dereference_bh(fl->next)) | ||
75 | |||
76 | #define for_each_sk_fl_rcu(np, sfl) \ | ||
77 | for (sfl = rcu_dereference_bh(np->ipv6_fl_list); \ | ||
78 | sfl != NULL; \ | ||
79 | sfl = rcu_dereference_bh(sfl->next)) | ||
67 | 80 | ||
68 | static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) | 81 | static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) |
69 | { | 82 | { |
70 | struct ip6_flowlabel *fl; | 83 | struct ip6_flowlabel *fl; |
71 | 84 | ||
72 | for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { | 85 | for_each_fl_rcu(FL_HASH(label), fl) { |
73 | if (fl->label == label && net_eq(fl->fl_net, net)) | 86 | if (fl->label == label && net_eq(fl->fl_net, net)) |
74 | return fl; | 87 | return fl; |
75 | } | 88 | } |
@@ -80,11 +93,11 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) | |||
80 | { | 93 | { |
81 | struct ip6_flowlabel *fl; | 94 | struct ip6_flowlabel *fl; |
82 | 95 | ||
83 | read_lock_bh(&ip6_fl_lock); | 96 | rcu_read_lock_bh(); |
84 | fl = __fl_lookup(net, label); | 97 | fl = __fl_lookup(net, label); |
85 | if (fl) | 98 | if (fl && !atomic_inc_not_zero(&fl->users)) |
86 | atomic_inc(&fl->users); | 99 | fl = NULL; |
87 | read_unlock_bh(&ip6_fl_lock); | 100 | rcu_read_unlock_bh(); |
88 | return fl; | 101 | return fl; |
89 | } | 102 | } |
90 | 103 | ||
@@ -96,13 +109,13 @@ static void fl_free(struct ip6_flowlabel *fl) | |||
96 | put_pid(fl->owner.pid); | 109 | put_pid(fl->owner.pid); |
97 | release_net(fl->fl_net); | 110 | release_net(fl->fl_net); |
98 | kfree(fl->opt); | 111 | kfree(fl->opt); |
112 | kfree_rcu(fl, rcu); | ||
99 | } | 113 | } |
100 | kfree(fl); | ||
101 | } | 114 | } |
102 | 115 | ||
103 | static void fl_release(struct ip6_flowlabel *fl) | 116 | static void fl_release(struct ip6_flowlabel *fl) |
104 | { | 117 | { |
105 | write_lock_bh(&ip6_fl_lock); | 118 | spin_lock_bh(&ip6_fl_lock); |
106 | 119 | ||
107 | fl->lastuse = jiffies; | 120 | fl->lastuse = jiffies; |
108 | if (atomic_dec_and_test(&fl->users)) { | 121 | if (atomic_dec_and_test(&fl->users)) { |
@@ -119,7 +132,7 @@ static void fl_release(struct ip6_flowlabel *fl) | |||
119 | time_after(ip6_fl_gc_timer.expires, ttd)) | 132 | time_after(ip6_fl_gc_timer.expires, ttd)) |
120 | mod_timer(&ip6_fl_gc_timer, ttd); | 133 | mod_timer(&ip6_fl_gc_timer, ttd); |
121 | } | 134 | } |
122 | write_unlock_bh(&ip6_fl_lock); | 135 | spin_unlock_bh(&ip6_fl_lock); |
123 | } | 136 | } |
124 | 137 | ||
125 | static void ip6_fl_gc(unsigned long dummy) | 138 | static void ip6_fl_gc(unsigned long dummy) |
@@ -128,12 +141,13 @@ static void ip6_fl_gc(unsigned long dummy) | |||
128 | unsigned long now = jiffies; | 141 | unsigned long now = jiffies; |
129 | unsigned long sched = 0; | 142 | unsigned long sched = 0; |
130 | 143 | ||
131 | write_lock(&ip6_fl_lock); | 144 | spin_lock(&ip6_fl_lock); |
132 | 145 | ||
133 | for (i=0; i<=FL_HASH_MASK; i++) { | 146 | for (i=0; i<=FL_HASH_MASK; i++) { |
134 | struct ip6_flowlabel *fl, **flp; | 147 | struct ip6_flowlabel *fl, **flp; |
135 | flp = &fl_ht[i]; | 148 | flp = &fl_ht[i]; |
136 | while ((fl=*flp) != NULL) { | 149 | while ((fl = rcu_dereference_protected(*flp, |
150 | lockdep_is_held(&ip6_fl_lock))) != NULL) { | ||
137 | if (atomic_read(&fl->users) == 0) { | 151 | if (atomic_read(&fl->users) == 0) { |
138 | unsigned long ttd = fl->lastuse + fl->linger; | 152 | unsigned long ttd = fl->lastuse + fl->linger; |
139 | if (time_after(ttd, fl->expires)) | 153 | if (time_after(ttd, fl->expires)) |
@@ -156,18 +170,19 @@ static void ip6_fl_gc(unsigned long dummy) | |||
156 | if (sched) { | 170 | if (sched) { |
157 | mod_timer(&ip6_fl_gc_timer, sched); | 171 | mod_timer(&ip6_fl_gc_timer, sched); |
158 | } | 172 | } |
159 | write_unlock(&ip6_fl_lock); | 173 | spin_unlock(&ip6_fl_lock); |
160 | } | 174 | } |
161 | 175 | ||
162 | static void __net_exit ip6_fl_purge(struct net *net) | 176 | static void __net_exit ip6_fl_purge(struct net *net) |
163 | { | 177 | { |
164 | int i; | 178 | int i; |
165 | 179 | ||
166 | write_lock(&ip6_fl_lock); | 180 | spin_lock(&ip6_fl_lock); |
167 | for (i = 0; i <= FL_HASH_MASK; i++) { | 181 | for (i = 0; i <= FL_HASH_MASK; i++) { |
168 | struct ip6_flowlabel *fl, **flp; | 182 | struct ip6_flowlabel *fl, **flp; |
169 | flp = &fl_ht[i]; | 183 | flp = &fl_ht[i]; |
170 | while ((fl = *flp) != NULL) { | 184 | while ((fl = rcu_dereference_protected(*flp, |
185 | lockdep_is_held(&ip6_fl_lock))) != NULL) { | ||
171 | if (net_eq(fl->fl_net, net) && | 186 | if (net_eq(fl->fl_net, net) && |
172 | atomic_read(&fl->users) == 0) { | 187 | atomic_read(&fl->users) == 0) { |
173 | *flp = fl->next; | 188 | *flp = fl->next; |
@@ -178,7 +193,7 @@ static void __net_exit ip6_fl_purge(struct net *net) | |||
178 | flp = &fl->next; | 193 | flp = &fl->next; |
179 | } | 194 | } |
180 | } | 195 | } |
181 | write_unlock(&ip6_fl_lock); | 196 | spin_unlock(&ip6_fl_lock); |
182 | } | 197 | } |
183 | 198 | ||
184 | static struct ip6_flowlabel *fl_intern(struct net *net, | 199 | static struct ip6_flowlabel *fl_intern(struct net *net, |
@@ -188,7 +203,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
188 | 203 | ||
189 | fl->label = label & IPV6_FLOWLABEL_MASK; | 204 | fl->label = label & IPV6_FLOWLABEL_MASK; |
190 | 205 | ||
191 | write_lock_bh(&ip6_fl_lock); | 206 | spin_lock_bh(&ip6_fl_lock); |
192 | if (label == 0) { | 207 | if (label == 0) { |
193 | for (;;) { | 208 | for (;;) { |
194 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; | 209 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; |
@@ -210,16 +225,16 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
210 | lfl = __fl_lookup(net, fl->label); | 225 | lfl = __fl_lookup(net, fl->label); |
211 | if (lfl != NULL) { | 226 | if (lfl != NULL) { |
212 | atomic_inc(&lfl->users); | 227 | atomic_inc(&lfl->users); |
213 | write_unlock_bh(&ip6_fl_lock); | 228 | spin_unlock_bh(&ip6_fl_lock); |
214 | return lfl; | 229 | return lfl; |
215 | } | 230 | } |
216 | } | 231 | } |
217 | 232 | ||
218 | fl->lastuse = jiffies; | 233 | fl->lastuse = jiffies; |
219 | fl->next = fl_ht[FL_HASH(fl->label)]; | 234 | fl->next = fl_ht[FL_HASH(fl->label)]; |
220 | fl_ht[FL_HASH(fl->label)] = fl; | 235 | rcu_assign_pointer(fl_ht[FL_HASH(fl->label)], fl); |
221 | atomic_inc(&fl_size); | 236 | atomic_inc(&fl_size); |
222 | write_unlock_bh(&ip6_fl_lock); | 237 | spin_unlock_bh(&ip6_fl_lock); |
223 | return NULL; | 238 | return NULL; |
224 | } | 239 | } |
225 | 240 | ||
@@ -234,17 +249,17 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) | |||
234 | 249 | ||
235 | label &= IPV6_FLOWLABEL_MASK; | 250 | label &= IPV6_FLOWLABEL_MASK; |
236 | 251 | ||
237 | read_lock_bh(&ip6_sk_fl_lock); | 252 | rcu_read_lock_bh(); |
238 | for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) { | 253 | for_each_sk_fl_rcu(np, sfl) { |
239 | struct ip6_flowlabel *fl = sfl->fl; | 254 | struct ip6_flowlabel *fl = sfl->fl; |
240 | if (fl->label == label) { | 255 | if (fl->label == label) { |
241 | fl->lastuse = jiffies; | 256 | fl->lastuse = jiffies; |
242 | atomic_inc(&fl->users); | 257 | atomic_inc(&fl->users); |
243 | read_unlock_bh(&ip6_sk_fl_lock); | 258 | rcu_read_unlock_bh(); |
244 | return fl; | 259 | return fl; |
245 | } | 260 | } |
246 | } | 261 | } |
247 | read_unlock_bh(&ip6_sk_fl_lock); | 262 | rcu_read_unlock_bh(); |
248 | return NULL; | 263 | return NULL; |
249 | } | 264 | } |
250 | 265 | ||
@@ -255,11 +270,21 @@ void fl6_free_socklist(struct sock *sk) | |||
255 | struct ipv6_pinfo *np = inet6_sk(sk); | 270 | struct ipv6_pinfo *np = inet6_sk(sk); |
256 | struct ipv6_fl_socklist *sfl; | 271 | struct ipv6_fl_socklist *sfl; |
257 | 272 | ||
258 | while ((sfl = np->ipv6_fl_list) != NULL) { | 273 | if (!rcu_access_pointer(np->ipv6_fl_list)) |
274 | return; | ||
275 | |||
276 | spin_lock_bh(&ip6_sk_fl_lock); | ||
277 | while ((sfl = rcu_dereference_protected(np->ipv6_fl_list, | ||
278 | lockdep_is_held(&ip6_sk_fl_lock))) != NULL) { | ||
259 | np->ipv6_fl_list = sfl->next; | 279 | np->ipv6_fl_list = sfl->next; |
280 | spin_unlock_bh(&ip6_sk_fl_lock); | ||
281 | |||
260 | fl_release(sfl->fl); | 282 | fl_release(sfl->fl); |
261 | kfree(sfl); | 283 | kfree_rcu(sfl, rcu); |
284 | |||
285 | spin_lock_bh(&ip6_sk_fl_lock); | ||
262 | } | 286 | } |
287 | spin_unlock_bh(&ip6_sk_fl_lock); | ||
263 | } | 288 | } |
264 | 289 | ||
265 | /* Service routines */ | 290 | /* Service routines */ |
@@ -365,8 +390,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, | |||
365 | msg.msg_control = (void*)(fl->opt+1); | 390 | msg.msg_control = (void*)(fl->opt+1); |
366 | memset(&flowi6, 0, sizeof(flowi6)); | 391 | memset(&flowi6, 0, sizeof(flowi6)); |
367 | 392 | ||
368 | err = datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, &junk, | 393 | err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, |
369 | &junk, &junk); | 394 | &junk, &junk, &junk); |
370 | if (err) | 395 | if (err) |
371 | goto done; | 396 | goto done; |
372 | err = -EINVAL; | 397 | err = -EINVAL; |
@@ -424,7 +449,7 @@ static int mem_check(struct sock *sk) | |||
424 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) | 449 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) |
425 | return 0; | 450 | return 0; |
426 | 451 | ||
427 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) | 452 | for_each_sk_fl_rcu(np, sfl) |
428 | count++; | 453 | count++; |
429 | 454 | ||
430 | if (room <= 0 || | 455 | if (room <= 0 || |
@@ -467,11 +492,11 @@ static bool ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) | |||
467 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | 492 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, |
468 | struct ip6_flowlabel *fl) | 493 | struct ip6_flowlabel *fl) |
469 | { | 494 | { |
470 | write_lock_bh(&ip6_sk_fl_lock); | 495 | spin_lock_bh(&ip6_sk_fl_lock); |
471 | sfl->fl = fl; | 496 | sfl->fl = fl; |
472 | sfl->next = np->ipv6_fl_list; | 497 | sfl->next = np->ipv6_fl_list; |
473 | np->ipv6_fl_list = sfl; | 498 | rcu_assign_pointer(np->ipv6_fl_list, sfl); |
474 | write_unlock_bh(&ip6_sk_fl_lock); | 499 | spin_unlock_bh(&ip6_sk_fl_lock); |
475 | } | 500 | } |
476 | 501 | ||
477 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 502 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) |
@@ -493,31 +518,33 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
493 | 518 | ||
494 | switch (freq.flr_action) { | 519 | switch (freq.flr_action) { |
495 | case IPV6_FL_A_PUT: | 520 | case IPV6_FL_A_PUT: |
496 | write_lock_bh(&ip6_sk_fl_lock); | 521 | spin_lock_bh(&ip6_sk_fl_lock); |
497 | for (sflp = &np->ipv6_fl_list; (sfl=*sflp)!=NULL; sflp = &sfl->next) { | 522 | for (sflp = &np->ipv6_fl_list; |
523 | (sfl = rcu_dereference(*sflp))!=NULL; | ||
524 | sflp = &sfl->next) { | ||
498 | if (sfl->fl->label == freq.flr_label) { | 525 | if (sfl->fl->label == freq.flr_label) { |
499 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) | 526 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) |
500 | np->flow_label &= ~IPV6_FLOWLABEL_MASK; | 527 | np->flow_label &= ~IPV6_FLOWLABEL_MASK; |
501 | *sflp = sfl->next; | 528 | *sflp = rcu_dereference(sfl->next); |
502 | write_unlock_bh(&ip6_sk_fl_lock); | 529 | spin_unlock_bh(&ip6_sk_fl_lock); |
503 | fl_release(sfl->fl); | 530 | fl_release(sfl->fl); |
504 | kfree(sfl); | 531 | kfree_rcu(sfl, rcu); |
505 | return 0; | 532 | return 0; |
506 | } | 533 | } |
507 | } | 534 | } |
508 | write_unlock_bh(&ip6_sk_fl_lock); | 535 | spin_unlock_bh(&ip6_sk_fl_lock); |
509 | return -ESRCH; | 536 | return -ESRCH; |
510 | 537 | ||
511 | case IPV6_FL_A_RENEW: | 538 | case IPV6_FL_A_RENEW: |
512 | read_lock_bh(&ip6_sk_fl_lock); | 539 | rcu_read_lock_bh(); |
513 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { | 540 | for_each_sk_fl_rcu(np, sfl) { |
514 | if (sfl->fl->label == freq.flr_label) { | 541 | if (sfl->fl->label == freq.flr_label) { |
515 | err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); | 542 | err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); |
516 | read_unlock_bh(&ip6_sk_fl_lock); | 543 | rcu_read_unlock_bh(); |
517 | return err; | 544 | return err; |
518 | } | 545 | } |
519 | } | 546 | } |
520 | read_unlock_bh(&ip6_sk_fl_lock); | 547 | rcu_read_unlock_bh(); |
521 | 548 | ||
522 | if (freq.flr_share == IPV6_FL_S_NONE && | 549 | if (freq.flr_share == IPV6_FL_S_NONE && |
523 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { | 550 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { |
@@ -541,11 +568,11 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
541 | 568 | ||
542 | if (freq.flr_label) { | 569 | if (freq.flr_label) { |
543 | err = -EEXIST; | 570 | err = -EEXIST; |
544 | read_lock_bh(&ip6_sk_fl_lock); | 571 | rcu_read_lock_bh(); |
545 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { | 572 | for_each_sk_fl_rcu(np, sfl) { |
546 | if (sfl->fl->label == freq.flr_label) { | 573 | if (sfl->fl->label == freq.flr_label) { |
547 | if (freq.flr_flags&IPV6_FL_F_EXCL) { | 574 | if (freq.flr_flags&IPV6_FL_F_EXCL) { |
548 | read_unlock_bh(&ip6_sk_fl_lock); | 575 | rcu_read_unlock_bh(); |
549 | goto done; | 576 | goto done; |
550 | } | 577 | } |
551 | fl1 = sfl->fl; | 578 | fl1 = sfl->fl; |
@@ -553,7 +580,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
553 | break; | 580 | break; |
554 | } | 581 | } |
555 | } | 582 | } |
556 | read_unlock_bh(&ip6_sk_fl_lock); | 583 | rcu_read_unlock_bh(); |
557 | 584 | ||
558 | if (fl1 == NULL) | 585 | if (fl1 == NULL) |
559 | fl1 = fl_lookup(net, freq.flr_label); | 586 | fl1 = fl_lookup(net, freq.flr_label); |
@@ -641,13 +668,13 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) | |||
641 | struct net *net = seq_file_net(seq); | 668 | struct net *net = seq_file_net(seq); |
642 | 669 | ||
643 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { | 670 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { |
644 | fl = fl_ht[state->bucket]; | 671 | for_each_fl_rcu(state->bucket, fl) { |
645 | 672 | if (net_eq(fl->fl_net, net)) | |
646 | while (fl && !net_eq(fl->fl_net, net)) | 673 | goto out; |
647 | fl = fl->next; | 674 | } |
648 | if (fl) | ||
649 | break; | ||
650 | } | 675 | } |
676 | fl = NULL; | ||
677 | out: | ||
651 | return fl; | 678 | return fl; |
652 | } | 679 | } |
653 | 680 | ||
@@ -656,18 +683,22 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo | |||
656 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | 683 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); |
657 | struct net *net = seq_file_net(seq); | 684 | struct net *net = seq_file_net(seq); |
658 | 685 | ||
659 | fl = fl->next; | 686 | for_each_fl_continue_rcu(fl) { |
687 | if (net_eq(fl->fl_net, net)) | ||
688 | goto out; | ||
689 | } | ||
690 | |||
660 | try_again: | 691 | try_again: |
661 | while (fl && !net_eq(fl->fl_net, net)) | 692 | if (++state->bucket <= FL_HASH_MASK) { |
662 | fl = fl->next; | 693 | for_each_fl_rcu(state->bucket, fl) { |
663 | 694 | if (net_eq(fl->fl_net, net)) | |
664 | while (!fl) { | 695 | goto out; |
665 | if (++state->bucket <= FL_HASH_MASK) { | 696 | } |
666 | fl = fl_ht[state->bucket]; | 697 | goto try_again; |
667 | goto try_again; | ||
668 | } else | ||
669 | break; | ||
670 | } | 698 | } |
699 | fl = NULL; | ||
700 | |||
701 | out: | ||
671 | return fl; | 702 | return fl; |
672 | } | 703 | } |
673 | 704 | ||
@@ -681,9 +712,9 @@ static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos) | |||
681 | } | 712 | } |
682 | 713 | ||
683 | static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) | 714 | static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) |
684 | __acquires(ip6_fl_lock) | 715 | __acquires(RCU) |
685 | { | 716 | { |
686 | read_lock_bh(&ip6_fl_lock); | 717 | rcu_read_lock_bh(); |
687 | return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 718 | return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
688 | } | 719 | } |
689 | 720 | ||
@@ -700,9 +731,9 @@ static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
700 | } | 731 | } |
701 | 732 | ||
702 | static void ip6fl_seq_stop(struct seq_file *seq, void *v) | 733 | static void ip6fl_seq_stop(struct seq_file *seq, void *v) |
703 | __releases(ip6_fl_lock) | 734 | __releases(RCU) |
704 | { | 735 | { |
705 | read_unlock_bh(&ip6_fl_lock); | 736 | rcu_read_unlock_bh(); |
706 | } | 737 | } |
707 | 738 | ||
708 | static int ip6fl_seq_show(struct seq_file *seq, void *v) | 739 | static int ip6fl_seq_show(struct seq_file *seq, void *v) |
@@ -775,15 +806,15 @@ static const struct file_operations ip6fl_seq_fops = { | |||
775 | 806 | ||
776 | static int __net_init ip6_flowlabel_proc_init(struct net *net) | 807 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |
777 | { | 808 | { |
778 | if (!proc_net_fops_create(net, "ip6_flowlabel", | 809 | if (!proc_create("ip6_flowlabel", S_IRUGO, net->proc_net, |
779 | S_IRUGO, &ip6fl_seq_fops)) | 810 | &ip6fl_seq_fops)) |
780 | return -ENOMEM; | 811 | return -ENOMEM; |
781 | return 0; | 812 | return 0; |
782 | } | 813 | } |
783 | 814 | ||
784 | static void __net_exit ip6_flowlabel_proc_fini(struct net *net) | 815 | static void __net_exit ip6_flowlabel_proc_fini(struct net *net) |
785 | { | 816 | { |
786 | proc_net_remove(net, "ip6_flowlabel"); | 817 | remove_proc_entry("ip6_flowlabel", net->proc_net); |
787 | } | 818 | } |
788 | #else | 819 | #else |
789 | static inline int ip6_flowlabel_proc_init(struct net *net) | 820 | static inline int ip6_flowlabel_proc_init(struct net *net) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 867466c96aac..e4efffe2522e 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -758,8 +758,6 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
758 | skb_dst_set_noref(skb, dst); | 758 | skb_dst_set_noref(skb, dst); |
759 | } | 759 | } |
760 | 760 | ||
761 | skb->transport_header = skb->network_header; | ||
762 | |||
763 | proto = NEXTHDR_GRE; | 761 | proto = NEXTHDR_GRE; |
764 | if (encap_limit >= 0) { | 762 | if (encap_limit >= 0) { |
765 | init_tel_txopt(&opt, encap_limit); | 763 | init_tel_txopt(&opt, encap_limit); |
@@ -768,14 +766,13 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
768 | 766 | ||
769 | skb_push(skb, gre_hlen); | 767 | skb_push(skb, gre_hlen); |
770 | skb_reset_network_header(skb); | 768 | skb_reset_network_header(skb); |
769 | skb_set_transport_header(skb, sizeof(*ipv6h)); | ||
771 | 770 | ||
772 | /* | 771 | /* |
773 | * Push down and install the IP header. | 772 | * Push down and install the IP header. |
774 | */ | 773 | */ |
775 | ipv6h = ipv6_hdr(skb); | 774 | ipv6h = ipv6_hdr(skb); |
776 | *(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000); | 775 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); |
777 | dsfield = INET_ECN_encapsulate(0, dsfield); | ||
778 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | ||
779 | ipv6h->hop_limit = tunnel->parms.hop_limit; | 776 | ipv6h->hop_limit = tunnel->parms.hop_limit; |
780 | ipv6h->nexthdr = proto; | 777 | ipv6h->nexthdr = proto; |
781 | ipv6h->saddr = fl6->saddr; | 778 | ipv6h->saddr = fl6->saddr; |
@@ -961,7 +958,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, | |||
961 | int ret; | 958 | int ret; |
962 | 959 | ||
963 | if (!ip6_tnl_xmit_ctl(t)) | 960 | if (!ip6_tnl_xmit_ctl(t)) |
964 | return -1; | 961 | goto tx_err; |
965 | 962 | ||
966 | switch (skb->protocol) { | 963 | switch (skb->protocol) { |
967 | case htons(ETH_P_IP): | 964 | case htons(ETH_P_IP): |
@@ -1241,7 +1238,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, | |||
1241 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); | 1238 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); |
1242 | __be16 *p = (__be16 *)(ipv6h+1); | 1239 | __be16 *p = (__be16 *)(ipv6h+1); |
1243 | 1240 | ||
1244 | *(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000); | 1241 | ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel); |
1245 | ipv6h->hop_limit = t->parms.hop_limit; | 1242 | ipv6h->hop_limit = t->parms.hop_limit; |
1246 | ipv6h->nexthdr = NEXTHDR_GRE; | 1243 | ipv6h->nexthdr = NEXTHDR_GRE; |
1247 | ipv6h->saddr = t->parms.laddr; | 1244 | ipv6h->saddr = t->parms.laddr; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a52d864d562b..e33fe0ab2568 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -118,6 +118,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
118 | ipv6_addr_loopback(&hdr->daddr)) | 118 | ipv6_addr_loopback(&hdr->daddr)) |
119 | goto err; | 119 | goto err; |
120 | 120 | ||
121 | /* RFC4291 2.7 | ||
122 | * Nodes must not originate a packet to a multicast address whose scope | ||
123 | * field contains the reserved value 0; if such a packet is received, it | ||
124 | * must be silently dropped. | ||
125 | */ | ||
126 | if (ipv6_addr_is_multicast(&hdr->daddr) && | ||
127 | IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) | ||
128 | goto err; | ||
129 | |||
121 | /* | 130 | /* |
122 | * RFC4291 2.7 | 131 | * RFC4291 2.7 |
123 | * Multicast addresses must not be used as source addresses in IPv6 | 132 | * Multicast addresses must not be used as source addresses in IPv6 |
@@ -212,7 +221,7 @@ resubmit: | |||
212 | if (ipv6_addr_is_multicast(&hdr->daddr) && | 221 | if (ipv6_addr_is_multicast(&hdr->daddr) && |
213 | !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, | 222 | !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, |
214 | &hdr->saddr) && | 223 | &hdr->saddr) && |
215 | !ipv6_is_mld(skb, nexthdr)) | 224 | !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) |
216 | goto discard; | 225 | goto discard; |
217 | } | 226 | } |
218 | if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && | 227 | if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && |
@@ -232,9 +241,11 @@ resubmit: | |||
232 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 241 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
233 | ICMPV6_UNK_NEXTHDR, nhoff); | 242 | ICMPV6_UNK_NEXTHDR, nhoff); |
234 | } | 243 | } |
235 | } else | 244 | kfree_skb(skb); |
245 | } else { | ||
236 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); | 246 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
237 | kfree_skb(skb); | 247 | consume_skb(skb); |
248 | } | ||
238 | } | 249 | } |
239 | rcu_read_unlock(); | 250 | rcu_read_unlock(); |
240 | return 0; | 251 | return 0; |
@@ -270,7 +281,8 @@ int ip6_mc_input(struct sk_buff *skb) | |||
270 | * IPv6 multicast router mode is now supported ;) | 281 | * IPv6 multicast router mode is now supported ;) |
271 | */ | 282 | */ |
272 | if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && | 283 | if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && |
273 | !(ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) && | 284 | !(ipv6_addr_type(&hdr->daddr) & |
285 | (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) && | ||
274 | likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { | 286 | likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { |
275 | /* | 287 | /* |
276 | * Okay, we try to forward - split and duplicate | 288 | * Okay, we try to forward - split and duplicate |
@@ -280,10 +292,8 @@ int ip6_mc_input(struct sk_buff *skb) | |||
280 | struct inet6_skb_parm *opt = IP6CB(skb); | 292 | struct inet6_skb_parm *opt = IP6CB(skb); |
281 | 293 | ||
282 | /* Check for MLD */ | 294 | /* Check for MLD */ |
283 | if (unlikely(opt->ra)) { | 295 | if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { |
284 | /* Check if this is a mld message */ | 296 | /* Check if this is a mld message */ |
285 | u8 *ptr = skb_network_header(skb) + opt->ra; | ||
286 | struct icmp6hdr *icmp6; | ||
287 | u8 nexthdr = hdr->nexthdr; | 297 | u8 nexthdr = hdr->nexthdr; |
288 | __be16 frag_off; | 298 | __be16 frag_off; |
289 | int offset; | 299 | int offset; |
@@ -291,7 +301,7 @@ int ip6_mc_input(struct sk_buff *skb) | |||
291 | /* Check if the value of Router Alert | 301 | /* Check if the value of Router Alert |
292 | * is for MLD (0x0000). | 302 | * is for MLD (0x0000). |
293 | */ | 303 | */ |
294 | if ((ptr[2] | ptr[3]) == 0) { | 304 | if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { |
295 | deliver = false; | 305 | deliver = false; |
296 | 306 | ||
297 | if (!ipv6_ext_hdr(nexthdr)) { | 307 | if (!ipv6_ext_hdr(nexthdr)) { |
@@ -303,24 +313,10 @@ int ip6_mc_input(struct sk_buff *skb) | |||
303 | if (offset < 0) | 313 | if (offset < 0) |
304 | goto out; | 314 | goto out; |
305 | 315 | ||
306 | if (nexthdr != IPPROTO_ICMPV6) | 316 | if (!ipv6_is_mld(skb, nexthdr, offset)) |
307 | goto out; | 317 | goto out; |
308 | 318 | ||
309 | if (!pskb_may_pull(skb, (skb_network_header(skb) + | 319 | deliver = true; |
310 | offset + 1 - skb->data))) | ||
311 | goto out; | ||
312 | |||
313 | icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); | ||
314 | |||
315 | switch (icmp6->icmp6_type) { | ||
316 | case ICMPV6_MGM_QUERY: | ||
317 | case ICMPV6_MGM_REPORT: | ||
318 | case ICMPV6_MGM_REDUCTION: | ||
319 | case ICMPV6_MLD2_REPORT: | ||
320 | deliver = true; | ||
321 | break; | ||
322 | } | ||
323 | goto out; | ||
324 | } | 320 | } |
325 | /* unknown RA - process it normally */ | 321 | /* unknown RA - process it normally */ |
326 | } | 322 | } |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index f26f0da7f095..8234c1dcdf72 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -99,6 +99,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
99 | ~(SKB_GSO_UDP | | 99 | ~(SKB_GSO_UDP | |
100 | SKB_GSO_DODGY | | 100 | SKB_GSO_DODGY | |
101 | SKB_GSO_TCP_ECN | | 101 | SKB_GSO_TCP_ECN | |
102 | SKB_GSO_GRE | | ||
102 | SKB_GSO_TCPV6 | | 103 | SKB_GSO_TCPV6 | |
103 | 0))) | 104 | 0))) |
104 | goto out; | 105 | goto out; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5552d13ae92f..155eccfa7760 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -56,8 +56,6 @@ | |||
56 | #include <net/checksum.h> | 56 | #include <net/checksum.h> |
57 | #include <linux/mroute6.h> | 57 | #include <linux/mroute6.h> |
58 | 58 | ||
59 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | ||
60 | |||
61 | int __ip6_local_out(struct sk_buff *skb) | 59 | int __ip6_local_out(struct sk_buff *skb) |
62 | { | 60 | { |
63 | int len; | 61 | int len; |
@@ -88,7 +86,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
88 | struct dst_entry *dst = skb_dst(skb); | 86 | struct dst_entry *dst = skb_dst(skb); |
89 | struct net_device *dev = dst->dev; | 87 | struct net_device *dev = dst->dev; |
90 | struct neighbour *neigh; | 88 | struct neighbour *neigh; |
91 | struct rt6_info *rt; | 89 | struct in6_addr *nexthop; |
90 | int ret; | ||
92 | 91 | ||
93 | skb->protocol = htons(ETH_P_IPV6); | 92 | skb->protocol = htons(ETH_P_IPV6); |
94 | skb->dev = dev; | 93 | skb->dev = dev; |
@@ -121,12 +120,26 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
121 | 120 | ||
122 | IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, | 121 | IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, |
123 | skb->len); | 122 | skb->len); |
123 | |||
124 | if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <= | ||
125 | IPV6_ADDR_SCOPE_NODELOCAL && | ||
126 | !(dev->flags & IFF_LOOPBACK)) { | ||
127 | kfree_skb(skb); | ||
128 | return 0; | ||
129 | } | ||
124 | } | 130 | } |
125 | 131 | ||
126 | rt = (struct rt6_info *) dst; | 132 | rcu_read_lock_bh(); |
127 | neigh = rt->n; | 133 | nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); |
128 | if (neigh) | 134 | neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); |
129 | return dst_neigh_output(dst, neigh, skb); | 135 | if (unlikely(!neigh)) |
136 | neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); | ||
137 | if (!IS_ERR(neigh)) { | ||
138 | ret = dst_neigh_output(dst, neigh, skb); | ||
139 | rcu_read_unlock_bh(); | ||
140 | return ret; | ||
141 | } | ||
142 | rcu_read_unlock_bh(); | ||
130 | 143 | ||
131 | IP6_INC_STATS_BH(dev_net(dst->dev), | 144 | IP6_INC_STATS_BH(dev_net(dst->dev), |
132 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 145 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
@@ -216,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
216 | if (hlimit < 0) | 229 | if (hlimit < 0) |
217 | hlimit = ip6_dst_hoplimit(dst); | 230 | hlimit = ip6_dst_hoplimit(dst); |
218 | 231 | ||
219 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; | 232 | ip6_flow_hdr(hdr, tclass, fl6->flowlabel); |
220 | 233 | ||
221 | hdr->payload_len = htons(seg_len); | 234 | hdr->payload_len = htons(seg_len); |
222 | hdr->nexthdr = proto; | 235 | hdr->nexthdr = proto; |
@@ -236,9 +249,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
236 | dst->dev, dst_output); | 249 | dst->dev, dst_output); |
237 | } | 250 | } |
238 | 251 | ||
239 | net_dbg_ratelimited("IPv6: sending pkt_too_big to self\n"); | ||
240 | skb->dev = dst->dev; | 252 | skb->dev = dst->dev; |
241 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 253 | ipv6_local_error(sk, EMSGSIZE, fl6, mtu); |
242 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); | 254 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
243 | kfree_skb(skb); | 255 | kfree_skb(skb); |
244 | return -EMSGSIZE; | 256 | return -EMSGSIZE; |
@@ -246,39 +258,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
246 | 258 | ||
247 | EXPORT_SYMBOL(ip6_xmit); | 259 | EXPORT_SYMBOL(ip6_xmit); |
248 | 260 | ||
249 | /* | ||
250 | * To avoid extra problems ND packets are send through this | ||
251 | * routine. It's code duplication but I really want to avoid | ||
252 | * extra checks since ipv6_build_header is used by TCP (which | ||
253 | * is for us performance critical) | ||
254 | */ | ||
255 | |||
256 | int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, | ||
257 | const struct in6_addr *saddr, const struct in6_addr *daddr, | ||
258 | int proto, int len) | ||
259 | { | ||
260 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
261 | struct ipv6hdr *hdr; | ||
262 | |||
263 | skb->protocol = htons(ETH_P_IPV6); | ||
264 | skb->dev = dev; | ||
265 | |||
266 | skb_reset_network_header(skb); | ||
267 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
268 | hdr = ipv6_hdr(skb); | ||
269 | |||
270 | *(__be32*)hdr = htonl(0x60000000); | ||
271 | |||
272 | hdr->payload_len = htons(len); | ||
273 | hdr->nexthdr = proto; | ||
274 | hdr->hop_limit = np->hop_limit; | ||
275 | |||
276 | hdr->saddr = *saddr; | ||
277 | hdr->daddr = *daddr; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | 261 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) |
283 | { | 262 | { |
284 | struct ip6_ra_chain *ra; | 263 | struct ip6_ra_chain *ra; |
@@ -913,8 +892,12 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
913 | * dst entry of the nexthop router | 892 | * dst entry of the nexthop router |
914 | */ | 893 | */ |
915 | rt = (struct rt6_info *) *dst; | 894 | rt = (struct rt6_info *) *dst; |
916 | n = rt->n; | 895 | rcu_read_lock_bh(); |
917 | if (n && !(n->nud_state & NUD_VALID)) { | 896 | n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr)); |
897 | err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; | ||
898 | rcu_read_unlock_bh(); | ||
899 | |||
900 | if (err) { | ||
918 | struct inet6_ifaddr *ifp; | 901 | struct inet6_ifaddr *ifp; |
919 | struct flowi6 fl_gw6; | 902 | struct flowi6 fl_gw6; |
920 | int redirect; | 903 | int redirect; |
@@ -1213,10 +1196,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1213 | if (dst_allfrag(rt->dst.path)) | 1196 | if (dst_allfrag(rt->dst.path)) |
1214 | cork->flags |= IPCORK_ALLFRAG; | 1197 | cork->flags |= IPCORK_ALLFRAG; |
1215 | cork->length = 0; | 1198 | cork->length = 0; |
1216 | exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len; | 1199 | exthdrlen = (opt ? opt->opt_flen : 0); |
1217 | length += exthdrlen; | 1200 | length += exthdrlen; |
1218 | transhdrlen += exthdrlen; | 1201 | transhdrlen += exthdrlen; |
1219 | dst_exthdrlen = rt->dst.header_len; | 1202 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; |
1220 | } else { | 1203 | } else { |
1221 | rt = (struct rt6_info *)cork->dst; | 1204 | rt = (struct rt6_info *)cork->dst; |
1222 | fl6 = &inet->cork.fl.u.ip6; | 1205 | fl6 = &inet->cork.fl.u.ip6; |
@@ -1548,9 +1531,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1548 | skb_reset_network_header(skb); | 1531 | skb_reset_network_header(skb); |
1549 | hdr = ipv6_hdr(skb); | 1532 | hdr = ipv6_hdr(skb); |
1550 | 1533 | ||
1551 | *(__be32*)hdr = fl6->flowlabel | | 1534 | ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); |
1552 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | ||
1553 | |||
1554 | hdr->hop_limit = np->cork.hop_limit; | 1535 | hdr->hop_limit = np->cork.hop_limit; |
1555 | hdr->nexthdr = proto; | 1536 | hdr->nexthdr = proto; |
1556 | hdr->saddr = fl6->saddr; | 1537 | hdr->saddr = fl6->saddr; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a14f28b280f5..fff83cbc197f 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -1030,9 +1030,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
1030 | skb_push(skb, sizeof(struct ipv6hdr)); | 1030 | skb_push(skb, sizeof(struct ipv6hdr)); |
1031 | skb_reset_network_header(skb); | 1031 | skb_reset_network_header(skb); |
1032 | ipv6h = ipv6_hdr(skb); | 1032 | ipv6h = ipv6_hdr(skb); |
1033 | *(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000); | 1033 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); |
1034 | dsfield = INET_ECN_encapsulate(0, dsfield); | ||
1035 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | ||
1036 | ipv6h->hop_limit = t->parms.hop_limit; | 1034 | ipv6h->hop_limit = t->parms.hop_limit; |
1037 | ipv6h->nexthdr = proto; | 1035 | ipv6h->nexthdr = proto; |
1038 | ipv6h->saddr = fl6->saddr; | 1036 | ipv6h->saddr = fl6->saddr; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 26dcdec9e3a5..96bfb4e4b820 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -1017,6 +1017,50 @@ static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, | |||
1017 | return NULL; | 1017 | return NULL; |
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | /* Look for a (*,*,oif) entry */ | ||
1021 | static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt, | ||
1022 | mifi_t mifi) | ||
1023 | { | ||
1024 | int line = MFC6_HASH(&in6addr_any, &in6addr_any); | ||
1025 | struct mfc6_cache *c; | ||
1026 | |||
1027 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) | ||
1028 | if (ipv6_addr_any(&c->mf6c_origin) && | ||
1029 | ipv6_addr_any(&c->mf6c_mcastgrp) && | ||
1030 | (c->mfc_un.res.ttls[mifi] < 255)) | ||
1031 | return c; | ||
1032 | |||
1033 | return NULL; | ||
1034 | } | ||
1035 | |||
1036 | /* Look for a (*,G) entry */ | ||
1037 | static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt, | ||
1038 | struct in6_addr *mcastgrp, | ||
1039 | mifi_t mifi) | ||
1040 | { | ||
1041 | int line = MFC6_HASH(mcastgrp, &in6addr_any); | ||
1042 | struct mfc6_cache *c, *proxy; | ||
1043 | |||
1044 | if (ipv6_addr_any(mcastgrp)) | ||
1045 | goto skip; | ||
1046 | |||
1047 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) | ||
1048 | if (ipv6_addr_any(&c->mf6c_origin) && | ||
1049 | ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) { | ||
1050 | if (c->mfc_un.res.ttls[mifi] < 255) | ||
1051 | return c; | ||
1052 | |||
1053 | /* It's ok if the mifi is part of the static tree */ | ||
1054 | proxy = ip6mr_cache_find_any_parent(mrt, | ||
1055 | c->mf6c_parent); | ||
1056 | if (proxy && proxy->mfc_un.res.ttls[mifi] < 255) | ||
1057 | return c; | ||
1058 | } | ||
1059 | |||
1060 | skip: | ||
1061 | return ip6mr_cache_find_any_parent(mrt, mifi); | ||
1062 | } | ||
1063 | |||
1020 | /* | 1064 | /* |
1021 | * Allocate a multicast cache entry | 1065 | * Allocate a multicast cache entry |
1022 | */ | 1066 | */ |
@@ -1247,7 +1291,8 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb) | |||
1247 | * MFC6 cache manipulation by user space | 1291 | * MFC6 cache manipulation by user space |
1248 | */ | 1292 | */ |
1249 | 1293 | ||
1250 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | 1294 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc, |
1295 | int parent) | ||
1251 | { | 1296 | { |
1252 | int line; | 1297 | int line; |
1253 | struct mfc6_cache *c, *next; | 1298 | struct mfc6_cache *c, *next; |
@@ -1256,7 +1301,9 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | |||
1256 | 1301 | ||
1257 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { | 1302 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { |
1258 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1303 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
1259 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { | 1304 | ipv6_addr_equal(&c->mf6c_mcastgrp, |
1305 | &mfc->mf6cc_mcastgrp.sin6_addr) && | ||
1306 | (parent == -1 || parent == c->mf6c_parent)) { | ||
1260 | write_lock_bh(&mrt_lock); | 1307 | write_lock_bh(&mrt_lock); |
1261 | list_del(&c->list); | 1308 | list_del(&c->list); |
1262 | write_unlock_bh(&mrt_lock); | 1309 | write_unlock_bh(&mrt_lock); |
@@ -1312,9 +1359,9 @@ static int __net_init ip6mr_net_init(struct net *net) | |||
1312 | 1359 | ||
1313 | #ifdef CONFIG_PROC_FS | 1360 | #ifdef CONFIG_PROC_FS |
1314 | err = -ENOMEM; | 1361 | err = -ENOMEM; |
1315 | if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops)) | 1362 | if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops)) |
1316 | goto proc_vif_fail; | 1363 | goto proc_vif_fail; |
1317 | if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops)) | 1364 | if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops)) |
1318 | goto proc_cache_fail; | 1365 | goto proc_cache_fail; |
1319 | #endif | 1366 | #endif |
1320 | 1367 | ||
@@ -1322,7 +1369,7 @@ static int __net_init ip6mr_net_init(struct net *net) | |||
1322 | 1369 | ||
1323 | #ifdef CONFIG_PROC_FS | 1370 | #ifdef CONFIG_PROC_FS |
1324 | proc_cache_fail: | 1371 | proc_cache_fail: |
1325 | proc_net_remove(net, "ip6_mr_vif"); | 1372 | remove_proc_entry("ip6_mr_vif", net->proc_net); |
1326 | proc_vif_fail: | 1373 | proc_vif_fail: |
1327 | ip6mr_rules_exit(net); | 1374 | ip6mr_rules_exit(net); |
1328 | #endif | 1375 | #endif |
@@ -1333,8 +1380,8 @@ fail: | |||
1333 | static void __net_exit ip6mr_net_exit(struct net *net) | 1380 | static void __net_exit ip6mr_net_exit(struct net *net) |
1334 | { | 1381 | { |
1335 | #ifdef CONFIG_PROC_FS | 1382 | #ifdef CONFIG_PROC_FS |
1336 | proc_net_remove(net, "ip6_mr_cache"); | 1383 | remove_proc_entry("ip6_mr_cache", net->proc_net); |
1337 | proc_net_remove(net, "ip6_mr_vif"); | 1384 | remove_proc_entry("ip6_mr_vif", net->proc_net); |
1338 | #endif | 1385 | #endif |
1339 | ip6mr_rules_exit(net); | 1386 | ip6mr_rules_exit(net); |
1340 | } | 1387 | } |
@@ -1391,7 +1438,7 @@ void ip6_mr_cleanup(void) | |||
1391 | } | 1438 | } |
1392 | 1439 | ||
1393 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | 1440 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, |
1394 | struct mf6cctl *mfc, int mrtsock) | 1441 | struct mf6cctl *mfc, int mrtsock, int parent) |
1395 | { | 1442 | { |
1396 | bool found = false; | 1443 | bool found = false; |
1397 | int line; | 1444 | int line; |
@@ -1413,7 +1460,9 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
1413 | 1460 | ||
1414 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { | 1461 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { |
1415 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1462 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
1416 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { | 1463 | ipv6_addr_equal(&c->mf6c_mcastgrp, |
1464 | &mfc->mf6cc_mcastgrp.sin6_addr) && | ||
1465 | (parent == -1 || parent == mfc->mf6cc_parent)) { | ||
1417 | found = true; | 1466 | found = true; |
1418 | break; | 1467 | break; |
1419 | } | 1468 | } |
@@ -1430,7 +1479,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
1430 | return 0; | 1479 | return 0; |
1431 | } | 1480 | } |
1432 | 1481 | ||
1433 | if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) | 1482 | if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) && |
1483 | !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) | ||
1434 | return -EINVAL; | 1484 | return -EINVAL; |
1435 | 1485 | ||
1436 | c = ip6mr_cache_alloc(); | 1486 | c = ip6mr_cache_alloc(); |
@@ -1596,7 +1646,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) | |||
1596 | 1646 | ||
1597 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) | 1647 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) |
1598 | { | 1648 | { |
1599 | int ret; | 1649 | int ret, parent = 0; |
1600 | struct mif6ctl vif; | 1650 | struct mif6ctl vif; |
1601 | struct mf6cctl mfc; | 1651 | struct mf6cctl mfc; |
1602 | mifi_t mifi; | 1652 | mifi_t mifi; |
@@ -1653,15 +1703,21 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1653 | */ | 1703 | */ |
1654 | case MRT6_ADD_MFC: | 1704 | case MRT6_ADD_MFC: |
1655 | case MRT6_DEL_MFC: | 1705 | case MRT6_DEL_MFC: |
1706 | parent = -1; | ||
1707 | case MRT6_ADD_MFC_PROXY: | ||
1708 | case MRT6_DEL_MFC_PROXY: | ||
1656 | if (optlen < sizeof(mfc)) | 1709 | if (optlen < sizeof(mfc)) |
1657 | return -EINVAL; | 1710 | return -EINVAL; |
1658 | if (copy_from_user(&mfc, optval, sizeof(mfc))) | 1711 | if (copy_from_user(&mfc, optval, sizeof(mfc))) |
1659 | return -EFAULT; | 1712 | return -EFAULT; |
1713 | if (parent == 0) | ||
1714 | parent = mfc.mf6cc_parent; | ||
1660 | rtnl_lock(); | 1715 | rtnl_lock(); |
1661 | if (optname == MRT6_DEL_MFC) | 1716 | if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY) |
1662 | ret = ip6mr_mfc_delete(mrt, &mfc); | 1717 | ret = ip6mr_mfc_delete(mrt, &mfc, parent); |
1663 | else | 1718 | else |
1664 | ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk); | 1719 | ret = ip6mr_mfc_add(net, mrt, &mfc, |
1720 | sk == mrt->mroute6_sk, parent); | ||
1665 | rtnl_unlock(); | 1721 | rtnl_unlock(); |
1666 | return ret; | 1722 | return ret; |
1667 | 1723 | ||
@@ -1710,6 +1766,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1710 | return -EINVAL; | 1766 | return -EINVAL; |
1711 | if (get_user(v, (u32 __user *)optval)) | 1767 | if (get_user(v, (u32 __user *)optval)) |
1712 | return -EFAULT; | 1768 | return -EFAULT; |
1769 | /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */ | ||
1770 | if (v != RT_TABLE_DEFAULT && v >= 100000000) | ||
1771 | return -EINVAL; | ||
1713 | if (sk == mrt->mroute6_sk) | 1772 | if (sk == mrt->mroute6_sk) |
1714 | return -EBUSY; | 1773 | return -EBUSY; |
1715 | 1774 | ||
@@ -2015,19 +2074,29 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2015 | { | 2074 | { |
2016 | int psend = -1; | 2075 | int psend = -1; |
2017 | int vif, ct; | 2076 | int vif, ct; |
2077 | int true_vifi = ip6mr_find_vif(mrt, skb->dev); | ||
2018 | 2078 | ||
2019 | vif = cache->mf6c_parent; | 2079 | vif = cache->mf6c_parent; |
2020 | cache->mfc_un.res.pkt++; | 2080 | cache->mfc_un.res.pkt++; |
2021 | cache->mfc_un.res.bytes += skb->len; | 2081 | cache->mfc_un.res.bytes += skb->len; |
2022 | 2082 | ||
2083 | if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) { | ||
2084 | struct mfc6_cache *cache_proxy; | ||
2085 | |||
2086 | /* For an (*,G) entry, we only check that the incomming | ||
2087 | * interface is part of the static tree. | ||
2088 | */ | ||
2089 | cache_proxy = ip6mr_cache_find_any_parent(mrt, vif); | ||
2090 | if (cache_proxy && | ||
2091 | cache_proxy->mfc_un.res.ttls[true_vifi] < 255) | ||
2092 | goto forward; | ||
2093 | } | ||
2094 | |||
2023 | /* | 2095 | /* |
2024 | * Wrong interface: drop packet and (maybe) send PIM assert. | 2096 | * Wrong interface: drop packet and (maybe) send PIM assert. |
2025 | */ | 2097 | */ |
2026 | if (mrt->vif6_table[vif].dev != skb->dev) { | 2098 | if (mrt->vif6_table[vif].dev != skb->dev) { |
2027 | int true_vifi; | ||
2028 | |||
2029 | cache->mfc_un.res.wrong_if++; | 2099 | cache->mfc_un.res.wrong_if++; |
2030 | true_vifi = ip6mr_find_vif(mrt, skb->dev); | ||
2031 | 2100 | ||
2032 | if (true_vifi >= 0 && mrt->mroute_do_assert && | 2101 | if (true_vifi >= 0 && mrt->mroute_do_assert && |
2033 | /* pimsm uses asserts, when switching from RPT to SPT, | 2102 | /* pimsm uses asserts, when switching from RPT to SPT, |
@@ -2045,14 +2114,32 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2045 | goto dont_forward; | 2114 | goto dont_forward; |
2046 | } | 2115 | } |
2047 | 2116 | ||
2117 | forward: | ||
2048 | mrt->vif6_table[vif].pkt_in++; | 2118 | mrt->vif6_table[vif].pkt_in++; |
2049 | mrt->vif6_table[vif].bytes_in += skb->len; | 2119 | mrt->vif6_table[vif].bytes_in += skb->len; |
2050 | 2120 | ||
2051 | /* | 2121 | /* |
2052 | * Forward the frame | 2122 | * Forward the frame |
2053 | */ | 2123 | */ |
2124 | if (ipv6_addr_any(&cache->mf6c_origin) && | ||
2125 | ipv6_addr_any(&cache->mf6c_mcastgrp)) { | ||
2126 | if (true_vifi >= 0 && | ||
2127 | true_vifi != cache->mf6c_parent && | ||
2128 | ipv6_hdr(skb)->hop_limit > | ||
2129 | cache->mfc_un.res.ttls[cache->mf6c_parent]) { | ||
2130 | /* It's an (*,*) entry and the packet is not coming from | ||
2131 | * the upstream: forward the packet to the upstream | ||
2132 | * only. | ||
2133 | */ | ||
2134 | psend = cache->mf6c_parent; | ||
2135 | goto last_forward; | ||
2136 | } | ||
2137 | goto dont_forward; | ||
2138 | } | ||
2054 | for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { | 2139 | for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { |
2055 | if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { | 2140 | /* For (*,G) entry, don't forward to the incoming interface */ |
2141 | if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) && | ||
2142 | ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { | ||
2056 | if (psend != -1) { | 2143 | if (psend != -1) { |
2057 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | 2144 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); |
2058 | if (skb2) | 2145 | if (skb2) |
@@ -2061,6 +2148,7 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2061 | psend = ct; | 2148 | psend = ct; |
2062 | } | 2149 | } |
2063 | } | 2150 | } |
2151 | last_forward: | ||
2064 | if (psend != -1) { | 2152 | if (psend != -1) { |
2065 | ip6mr_forward2(net, mrt, skb, cache, psend); | 2153 | ip6mr_forward2(net, mrt, skb, cache, psend); |
2066 | return 0; | 2154 | return 0; |
@@ -2096,6 +2184,14 @@ int ip6_mr_input(struct sk_buff *skb) | |||
2096 | read_lock(&mrt_lock); | 2184 | read_lock(&mrt_lock); |
2097 | cache = ip6mr_cache_find(mrt, | 2185 | cache = ip6mr_cache_find(mrt, |
2098 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); | 2186 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); |
2187 | if (cache == NULL) { | ||
2188 | int vif = ip6mr_find_vif(mrt, skb->dev); | ||
2189 | |||
2190 | if (vif >= 0) | ||
2191 | cache = ip6mr_cache_find_any(mrt, | ||
2192 | &ipv6_hdr(skb)->daddr, | ||
2193 | vif); | ||
2194 | } | ||
2099 | 2195 | ||
2100 | /* | 2196 | /* |
2101 | * No usable cache entry | 2197 | * No usable cache entry |
@@ -2183,6 +2279,13 @@ int ip6mr_get_route(struct net *net, | |||
2183 | 2279 | ||
2184 | read_lock(&mrt_lock); | 2280 | read_lock(&mrt_lock); |
2185 | cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); | 2281 | cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); |
2282 | if (!cache && skb->dev) { | ||
2283 | int vif = ip6mr_find_vif(mrt, skb->dev); | ||
2284 | |||
2285 | if (vif >= 0) | ||
2286 | cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr, | ||
2287 | vif); | ||
2288 | } | ||
2186 | 2289 | ||
2187 | if (!cache) { | 2290 | if (!cache) { |
2188 | struct sk_buff *skb2; | 2291 | struct sk_buff *skb2; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index ee94d31c9d4d..d1e2e8ef29c5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -476,8 +476,8 @@ sticky_done: | |||
476 | msg.msg_controllen = optlen; | 476 | msg.msg_controllen = optlen; |
477 | msg.msg_control = (void*)(opt+1); | 477 | msg.msg_control = (void*)(opt+1); |
478 | 478 | ||
479 | retv = datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, &junk, | 479 | retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, |
480 | &junk); | 480 | &junk, &junk); |
481 | if (retv) | 481 | if (retv) |
482 | goto done; | 482 | goto done; |
483 | update: | 483 | update: |
@@ -1002,7 +1002,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1002 | release_sock(sk); | 1002 | release_sock(sk); |
1003 | 1003 | ||
1004 | if (skb) { | 1004 | if (skb) { |
1005 | int err = datagram_recv_ctl(sk, &msg, skb); | 1005 | int err = ip6_datagram_recv_ctl(sk, &msg, skb); |
1006 | kfree_skb(skb); | 1006 | kfree_skb(skb); |
1007 | if (err) | 1007 | if (err) |
1008 | return err; | 1008 | return err; |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 28dfa5f3801f..bfa6cc36ef2a 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -376,8 +376,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
376 | goto done; /* err = -EADDRNOTAVAIL */ | 376 | goto done; /* err = -EADDRNOTAVAIL */ |
377 | rv = !0; | 377 | rv = !0; |
378 | for (i=0; i<psl->sl_count; i++) { | 378 | for (i=0; i<psl->sl_count; i++) { |
379 | rv = memcmp(&psl->sl_addr[i], source, | 379 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
380 | sizeof(struct in6_addr)); | ||
381 | if (rv == 0) | 380 | if (rv == 0) |
382 | break; | 381 | break; |
383 | } | 382 | } |
@@ -427,12 +426,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
427 | } | 426 | } |
428 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ | 427 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ |
429 | for (i=0; i<psl->sl_count; i++) { | 428 | for (i=0; i<psl->sl_count; i++) { |
430 | rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr)); | 429 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
431 | if (rv == 0) | 430 | if (rv == 0) /* There is an error in the address. */ |
432 | break; | 431 | goto done; |
433 | } | 432 | } |
434 | if (rv == 0) /* address already there is an error */ | ||
435 | goto done; | ||
436 | for (j=psl->sl_count-1; j>=i; j--) | 433 | for (j=psl->sl_count-1; j>=i; j--) |
437 | psl->sl_addr[j+1] = psl->sl_addr[j]; | 434 | psl->sl_addr[j+1] = psl->sl_addr[j]; |
438 | psl->sl_addr[i] = *source; | 435 | psl->sl_addr[i] = *source; |
@@ -664,6 +661,10 @@ static void igmp6_group_added(struct ifmcaddr6 *mc) | |||
664 | struct net_device *dev = mc->idev->dev; | 661 | struct net_device *dev = mc->idev->dev; |
665 | char buf[MAX_ADDR_LEN]; | 662 | char buf[MAX_ADDR_LEN]; |
666 | 663 | ||
664 | if (IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < | ||
665 | IPV6_ADDR_SCOPE_LINKLOCAL) | ||
666 | return; | ||
667 | |||
667 | spin_lock_bh(&mc->mca_lock); | 668 | spin_lock_bh(&mc->mca_lock); |
668 | if (!(mc->mca_flags&MAF_LOADED)) { | 669 | if (!(mc->mca_flags&MAF_LOADED)) { |
669 | mc->mca_flags |= MAF_LOADED; | 670 | mc->mca_flags |= MAF_LOADED; |
@@ -690,6 +691,10 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc) | |||
690 | struct net_device *dev = mc->idev->dev; | 691 | struct net_device *dev = mc->idev->dev; |
691 | char buf[MAX_ADDR_LEN]; | 692 | char buf[MAX_ADDR_LEN]; |
692 | 693 | ||
694 | if (IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < | ||
695 | IPV6_ADDR_SCOPE_LINKLOCAL) | ||
696 | return; | ||
697 | |||
693 | spin_lock_bh(&mc->mca_lock); | 698 | spin_lock_bh(&mc->mca_lock); |
694 | if (mc->mca_flags&MAF_LOADED) { | 699 | if (mc->mca_flags&MAF_LOADED) { |
695 | mc->mca_flags &= ~MAF_LOADED; | 700 | mc->mca_flags &= ~MAF_LOADED; |
@@ -935,33 +940,6 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) | |||
935 | } | 940 | } |
936 | 941 | ||
937 | /* | 942 | /* |
938 | * identify MLD packets for MLD filter exceptions | ||
939 | */ | ||
940 | bool ipv6_is_mld(struct sk_buff *skb, int nexthdr) | ||
941 | { | ||
942 | struct icmp6hdr *pic; | ||
943 | |||
944 | if (nexthdr != IPPROTO_ICMPV6) | ||
945 | return false; | ||
946 | |||
947 | if (!pskb_may_pull(skb, sizeof(struct icmp6hdr))) | ||
948 | return false; | ||
949 | |||
950 | pic = icmp6_hdr(skb); | ||
951 | |||
952 | switch (pic->icmp6_type) { | ||
953 | case ICMPV6_MGM_QUERY: | ||
954 | case ICMPV6_MGM_REPORT: | ||
955 | case ICMPV6_MGM_REDUCTION: | ||
956 | case ICMPV6_MLD2_REPORT: | ||
957 | return true; | ||
958 | default: | ||
959 | break; | ||
960 | } | ||
961 | return false; | ||
962 | } | ||
963 | |||
964 | /* | ||
965 | * check if the interface/address pair is valid | 943 | * check if the interface/address pair is valid |
966 | */ | 944 | */ |
967 | bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | 945 | bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, |
@@ -1340,6 +1318,31 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) | |||
1340 | return scount; | 1318 | return scount; |
1341 | } | 1319 | } |
1342 | 1320 | ||
1321 | static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb, | ||
1322 | struct net_device *dev, | ||
1323 | const struct in6_addr *saddr, | ||
1324 | const struct in6_addr *daddr, | ||
1325 | int proto, int len) | ||
1326 | { | ||
1327 | struct ipv6hdr *hdr; | ||
1328 | |||
1329 | skb->protocol = htons(ETH_P_IPV6); | ||
1330 | skb->dev = dev; | ||
1331 | |||
1332 | skb_reset_network_header(skb); | ||
1333 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
1334 | hdr = ipv6_hdr(skb); | ||
1335 | |||
1336 | ip6_flow_hdr(hdr, 0, 0); | ||
1337 | |||
1338 | hdr->payload_len = htons(len); | ||
1339 | hdr->nexthdr = proto; | ||
1340 | hdr->hop_limit = inet6_sk(sk)->hop_limit; | ||
1341 | |||
1342 | hdr->saddr = *saddr; | ||
1343 | hdr->daddr = *daddr; | ||
1344 | } | ||
1345 | |||
1343 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) | 1346 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) |
1344 | { | 1347 | { |
1345 | struct net *net = dev_net(dev); | 1348 | struct net *net = dev_net(dev); |
@@ -1375,7 +1378,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1375 | } else | 1378 | } else |
1376 | saddr = &addr_buf; | 1379 | saddr = &addr_buf; |
1377 | 1380 | ||
1378 | ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); | 1381 | ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); |
1379 | 1382 | ||
1380 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1383 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1381 | 1384 | ||
@@ -1418,7 +1421,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1418 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, | 1421 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, |
1419 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1422 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1420 | skb->dev->ifindex); | 1423 | skb->dev->ifindex); |
1421 | dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); | 1424 | dst = icmp6_dst_alloc(skb->dev, &fl6); |
1422 | 1425 | ||
1423 | err = 0; | 1426 | err = 0; |
1424 | if (IS_ERR(dst)) { | 1427 | if (IS_ERR(dst)) { |
@@ -1767,7 +1770,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1767 | } else | 1770 | } else |
1768 | saddr = &addr_buf; | 1771 | saddr = &addr_buf; |
1769 | 1772 | ||
1770 | ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); | 1773 | ip6_mc_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); |
1771 | 1774 | ||
1772 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1775 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1773 | 1776 | ||
@@ -1786,7 +1789,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1786 | icmpv6_flow_init(sk, &fl6, type, | 1789 | icmpv6_flow_init(sk, &fl6, type, |
1787 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1790 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1788 | skb->dev->ifindex); | 1791 | skb->dev->ifindex); |
1789 | dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); | 1792 | dst = icmp6_dst_alloc(skb->dev, &fl6); |
1790 | if (IS_ERR(dst)) { | 1793 | if (IS_ERR(dst)) { |
1791 | err = PTR_ERR(dst); | 1794 | err = PTR_ERR(dst); |
1792 | goto err_out; | 1795 | goto err_out; |
@@ -2596,10 +2599,10 @@ static int __net_init igmp6_proc_init(struct net *net) | |||
2596 | int err; | 2599 | int err; |
2597 | 2600 | ||
2598 | err = -ENOMEM; | 2601 | err = -ENOMEM; |
2599 | if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) | 2602 | if (!proc_create("igmp6", S_IRUGO, net->proc_net, &igmp6_mc_seq_fops)) |
2600 | goto out; | 2603 | goto out; |
2601 | if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, | 2604 | if (!proc_create("mcfilter6", S_IRUGO, net->proc_net, |
2602 | &igmp6_mcf_seq_fops)) | 2605 | &igmp6_mcf_seq_fops)) |
2603 | goto out_proc_net_igmp6; | 2606 | goto out_proc_net_igmp6; |
2604 | 2607 | ||
2605 | err = 0; | 2608 | err = 0; |
@@ -2607,14 +2610,14 @@ out: | |||
2607 | return err; | 2610 | return err; |
2608 | 2611 | ||
2609 | out_proc_net_igmp6: | 2612 | out_proc_net_igmp6: |
2610 | proc_net_remove(net, "igmp6"); | 2613 | remove_proc_entry("igmp6", net->proc_net); |
2611 | goto out; | 2614 | goto out; |
2612 | } | 2615 | } |
2613 | 2616 | ||
2614 | static void __net_exit igmp6_proc_exit(struct net *net) | 2617 | static void __net_exit igmp6_proc_exit(struct net *net) |
2615 | { | 2618 | { |
2616 | proc_net_remove(net, "mcfilter6"); | 2619 | remove_proc_entry("mcfilter6", net->proc_net); |
2617 | proc_net_remove(net, "igmp6"); | 2620 | remove_proc_entry("igmp6", net->proc_net); |
2618 | } | 2621 | } |
2619 | #else | 2622 | #else |
2620 | static inline int igmp6_proc_init(struct net *net) | 2623 | static inline int igmp6_proc_init(struct net *net) |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 6574175795df..76ef4353d518 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -143,16 +143,12 @@ struct neigh_table nd_tbl = { | |||
143 | .gc_thresh3 = 1024, | 143 | .gc_thresh3 = 1024, |
144 | }; | 144 | }; |
145 | 145 | ||
146 | static inline int ndisc_opt_addr_space(struct net_device *dev) | 146 | static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data) |
147 | { | 147 | { |
148 | return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); | 148 | int pad = ndisc_addr_option_pad(skb->dev->type); |
149 | } | 149 | int data_len = skb->dev->addr_len; |
150 | 150 | int space = ndisc_opt_addr_space(skb->dev); | |
151 | static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, | 151 | u8 *opt = skb_put(skb, space); |
152 | unsigned short addr_type) | ||
153 | { | ||
154 | int pad = ndisc_addr_option_pad(addr_type); | ||
155 | int space = NDISC_OPT_SPACE(data_len + pad); | ||
156 | 152 | ||
157 | opt[0] = type; | 153 | opt[0] = type; |
158 | opt[1] = space>>3; | 154 | opt[1] = space>>3; |
@@ -166,7 +162,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, | |||
166 | opt += data_len; | 162 | opt += data_len; |
167 | if ((space -= data_len) > 0) | 163 | if ((space -= data_len) > 0) |
168 | memset(opt, 0, space); | 164 | memset(opt, 0, space); |
169 | return opt + space; | ||
170 | } | 165 | } |
171 | 166 | ||
172 | static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | 167 | static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, |
@@ -370,91 +365,88 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
370 | ipv6_dev_mc_dec(dev, &maddr); | 365 | ipv6_dev_mc_dec(dev, &maddr); |
371 | } | 366 | } |
372 | 367 | ||
373 | static struct sk_buff *ndisc_build_skb(struct net_device *dev, | 368 | static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, |
374 | const struct in6_addr *daddr, | 369 | int len) |
375 | const struct in6_addr *saddr, | ||
376 | struct icmp6hdr *icmp6h, | ||
377 | const struct in6_addr *target, | ||
378 | int llinfo) | ||
379 | { | 370 | { |
380 | struct net *net = dev_net(dev); | ||
381 | struct sock *sk = net->ipv6.ndisc_sk; | ||
382 | struct sk_buff *skb; | ||
383 | struct icmp6hdr *hdr; | ||
384 | int hlen = LL_RESERVED_SPACE(dev); | 371 | int hlen = LL_RESERVED_SPACE(dev); |
385 | int tlen = dev->needed_tailroom; | 372 | int tlen = dev->needed_tailroom; |
386 | int len; | 373 | struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; |
374 | struct sk_buff *skb; | ||
387 | int err; | 375 | int err; |
388 | u8 *opt; | ||
389 | |||
390 | if (!dev->addr_len) | ||
391 | llinfo = 0; | ||
392 | |||
393 | len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); | ||
394 | if (llinfo) | ||
395 | len += ndisc_opt_addr_space(dev); | ||
396 | 376 | ||
397 | skb = sock_alloc_send_skb(sk, | 377 | skb = sock_alloc_send_skb(sk, |
398 | (MAX_HEADER + sizeof(struct ipv6hdr) + | 378 | hlen + sizeof(struct ipv6hdr) + len + tlen, |
399 | len + hlen + tlen), | ||
400 | 1, &err); | 379 | 1, &err); |
401 | if (!skb) { | 380 | if (!skb) { |
402 | ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n", | 381 | ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n", |
403 | __func__, err); | 382 | __func__, err); |
404 | return NULL; | 383 | return NULL; |
405 | } | 384 | } |
406 | 385 | ||
407 | skb_reserve(skb, hlen); | 386 | skb->protocol = htons(ETH_P_IPV6); |
408 | ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); | 387 | skb->dev = dev; |
409 | 388 | ||
410 | skb->transport_header = skb->tail; | 389 | skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); |
411 | skb_put(skb, len); | 390 | skb_reset_transport_header(skb); |
412 | 391 | ||
413 | hdr = (struct icmp6hdr *)skb_transport_header(skb); | 392 | return skb; |
414 | memcpy(hdr, icmp6h, sizeof(*hdr)); | 393 | } |
415 | 394 | ||
416 | opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); | 395 | static void ip6_nd_hdr(struct sk_buff *skb, |
417 | if (target) { | 396 | const struct in6_addr *saddr, |
418 | *(struct in6_addr *)opt = *target; | 397 | const struct in6_addr *daddr, |
419 | opt += sizeof(*target); | 398 | int hop_limit, int len) |
420 | } | 399 | { |
400 | struct ipv6hdr *hdr; | ||
421 | 401 | ||
422 | if (llinfo) | 402 | skb_push(skb, sizeof(*hdr)); |
423 | ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, | 403 | skb_reset_network_header(skb); |
424 | dev->addr_len, dev->type); | 404 | hdr = ipv6_hdr(skb); |
425 | 405 | ||
426 | hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, | 406 | ip6_flow_hdr(hdr, 0, 0); |
427 | IPPROTO_ICMPV6, | ||
428 | csum_partial(hdr, | ||
429 | len, 0)); | ||
430 | 407 | ||
431 | return skb; | 408 | hdr->payload_len = htons(len); |
409 | hdr->nexthdr = IPPROTO_ICMPV6; | ||
410 | hdr->hop_limit = hop_limit; | ||
411 | |||
412 | hdr->saddr = *saddr; | ||
413 | hdr->daddr = *daddr; | ||
432 | } | 414 | } |
433 | 415 | ||
434 | static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, | 416 | static void ndisc_send_skb(struct sk_buff *skb, |
435 | struct neighbour *neigh, | ||
436 | const struct in6_addr *daddr, | 417 | const struct in6_addr *daddr, |
437 | const struct in6_addr *saddr, | 418 | const struct in6_addr *saddr) |
438 | struct icmp6hdr *icmp6h) | ||
439 | { | 419 | { |
440 | struct flowi6 fl6; | 420 | struct dst_entry *dst = skb_dst(skb); |
441 | struct dst_entry *dst; | 421 | struct net *net = dev_net(skb->dev); |
442 | struct net *net = dev_net(dev); | ||
443 | struct sock *sk = net->ipv6.ndisc_sk; | 422 | struct sock *sk = net->ipv6.ndisc_sk; |
444 | struct inet6_dev *idev; | 423 | struct inet6_dev *idev; |
445 | int err; | 424 | int err; |
425 | struct icmp6hdr *icmp6h = icmp6_hdr(skb); | ||
446 | u8 type; | 426 | u8 type; |
447 | 427 | ||
448 | type = icmp6h->icmp6_type; | 428 | type = icmp6h->icmp6_type; |
449 | 429 | ||
450 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); | 430 | if (!dst) { |
451 | dst = icmp6_dst_alloc(dev, neigh, &fl6); | 431 | struct sock *sk = net->ipv6.ndisc_sk; |
452 | if (IS_ERR(dst)) { | 432 | struct flowi6 fl6; |
453 | kfree_skb(skb); | 433 | |
454 | return; | 434 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex); |
435 | dst = icmp6_dst_alloc(skb->dev, &fl6); | ||
436 | if (IS_ERR(dst)) { | ||
437 | kfree_skb(skb); | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | skb_dst_set(skb, dst); | ||
455 | } | 442 | } |
456 | 443 | ||
457 | skb_dst_set(skb, dst); | 444 | icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, |
445 | IPPROTO_ICMPV6, | ||
446 | csum_partial(icmp6h, | ||
447 | skb->len, 0)); | ||
448 | |||
449 | ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); | ||
458 | 450 | ||
459 | rcu_read_lock(); | 451 | rcu_read_lock(); |
460 | idev = __in6_dev_get(dst->dev); | 452 | idev = __in6_dev_get(dst->dev); |
@@ -470,36 +462,17 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, | |||
470 | rcu_read_unlock(); | 462 | rcu_read_unlock(); |
471 | } | 463 | } |
472 | 464 | ||
473 | /* | ||
474 | * Send a Neighbour Discover packet | ||
475 | */ | ||
476 | static void __ndisc_send(struct net_device *dev, | ||
477 | struct neighbour *neigh, | ||
478 | const struct in6_addr *daddr, | ||
479 | const struct in6_addr *saddr, | ||
480 | struct icmp6hdr *icmp6h, const struct in6_addr *target, | ||
481 | int llinfo) | ||
482 | { | ||
483 | struct sk_buff *skb; | ||
484 | |||
485 | skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); | ||
486 | if (!skb) | ||
487 | return; | ||
488 | |||
489 | ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); | ||
490 | } | ||
491 | |||
492 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 465 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
493 | const struct in6_addr *daddr, | 466 | const struct in6_addr *daddr, |
494 | const struct in6_addr *solicited_addr, | 467 | const struct in6_addr *solicited_addr, |
495 | int router, int solicited, int override, int inc_opt) | 468 | bool router, bool solicited, bool override, bool inc_opt) |
496 | { | 469 | { |
470 | struct sk_buff *skb; | ||
497 | struct in6_addr tmpaddr; | 471 | struct in6_addr tmpaddr; |
498 | struct inet6_ifaddr *ifp; | 472 | struct inet6_ifaddr *ifp; |
499 | const struct in6_addr *src_addr; | 473 | const struct in6_addr *src_addr; |
500 | struct icmp6hdr icmp6h = { | 474 | struct nd_msg *msg; |
501 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | 475 | int optlen = 0; |
502 | }; | ||
503 | 476 | ||
504 | /* for anycast or proxy, solicited_addr != src_addr */ | 477 | /* for anycast or proxy, solicited_addr != src_addr */ |
505 | ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); | 478 | ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); |
@@ -517,13 +490,32 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
517 | src_addr = &tmpaddr; | 490 | src_addr = &tmpaddr; |
518 | } | 491 | } |
519 | 492 | ||
520 | icmp6h.icmp6_router = router; | 493 | if (!dev->addr_len) |
521 | icmp6h.icmp6_solicited = solicited; | 494 | inc_opt = 0; |
522 | icmp6h.icmp6_override = override; | 495 | if (inc_opt) |
496 | optlen += ndisc_opt_addr_space(dev); | ||
497 | |||
498 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
499 | if (!skb) | ||
500 | return; | ||
523 | 501 | ||
524 | __ndisc_send(dev, neigh, daddr, src_addr, | 502 | msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); |
525 | &icmp6h, solicited_addr, | 503 | *msg = (struct nd_msg) { |
526 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 504 | .icmph = { |
505 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | ||
506 | .icmp6_router = router, | ||
507 | .icmp6_solicited = solicited, | ||
508 | .icmp6_override = override, | ||
509 | }, | ||
510 | .target = *solicited_addr, | ||
511 | }; | ||
512 | |||
513 | if (inc_opt) | ||
514 | ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, | ||
515 | dev->dev_addr); | ||
516 | |||
517 | |||
518 | ndisc_send_skb(skb, daddr, src_addr); | ||
527 | } | 519 | } |
528 | 520 | ||
529 | static void ndisc_send_unsol_na(struct net_device *dev) | 521 | static void ndisc_send_unsol_na(struct net_device *dev) |
@@ -551,10 +543,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
551 | const struct in6_addr *solicit, | 543 | const struct in6_addr *solicit, |
552 | const struct in6_addr *daddr, const struct in6_addr *saddr) | 544 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
553 | { | 545 | { |
546 | struct sk_buff *skb; | ||
554 | struct in6_addr addr_buf; | 547 | struct in6_addr addr_buf; |
555 | struct icmp6hdr icmp6h = { | 548 | int inc_opt = dev->addr_len; |
556 | .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, | 549 | int optlen = 0; |
557 | }; | 550 | struct nd_msg *msg; |
558 | 551 | ||
559 | if (saddr == NULL) { | 552 | if (saddr == NULL) { |
560 | if (ipv6_get_lladdr(dev, &addr_buf, | 553 | if (ipv6_get_lladdr(dev, &addr_buf, |
@@ -563,18 +556,37 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
563 | saddr = &addr_buf; | 556 | saddr = &addr_buf; |
564 | } | 557 | } |
565 | 558 | ||
566 | __ndisc_send(dev, neigh, daddr, saddr, | 559 | if (ipv6_addr_any(saddr)) |
567 | &icmp6h, solicit, | 560 | inc_opt = 0; |
568 | !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); | 561 | if (inc_opt) |
562 | optlen += ndisc_opt_addr_space(dev); | ||
563 | |||
564 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
565 | if (!skb) | ||
566 | return; | ||
567 | |||
568 | msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); | ||
569 | *msg = (struct nd_msg) { | ||
570 | .icmph = { | ||
571 | .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, | ||
572 | }, | ||
573 | .target = *solicit, | ||
574 | }; | ||
575 | |||
576 | if (inc_opt) | ||
577 | ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, | ||
578 | dev->dev_addr); | ||
579 | |||
580 | ndisc_send_skb(skb, daddr, saddr); | ||
569 | } | 581 | } |
570 | 582 | ||
571 | void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, | 583 | void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, |
572 | const struct in6_addr *daddr) | 584 | const struct in6_addr *daddr) |
573 | { | 585 | { |
574 | struct icmp6hdr icmp6h = { | 586 | struct sk_buff *skb; |
575 | .icmp6_type = NDISC_ROUTER_SOLICITATION, | 587 | struct rs_msg *msg; |
576 | }; | ||
577 | int send_sllao = dev->addr_len; | 588 | int send_sllao = dev->addr_len; |
589 | int optlen = 0; | ||
578 | 590 | ||
579 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 591 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
580 | /* | 592 | /* |
@@ -598,9 +610,27 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, | |||
598 | } | 610 | } |
599 | } | 611 | } |
600 | #endif | 612 | #endif |
601 | __ndisc_send(dev, NULL, daddr, saddr, | 613 | if (!dev->addr_len) |
602 | &icmp6h, NULL, | 614 | send_sllao = 0; |
603 | send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); | 615 | if (send_sllao) |
616 | optlen += ndisc_opt_addr_space(dev); | ||
617 | |||
618 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
619 | if (!skb) | ||
620 | return; | ||
621 | |||
622 | msg = (struct rs_msg *)skb_put(skb, sizeof(*msg)); | ||
623 | *msg = (struct rs_msg) { | ||
624 | .icmph = { | ||
625 | .icmp6_type = NDISC_ROUTER_SOLICITATION, | ||
626 | }, | ||
627 | }; | ||
628 | |||
629 | if (send_sllao) | ||
630 | ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, | ||
631 | dev->dev_addr); | ||
632 | |||
633 | ndisc_send_skb(skb, daddr, saddr); | ||
604 | } | 634 | } |
605 | 635 | ||
606 | 636 | ||
@@ -676,6 +706,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
676 | bool inc; | 706 | bool inc; |
677 | int is_router = -1; | 707 | int is_router = -1; |
678 | 708 | ||
709 | if (skb->len < sizeof(struct nd_msg)) { | ||
710 | ND_PRINTK(2, warn, "NS: packet too short\n"); | ||
711 | return; | ||
712 | } | ||
713 | |||
679 | if (ipv6_addr_is_multicast(&msg->target)) { | 714 | if (ipv6_addr_is_multicast(&msg->target)) { |
680 | ND_PRINTK(2, warn, "NS: multicast target address\n"); | 715 | ND_PRINTK(2, warn, "NS: multicast target address\n"); |
681 | return; | 716 | return; |
@@ -685,11 +720,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
685 | * RFC2461 7.1.1: | 720 | * RFC2461 7.1.1: |
686 | * DAD has to be destined for solicited node multicast address. | 721 | * DAD has to be destined for solicited node multicast address. |
687 | */ | 722 | */ |
688 | if (dad && | 723 | if (dad && !ipv6_addr_is_solict_mult(daddr)) { |
689 | !(daddr->s6_addr32[0] == htonl(0xff020000) && | ||
690 | daddr->s6_addr32[1] == htonl(0x00000000) && | ||
691 | daddr->s6_addr32[2] == htonl(0x00000001) && | ||
692 | daddr->s6_addr [12] == 0xff )) { | ||
693 | ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); | 724 | ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); |
694 | return; | 725 | return; |
695 | } | 726 | } |
@@ -780,11 +811,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
780 | } | 811 | } |
781 | 812 | ||
782 | if (is_router < 0) | 813 | if (is_router < 0) |
783 | is_router = !!idev->cnf.forwarding; | 814 | is_router = idev->cnf.forwarding; |
784 | 815 | ||
785 | if (dad) { | 816 | if (dad) { |
786 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, | 817 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, |
787 | is_router, 0, (ifp != NULL), 1); | 818 | !!is_router, false, (ifp != NULL), true); |
788 | goto out; | 819 | goto out; |
789 | } | 820 | } |
790 | 821 | ||
@@ -805,8 +836,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
805 | NEIGH_UPDATE_F_OVERRIDE); | 836 | NEIGH_UPDATE_F_OVERRIDE); |
806 | if (neigh || !dev->header_ops) { | 837 | if (neigh || !dev->header_ops) { |
807 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 838 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
808 | is_router, | 839 | !!is_router, |
809 | 1, (ifp != NULL && inc), inc); | 840 | true, (ifp != NULL && inc), inc); |
810 | if (neigh) | 841 | if (neigh) |
811 | neigh_release(neigh); | 842 | neigh_release(neigh); |
812 | } | 843 | } |
@@ -1350,25 +1381,34 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1350 | icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); | 1381 | icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); |
1351 | } | 1382 | } |
1352 | 1383 | ||
1384 | static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, | ||
1385 | struct sk_buff *orig_skb, | ||
1386 | int rd_len) | ||
1387 | { | ||
1388 | u8 *opt = skb_put(skb, rd_len); | ||
1389 | |||
1390 | memset(opt, 0, 8); | ||
1391 | *(opt++) = ND_OPT_REDIRECT_HDR; | ||
1392 | *(opt++) = (rd_len >> 3); | ||
1393 | opt += 6; | ||
1394 | |||
1395 | memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); | ||
1396 | } | ||
1397 | |||
1353 | void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | 1398 | void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) |
1354 | { | 1399 | { |
1355 | struct net_device *dev = skb->dev; | 1400 | struct net_device *dev = skb->dev; |
1356 | struct net *net = dev_net(dev); | 1401 | struct net *net = dev_net(dev); |
1357 | struct sock *sk = net->ipv6.ndisc_sk; | 1402 | struct sock *sk = net->ipv6.ndisc_sk; |
1358 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1403 | int optlen = 0; |
1359 | struct inet_peer *peer; | 1404 | struct inet_peer *peer; |
1360 | struct sk_buff *buff; | 1405 | struct sk_buff *buff; |
1361 | struct icmp6hdr *icmph; | 1406 | struct rd_msg *msg; |
1362 | struct in6_addr saddr_buf; | 1407 | struct in6_addr saddr_buf; |
1363 | struct in6_addr *addrp; | ||
1364 | struct rt6_info *rt; | 1408 | struct rt6_info *rt; |
1365 | struct dst_entry *dst; | 1409 | struct dst_entry *dst; |
1366 | struct inet6_dev *idev; | ||
1367 | struct flowi6 fl6; | 1410 | struct flowi6 fl6; |
1368 | u8 *opt; | ||
1369 | int hlen, tlen; | ||
1370 | int rd_len; | 1411 | int rd_len; |
1371 | int err; | ||
1372 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; | 1412 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; |
1373 | bool ret; | 1413 | bool ret; |
1374 | 1414 | ||
@@ -1424,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | |||
1424 | memcpy(ha_buf, neigh->ha, dev->addr_len); | 1464 | memcpy(ha_buf, neigh->ha, dev->addr_len); |
1425 | read_unlock_bh(&neigh->lock); | 1465 | read_unlock_bh(&neigh->lock); |
1426 | ha = ha_buf; | 1466 | ha = ha_buf; |
1427 | len += ndisc_opt_addr_space(dev); | 1467 | optlen += ndisc_opt_addr_space(dev); |
1428 | } else | 1468 | } else |
1429 | read_unlock_bh(&neigh->lock); | 1469 | read_unlock_bh(&neigh->lock); |
1430 | 1470 | ||
@@ -1432,80 +1472,40 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | |||
1432 | } | 1472 | } |
1433 | 1473 | ||
1434 | rd_len = min_t(unsigned int, | 1474 | rd_len = min_t(unsigned int, |
1435 | IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); | 1475 | IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen, |
1476 | skb->len + 8); | ||
1436 | rd_len &= ~0x7; | 1477 | rd_len &= ~0x7; |
1437 | len += rd_len; | 1478 | optlen += rd_len; |
1438 | |||
1439 | hlen = LL_RESERVED_SPACE(dev); | ||
1440 | tlen = dev->needed_tailroom; | ||
1441 | buff = sock_alloc_send_skb(sk, | ||
1442 | (MAX_HEADER + sizeof(struct ipv6hdr) + | ||
1443 | len + hlen + tlen), | ||
1444 | 1, &err); | ||
1445 | if (buff == NULL) { | ||
1446 | ND_PRINTK(0, err, | ||
1447 | "Redirect: %s failed to allocate an skb, err=%d\n", | ||
1448 | __func__, err); | ||
1449 | goto release; | ||
1450 | } | ||
1451 | |||
1452 | skb_reserve(buff, hlen); | ||
1453 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, | ||
1454 | IPPROTO_ICMPV6, len); | ||
1455 | |||
1456 | skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); | ||
1457 | skb_put(buff, len); | ||
1458 | icmph = icmp6_hdr(buff); | ||
1459 | |||
1460 | memset(icmph, 0, sizeof(struct icmp6hdr)); | ||
1461 | icmph->icmp6_type = NDISC_REDIRECT; | ||
1462 | 1479 | ||
1463 | /* | 1480 | buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
1464 | * copy target and destination addresses | 1481 | if (!buff) |
1465 | */ | 1482 | goto release; |
1466 | |||
1467 | addrp = (struct in6_addr *)(icmph + 1); | ||
1468 | *addrp = *target; | ||
1469 | addrp++; | ||
1470 | *addrp = ipv6_hdr(skb)->daddr; | ||
1471 | 1483 | ||
1472 | opt = (u8*) (addrp + 1); | 1484 | msg = (struct rd_msg *)skb_put(buff, sizeof(*msg)); |
1485 | *msg = (struct rd_msg) { | ||
1486 | .icmph = { | ||
1487 | .icmp6_type = NDISC_REDIRECT, | ||
1488 | }, | ||
1489 | .target = *target, | ||
1490 | .dest = ipv6_hdr(skb)->daddr, | ||
1491 | }; | ||
1473 | 1492 | ||
1474 | /* | 1493 | /* |
1475 | * include target_address option | 1494 | * include target_address option |
1476 | */ | 1495 | */ |
1477 | 1496 | ||
1478 | if (ha) | 1497 | if (ha) |
1479 | opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, | 1498 | ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha); |
1480 | dev->addr_len, dev->type); | ||
1481 | 1499 | ||
1482 | /* | 1500 | /* |
1483 | * build redirect option and copy skb over to the new packet. | 1501 | * build redirect option and copy skb over to the new packet. |
1484 | */ | 1502 | */ |
1485 | 1503 | ||
1486 | memset(opt, 0, 8); | 1504 | if (rd_len) |
1487 | *(opt++) = ND_OPT_REDIRECT_HDR; | 1505 | ndisc_fill_redirect_hdr_option(buff, skb, rd_len); |
1488 | *(opt++) = (rd_len >> 3); | ||
1489 | opt += 6; | ||
1490 | |||
1491 | memcpy(opt, ipv6_hdr(skb), rd_len - 8); | ||
1492 | |||
1493 | icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, | ||
1494 | len, IPPROTO_ICMPV6, | ||
1495 | csum_partial(icmph, len, 0)); | ||
1496 | 1506 | ||
1497 | skb_dst_set(buff, dst); | 1507 | skb_dst_set(buff, dst); |
1498 | rcu_read_lock(); | 1508 | ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); |
1499 | idev = __in6_dev_get(dst->dev); | ||
1500 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | ||
1501 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, | ||
1502 | dst_output); | ||
1503 | if (!err) { | ||
1504 | ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); | ||
1505 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | ||
1506 | } | ||
1507 | |||
1508 | rcu_read_unlock(); | ||
1509 | return; | 1509 | return; |
1510 | 1510 | ||
1511 | release: | 1511 | release: |
@@ -1522,7 +1522,7 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1522 | { | 1522 | { |
1523 | struct nd_msg *msg; | 1523 | struct nd_msg *msg; |
1524 | 1524 | ||
1525 | if (!pskb_may_pull(skb, skb->len)) | 1525 | if (skb_linearize(skb)) |
1526 | return 0; | 1526 | return 0; |
1527 | 1527 | ||
1528 | msg = (struct nd_msg *)skb_transport_header(skb); | 1528 | msg = (struct nd_msg *)skb_transport_header(skb); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 125a90d6a795..341b54ade72c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -1098,7 +1098,7 @@ static int get_info(struct net *net, void __user *user, | |||
1098 | #endif | 1098 | #endif |
1099 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), | 1099 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), |
1100 | "ip6table_%s", name); | 1100 | "ip6table_%s", name); |
1101 | if (t && !IS_ERR(t)) { | 1101 | if (!IS_ERR_OR_NULL(t)) { |
1102 | struct ip6t_getinfo info; | 1102 | struct ip6t_getinfo info; |
1103 | const struct xt_table_info *private = t->private; | 1103 | const struct xt_table_info *private = t->private; |
1104 | #ifdef CONFIG_COMPAT | 1104 | #ifdef CONFIG_COMPAT |
@@ -1157,7 +1157,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, | |||
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | t = xt_find_table_lock(net, AF_INET6, get.name); | 1159 | t = xt_find_table_lock(net, AF_INET6, get.name); |
1160 | if (t && !IS_ERR(t)) { | 1160 | if (!IS_ERR_OR_NULL(t)) { |
1161 | struct xt_table_info *private = t->private; | 1161 | struct xt_table_info *private = t->private; |
1162 | duprintf("t->private->number = %u\n", private->number); | 1162 | duprintf("t->private->number = %u\n", private->number); |
1163 | if (get.size == private->size) | 1163 | if (get.size == private->size) |
@@ -1197,7 +1197,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1197 | 1197 | ||
1198 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), | 1198 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), |
1199 | "ip6table_%s", name); | 1199 | "ip6table_%s", name); |
1200 | if (!t || IS_ERR(t)) { | 1200 | if (IS_ERR_OR_NULL(t)) { |
1201 | ret = t ? PTR_ERR(t) : -ENOENT; | 1201 | ret = t ? PTR_ERR(t) : -ENOENT; |
1202 | goto free_newinfo_counters_untrans; | 1202 | goto free_newinfo_counters_untrans; |
1203 | } | 1203 | } |
@@ -1355,7 +1355,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | t = xt_find_table_lock(net, AF_INET6, name); | 1357 | t = xt_find_table_lock(net, AF_INET6, name); |
1358 | if (!t || IS_ERR(t)) { | 1358 | if (IS_ERR_OR_NULL(t)) { |
1359 | ret = t ? PTR_ERR(t) : -ENOENT; | 1359 | ret = t ? PTR_ERR(t) : -ENOENT; |
1360 | goto free; | 1360 | goto free; |
1361 | } | 1361 | } |
@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, | |||
1939 | 1939 | ||
1940 | xt_compat_lock(AF_INET6); | 1940 | xt_compat_lock(AF_INET6); |
1941 | t = xt_find_table_lock(net, AF_INET6, get.name); | 1941 | t = xt_find_table_lock(net, AF_INET6, get.name); |
1942 | if (t && !IS_ERR(t)) { | 1942 | if (!IS_ERR_OR_NULL(t)) { |
1943 | const struct xt_table_info *private = t->private; | 1943 | const struct xt_table_info *private = t->private; |
1944 | struct xt_table_info info; | 1944 | struct xt_table_info info; |
1945 | duprintf("t->private->number = %u\n", private->number); | 1945 | duprintf("t->private->number = %u\n", private->number); |
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index e9486915eff6..83acc1405a18 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c | |||
@@ -9,47 +9,38 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
12 | #include <net/ipv6.h> | ||
12 | #include <linux/netfilter.h> | 13 | #include <linux/netfilter.h> |
13 | #include <linux/netfilter_ipv6.h> | 14 | #include <linux/netfilter_ipv6.h> |
14 | #include <linux/netfilter_ipv6/ip6t_NPT.h> | 15 | #include <linux/netfilter_ipv6/ip6t_NPT.h> |
15 | #include <linux/netfilter/x_tables.h> | 16 | #include <linux/netfilter/x_tables.h> |
16 | 17 | ||
17 | static __sum16 csum16_complement(__sum16 a) | ||
18 | { | ||
19 | return (__force __sum16)(0xffff - (__force u16)a); | ||
20 | } | ||
21 | |||
22 | static __sum16 csum16_add(__sum16 a, __sum16 b) | ||
23 | { | ||
24 | u16 sum; | ||
25 | |||
26 | sum = (__force u16)a + (__force u16)b; | ||
27 | sum += (__force u16)a < (__force u16)b; | ||
28 | return (__force __sum16)sum; | ||
29 | } | ||
30 | |||
31 | static __sum16 csum16_sub(__sum16 a, __sum16 b) | ||
32 | { | ||
33 | return csum16_add(a, csum16_complement(b)); | ||
34 | } | ||
35 | |||
36 | static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) | 18 | static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) |
37 | { | 19 | { |
38 | struct ip6t_npt_tginfo *npt = par->targinfo; | 20 | struct ip6t_npt_tginfo *npt = par->targinfo; |
39 | __sum16 src_sum = 0, dst_sum = 0; | 21 | __wsum src_sum = 0, dst_sum = 0; |
22 | struct in6_addr pfx; | ||
40 | unsigned int i; | 23 | unsigned int i; |
41 | 24 | ||
42 | if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) | 25 | if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) |
43 | return -EINVAL; | 26 | return -EINVAL; |
44 | 27 | ||
28 | /* Ensure that LSB of prefix is zero */ | ||
29 | ipv6_addr_prefix(&pfx, &npt->src_pfx.in6, npt->src_pfx_len); | ||
30 | if (!ipv6_addr_equal(&pfx, &npt->src_pfx.in6)) | ||
31 | return -EINVAL; | ||
32 | ipv6_addr_prefix(&pfx, &npt->dst_pfx.in6, npt->dst_pfx_len); | ||
33 | if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6)) | ||
34 | return -EINVAL; | ||
35 | |||
45 | for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { | 36 | for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { |
46 | src_sum = csum16_add(src_sum, | 37 | src_sum = csum_add(src_sum, |
47 | (__force __sum16)npt->src_pfx.in6.s6_addr16[i]); | 38 | (__force __wsum)npt->src_pfx.in6.s6_addr16[i]); |
48 | dst_sum = csum16_add(dst_sum, | 39 | dst_sum = csum_add(dst_sum, |
49 | (__force __sum16)npt->dst_pfx.in6.s6_addr16[i]); | 40 | (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]); |
50 | } | 41 | } |
51 | 42 | ||
52 | npt->adjustment = csum16_sub(src_sum, dst_sum); | 43 | npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum)); |
53 | return 0; | 44 | return 0; |
54 | } | 45 | } |
55 | 46 | ||
@@ -70,7 +61,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, | |||
70 | 61 | ||
71 | idx = i / 32; | 62 | idx = i / 32; |
72 | addr->s6_addr32[idx] &= mask; | 63 | addr->s6_addr32[idx] &= mask; |
73 | addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx]; | 64 | addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx]; |
74 | } | 65 | } |
75 | 66 | ||
76 | if (pfx_len <= 48) | 67 | if (pfx_len <= 48) |
@@ -85,8 +76,8 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, | |||
85 | return false; | 76 | return false; |
86 | } | 77 | } |
87 | 78 | ||
88 | sum = csum16_add((__force __sum16)addr->s6_addr16[idx], | 79 | sum = ~csum_fold(csum_add(csum_unfold((__force __sum16)addr->s6_addr16[idx]), |
89 | npt->adjustment); | 80 | csum_unfold(npt->adjustment))); |
90 | if (sum == CSUM_MANGLED_0) | 81 | if (sum == CSUM_MANGLED_0) |
91 | sum = 0; | 82 | sum = 0; |
92 | *(__force __sum16 *)&addr->s6_addr16[idx] = sum; | 83 | *(__force __sum16 *)&addr->s6_addr16[idx] = sum; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index fd4fb34c51c7..ed3b427b2841 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -126,12 +126,13 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
126 | skb_put(nskb, sizeof(struct ipv6hdr)); | 126 | skb_put(nskb, sizeof(struct ipv6hdr)); |
127 | skb_reset_network_header(nskb); | 127 | skb_reset_network_header(nskb); |
128 | ip6h = ipv6_hdr(nskb); | 128 | ip6h = ipv6_hdr(nskb); |
129 | *(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20)); | 129 | ip6_flow_hdr(ip6h, tclass, 0); |
130 | ip6h->hop_limit = ip6_dst_hoplimit(dst); | 130 | ip6h->hop_limit = ip6_dst_hoplimit(dst); |
131 | ip6h->nexthdr = IPPROTO_TCP; | 131 | ip6h->nexthdr = IPPROTO_TCP; |
132 | ip6h->saddr = oip6h->daddr; | 132 | ip6h->saddr = oip6h->daddr; |
133 | ip6h->daddr = oip6h->saddr; | 133 | ip6h->daddr = oip6h->saddr; |
134 | 134 | ||
135 | skb_reset_transport_header(nskb); | ||
135 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | 136 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); |
136 | /* Truncate to length (no data) */ | 137 | /* Truncate to length (no data) */ |
137 | tcph->doff = sizeof(struct tcphdr)/4; | 138 | tcph->doff = sizeof(struct tcphdr)/4; |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 7431121b87de..6134a1ebfb1b 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/netfilter_ipv6/ip6_tables.h> | 12 | #include <linux/netfilter_ipv6/ip6_tables.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <net/ipv6.h> | ||
14 | 15 | ||
15 | MODULE_LICENSE("GPL"); | 16 | MODULE_LICENSE("GPL"); |
16 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 17 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -60,8 +61,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
60 | dev_net(out)->ipv6.ip6table_mangle); | 61 | dev_net(out)->ipv6.ip6table_mangle); |
61 | 62 | ||
62 | if (ret != NF_DROP && ret != NF_STOLEN && | 63 | if (ret != NF_DROP && ret != NF_STOLEN && |
63 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | 64 | (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || |
64 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | 65 | !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) || |
65 | skb->mark != mark || | 66 | skb->mark != mark || |
66 | ipv6_hdr(skb)->hop_limit != hop_limit || | 67 | ipv6_hdr(skb)->hop_limit != hop_limit || |
67 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) | 68 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) |
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 6c8ae24b85eb..e0e788d25b14 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -127,23 +127,28 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
127 | ret = nf_nat_rule_find(skb, hooknum, in, out, ct); | 127 | ret = nf_nat_rule_find(skb, hooknum, in, out, ct); |
128 | if (ret != NF_ACCEPT) | 128 | if (ret != NF_ACCEPT) |
129 | return ret; | 129 | return ret; |
130 | } else | 130 | } else { |
131 | pr_debug("Already setup manip %s for ct %p\n", | 131 | pr_debug("Already setup manip %s for ct %p\n", |
132 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | 132 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", |
133 | ct); | 133 | ct); |
134 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) | ||
135 | goto oif_changed; | ||
136 | } | ||
134 | break; | 137 | break; |
135 | 138 | ||
136 | default: | 139 | default: |
137 | /* ESTABLISHED */ | 140 | /* ESTABLISHED */ |
138 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | 141 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || |
139 | ctinfo == IP_CT_ESTABLISHED_REPLY); | 142 | ctinfo == IP_CT_ESTABLISHED_REPLY); |
140 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) { | 143 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) |
141 | nf_ct_kill_acct(ct, ctinfo, skb); | 144 | goto oif_changed; |
142 | return NF_DROP; | ||
143 | } | ||
144 | } | 145 | } |
145 | 146 | ||
146 | return nf_nat_packet(ct, ctinfo, hooknum, skb); | 147 | return nf_nat_packet(ct, ctinfo, hooknum, skb); |
148 | |||
149 | oif_changed: | ||
150 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
151 | return NF_DROP; | ||
147 | } | 152 | } |
148 | 153 | ||
149 | static unsigned int | 154 | static unsigned int |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 00ee17c3e893..2b6c226f5198 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -81,8 +81,8 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, | |||
81 | } | 81 | } |
82 | protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off); | 82 | protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off); |
83 | /* | 83 | /* |
84 | * (protoff == skb->len) mean that the packet doesn't have no data | 84 | * (protoff == skb->len) means the packet has not data, just |
85 | * except of IPv6 & ext headers. but it's tracked anyway. - YK | 85 | * IPv6 and possibly extensions headers, but it is tracked anyway |
86 | */ | 86 | */ |
87 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { | 87 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { |
88 | pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); | 88 | pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); |
@@ -104,7 +104,6 @@ static unsigned int ipv6_helper(unsigned int hooknum, | |||
104 | const struct nf_conn_help *help; | 104 | const struct nf_conn_help *help; |
105 | const struct nf_conntrack_helper *helper; | 105 | const struct nf_conntrack_helper *helper; |
106 | enum ip_conntrack_info ctinfo; | 106 | enum ip_conntrack_info ctinfo; |
107 | unsigned int ret; | ||
108 | __be16 frag_off; | 107 | __be16 frag_off; |
109 | int protoff; | 108 | int protoff; |
110 | u8 nexthdr; | 109 | u8 nexthdr; |
@@ -130,12 +129,7 @@ static unsigned int ipv6_helper(unsigned int hooknum, | |||
130 | return NF_ACCEPT; | 129 | return NF_ACCEPT; |
131 | } | 130 | } |
132 | 131 | ||
133 | ret = helper->help(skb, protoff, ct, ctinfo); | 132 | return helper->help(skb, protoff, ct, ctinfo); |
134 | if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) { | ||
135 | nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL, | ||
136 | "nf_ct_%s: dropping packet", helper->name); | ||
137 | } | ||
138 | return ret; | ||
139 | } | 133 | } |
140 | 134 | ||
141 | static unsigned int ipv6_confirm(unsigned int hooknum, | 135 | static unsigned int ipv6_confirm(unsigned int hooknum, |
@@ -421,54 +415,43 @@ static int ipv6_net_init(struct net *net) | |||
421 | { | 415 | { |
422 | int ret = 0; | 416 | int ret = 0; |
423 | 417 | ||
424 | ret = nf_conntrack_l4proto_register(net, | 418 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6); |
425 | &nf_conntrack_l4proto_tcp6); | ||
426 | if (ret < 0) { | 419 | if (ret < 0) { |
427 | printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n"); | 420 | pr_err("nf_conntrack_tcp6: pernet registration failed\n"); |
428 | goto out; | 421 | goto out; |
429 | } | 422 | } |
430 | ret = nf_conntrack_l4proto_register(net, | 423 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6); |
431 | &nf_conntrack_l4proto_udp6); | ||
432 | if (ret < 0) { | 424 | if (ret < 0) { |
433 | printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n"); | 425 | pr_err("nf_conntrack_udp6: pernet registration failed\n"); |
434 | goto cleanup_tcp6; | 426 | goto cleanup_tcp6; |
435 | } | 427 | } |
436 | ret = nf_conntrack_l4proto_register(net, | 428 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6); |
437 | &nf_conntrack_l4proto_icmpv6); | ||
438 | if (ret < 0) { | 429 | if (ret < 0) { |
439 | printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n"); | 430 | pr_err("nf_conntrack_icmp6: pernet registration failed\n"); |
440 | goto cleanup_udp6; | 431 | goto cleanup_udp6; |
441 | } | 432 | } |
442 | ret = nf_conntrack_l3proto_register(net, | 433 | ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6); |
443 | &nf_conntrack_l3proto_ipv6); | ||
444 | if (ret < 0) { | 434 | if (ret < 0) { |
445 | printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n"); | 435 | pr_err("nf_conntrack_ipv6: pernet registration failed.\n"); |
446 | goto cleanup_icmpv6; | 436 | goto cleanup_icmpv6; |
447 | } | 437 | } |
448 | return 0; | 438 | return 0; |
449 | cleanup_icmpv6: | 439 | cleanup_icmpv6: |
450 | nf_conntrack_l4proto_unregister(net, | 440 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
451 | &nf_conntrack_l4proto_icmpv6); | ||
452 | cleanup_udp6: | 441 | cleanup_udp6: |
453 | nf_conntrack_l4proto_unregister(net, | 442 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
454 | &nf_conntrack_l4proto_udp6); | ||
455 | cleanup_tcp6: | 443 | cleanup_tcp6: |
456 | nf_conntrack_l4proto_unregister(net, | 444 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
457 | &nf_conntrack_l4proto_tcp6); | ||
458 | out: | 445 | out: |
459 | return ret; | 446 | return ret; |
460 | } | 447 | } |
461 | 448 | ||
462 | static void ipv6_net_exit(struct net *net) | 449 | static void ipv6_net_exit(struct net *net) |
463 | { | 450 | { |
464 | nf_conntrack_l3proto_unregister(net, | 451 | nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6); |
465 | &nf_conntrack_l3proto_ipv6); | 452 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
466 | nf_conntrack_l4proto_unregister(net, | 453 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
467 | &nf_conntrack_l4proto_icmpv6); | 454 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
468 | nf_conntrack_l4proto_unregister(net, | ||
469 | &nf_conntrack_l4proto_udp6); | ||
470 | nf_conntrack_l4proto_unregister(net, | ||
471 | &nf_conntrack_l4proto_tcp6); | ||
472 | } | 455 | } |
473 | 456 | ||
474 | static struct pernet_operations ipv6_net_ops = { | 457 | static struct pernet_operations ipv6_net_ops = { |
@@ -491,19 +474,52 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
491 | 474 | ||
492 | ret = register_pernet_subsys(&ipv6_net_ops); | 475 | ret = register_pernet_subsys(&ipv6_net_ops); |
493 | if (ret < 0) | 476 | if (ret < 0) |
494 | goto cleanup_pernet; | 477 | goto cleanup_sockopt; |
478 | |||
495 | ret = nf_register_hooks(ipv6_conntrack_ops, | 479 | ret = nf_register_hooks(ipv6_conntrack_ops, |
496 | ARRAY_SIZE(ipv6_conntrack_ops)); | 480 | ARRAY_SIZE(ipv6_conntrack_ops)); |
497 | if (ret < 0) { | 481 | if (ret < 0) { |
498 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " | 482 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " |
499 | "hook.\n"); | 483 | "hook.\n"); |
500 | goto cleanup_ipv6; | 484 | goto cleanup_pernet; |
485 | } | ||
486 | |||
487 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6); | ||
488 | if (ret < 0) { | ||
489 | pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n"); | ||
490 | goto cleanup_hooks; | ||
491 | } | ||
492 | |||
493 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6); | ||
494 | if (ret < 0) { | ||
495 | pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n"); | ||
496 | goto cleanup_tcp6; | ||
497 | } | ||
498 | |||
499 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6); | ||
500 | if (ret < 0) { | ||
501 | pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n"); | ||
502 | goto cleanup_udp6; | ||
503 | } | ||
504 | |||
505 | ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6); | ||
506 | if (ret < 0) { | ||
507 | pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n"); | ||
508 | goto cleanup_icmpv6; | ||
501 | } | 509 | } |
502 | return ret; | 510 | return ret; |
503 | 511 | ||
504 | cleanup_ipv6: | 512 | cleanup_icmpv6: |
505 | unregister_pernet_subsys(&ipv6_net_ops); | 513 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); |
514 | cleanup_udp6: | ||
515 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
516 | cleanup_tcp6: | ||
517 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
518 | cleanup_hooks: | ||
519 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | ||
506 | cleanup_pernet: | 520 | cleanup_pernet: |
521 | unregister_pernet_subsys(&ipv6_net_ops); | ||
522 | cleanup_sockopt: | ||
507 | nf_unregister_sockopt(&so_getorigdst6); | 523 | nf_unregister_sockopt(&so_getorigdst6); |
508 | return ret; | 524 | return ret; |
509 | } | 525 | } |
@@ -511,6 +527,10 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
511 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) | 527 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) |
512 | { | 528 | { |
513 | synchronize_net(); | 529 | synchronize_net(); |
530 | nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | ||
531 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
532 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
533 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); | ||
514 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | 534 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); |
515 | unregister_pernet_subsys(&ipv6_net_ops); | 535 | unregister_pernet_subsys(&ipv6_net_ops); |
516 | nf_unregister_sockopt(&so_getorigdst6); | 536 | nf_unregister_sockopt(&so_getorigdst6); |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 22c8ea951185..54087e96d7b8 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -97,9 +97,9 @@ static int nf_ct_frag6_sysctl_register(struct net *net) | |||
97 | if (table == NULL) | 97 | if (table == NULL) |
98 | goto err_alloc; | 98 | goto err_alloc; |
99 | 99 | ||
100 | table[0].data = &net->ipv6.frags.high_thresh; | 100 | table[0].data = &net->nf_frag.frags.timeout; |
101 | table[1].data = &net->ipv6.frags.low_thresh; | 101 | table[1].data = &net->nf_frag.frags.low_thresh; |
102 | table[2].data = &net->ipv6.frags.timeout; | 102 | table[2].data = &net->nf_frag.frags.high_thresh; |
103 | } | 103 | } |
104 | 104 | ||
105 | hdr = register_net_sysctl(net, "net/netfilter", table); | 105 | hdr = register_net_sysctl(net, "net/netfilter", table); |
@@ -311,12 +311,15 @@ found: | |||
311 | else | 311 | else |
312 | fq->q.fragments = skb; | 312 | fq->q.fragments = skb; |
313 | 313 | ||
314 | skb->dev = NULL; | 314 | if (skb->dev) { |
315 | fq->iif = skb->dev->ifindex; | ||
316 | skb->dev = NULL; | ||
317 | } | ||
315 | fq->q.stamp = skb->tstamp; | 318 | fq->q.stamp = skb->tstamp; |
316 | fq->q.meat += skb->len; | 319 | fq->q.meat += skb->len; |
317 | if (payload_len > fq->q.max_size) | 320 | if (payload_len > fq->q.max_size) |
318 | fq->q.max_size = payload_len; | 321 | fq->q.max_size = payload_len; |
319 | atomic_add(skb->truesize, &fq->q.net->mem); | 322 | add_frag_mem_limit(&fq->q, skb->truesize); |
320 | 323 | ||
321 | /* The first fragment. | 324 | /* The first fragment. |
322 | * nhoffset is obtained from the first fragment, of course. | 325 | * nhoffset is obtained from the first fragment, of course. |
@@ -325,9 +328,8 @@ found: | |||
325 | fq->nhoffset = nhoff; | 328 | fq->nhoffset = nhoff; |
326 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 329 | fq->q.last_in |= INET_FRAG_FIRST_IN; |
327 | } | 330 | } |
328 | write_lock(&nf_frags.lock); | 331 | |
329 | list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list); | 332 | inet_frag_lru_move(&fq->q); |
330 | write_unlock(&nf_frags.lock); | ||
331 | return 0; | 333 | return 0; |
332 | 334 | ||
333 | discard_fq: | 335 | discard_fq: |
@@ -366,7 +368,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
366 | } | 368 | } |
367 | 369 | ||
368 | /* Head of list must not be cloned. */ | 370 | /* Head of list must not be cloned. */ |
369 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) { | 371 | if (skb_unclone(head, GFP_ATOMIC)) { |
370 | pr_debug("skb is cloned but can't expand head"); | 372 | pr_debug("skb is cloned but can't expand head"); |
371 | goto out_oom; | 373 | goto out_oom; |
372 | } | 374 | } |
@@ -395,7 +397,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
395 | clone->ip_summed = head->ip_summed; | 397 | clone->ip_summed = head->ip_summed; |
396 | 398 | ||
397 | NFCT_FRAG6_CB(clone)->orig = NULL; | 399 | NFCT_FRAG6_CB(clone)->orig = NULL; |
398 | atomic_add(clone->truesize, &fq->q.net->mem); | 400 | add_frag_mem_limit(&fq->q, clone->truesize); |
399 | } | 401 | } |
400 | 402 | ||
401 | /* We have to remove fragment header from datagram and to relocate | 403 | /* We have to remove fragment header from datagram and to relocate |
@@ -419,7 +421,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
419 | head->csum = csum_add(head->csum, fp->csum); | 421 | head->csum = csum_add(head->csum, fp->csum); |
420 | head->truesize += fp->truesize; | 422 | head->truesize += fp->truesize; |
421 | } | 423 | } |
422 | atomic_sub(head->truesize, &fq->q.net->mem); | 424 | sub_frag_mem_limit(&fq->q, head->truesize); |
423 | 425 | ||
424 | head->local_df = 1; | 426 | head->local_df = 1; |
425 | head->next = NULL; | 427 | head->next = NULL; |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 745a32042950..bbbe53a99b57 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -295,11 +295,11 @@ int snmp6_unregister_dev(struct inet6_dev *idev) | |||
295 | 295 | ||
296 | static int __net_init ipv6_proc_init_net(struct net *net) | 296 | static int __net_init ipv6_proc_init_net(struct net *net) |
297 | { | 297 | { |
298 | if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, | 298 | if (!proc_create("sockstat6", S_IRUGO, net->proc_net, |
299 | &sockstat6_seq_fops)) | 299 | &sockstat6_seq_fops)) |
300 | return -ENOMEM; | 300 | return -ENOMEM; |
301 | 301 | ||
302 | if (!proc_net_fops_create(net, "snmp6", S_IRUGO, &snmp6_seq_fops)) | 302 | if (!proc_create("snmp6", S_IRUGO, net->proc_net, &snmp6_seq_fops)) |
303 | goto proc_snmp6_fail; | 303 | goto proc_snmp6_fail; |
304 | 304 | ||
305 | net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net); | 305 | net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net); |
@@ -308,17 +308,17 @@ static int __net_init ipv6_proc_init_net(struct net *net) | |||
308 | return 0; | 308 | return 0; |
309 | 309 | ||
310 | proc_dev_snmp6_fail: | 310 | proc_dev_snmp6_fail: |
311 | proc_net_remove(net, "snmp6"); | 311 | remove_proc_entry("snmp6", net->proc_net); |
312 | proc_snmp6_fail: | 312 | proc_snmp6_fail: |
313 | proc_net_remove(net, "sockstat6"); | 313 | remove_proc_entry("sockstat6", net->proc_net); |
314 | return -ENOMEM; | 314 | return -ENOMEM; |
315 | } | 315 | } |
316 | 316 | ||
317 | static void __net_exit ipv6_proc_exit_net(struct net *net) | 317 | static void __net_exit ipv6_proc_exit_net(struct net *net) |
318 | { | 318 | { |
319 | proc_net_remove(net, "sockstat6"); | 319 | remove_proc_entry("sockstat6", net->proc_net); |
320 | proc_net_remove(net, "dev_snmp6"); | 320 | remove_proc_entry("dev_snmp6", net->proc_net); |
321 | proc_net_remove(net, "snmp6"); | 321 | remove_proc_entry("snmp6", net->proc_net); |
322 | } | 322 | } |
323 | 323 | ||
324 | static struct pernet_operations ipv6_proc_ops = { | 324 | static struct pernet_operations ipv6_proc_ops = { |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 6cd29b1e8b92..330b5e7b7df6 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -71,10 +71,9 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | |||
71 | unsigned short num, const struct in6_addr *loc_addr, | 71 | unsigned short num, const struct in6_addr *loc_addr, |
72 | const struct in6_addr *rmt_addr, int dif) | 72 | const struct in6_addr *rmt_addr, int dif) |
73 | { | 73 | { |
74 | struct hlist_node *node; | ||
75 | bool is_multicast = ipv6_addr_is_multicast(loc_addr); | 74 | bool is_multicast = ipv6_addr_is_multicast(loc_addr); |
76 | 75 | ||
77 | sk_for_each_from(sk, node) | 76 | sk_for_each_from(sk) |
78 | if (inet_sk(sk)->inet_num == num) { | 77 | if (inet_sk(sk)->inet_num == num) { |
79 | struct ipv6_pinfo *np = inet6_sk(sk); | 78 | struct ipv6_pinfo *np = inet6_sk(sk); |
80 | 79 | ||
@@ -507,7 +506,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
507 | sock_recv_ts_and_drops(msg, sk, skb); | 506 | sock_recv_ts_and_drops(msg, sk, skb); |
508 | 507 | ||
509 | if (np->rxopt.all) | 508 | if (np->rxopt.all) |
510 | datagram_recv_ctl(sk, msg, skb); | 509 | ip6_datagram_recv_ctl(sk, msg, skb); |
511 | 510 | ||
512 | err = copied; | 511 | err = copied; |
513 | if (flags & MSG_TRUNC) | 512 | if (flags & MSG_TRUNC) |
@@ -822,8 +821,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
822 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 821 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
823 | opt->tot_len = sizeof(struct ipv6_txoptions); | 822 | opt->tot_len = sizeof(struct ipv6_txoptions); |
824 | 823 | ||
825 | err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, | 824 | err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, |
826 | &hlimit, &tclass, &dontfrag); | 825 | &hlimit, &tclass, &dontfrag); |
827 | if (err < 0) { | 826 | if (err < 0) { |
828 | fl6_sock_release(flowlabel); | 827 | fl6_sock_release(flowlabel); |
829 | return err; | 828 | return err; |
@@ -1292,7 +1291,7 @@ static const struct file_operations raw6_seq_fops = { | |||
1292 | 1291 | ||
1293 | static int __net_init raw6_init_net(struct net *net) | 1292 | static int __net_init raw6_init_net(struct net *net) |
1294 | { | 1293 | { |
1295 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) | 1294 | if (!proc_create("raw6", S_IRUGO, net->proc_net, &raw6_seq_fops)) |
1296 | return -ENOMEM; | 1295 | return -ENOMEM; |
1297 | 1296 | ||
1298 | return 0; | 1297 | return 0; |
@@ -1300,7 +1299,7 @@ static int __net_init raw6_init_net(struct net *net) | |||
1300 | 1299 | ||
1301 | static void __net_exit raw6_exit_net(struct net *net) | 1300 | static void __net_exit raw6_exit_net(struct net *net) |
1302 | { | 1301 | { |
1303 | proc_net_remove(net, "raw6"); | 1302 | remove_proc_entry("raw6", net->proc_net); |
1304 | } | 1303 | } |
1305 | 1304 | ||
1306 | static struct pernet_operations raw6_net_ops = { | 1305 | static struct pernet_operations raw6_net_ops = { |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index e5253ec9e0fc..3c6a77290c6e 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -79,20 +79,8 @@ unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, | |||
79 | { | 79 | { |
80 | u32 c; | 80 | u32 c; |
81 | 81 | ||
82 | c = jhash_3words((__force u32)saddr->s6_addr32[0], | 82 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), |
83 | (__force u32)saddr->s6_addr32[1], | 83 | (__force u32)id, rnd); |
84 | (__force u32)saddr->s6_addr32[2], | ||
85 | rnd); | ||
86 | |||
87 | c = jhash_3words((__force u32)saddr->s6_addr32[3], | ||
88 | (__force u32)daddr->s6_addr32[0], | ||
89 | (__force u32)daddr->s6_addr32[1], | ||
90 | c); | ||
91 | |||
92 | c = jhash_3words((__force u32)daddr->s6_addr32[2], | ||
93 | (__force u32)daddr->s6_addr32[3], | ||
94 | (__force u32)id, | ||
95 | c); | ||
96 | 84 | ||
97 | return c & (INETFRAGS_HASHSZ - 1); | 85 | return c & (INETFRAGS_HASHSZ - 1); |
98 | } | 86 | } |
@@ -327,7 +315,7 @@ found: | |||
327 | } | 315 | } |
328 | fq->q.stamp = skb->tstamp; | 316 | fq->q.stamp = skb->tstamp; |
329 | fq->q.meat += skb->len; | 317 | fq->q.meat += skb->len; |
330 | atomic_add(skb->truesize, &fq->q.net->mem); | 318 | add_frag_mem_limit(&fq->q, skb->truesize); |
331 | 319 | ||
332 | /* The first fragment. | 320 | /* The first fragment. |
333 | * nhoffset is obtained from the first fragment, of course. | 321 | * nhoffset is obtained from the first fragment, of course. |
@@ -341,9 +329,7 @@ found: | |||
341 | fq->q.meat == fq->q.len) | 329 | fq->q.meat == fq->q.len) |
342 | return ip6_frag_reasm(fq, prev, dev); | 330 | return ip6_frag_reasm(fq, prev, dev); |
343 | 331 | ||
344 | write_lock(&ip6_frags.lock); | 332 | inet_frag_lru_move(&fq->q); |
345 | list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list); | ||
346 | write_unlock(&ip6_frags.lock); | ||
347 | return -1; | 333 | return -1; |
348 | 334 | ||
349 | discard_fq: | 335 | discard_fq: |
@@ -406,7 +392,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
406 | goto out_oversize; | 392 | goto out_oversize; |
407 | 393 | ||
408 | /* Head of list must not be cloned. */ | 394 | /* Head of list must not be cloned. */ |
409 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) | 395 | if (skb_unclone(head, GFP_ATOMIC)) |
410 | goto out_oom; | 396 | goto out_oom; |
411 | 397 | ||
412 | /* If the first fragment is fragmented itself, we split | 398 | /* If the first fragment is fragmented itself, we split |
@@ -429,7 +415,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
429 | head->len -= clone->len; | 415 | head->len -= clone->len; |
430 | clone->csum = 0; | 416 | clone->csum = 0; |
431 | clone->ip_summed = head->ip_summed; | 417 | clone->ip_summed = head->ip_summed; |
432 | atomic_add(clone->truesize, &fq->q.net->mem); | 418 | add_frag_mem_limit(&fq->q, clone->truesize); |
433 | } | 419 | } |
434 | 420 | ||
435 | /* We have to remove fragment header from datagram and to relocate | 421 | /* We have to remove fragment header from datagram and to relocate |
@@ -467,7 +453,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
467 | } | 453 | } |
468 | fp = next; | 454 | fp = next; |
469 | } | 455 | } |
470 | atomic_sub(sum_truesize, &fq->q.net->mem); | 456 | sub_frag_mem_limit(&fq->q, sum_truesize); |
471 | 457 | ||
472 | head->next = NULL; | 458 | head->next = NULL; |
473 | head->dev = dev; | 459 | head->dev = dev; |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e229a3bc345d..e5fe0041adfa 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -145,25 +145,12 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, | |||
145 | struct neighbour *n; | 145 | struct neighbour *n; |
146 | 146 | ||
147 | daddr = choose_neigh_daddr(rt, skb, daddr); | 147 | daddr = choose_neigh_daddr(rt, skb, daddr); |
148 | n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr); | 148 | n = __ipv6_neigh_lookup(dst->dev, daddr); |
149 | if (n) | 149 | if (n) |
150 | return n; | 150 | return n; |
151 | return neigh_create(&nd_tbl, daddr, dst->dev); | 151 | return neigh_create(&nd_tbl, daddr, dst->dev); |
152 | } | 152 | } |
153 | 153 | ||
154 | static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev) | ||
155 | { | ||
156 | struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway); | ||
157 | if (!n) { | ||
158 | n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev); | ||
159 | if (IS_ERR(n)) | ||
160 | return PTR_ERR(n); | ||
161 | } | ||
162 | rt->n = n; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct dst_ops ip6_dst_ops_template = { | 154 | static struct dst_ops ip6_dst_ops_template = { |
168 | .family = AF_INET6, | 155 | .family = AF_INET6, |
169 | .protocol = cpu_to_be16(ETH_P_IPV6), | 156 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -300,9 +287,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
300 | { | 287 | { |
301 | struct rt6_info *rt = (struct rt6_info *)dst; | 288 | struct rt6_info *rt = (struct rt6_info *)dst; |
302 | struct inet6_dev *idev = rt->rt6i_idev; | 289 | struct inet6_dev *idev = rt->rt6i_idev; |
303 | 290 | struct dst_entry *from = dst->from; | |
304 | if (rt->n) | ||
305 | neigh_release(rt->n); | ||
306 | 291 | ||
307 | if (!(rt->dst.flags & DST_HOST)) | 292 | if (!(rt->dst.flags & DST_HOST)) |
308 | dst_destroy_metrics_generic(dst); | 293 | dst_destroy_metrics_generic(dst); |
@@ -312,8 +297,8 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
312 | in6_dev_put(idev); | 297 | in6_dev_put(idev); |
313 | } | 298 | } |
314 | 299 | ||
315 | if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from) | 300 | dst->from = NULL; |
316 | dst_release(dst->from); | 301 | dst_release(from); |
317 | 302 | ||
318 | if (rt6_has_peer(rt)) { | 303 | if (rt6_has_peer(rt)) { |
319 | struct inet_peer *peer = rt6_peer_ptr(rt); | 304 | struct inet_peer *peer = rt6_peer_ptr(rt); |
@@ -354,11 +339,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
354 | in6_dev_put(idev); | 339 | in6_dev_put(idev); |
355 | } | 340 | } |
356 | } | 341 | } |
357 | if (rt->n && rt->n->dev == dev) { | ||
358 | rt->n->dev = loopback_dev; | ||
359 | dev_hold(loopback_dev); | ||
360 | dev_put(dev); | ||
361 | } | ||
362 | } | 342 | } |
363 | } | 343 | } |
364 | 344 | ||
@@ -388,15 +368,8 @@ static int rt6_info_hash_nhsfn(unsigned int candidate_count, | |||
388 | { | 368 | { |
389 | unsigned int val = fl6->flowi6_proto; | 369 | unsigned int val = fl6->flowi6_proto; |
390 | 370 | ||
391 | val ^= (__force u32)fl6->daddr.s6_addr32[0]; | 371 | val ^= ipv6_addr_hash(&fl6->daddr); |
392 | val ^= (__force u32)fl6->daddr.s6_addr32[1]; | 372 | val ^= ipv6_addr_hash(&fl6->saddr); |
393 | val ^= (__force u32)fl6->daddr.s6_addr32[2]; | ||
394 | val ^= (__force u32)fl6->daddr.s6_addr32[3]; | ||
395 | |||
396 | val ^= (__force u32)fl6->saddr.s6_addr32[0]; | ||
397 | val ^= (__force u32)fl6->saddr.s6_addr32[1]; | ||
398 | val ^= (__force u32)fl6->saddr.s6_addr32[2]; | ||
399 | val ^= (__force u32)fl6->saddr.s6_addr32[3]; | ||
400 | 373 | ||
401 | /* Work only if this not encapsulated */ | 374 | /* Work only if this not encapsulated */ |
402 | switch (fl6->flowi6_proto) { | 375 | switch (fl6->flowi6_proto) { |
@@ -505,24 +478,34 @@ static void rt6_probe(struct rt6_info *rt) | |||
505 | * Router Reachability Probe MUST be rate-limited | 478 | * Router Reachability Probe MUST be rate-limited |
506 | * to no more than one per minute. | 479 | * to no more than one per minute. |
507 | */ | 480 | */ |
508 | neigh = rt ? rt->n : NULL; | 481 | if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) |
509 | if (!neigh || (neigh->nud_state & NUD_VALID)) | ||
510 | return; | 482 | return; |
511 | read_lock_bh(&neigh->lock); | 483 | rcu_read_lock_bh(); |
512 | if (!(neigh->nud_state & NUD_VALID) && | 484 | neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); |
485 | if (neigh) { | ||
486 | write_lock(&neigh->lock); | ||
487 | if (neigh->nud_state & NUD_VALID) | ||
488 | goto out; | ||
489 | } | ||
490 | |||
491 | if (!neigh || | ||
513 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 492 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
514 | struct in6_addr mcaddr; | 493 | struct in6_addr mcaddr; |
515 | struct in6_addr *target; | 494 | struct in6_addr *target; |
516 | 495 | ||
517 | neigh->updated = jiffies; | 496 | if (neigh) { |
518 | read_unlock_bh(&neigh->lock); | 497 | neigh->updated = jiffies; |
498 | write_unlock(&neigh->lock); | ||
499 | } | ||
519 | 500 | ||
520 | target = (struct in6_addr *)&neigh->primary_key; | 501 | target = (struct in6_addr *)&rt->rt6i_gateway; |
521 | addrconf_addr_solict_mult(target, &mcaddr); | 502 | addrconf_addr_solict_mult(target, &mcaddr); |
522 | ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL); | 503 | ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL); |
523 | } else { | 504 | } else { |
524 | read_unlock_bh(&neigh->lock); | 505 | out: |
506 | write_unlock(&neigh->lock); | ||
525 | } | 507 | } |
508 | rcu_read_unlock_bh(); | ||
526 | } | 509 | } |
527 | #else | 510 | #else |
528 | static inline void rt6_probe(struct rt6_info *rt) | 511 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -549,20 +532,24 @@ static inline bool rt6_check_neigh(struct rt6_info *rt) | |||
549 | struct neighbour *neigh; | 532 | struct neighbour *neigh; |
550 | bool ret = false; | 533 | bool ret = false; |
551 | 534 | ||
552 | neigh = rt->n; | ||
553 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 535 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
554 | !(rt->rt6i_flags & RTF_GATEWAY)) | 536 | !(rt->rt6i_flags & RTF_GATEWAY)) |
555 | ret = true; | 537 | return true; |
556 | else if (neigh) { | 538 | |
557 | read_lock_bh(&neigh->lock); | 539 | rcu_read_lock_bh(); |
540 | neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); | ||
541 | if (neigh) { | ||
542 | read_lock(&neigh->lock); | ||
558 | if (neigh->nud_state & NUD_VALID) | 543 | if (neigh->nud_state & NUD_VALID) |
559 | ret = true; | 544 | ret = true; |
560 | #ifdef CONFIG_IPV6_ROUTER_PREF | 545 | #ifdef CONFIG_IPV6_ROUTER_PREF |
561 | else if (!(neigh->nud_state & NUD_FAILED)) | 546 | else if (!(neigh->nud_state & NUD_FAILED)) |
562 | ret = true; | 547 | ret = true; |
563 | #endif | 548 | #endif |
564 | read_unlock_bh(&neigh->lock); | 549 | read_unlock(&neigh->lock); |
565 | } | 550 | } |
551 | rcu_read_unlock_bh(); | ||
552 | |||
566 | return ret; | 553 | return ret; |
567 | } | 554 | } |
568 | 555 | ||
@@ -838,8 +825,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
838 | rt = ip6_rt_copy(ort, daddr); | 825 | rt = ip6_rt_copy(ort, daddr); |
839 | 826 | ||
840 | if (rt) { | 827 | if (rt) { |
841 | int attempts = !in_softirq(); | ||
842 | |||
843 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { | 828 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { |
844 | if (ort->rt6i_dst.plen != 128 && | 829 | if (ort->rt6i_dst.plen != 128 && |
845 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) | 830 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
@@ -855,32 +840,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
855 | rt->rt6i_src.plen = 128; | 840 | rt->rt6i_src.plen = 128; |
856 | } | 841 | } |
857 | #endif | 842 | #endif |
858 | |||
859 | retry: | ||
860 | if (rt6_bind_neighbour(rt, rt->dst.dev)) { | ||
861 | struct net *net = dev_net(rt->dst.dev); | ||
862 | int saved_rt_min_interval = | ||
863 | net->ipv6.sysctl.ip6_rt_gc_min_interval; | ||
864 | int saved_rt_elasticity = | ||
865 | net->ipv6.sysctl.ip6_rt_gc_elasticity; | ||
866 | |||
867 | if (attempts-- > 0) { | ||
868 | net->ipv6.sysctl.ip6_rt_gc_elasticity = 1; | ||
869 | net->ipv6.sysctl.ip6_rt_gc_min_interval = 0; | ||
870 | |||
871 | ip6_dst_gc(&net->ipv6.ip6_dst_ops); | ||
872 | |||
873 | net->ipv6.sysctl.ip6_rt_gc_elasticity = | ||
874 | saved_rt_elasticity; | ||
875 | net->ipv6.sysctl.ip6_rt_gc_min_interval = | ||
876 | saved_rt_min_interval; | ||
877 | goto retry; | ||
878 | } | ||
879 | |||
880 | net_warn_ratelimited("Neighbour table overflow\n"); | ||
881 | dst_free(&rt->dst); | ||
882 | return NULL; | ||
883 | } | ||
884 | } | 843 | } |
885 | 844 | ||
886 | return rt; | 845 | return rt; |
@@ -891,10 +850,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, | |||
891 | { | 850 | { |
892 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); | 851 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); |
893 | 852 | ||
894 | if (rt) { | 853 | if (rt) |
895 | rt->rt6i_flags |= RTF_CACHE; | 854 | rt->rt6i_flags |= RTF_CACHE; |
896 | rt->n = neigh_clone(ort->n); | ||
897 | } | ||
898 | return rt; | 855 | return rt; |
899 | } | 856 | } |
900 | 857 | ||
@@ -928,7 +885,7 @@ restart: | |||
928 | dst_hold(&rt->dst); | 885 | dst_hold(&rt->dst); |
929 | read_unlock_bh(&table->tb6_lock); | 886 | read_unlock_bh(&table->tb6_lock); |
930 | 887 | ||
931 | if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 888 | if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY))) |
932 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 889 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
933 | else if (!(rt->dst.flags & DST_HOST)) | 890 | else if (!(rt->dst.flags & DST_HOST)) |
934 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 891 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
@@ -994,7 +951,7 @@ void ip6_route_input(struct sk_buff *skb) | |||
994 | .flowi6_iif = skb->dev->ifindex, | 951 | .flowi6_iif = skb->dev->ifindex, |
995 | .daddr = iph->daddr, | 952 | .daddr = iph->daddr, |
996 | .saddr = iph->saddr, | 953 | .saddr = iph->saddr, |
997 | .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK, | 954 | .flowlabel = ip6_flowinfo(iph), |
998 | .flowi6_mark = skb->mark, | 955 | .flowi6_mark = skb->mark, |
999 | .flowi6_proto = iph->nexthdr, | 956 | .flowi6_proto = iph->nexthdr, |
1000 | }; | 957 | }; |
@@ -1054,7 +1011,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori | |||
1054 | 1011 | ||
1055 | rt->rt6i_gateway = ort->rt6i_gateway; | 1012 | rt->rt6i_gateway = ort->rt6i_gateway; |
1056 | rt->rt6i_flags = ort->rt6i_flags; | 1013 | rt->rt6i_flags = ort->rt6i_flags; |
1057 | rt6_clean_expires(rt); | ||
1058 | rt->rt6i_metric = 0; | 1014 | rt->rt6i_metric = 0; |
1059 | 1015 | ||
1060 | memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); | 1016 | memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); |
@@ -1159,7 +1115,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, | |||
1159 | fl6.flowi6_flags = 0; | 1115 | fl6.flowi6_flags = 0; |
1160 | fl6.daddr = iph->daddr; | 1116 | fl6.daddr = iph->daddr; |
1161 | fl6.saddr = iph->saddr; | 1117 | fl6.saddr = iph->saddr; |
1162 | fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK; | 1118 | fl6.flowlabel = ip6_flowinfo(iph); |
1163 | 1119 | ||
1164 | dst = ip6_route_output(net, NULL, &fl6); | 1120 | dst = ip6_route_output(net, NULL, &fl6); |
1165 | if (!dst->error) | 1121 | if (!dst->error) |
@@ -1187,7 +1143,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) | |||
1187 | fl6.flowi6_flags = 0; | 1143 | fl6.flowi6_flags = 0; |
1188 | fl6.daddr = iph->daddr; | 1144 | fl6.daddr = iph->daddr; |
1189 | fl6.saddr = iph->saddr; | 1145 | fl6.saddr = iph->saddr; |
1190 | fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK; | 1146 | fl6.flowlabel = ip6_flowinfo(iph); |
1191 | 1147 | ||
1192 | dst = ip6_route_output(net, NULL, &fl6); | 1148 | dst = ip6_route_output(net, NULL, &fl6); |
1193 | if (!dst->error) | 1149 | if (!dst->error) |
@@ -1247,7 +1203,6 @@ static struct dst_entry *icmp6_dst_gc_list; | |||
1247 | static DEFINE_SPINLOCK(icmp6_dst_lock); | 1203 | static DEFINE_SPINLOCK(icmp6_dst_lock); |
1248 | 1204 | ||
1249 | struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | 1205 | struct dst_entry *icmp6_dst_alloc(struct net_device *dev, |
1250 | struct neighbour *neigh, | ||
1251 | struct flowi6 *fl6) | 1206 | struct flowi6 *fl6) |
1252 | { | 1207 | { |
1253 | struct dst_entry *dst; | 1208 | struct dst_entry *dst; |
@@ -1265,20 +1220,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1265 | goto out; | 1220 | goto out; |
1266 | } | 1221 | } |
1267 | 1222 | ||
1268 | if (neigh) | ||
1269 | neigh_hold(neigh); | ||
1270 | else { | ||
1271 | neigh = ip6_neigh_lookup(&rt->dst, NULL, &fl6->daddr); | ||
1272 | if (IS_ERR(neigh)) { | ||
1273 | in6_dev_put(idev); | ||
1274 | dst_free(&rt->dst); | ||
1275 | return ERR_CAST(neigh); | ||
1276 | } | ||
1277 | } | ||
1278 | |||
1279 | rt->dst.flags |= DST_HOST; | 1223 | rt->dst.flags |= DST_HOST; |
1280 | rt->dst.output = ip6_output; | 1224 | rt->dst.output = ip6_output; |
1281 | rt->n = neigh; | ||
1282 | atomic_set(&rt->dst.__refcnt, 1); | 1225 | atomic_set(&rt->dst.__refcnt, 1); |
1283 | rt->rt6i_dst.addr = fl6->daddr; | 1226 | rt->rt6i_dst.addr = fl6->daddr; |
1284 | rt->rt6i_dst.plen = 128; | 1227 | rt->rt6i_dst.plen = 128; |
@@ -1587,12 +1530,6 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1587 | } else | 1530 | } else |
1588 | rt->rt6i_prefsrc.plen = 0; | 1531 | rt->rt6i_prefsrc.plen = 0; |
1589 | 1532 | ||
1590 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | ||
1591 | err = rt6_bind_neighbour(rt, dev); | ||
1592 | if (err) | ||
1593 | goto out; | ||
1594 | } | ||
1595 | |||
1596 | rt->rt6i_flags = cfg->fc_flags; | 1533 | rt->rt6i_flags = cfg->fc_flags; |
1597 | 1534 | ||
1598 | install_route: | 1535 | install_route: |
@@ -1705,37 +1642,32 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1705 | struct net *net = dev_net(skb->dev); | 1642 | struct net *net = dev_net(skb->dev); |
1706 | struct netevent_redirect netevent; | 1643 | struct netevent_redirect netevent; |
1707 | struct rt6_info *rt, *nrt = NULL; | 1644 | struct rt6_info *rt, *nrt = NULL; |
1708 | const struct in6_addr *target; | ||
1709 | struct ndisc_options ndopts; | 1645 | struct ndisc_options ndopts; |
1710 | const struct in6_addr *dest; | ||
1711 | struct neighbour *old_neigh; | ||
1712 | struct inet6_dev *in6_dev; | 1646 | struct inet6_dev *in6_dev; |
1713 | struct neighbour *neigh; | 1647 | struct neighbour *neigh; |
1714 | struct icmp6hdr *icmph; | 1648 | struct rd_msg *msg; |
1715 | int optlen, on_link; | 1649 | int optlen, on_link; |
1716 | u8 *lladdr; | 1650 | u8 *lladdr; |
1717 | 1651 | ||
1718 | optlen = skb->tail - skb->transport_header; | 1652 | optlen = skb->tail - skb->transport_header; |
1719 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1653 | optlen -= sizeof(*msg); |
1720 | 1654 | ||
1721 | if (optlen < 0) { | 1655 | if (optlen < 0) { |
1722 | net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); | 1656 | net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); |
1723 | return; | 1657 | return; |
1724 | } | 1658 | } |
1725 | 1659 | ||
1726 | icmph = icmp6_hdr(skb); | 1660 | msg = (struct rd_msg *)icmp6_hdr(skb); |
1727 | target = (const struct in6_addr *) (icmph + 1); | ||
1728 | dest = target + 1; | ||
1729 | 1661 | ||
1730 | if (ipv6_addr_is_multicast(dest)) { | 1662 | if (ipv6_addr_is_multicast(&msg->dest)) { |
1731 | net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); | 1663 | net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); |
1732 | return; | 1664 | return; |
1733 | } | 1665 | } |
1734 | 1666 | ||
1735 | on_link = 0; | 1667 | on_link = 0; |
1736 | if (ipv6_addr_equal(dest, target)) { | 1668 | if (ipv6_addr_equal(&msg->dest, &msg->target)) { |
1737 | on_link = 1; | 1669 | on_link = 1; |
1738 | } else if (ipv6_addr_type(target) != | 1670 | } else if (ipv6_addr_type(&msg->target) != |
1739 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { | 1671 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
1740 | net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); | 1672 | net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); |
1741 | return; | 1673 | return; |
@@ -1752,7 +1684,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1752 | * first-hop router for the specified ICMP Destination Address. | 1684 | * first-hop router for the specified ICMP Destination Address. |
1753 | */ | 1685 | */ |
1754 | 1686 | ||
1755 | if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { | 1687 | if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) { |
1756 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); | 1688 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); |
1757 | return; | 1689 | return; |
1758 | } | 1690 | } |
@@ -1779,15 +1711,10 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1779 | */ | 1711 | */ |
1780 | dst_confirm(&rt->dst); | 1712 | dst_confirm(&rt->dst); |
1781 | 1713 | ||
1782 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1714 | neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); |
1783 | if (!neigh) | 1715 | if (!neigh) |
1784 | return; | 1716 | return; |
1785 | 1717 | ||
1786 | /* Duplicate redirect: silently ignore. */ | ||
1787 | old_neigh = rt->n; | ||
1788 | if (neigh == old_neigh) | ||
1789 | goto out; | ||
1790 | |||
1791 | /* | 1718 | /* |
1792 | * We have finally decided to accept it. | 1719 | * We have finally decided to accept it. |
1793 | */ | 1720 | */ |
@@ -1799,7 +1726,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1799 | NEIGH_UPDATE_F_ISROUTER)) | 1726 | NEIGH_UPDATE_F_ISROUTER)) |
1800 | ); | 1727 | ); |
1801 | 1728 | ||
1802 | nrt = ip6_rt_copy(rt, dest); | 1729 | nrt = ip6_rt_copy(rt, &msg->dest); |
1803 | if (!nrt) | 1730 | if (!nrt) |
1804 | goto out; | 1731 | goto out; |
1805 | 1732 | ||
@@ -1808,16 +1735,14 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1808 | nrt->rt6i_flags &= ~RTF_GATEWAY; | 1735 | nrt->rt6i_flags &= ~RTF_GATEWAY; |
1809 | 1736 | ||
1810 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; | 1737 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; |
1811 | nrt->n = neigh_clone(neigh); | ||
1812 | 1738 | ||
1813 | if (ip6_ins_rt(nrt)) | 1739 | if (ip6_ins_rt(nrt)) |
1814 | goto out; | 1740 | goto out; |
1815 | 1741 | ||
1816 | netevent.old = &rt->dst; | 1742 | netevent.old = &rt->dst; |
1817 | netevent.old_neigh = old_neigh; | ||
1818 | netevent.new = &nrt->dst; | 1743 | netevent.new = &nrt->dst; |
1819 | netevent.new_neigh = neigh; | 1744 | netevent.daddr = &msg->dest; |
1820 | netevent.daddr = dest; | 1745 | netevent.neigh = neigh; |
1821 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1746 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
1822 | 1747 | ||
1823 | if (rt->rt6i_flags & RTF_CACHE) { | 1748 | if (rt->rt6i_flags & RTF_CACHE) { |
@@ -1859,8 +1784,6 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, | |||
1859 | if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == | 1784 | if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == |
1860 | (RTF_DEFAULT | RTF_ADDRCONF)) | 1785 | (RTF_DEFAULT | RTF_ADDRCONF)) |
1861 | rt6_set_from(rt, ort); | 1786 | rt6_set_from(rt, ort); |
1862 | else | ||
1863 | rt6_clean_expires(rt); | ||
1864 | rt->rt6i_metric = 0; | 1787 | rt->rt6i_metric = 0; |
1865 | 1788 | ||
1866 | #ifdef CONFIG_IPV6_SUBTREES | 1789 | #ifdef CONFIG_IPV6_SUBTREES |
@@ -1992,7 +1915,8 @@ void rt6_purge_dflt_routers(struct net *net) | |||
1992 | restart: | 1915 | restart: |
1993 | read_lock_bh(&table->tb6_lock); | 1916 | read_lock_bh(&table->tb6_lock); |
1994 | for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { | 1917 | for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { |
1995 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1918 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && |
1919 | (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { | ||
1996 | dst_hold(&rt->dst); | 1920 | dst_hold(&rt->dst); |
1997 | read_unlock_bh(&table->tb6_lock); | 1921 | read_unlock_bh(&table->tb6_lock); |
1998 | ip6_del_rt(rt); | 1922 | ip6_del_rt(rt); |
@@ -2123,7 +2047,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2123 | { | 2047 | { |
2124 | struct net *net = dev_net(idev->dev); | 2048 | struct net *net = dev_net(idev->dev); |
2125 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); | 2049 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); |
2126 | int err; | ||
2127 | 2050 | ||
2128 | if (!rt) { | 2051 | if (!rt) { |
2129 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); | 2052 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); |
@@ -2142,11 +2065,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2142 | rt->rt6i_flags |= RTF_ANYCAST; | 2065 | rt->rt6i_flags |= RTF_ANYCAST; |
2143 | else | 2066 | else |
2144 | rt->rt6i_flags |= RTF_LOCAL; | 2067 | rt->rt6i_flags |= RTF_LOCAL; |
2145 | err = rt6_bind_neighbour(rt, rt->dst.dev); | ||
2146 | if (err) { | ||
2147 | dst_free(&rt->dst); | ||
2148 | return ERR_PTR(err); | ||
2149 | } | ||
2150 | 2068 | ||
2151 | rt->rt6i_dst.addr = *addr; | 2069 | rt->rt6i_dst.addr = *addr; |
2152 | rt->rt6i_dst.plen = 128; | 2070 | rt->rt6i_dst.plen = 128; |
@@ -2492,7 +2410,6 @@ static int rt6_fill_node(struct net *net, | |||
2492 | struct nlmsghdr *nlh; | 2410 | struct nlmsghdr *nlh; |
2493 | long expires; | 2411 | long expires; |
2494 | u32 table; | 2412 | u32 table; |
2495 | struct neighbour *n; | ||
2496 | 2413 | ||
2497 | if (prefix) { /* user wants prefix routes only */ | 2414 | if (prefix) { /* user wants prefix routes only */ |
2498 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 2415 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -2605,9 +2522,8 @@ static int rt6_fill_node(struct net *net, | |||
2605 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2522 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2606 | goto nla_put_failure; | 2523 | goto nla_put_failure; |
2607 | 2524 | ||
2608 | n = rt->n; | 2525 | if (rt->rt6i_flags & RTF_GATEWAY) { |
2609 | if (n) { | 2526 | if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0) |
2610 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) | ||
2611 | goto nla_put_failure; | 2527 | goto nla_put_failure; |
2612 | } | 2528 | } |
2613 | 2529 | ||
@@ -2802,7 +2718,6 @@ struct rt6_proc_arg | |||
2802 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) | 2718 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) |
2803 | { | 2719 | { |
2804 | struct seq_file *m = p_arg; | 2720 | struct seq_file *m = p_arg; |
2805 | struct neighbour *n; | ||
2806 | 2721 | ||
2807 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | 2722 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); |
2808 | 2723 | ||
@@ -2811,9 +2726,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2811 | #else | 2726 | #else |
2812 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2727 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2813 | #endif | 2728 | #endif |
2814 | n = rt->n; | 2729 | if (rt->rt6i_flags & RTF_GATEWAY) { |
2815 | if (n) { | 2730 | seq_printf(m, "%pi6", &rt->rt6i_gateway); |
2816 | seq_printf(m, "%pi6", n->primary_key); | ||
2817 | } else { | 2731 | } else { |
2818 | seq_puts(m, "00000000000000000000000000000000"); | 2732 | seq_puts(m, "00000000000000000000000000000000"); |
2819 | } | 2733 | } |
@@ -3080,8 +2994,8 @@ static void __net_exit ip6_route_net_exit(struct net *net) | |||
3080 | static int __net_init ip6_route_net_init_late(struct net *net) | 2994 | static int __net_init ip6_route_net_init_late(struct net *net) |
3081 | { | 2995 | { |
3082 | #ifdef CONFIG_PROC_FS | 2996 | #ifdef CONFIG_PROC_FS |
3083 | proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); | 2997 | proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops); |
3084 | proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); | 2998 | proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops); |
3085 | #endif | 2999 | #endif |
3086 | return 0; | 3000 | return 0; |
3087 | } | 3001 | } |
@@ -3089,8 +3003,8 @@ static int __net_init ip6_route_net_init_late(struct net *net) | |||
3089 | static void __net_exit ip6_route_net_exit_late(struct net *net) | 3003 | static void __net_exit ip6_route_net_exit_late(struct net *net) |
3090 | { | 3004 | { |
3091 | #ifdef CONFIG_PROC_FS | 3005 | #ifdef CONFIG_PROC_FS |
3092 | proc_net_remove(net, "ipv6_route"); | 3006 | remove_proc_entry("ipv6_route", net->proc_net); |
3093 | proc_net_remove(net, "rt6_stats"); | 3007 | remove_proc_entry("rt6_stats", net->proc_net); |
3094 | #endif | 3008 | #endif |
3095 | } | 3009 | } |
3096 | 3010 | ||
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cfba99b2c2a4..02f96dcbcf02 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | |||
72 | static int ipip6_tunnel_init(struct net_device *dev); | 72 | static int ipip6_tunnel_init(struct net_device *dev); |
73 | static void ipip6_tunnel_setup(struct net_device *dev); | 73 | static void ipip6_tunnel_setup(struct net_device *dev); |
74 | static void ipip6_dev_free(struct net_device *dev); | 74 | static void ipip6_dev_free(struct net_device *dev); |
75 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, | ||
76 | __be32 *v4dst); | ||
75 | static struct rtnl_link_ops sit_link_ops __read_mostly; | 77 | static struct rtnl_link_ops sit_link_ops __read_mostly; |
76 | 78 | ||
77 | static int sit_net_id __read_mostly; | 79 | static int sit_net_id __read_mostly; |
@@ -590,17 +592,21 @@ out: | |||
590 | return err; | 592 | return err; |
591 | } | 593 | } |
592 | 594 | ||
595 | static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr, | ||
596 | const struct in6_addr *v6addr) | ||
597 | { | ||
598 | __be32 v4embed = 0; | ||
599 | if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed) | ||
600 | return true; | ||
601 | return false; | ||
602 | } | ||
603 | |||
593 | static int ipip6_rcv(struct sk_buff *skb) | 604 | static int ipip6_rcv(struct sk_buff *skb) |
594 | { | 605 | { |
595 | const struct iphdr *iph; | 606 | const struct iphdr *iph = ip_hdr(skb); |
596 | struct ip_tunnel *tunnel; | 607 | struct ip_tunnel *tunnel; |
597 | int err; | 608 | int err; |
598 | 609 | ||
599 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
600 | goto out; | ||
601 | |||
602 | iph = ip_hdr(skb); | ||
603 | |||
604 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 610 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
605 | iph->saddr, iph->daddr); | 611 | iph->saddr, iph->daddr); |
606 | if (tunnel != NULL) { | 612 | if (tunnel != NULL) { |
@@ -613,10 +619,19 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
613 | skb->protocol = htons(ETH_P_IPV6); | 619 | skb->protocol = htons(ETH_P_IPV6); |
614 | skb->pkt_type = PACKET_HOST; | 620 | skb->pkt_type = PACKET_HOST; |
615 | 621 | ||
616 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 622 | if (tunnel->dev->priv_flags & IFF_ISATAP) { |
617 | !isatap_chksrc(skb, iph, tunnel)) { | 623 | if (!isatap_chksrc(skb, iph, tunnel)) { |
618 | tunnel->dev->stats.rx_errors++; | 624 | tunnel->dev->stats.rx_errors++; |
619 | goto out; | 625 | goto out; |
626 | } | ||
627 | } else { | ||
628 | if (is_spoofed_6rd(tunnel, iph->saddr, | ||
629 | &ipv6_hdr(skb)->saddr) || | ||
630 | is_spoofed_6rd(tunnel, iph->daddr, | ||
631 | &ipv6_hdr(skb)->daddr)) { | ||
632 | tunnel->dev->stats.rx_errors++; | ||
633 | goto out; | ||
634 | } | ||
620 | } | 635 | } |
621 | 636 | ||
622 | __skb_tunnel_rx(skb, tunnel->dev); | 637 | __skb_tunnel_rx(skb, tunnel->dev); |
@@ -650,14 +665,12 @@ out: | |||
650 | } | 665 | } |
651 | 666 | ||
652 | /* | 667 | /* |
653 | * Returns the embedded IPv4 address if the IPv6 address | 668 | * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function |
654 | * comes from 6rd / 6to4 (RFC 3056) addr space. | 669 | * stores the embedded IPv4 address in v4dst and returns true. |
655 | */ | 670 | */ |
656 | static inline | 671 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, |
657 | __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | 672 | __be32 *v4dst) |
658 | { | 673 | { |
659 | __be32 dst = 0; | ||
660 | |||
661 | #ifdef CONFIG_IPV6_SIT_6RD | 674 | #ifdef CONFIG_IPV6_SIT_6RD |
662 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 675 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
663 | tunnel->ip6rd.prefixlen)) { | 676 | tunnel->ip6rd.prefixlen)) { |
@@ -676,14 +689,24 @@ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | |||
676 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> | 689 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> |
677 | (32 - pbi1); | 690 | (32 - pbi1); |
678 | 691 | ||
679 | dst = tunnel->ip6rd.relay_prefix | htonl(d); | 692 | *v4dst = tunnel->ip6rd.relay_prefix | htonl(d); |
693 | return true; | ||
680 | } | 694 | } |
681 | #else | 695 | #else |
682 | if (v6dst->s6_addr16[0] == htons(0x2002)) { | 696 | if (v6dst->s6_addr16[0] == htons(0x2002)) { |
683 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ | 697 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ |
684 | memcpy(&dst, &v6dst->s6_addr16[1], 4); | 698 | memcpy(v4dst, &v6dst->s6_addr16[1], 4); |
699 | return true; | ||
685 | } | 700 | } |
686 | #endif | 701 | #endif |
702 | return false; | ||
703 | } | ||
704 | |||
705 | static inline __be32 try_6rd(struct ip_tunnel *tunnel, | ||
706 | const struct in6_addr *v6dst) | ||
707 | { | ||
708 | __be32 dst = 0; | ||
709 | check_6rd(tunnel, v6dst, &dst); | ||
687 | return dst; | 710 | return dst; |
688 | } | 711 | } |
689 | 712 | ||
@@ -744,7 +767,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
744 | } | 767 | } |
745 | 768 | ||
746 | if (!dst) | 769 | if (!dst) |
747 | dst = try_6rd(&iph6->daddr, tunnel); | 770 | dst = try_6rd(tunnel, &iph6->daddr); |
748 | 771 | ||
749 | if (!dst) { | 772 | if (!dst) { |
750 | struct neighbour *neigh = NULL; | 773 | struct neighbour *neigh = NULL; |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 40161977f7cf..8a0848b60b35 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -179,7 +179,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
179 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 179 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
180 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); | 180 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); |
181 | 181 | ||
182 | if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) | 182 | if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok)) |
183 | goto out; | 183 | goto out; |
184 | 184 | ||
185 | ret = NULL; | 185 | ret = NULL; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 93825dd3a7c0..9b6460055df5 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -423,6 +423,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
423 | } | 423 | } |
424 | 424 | ||
425 | inet_csk_reqsk_queue_drop(sk, req, prev); | 425 | inet_csk_reqsk_queue_drop(sk, req, prev); |
426 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
426 | goto out; | 427 | goto out; |
427 | 428 | ||
428 | case TCP_SYN_SENT: | 429 | case TCP_SYN_SENT: |
@@ -712,7 +713,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
712 | #endif | 713 | #endif |
713 | 714 | ||
714 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | 715 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
715 | u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass) | 716 | u32 tsval, u32 tsecr, |
717 | struct tcp_md5sig_key *key, int rst, u8 tclass) | ||
716 | { | 718 | { |
717 | const struct tcphdr *th = tcp_hdr(skb); | 719 | const struct tcphdr *th = tcp_hdr(skb); |
718 | struct tcphdr *t1; | 720 | struct tcphdr *t1; |
@@ -724,7 +726,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
724 | struct dst_entry *dst; | 726 | struct dst_entry *dst; |
725 | __be32 *topt; | 727 | __be32 *topt; |
726 | 728 | ||
727 | if (ts) | 729 | if (tsecr) |
728 | tot_len += TCPOLEN_TSTAMP_ALIGNED; | 730 | tot_len += TCPOLEN_TSTAMP_ALIGNED; |
729 | #ifdef CONFIG_TCP_MD5SIG | 731 | #ifdef CONFIG_TCP_MD5SIG |
730 | if (key) | 732 | if (key) |
@@ -754,11 +756,11 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
754 | 756 | ||
755 | topt = (__be32 *)(t1 + 1); | 757 | topt = (__be32 *)(t1 + 1); |
756 | 758 | ||
757 | if (ts) { | 759 | if (tsecr) { |
758 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 760 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
759 | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); | 761 | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); |
760 | *topt++ = htonl(tcp_time_stamp); | 762 | *topt++ = htonl(tsval); |
761 | *topt++ = htonl(ts); | 763 | *topt++ = htonl(tsecr); |
762 | } | 764 | } |
763 | 765 | ||
764 | #ifdef CONFIG_TCP_MD5SIG | 766 | #ifdef CONFIG_TCP_MD5SIG |
@@ -834,7 +836,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
834 | * no RST generated if md5 hash doesn't match. | 836 | * no RST generated if md5 hash doesn't match. |
835 | */ | 837 | */ |
836 | sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), | 838 | sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), |
837 | &tcp_hashinfo, &ipv6h->daddr, | 839 | &tcp_hashinfo, &ipv6h->saddr, |
840 | th->source, &ipv6h->daddr, | ||
838 | ntohs(th->source), inet6_iif(skb)); | 841 | ntohs(th->source), inet6_iif(skb)); |
839 | if (!sk1) | 842 | if (!sk1) |
840 | return; | 843 | return; |
@@ -858,7 +861,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
858 | ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - | 861 | ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - |
859 | (th->doff << 2); | 862 | (th->doff << 2); |
860 | 863 | ||
861 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); | 864 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0); |
862 | 865 | ||
863 | #ifdef CONFIG_TCP_MD5SIG | 866 | #ifdef CONFIG_TCP_MD5SIG |
864 | release_sk1: | 867 | release_sk1: |
@@ -869,10 +872,11 @@ release_sk1: | |||
869 | #endif | 872 | #endif |
870 | } | 873 | } |
871 | 874 | ||
872 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, | 875 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, |
876 | u32 win, u32 tsval, u32 tsecr, | ||
873 | struct tcp_md5sig_key *key, u8 tclass) | 877 | struct tcp_md5sig_key *key, u8 tclass) |
874 | { | 878 | { |
875 | tcp_v6_send_response(skb, seq, ack, win, ts, key, 0, tclass); | 879 | tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass); |
876 | } | 880 | } |
877 | 881 | ||
878 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | 882 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) |
@@ -882,6 +886,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
882 | 886 | ||
883 | tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, | 887 | tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, |
884 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, | 888 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
889 | tcp_time_stamp + tcptw->tw_ts_offset, | ||
885 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), | 890 | tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), |
886 | tw->tw_tclass); | 891 | tw->tw_tclass); |
887 | 892 | ||
@@ -891,7 +896,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
891 | static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | 896 | static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, |
892 | struct request_sock *req) | 897 | struct request_sock *req) |
893 | { | 898 | { |
894 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, | 899 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, |
900 | req->rcv_wnd, tcp_time_stamp, req->ts_recent, | ||
895 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); | 901 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); |
896 | } | 902 | } |
897 | 903 | ||
@@ -958,8 +964,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
958 | goto drop; | 964 | goto drop; |
959 | } | 965 | } |
960 | 966 | ||
961 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | 967 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { |
968 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | ||
962 | goto drop; | 969 | goto drop; |
970 | } | ||
963 | 971 | ||
964 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); | 972 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); |
965 | if (req == NULL) | 973 | if (req == NULL) |
@@ -1027,7 +1035,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1027 | treq->rmt_addr = ipv6_hdr(skb)->saddr; | 1035 | treq->rmt_addr = ipv6_hdr(skb)->saddr; |
1028 | treq->loc_addr = ipv6_hdr(skb)->daddr; | 1036 | treq->loc_addr = ipv6_hdr(skb)->daddr; |
1029 | if (!want_cookie || tmp_opt.tstamp_ok) | 1037 | if (!want_cookie || tmp_opt.tstamp_ok) |
1030 | TCP_ECN_create_request(req, skb); | 1038 | TCP_ECN_create_request(req, skb, sock_net(sk)); |
1031 | 1039 | ||
1032 | treq->iif = sk->sk_bound_dev_if; | 1040 | treq->iif = sk->sk_bound_dev_if; |
1033 | 1041 | ||
@@ -1108,6 +1116,7 @@ drop_and_release: | |||
1108 | drop_and_free: | 1116 | drop_and_free: |
1109 | reqsk_free(req); | 1117 | reqsk_free(req); |
1110 | drop: | 1118 | drop: |
1119 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
1111 | return 0; /* don't send reset */ | 1120 | return 0; /* don't send reset */ |
1112 | } | 1121 | } |
1113 | 1122 | ||
@@ -1163,7 +1172,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1163 | newnp->opt = NULL; | 1172 | newnp->opt = NULL; |
1164 | newnp->mcast_oif = inet6_iif(skb); | 1173 | newnp->mcast_oif = inet6_iif(skb); |
1165 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1174 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1166 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1175 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1167 | 1176 | ||
1168 | /* | 1177 | /* |
1169 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count | 1178 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count |
@@ -1243,7 +1252,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1243 | newnp->opt = NULL; | 1252 | newnp->opt = NULL; |
1244 | newnp->mcast_oif = inet6_iif(skb); | 1253 | newnp->mcast_oif = inet6_iif(skb); |
1245 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1254 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1246 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1255 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1247 | 1256 | ||
1248 | /* Clone native IPv6 options from listening socket (if any) | 1257 | /* Clone native IPv6 options from listening socket (if any) |
1249 | 1258 | ||
@@ -1456,7 +1465,7 @@ ipv6_pktoptions: | |||
1456 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) | 1465 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) |
1457 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; | 1466 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; |
1458 | if (np->rxopt.bits.rxtclass) | 1467 | if (np->rxopt.bits.rxtclass) |
1459 | np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1468 | np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1460 | if (ipv6_opt_accepted(sk, opt_skb)) { | 1469 | if (ipv6_opt_accepted(sk, opt_skb)) { |
1461 | skb_set_owner_r(opt_skb, sk); | 1470 | skb_set_owner_r(opt_skb, sk); |
1462 | opt_skb = xchg(&np->pktoptions, opt_skb); | 1471 | opt_skb = xchg(&np->pktoptions, opt_skb); |
@@ -1598,6 +1607,7 @@ do_time_wait: | |||
1598 | struct sock *sk2; | 1607 | struct sock *sk2; |
1599 | 1608 | ||
1600 | sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, | 1609 | sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, |
1610 | &ipv6_hdr(skb)->saddr, th->source, | ||
1601 | &ipv6_hdr(skb)->daddr, | 1611 | &ipv6_hdr(skb)->daddr, |
1602 | ntohs(th->dest), inet6_iif(skb)); | 1612 | ntohs(th->dest), inet6_iif(skb)); |
1603 | if (sk2 != NULL) { | 1613 | if (sk2 != NULL) { |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index dfaa29b8b293..599e1ba6d1ce 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <net/tcp_states.h> | 45 | #include <net/tcp_states.h> |
46 | #include <net/ip6_checksum.h> | 46 | #include <net/ip6_checksum.h> |
47 | #include <net/xfrm.h> | 47 | #include <net/xfrm.h> |
48 | #include <net/inet6_hashtables.h> | ||
48 | 49 | ||
49 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
50 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
203 | { | 204 | { |
204 | struct sock *sk, *result; | 205 | struct sock *sk, *result; |
205 | struct hlist_nulls_node *node; | 206 | struct hlist_nulls_node *node; |
206 | int score, badness; | 207 | int score, badness, matches = 0, reuseport = 0; |
208 | u32 hash = 0; | ||
207 | 209 | ||
208 | begin: | 210 | begin: |
209 | result = NULL; | 211 | result = NULL; |
@@ -214,8 +216,18 @@ begin: | |||
214 | if (score > badness) { | 216 | if (score > badness) { |
215 | result = sk; | 217 | result = sk; |
216 | badness = score; | 218 | badness = score; |
217 | if (score == SCORE2_MAX) | 219 | reuseport = sk->sk_reuseport; |
220 | if (reuseport) { | ||
221 | hash = inet6_ehashfn(net, daddr, hnum, | ||
222 | saddr, sport); | ||
223 | matches = 1; | ||
224 | } else if (score == SCORE2_MAX) | ||
218 | goto exact_match; | 225 | goto exact_match; |
226 | } else if (score == badness && reuseport) { | ||
227 | matches++; | ||
228 | if (((u64)hash * matches) >> 32 == 0) | ||
229 | result = sk; | ||
230 | hash = next_pseudo_random32(hash); | ||
219 | } | 231 | } |
220 | } | 232 | } |
221 | /* | 233 | /* |
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
249 | unsigned short hnum = ntohs(dport); | 261 | unsigned short hnum = ntohs(dport); |
250 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); | 262 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); |
251 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; | 263 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; |
252 | int score, badness; | 264 | int score, badness, matches = 0, reuseport = 0; |
265 | u32 hash = 0; | ||
253 | 266 | ||
254 | rcu_read_lock(); | 267 | rcu_read_lock(); |
255 | if (hslot->count > 10) { | 268 | if (hslot->count > 10) { |
@@ -284,6 +297,17 @@ begin: | |||
284 | if (score > badness) { | 297 | if (score > badness) { |
285 | result = sk; | 298 | result = sk; |
286 | badness = score; | 299 | badness = score; |
300 | reuseport = sk->sk_reuseport; | ||
301 | if (reuseport) { | ||
302 | hash = inet6_ehashfn(net, daddr, hnum, | ||
303 | saddr, sport); | ||
304 | matches = 1; | ||
305 | } | ||
306 | } else if (score == badness && reuseport) { | ||
307 | matches++; | ||
308 | if (((u64)hash * matches) >> 32 == 0) | ||
309 | result = sk; | ||
310 | hash = next_pseudo_random32(hash); | ||
287 | } | 311 | } |
288 | } | 312 | } |
289 | /* | 313 | /* |
@@ -443,7 +467,7 @@ try_again: | |||
443 | ip_cmsg_recv(msg, skb); | 467 | ip_cmsg_recv(msg, skb); |
444 | } else { | 468 | } else { |
445 | if (np->rxopt.all) | 469 | if (np->rxopt.all) |
446 | datagram_recv_ctl(sk, msg, skb); | 470 | ip6_datagram_recv_ctl(sk, msg, skb); |
447 | } | 471 | } |
448 | 472 | ||
449 | err = copied; | 473 | err = copied; |
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
752 | return 0; | 776 | return 0; |
753 | } | 777 | } |
754 | 778 | ||
755 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | ||
756 | int proto) | ||
757 | { | ||
758 | int err; | ||
759 | |||
760 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
761 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
762 | |||
763 | if (proto == IPPROTO_UDPLITE) { | ||
764 | err = udplite_checksum_init(skb, uh); | ||
765 | if (err) | ||
766 | return err; | ||
767 | } | ||
768 | |||
769 | if (uh->check == 0) { | ||
770 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
771 | this error. Well, it is reasonable. | ||
772 | */ | ||
773 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
774 | return 1; | ||
775 | } | ||
776 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
777 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
778 | skb->len, proto, skb->csum)) | ||
779 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
780 | |||
781 | if (!skb_csum_unnecessary(skb)) | ||
782 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
783 | &ipv6_hdr(skb)->daddr, | ||
784 | skb->len, proto, 0)); | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 779 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
790 | int proto) | 780 | int proto) |
791 | { | 781 | { |
@@ -1153,8 +1143,8 @@ do_udp_sendmsg: | |||
1153 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1143 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
1154 | opt->tot_len = sizeof(*opt); | 1144 | opt->tot_len = sizeof(*opt); |
1155 | 1145 | ||
1156 | err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, | 1146 | err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, |
1157 | &hlimit, &tclass, &dontfrag); | 1147 | &hlimit, &tclass, &dontfrag); |
1158 | if (err < 0) { | 1148 | if (err < 0) { |
1159 | fl6_sock_release(flowlabel); | 1149 | fl6_sock_release(flowlabel); |
1160 | return err; | 1150 | return err; |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 0c8934a317c2..cf05cf073c51 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -56,7 +56,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
56 | /* Packet is from an untrusted source, reset gso_segs. */ | 56 | /* Packet is from an untrusted source, reset gso_segs. */ |
57 | int type = skb_shinfo(skb)->gso_type; | 57 | int type = skb_shinfo(skb)->gso_type; |
58 | 58 | ||
59 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || | 59 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | |
60 | SKB_GSO_GRE) || | ||
60 | !(type & (SKB_GSO_UDP)))) | 61 | !(type & (SKB_GSO_UDP)))) |
61 | goto out; | 62 | goto out; |
62 | 63 | ||
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 9f2095b19ad0..9bf6a74a71d2 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -69,8 +69,8 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
69 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 69 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
70 | goto out; | 70 | goto out; |
71 | 71 | ||
72 | if (skb_cloned(skb) && | 72 | err = skb_unclone(skb, GFP_ATOMIC); |
73 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 73 | if (err) |
74 | goto out; | 74 | goto out; |
75 | 75 | ||
76 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | 76 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index c9844135c9ca..4ef7bdb65440 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -110,7 +110,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
110 | 110 | ||
111 | /* Sheit... I remember I did this right. Apparently, | 111 | /* Sheit... I remember I did this right. Apparently, |
112 | * it was magically lost, so this code needs audit */ | 112 | * it was magically lost, so this code needs audit */ |
113 | xdst->u.rt6.n = neigh_clone(rt->n); | ||
114 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | | 113 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | |
115 | RTF_LOCAL); | 114 | RTF_LOCAL); |
116 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; | 115 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; |
@@ -321,7 +320,51 @@ static struct ctl_table xfrm6_policy_table[] = { | |||
321 | { } | 320 | { } |
322 | }; | 321 | }; |
323 | 322 | ||
324 | static struct ctl_table_header *sysctl_hdr; | 323 | static int __net_init xfrm6_net_init(struct net *net) |
324 | { | ||
325 | struct ctl_table *table; | ||
326 | struct ctl_table_header *hdr; | ||
327 | |||
328 | table = xfrm6_policy_table; | ||
329 | if (!net_eq(net, &init_net)) { | ||
330 | table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL); | ||
331 | if (!table) | ||
332 | goto err_alloc; | ||
333 | |||
334 | table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; | ||
335 | } | ||
336 | |||
337 | hdr = register_net_sysctl(net, "net/ipv6", table); | ||
338 | if (!hdr) | ||
339 | goto err_reg; | ||
340 | |||
341 | net->ipv6.sysctl.xfrm6_hdr = hdr; | ||
342 | return 0; | ||
343 | |||
344 | err_reg: | ||
345 | if (!net_eq(net, &init_net)) | ||
346 | kfree(table); | ||
347 | err_alloc: | ||
348 | return -ENOMEM; | ||
349 | } | ||
350 | |||
351 | static void __net_exit xfrm6_net_exit(struct net *net) | ||
352 | { | ||
353 | struct ctl_table *table; | ||
354 | |||
355 | if (net->ipv6.sysctl.xfrm6_hdr == NULL) | ||
356 | return; | ||
357 | |||
358 | table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; | ||
359 | unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); | ||
360 | if (!net_eq(net, &init_net)) | ||
361 | kfree(table); | ||
362 | } | ||
363 | |||
364 | static struct pernet_operations xfrm6_net_ops = { | ||
365 | .init = xfrm6_net_init, | ||
366 | .exit = xfrm6_net_exit, | ||
367 | }; | ||
325 | #endif | 368 | #endif |
326 | 369 | ||
327 | int __init xfrm6_init(void) | 370 | int __init xfrm6_init(void) |
@@ -340,8 +383,7 @@ int __init xfrm6_init(void) | |||
340 | goto out_policy; | 383 | goto out_policy; |
341 | 384 | ||
342 | #ifdef CONFIG_SYSCTL | 385 | #ifdef CONFIG_SYSCTL |
343 | sysctl_hdr = register_net_sysctl(&init_net, "net/ipv6", | 386 | register_pernet_subsys(&xfrm6_net_ops); |
344 | xfrm6_policy_table); | ||
345 | #endif | 387 | #endif |
346 | out: | 388 | out: |
347 | return ret; | 389 | return ret; |
@@ -353,8 +395,7 @@ out_policy: | |||
353 | void xfrm6_fini(void) | 395 | void xfrm6_fini(void) |
354 | { | 396 | { |
355 | #ifdef CONFIG_SYSCTL | 397 | #ifdef CONFIG_SYSCTL |
356 | if (sysctl_hdr) | 398 | unregister_pernet_subsys(&xfrm6_net_ops); |
357 | unregister_net_sysctl_table(sysctl_hdr); | ||
358 | #endif | 399 | #endif |
359 | xfrm6_policy_fini(); | 400 | xfrm6_policy_fini(); |
360 | xfrm6_state_fini(); | 401 | xfrm6_state_fini(); |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index ee5a7065aacc..de2bcfaaf759 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -72,7 +72,7 @@ static inline unsigned int xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *ad | |||
72 | { | 72 | { |
73 | unsigned int h; | 73 | unsigned int h; |
74 | 74 | ||
75 | h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]); | 75 | h = ipv6_addr_hash((const struct in6_addr *)addr); |
76 | h ^= h >> 16; | 76 | h ^= h >> 16; |
77 | h ^= h >> 8; | 77 | h ^= h >> 8; |
78 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; | 78 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; |
@@ -89,12 +89,11 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const | |||
89 | { | 89 | { |
90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
91 | struct xfrm6_tunnel_spi *x6spi; | 91 | struct xfrm6_tunnel_spi *x6spi; |
92 | struct hlist_node *pos; | ||
93 | 92 | ||
94 | hlist_for_each_entry_rcu(x6spi, pos, | 93 | hlist_for_each_entry_rcu(x6spi, |
95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 94 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
96 | list_byaddr) { | 95 | list_byaddr) { |
97 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 96 | if (xfrm6_addr_equal(&x6spi->addr, saddr)) |
98 | return x6spi; | 97 | return x6spi; |
99 | } | 98 | } |
100 | 99 | ||
@@ -120,9 +119,8 @@ static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) | |||
120 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 119 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
121 | struct xfrm6_tunnel_spi *x6spi; | 120 | struct xfrm6_tunnel_spi *x6spi; |
122 | int index = xfrm6_tunnel_spi_hash_byspi(spi); | 121 | int index = xfrm6_tunnel_spi_hash_byspi(spi); |
123 | struct hlist_node *pos; | ||
124 | 122 | ||
125 | hlist_for_each_entry(x6spi, pos, | 123 | hlist_for_each_entry(x6spi, |
126 | &xfrm6_tn->spi_byspi[index], | 124 | &xfrm6_tn->spi_byspi[index], |
127 | list_byspi) { | 125 | list_byspi) { |
128 | if (x6spi->spi == spi) | 126 | if (x6spi->spi == spi) |
@@ -203,15 +201,15 @@ static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | |||
203 | { | 201 | { |
204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 202 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
205 | struct xfrm6_tunnel_spi *x6spi; | 203 | struct xfrm6_tunnel_spi *x6spi; |
206 | struct hlist_node *pos, *n; | 204 | struct hlist_node *n; |
207 | 205 | ||
208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); | 206 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
209 | 207 | ||
210 | hlist_for_each_entry_safe(x6spi, pos, n, | 208 | hlist_for_each_entry_safe(x6spi, n, |
211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 209 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
212 | list_byaddr) | 210 | list_byaddr) |
213 | { | 211 | { |
214 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 212 | if (xfrm6_addr_equal(&x6spi->addr, saddr)) { |
215 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 213 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
216 | hlist_del_rcu(&x6spi->list_byaddr); | 214 | hlist_del_rcu(&x6spi->list_byaddr); |
217 | hlist_del_rcu(&x6spi->list_byspi); | 215 | hlist_del_rcu(&x6spi->list_byspi); |