diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ip6_fib.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_offload.c | 6 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 8 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 8 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 2 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 7 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 6 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_rpfilter.c | 1 | ||||
-rw-r--r-- | net/ipv6/output_core.c | 11 | ||||
-rw-r--r-- | net/ipv6/route.c | 26 | ||||
-rw-r--r-- | net/ipv6/tcpv6_offload.c | 2 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 22 | ||||
-rw-r--r-- | net/ipv6/xfrm6_protocol.c | 11 |
14 files changed, 75 insertions, 40 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 34e0ded5c14b..87891f5f57b5 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1459,7 +1459,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1459 | 1459 | ||
1460 | if (w->skip) { | 1460 | if (w->skip) { |
1461 | w->skip--; | 1461 | w->skip--; |
1462 | continue; | 1462 | goto skip; |
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | err = w->func(w); | 1465 | err = w->func(w); |
@@ -1469,6 +1469,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1469 | w->count++; | 1469 | w->count++; |
1470 | continue; | 1470 | continue; |
1471 | } | 1471 | } |
1472 | skip: | ||
1472 | w->state = FWS_U; | 1473 | w->state = FWS_U; |
1473 | case FWS_U: | 1474 | case FWS_U: |
1474 | if (fn == w->root) | 1475 | if (fn == w->root) |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 59f95affceb0..b2f091566f88 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -196,7 +196,6 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
196 | unsigned int off; | 196 | unsigned int off; |
197 | u16 flush = 1; | 197 | u16 flush = 1; |
198 | int proto; | 198 | int proto; |
199 | __wsum csum; | ||
200 | 199 | ||
201 | off = skb_gro_offset(skb); | 200 | off = skb_gro_offset(skb); |
202 | hlen = off + sizeof(*iph); | 201 | hlen = off + sizeof(*iph); |
@@ -264,13 +263,10 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
264 | 263 | ||
265 | NAPI_GRO_CB(skb)->flush |= flush; | 264 | NAPI_GRO_CB(skb)->flush |= flush; |
266 | 265 | ||
267 | csum = skb->csum; | 266 | skb_gro_postpull_rcsum(skb, iph, nlen); |
268 | skb_postpull_rcsum(skb, iph, skb_network_header_len(skb)); | ||
269 | 267 | ||
270 | pp = ops->callbacks.gro_receive(head, skb); | 268 | pp = ops->callbacks.gro_receive(head, skb); |
271 | 269 | ||
272 | skb->csum = csum; | ||
273 | |||
274 | out_unlock: | 270 | out_unlock: |
275 | rcu_read_unlock(); | 271 | rcu_read_unlock(); |
276 | 272 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 40e7581374f7..fbf11562b54c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -344,12 +344,16 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) | |||
344 | 344 | ||
345 | static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) | 345 | static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) |
346 | { | 346 | { |
347 | if (skb->len <= mtu || skb->local_df) | 347 | if (skb->len <= mtu) |
348 | return false; | 348 | return false; |
349 | 349 | ||
350 | /* ipv6 conntrack defrag sets max_frag_size + local_df */ | ||
350 | if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) | 351 | if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) |
351 | return true; | 352 | return true; |
352 | 353 | ||
354 | if (skb->local_df) | ||
355 | return false; | ||
356 | |||
353 | if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) | 357 | if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) |
354 | return false; | 358 | return false; |
355 | 359 | ||
@@ -1225,7 +1229,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1225 | unsigned int maxnonfragsize, headersize; | 1229 | unsigned int maxnonfragsize, headersize; |
1226 | 1230 | ||
1227 | headersize = sizeof(struct ipv6hdr) + | 1231 | headersize = sizeof(struct ipv6hdr) + |
1228 | (opt ? opt->tot_len : 0) + | 1232 | (opt ? opt->opt_flen + opt->opt_nflen : 0) + |
1229 | (dst_allfrag(&rt->dst) ? | 1233 | (dst_allfrag(&rt->dst) ? |
1230 | sizeof(struct frag_hdr) : 0) + | 1234 | sizeof(struct frag_hdr) : 0) + |
1231 | rt->rt6i_nfheader_len; | 1235 | rt->rt6i_nfheader_len; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index b05b609f69d1..f6a66bb4114d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -1557,7 +1557,7 @@ static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
1557 | { | 1557 | { |
1558 | u8 proto; | 1558 | u8 proto; |
1559 | 1559 | ||
1560 | if (!data) | 1560 | if (!data || !data[IFLA_IPTUN_PROTO]) |
1561 | return 0; | 1561 | return 0; |
1562 | 1562 | ||
1563 | proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); | 1563 | proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index b7c0f827140b..6cc9f9371cc5 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -511,6 +511,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
511 | u8 type, u8 code, int offset, __be32 info) | 511 | u8 type, u8 code, int offset, __be32 info) |
512 | { | 512 | { |
513 | __be32 spi; | 513 | __be32 spi; |
514 | __u32 mark; | ||
514 | struct xfrm_state *x; | 515 | struct xfrm_state *x; |
515 | struct ip6_tnl *t; | 516 | struct ip6_tnl *t; |
516 | struct ip_esp_hdr *esph; | 517 | struct ip_esp_hdr *esph; |
@@ -524,6 +525,8 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
524 | if (!t) | 525 | if (!t) |
525 | return -1; | 526 | return -1; |
526 | 527 | ||
528 | mark = be32_to_cpu(t->parms.o_key); | ||
529 | |||
527 | switch (protocol) { | 530 | switch (protocol) { |
528 | case IPPROTO_ESP: | 531 | case IPPROTO_ESP: |
529 | esph = (struct ip_esp_hdr *)(skb->data + offset); | 532 | esph = (struct ip_esp_hdr *)(skb->data + offset); |
@@ -545,7 +548,7 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
545 | type != NDISC_REDIRECT) | 548 | type != NDISC_REDIRECT) |
546 | return 0; | 549 | return 0; |
547 | 550 | ||
548 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, | 551 | x = xfrm_state_lookup(net, mark, (const xfrm_address_t *)&iph->daddr, |
549 | spi, protocol, AF_INET6); | 552 | spi, protocol, AF_INET6); |
550 | if (!x) | 553 | if (!x) |
551 | return 0; | 554 | return 0; |
@@ -1097,7 +1100,6 @@ static int __init vti6_tunnel_init(void) | |||
1097 | 1100 | ||
1098 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); | 1101 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); |
1099 | if (err < 0) { | 1102 | if (err < 0) { |
1100 | unregister_pernet_device(&vti6_net_ops); | ||
1101 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1103 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1102 | 1104 | ||
1103 | goto out; | 1105 | goto out; |
@@ -1106,7 +1108,6 @@ static int __init vti6_tunnel_init(void) | |||
1106 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); | 1108 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); |
1107 | if (err < 0) { | 1109 | if (err < 0) { |
1108 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1110 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
1109 | unregister_pernet_device(&vti6_net_ops); | ||
1110 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1111 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1111 | 1112 | ||
1112 | goto out; | 1113 | goto out; |
@@ -1116,7 +1117,6 @@ static int __init vti6_tunnel_init(void) | |||
1116 | if (err < 0) { | 1117 | if (err < 0) { |
1117 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | 1118 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); |
1118 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1119 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
1119 | unregister_pernet_device(&vti6_net_ops); | ||
1120 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1120 | pr_err("%s: can't register vti6 protocol\n", __func__); |
1121 | 1121 | ||
1122 | goto out; | 1122 | goto out; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8659067da28e..8250474ab7dc 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -1633,7 +1633,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) | |||
1633 | { | 1633 | { |
1634 | struct mr6_table *mrt; | 1634 | struct mr6_table *mrt; |
1635 | struct flowi6 fl6 = { | 1635 | struct flowi6 fl6 = { |
1636 | .flowi6_iif = skb->skb_iif, | 1636 | .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX, |
1637 | .flowi6_oif = skb->dev->ifindex, | 1637 | .flowi6_oif = skb->dev->ifindex, |
1638 | .flowi6_mark = skb->mark, | 1638 | .flowi6_mark = skb->mark, |
1639 | }; | 1639 | }; |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 09a22f4f36c9..ca8d4ea48a5d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -851,7 +851,7 @@ out: | |||
851 | static void ndisc_recv_na(struct sk_buff *skb) | 851 | static void ndisc_recv_na(struct sk_buff *skb) |
852 | { | 852 | { |
853 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 853 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
854 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 854 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
855 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 855 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
856 | u8 *lladdr = NULL; | 856 | u8 *lladdr = NULL; |
857 | u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + | 857 | u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + |
@@ -944,10 +944,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
944 | /* | 944 | /* |
945 | * Change: router to host | 945 | * Change: router to host |
946 | */ | 946 | */ |
947 | struct rt6_info *rt; | 947 | rt6_clean_tohost(dev_net(dev), saddr); |
948 | rt = rt6_get_dflt_router(saddr, dev); | ||
949 | if (rt) | ||
950 | ip6_del_rt(rt); | ||
951 | } | 948 | } |
952 | 949 | ||
953 | out: | 950 | out: |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 95f3f1da0d7f..d38e6a8d8b9f 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -30,13 +30,15 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
30 | .daddr = iph->daddr, | 30 | .daddr = iph->daddr, |
31 | .saddr = iph->saddr, | 31 | .saddr = iph->saddr, |
32 | }; | 32 | }; |
33 | int err; | ||
33 | 34 | ||
34 | dst = ip6_route_output(net, skb->sk, &fl6); | 35 | dst = ip6_route_output(net, skb->sk, &fl6); |
35 | if (dst->error) { | 36 | err = dst->error; |
37 | if (err) { | ||
36 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 38 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
37 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); | 39 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); |
38 | dst_release(dst); | 40 | dst_release(dst); |
39 | return dst->error; | 41 | return err; |
40 | } | 42 | } |
41 | 43 | ||
42 | /* Drop old route. */ | 44 | /* Drop old route. */ |
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c index e0983f3648a6..790e0c6b19e1 100644 --- a/net/ipv6/netfilter/ip6t_rpfilter.c +++ b/net/ipv6/netfilter/ip6t_rpfilter.c | |||
@@ -33,6 +33,7 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb, | |||
33 | struct ipv6hdr *iph = ipv6_hdr(skb); | 33 | struct ipv6hdr *iph = ipv6_hdr(skb); |
34 | bool ret = false; | 34 | bool ret = false; |
35 | struct flowi6 fl6 = { | 35 | struct flowi6 fl6 = { |
36 | .flowi6_iif = LOOPBACK_IFINDEX, | ||
36 | .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK, | 37 | .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK, |
37 | .flowi6_proto = iph->nexthdr, | 38 | .flowi6_proto = iph->nexthdr, |
38 | .daddr = iph->saddr, | 39 | .daddr = iph->saddr, |
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 6313abd53c9d..56596ce390a1 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c | |||
@@ -12,7 +12,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | |||
12 | { | 12 | { |
13 | static atomic_t ipv6_fragmentation_id; | 13 | static atomic_t ipv6_fragmentation_id; |
14 | struct in6_addr addr; | 14 | struct in6_addr addr; |
15 | int old, new; | 15 | int ident; |
16 | 16 | ||
17 | #if IS_ENABLED(CONFIG_IPV6) | 17 | #if IS_ENABLED(CONFIG_IPV6) |
18 | struct inet_peer *peer; | 18 | struct inet_peer *peer; |
@@ -26,15 +26,10 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | |||
26 | return; | 26 | return; |
27 | } | 27 | } |
28 | #endif | 28 | #endif |
29 | do { | 29 | ident = atomic_inc_return(&ipv6_fragmentation_id); |
30 | old = atomic_read(&ipv6_fragmentation_id); | ||
31 | new = old + 1; | ||
32 | if (!new) | ||
33 | new = 1; | ||
34 | } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); | ||
35 | 30 | ||
36 | addr = rt->rt6i_dst.addr; | 31 | addr = rt->rt6i_dst.addr; |
37 | addr.s6_addr32[0] ^= (__force __be32)new; | 32 | addr.s6_addr32[0] ^= (__force __be32)ident; |
38 | fhdr->identification = htonl(secure_ipv6_id(addr.s6_addr32)); | 33 | fhdr->identification = htonl(secure_ipv6_id(addr.s6_addr32)); |
39 | } | 34 | } |
40 | EXPORT_SYMBOL(ipv6_select_ident); | 35 | EXPORT_SYMBOL(ipv6_select_ident); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4011617cca68..6ebdb7b6744c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1273,6 +1273,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) | |||
1273 | struct flowi6 fl6; | 1273 | struct flowi6 fl6; |
1274 | 1274 | ||
1275 | memset(&fl6, 0, sizeof(fl6)); | 1275 | memset(&fl6, 0, sizeof(fl6)); |
1276 | fl6.flowi6_iif = LOOPBACK_IFINDEX; | ||
1276 | fl6.flowi6_oif = oif; | 1277 | fl6.flowi6_oif = oif; |
1277 | fl6.flowi6_mark = mark; | 1278 | fl6.flowi6_mark = mark; |
1278 | fl6.daddr = iph->daddr; | 1279 | fl6.daddr = iph->daddr; |
@@ -1294,6 +1295,7 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, | |||
1294 | struct flowi6 fl6; | 1295 | struct flowi6 fl6; |
1295 | 1296 | ||
1296 | memset(&fl6, 0, sizeof(fl6)); | 1297 | memset(&fl6, 0, sizeof(fl6)); |
1298 | fl6.flowi6_iif = LOOPBACK_IFINDEX; | ||
1297 | fl6.flowi6_oif = oif; | 1299 | fl6.flowi6_oif = oif; |
1298 | fl6.flowi6_mark = mark; | 1300 | fl6.flowi6_mark = mark; |
1299 | fl6.daddr = msg->dest; | 1301 | fl6.daddr = msg->dest; |
@@ -2232,6 +2234,27 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) | |||
2232 | fib6_clean_all(net, fib6_remove_prefsrc, &adni); | 2234 | fib6_clean_all(net, fib6_remove_prefsrc, &adni); |
2233 | } | 2235 | } |
2234 | 2236 | ||
2237 | #define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY) | ||
2238 | #define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE) | ||
2239 | |||
2240 | /* Remove routers and update dst entries when gateway turn into host. */ | ||
2241 | static int fib6_clean_tohost(struct rt6_info *rt, void *arg) | ||
2242 | { | ||
2243 | struct in6_addr *gateway = (struct in6_addr *)arg; | ||
2244 | |||
2245 | if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) || | ||
2246 | ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) && | ||
2247 | ipv6_addr_equal(gateway, &rt->rt6i_gateway)) { | ||
2248 | return -1; | ||
2249 | } | ||
2250 | return 0; | ||
2251 | } | ||
2252 | |||
2253 | void rt6_clean_tohost(struct net *net, struct in6_addr *gateway) | ||
2254 | { | ||
2255 | fib6_clean_all(net, fib6_clean_tohost, gateway); | ||
2256 | } | ||
2257 | |||
2235 | struct arg_dev_net { | 2258 | struct arg_dev_net { |
2236 | struct net_device *dev; | 2259 | struct net_device *dev; |
2237 | struct net *net; | 2260 | struct net *net; |
@@ -2707,6 +2730,9 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh) | |||
2707 | if (tb[RTA_OIF]) | 2730 | if (tb[RTA_OIF]) |
2708 | oif = nla_get_u32(tb[RTA_OIF]); | 2731 | oif = nla_get_u32(tb[RTA_OIF]); |
2709 | 2732 | ||
2733 | if (tb[RTA_MARK]) | ||
2734 | fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]); | ||
2735 | |||
2710 | if (iif) { | 2736 | if (iif) { |
2711 | struct net_device *dev; | 2737 | struct net_device *dev; |
2712 | int flags = 0; | 2738 | int flags = 0; |
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 0d78132ff18a..8517d3cd1aed 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c | |||
@@ -42,7 +42,7 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | |||
42 | if (NAPI_GRO_CB(skb)->flush) | 42 | if (NAPI_GRO_CB(skb)->flush) |
43 | goto skip_csum; | 43 | goto skip_csum; |
44 | 44 | ||
45 | wsum = skb->csum; | 45 | wsum = NAPI_GRO_CB(skb)->csum; |
46 | 46 | ||
47 | switch (skb->ip_summed) { | 47 | switch (skb->ip_summed) { |
48 | case CHECKSUM_NONE: | 48 | case CHECKSUM_NONE: |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 19ef329bdbf8..b930d080c66f 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
114 | if (err) | 114 | if (err) |
115 | return err; | 115 | return err; |
116 | 116 | ||
117 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
118 | #ifdef CONFIG_NETFILTER | ||
119 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | ||
120 | #endif | ||
121 | |||
122 | skb->protocol = htons(ETH_P_IPV6); | ||
123 | skb->local_df = 1; | 117 | skb->local_df = 1; |
124 | 118 | ||
125 | return x->outer_mode->output2(x, skb); | 119 | return x->outer_mode->output2(x, skb); |
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output); | |||
128 | 122 | ||
129 | int xfrm6_output_finish(struct sk_buff *skb) | 123 | int xfrm6_output_finish(struct sk_buff *skb) |
130 | { | 124 | { |
125 | memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); | ||
126 | skb->protocol = htons(ETH_P_IPV6); | ||
127 | |||
131 | #ifdef CONFIG_NETFILTER | 128 | #ifdef CONFIG_NETFILTER |
132 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | 129 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; |
133 | #endif | 130 | #endif |
134 | 131 | ||
135 | skb->protocol = htons(ETH_P_IPV6); | ||
136 | return xfrm_output(skb); | 132 | return xfrm_output(skb); |
137 | } | 133 | } |
138 | 134 | ||
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb) | |||
142 | struct xfrm_state *x = dst->xfrm; | 138 | struct xfrm_state *x = dst->xfrm; |
143 | int mtu; | 139 | int mtu; |
144 | 140 | ||
141 | #ifdef CONFIG_NETFILTER | ||
142 | if (!x) { | ||
143 | IP6CB(skb)->flags |= IP6SKB_REROUTED; | ||
144 | return dst_output(skb); | ||
145 | } | ||
146 | #endif | ||
147 | |||
145 | if (skb->protocol == htons(ETH_P_IPV6)) | 148 | if (skb->protocol == htons(ETH_P_IPV6)) |
146 | mtu = ip6_skb_dst_mtu(skb); | 149 | mtu = ip6_skb_dst_mtu(skb); |
147 | else | 150 | else |
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb) | |||
165 | 168 | ||
166 | int xfrm6_output(struct sock *sk, struct sk_buff *skb) | 169 | int xfrm6_output(struct sock *sk, struct sk_buff *skb) |
167 | { | 170 | { |
168 | return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, | 171 | return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, |
169 | skb_dst(skb)->dev, __xfrm6_output); | 172 | NULL, skb_dst(skb)->dev, __xfrm6_output, |
173 | !(IP6CB(skb)->flags & IP6SKB_REROUTED)); | ||
170 | } | 174 | } |
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c index 6ab989c486f7..54d13f8dbbae 100644 --- a/net/ipv6/xfrm6_protocol.c +++ b/net/ipv6/xfrm6_protocol.c | |||
@@ -50,6 +50,10 @@ int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) | |||
50 | { | 50 | { |
51 | int ret; | 51 | int ret; |
52 | struct xfrm6_protocol *handler; | 52 | struct xfrm6_protocol *handler; |
53 | struct xfrm6_protocol __rcu **head = proto_handlers(protocol); | ||
54 | |||
55 | if (!head) | ||
56 | return 0; | ||
53 | 57 | ||
54 | for_each_protocol_rcu(*proto_handlers(protocol), handler) | 58 | for_each_protocol_rcu(*proto_handlers(protocol), handler) |
55 | if ((ret = handler->cb_handler(skb, err)) <= 0) | 59 | if ((ret = handler->cb_handler(skb, err)) <= 0) |
@@ -184,10 +188,12 @@ int xfrm6_protocol_register(struct xfrm6_protocol *handler, | |||
184 | struct xfrm6_protocol __rcu **pprev; | 188 | struct xfrm6_protocol __rcu **pprev; |
185 | struct xfrm6_protocol *t; | 189 | struct xfrm6_protocol *t; |
186 | bool add_netproto = false; | 190 | bool add_netproto = false; |
187 | |||
188 | int ret = -EEXIST; | 191 | int ret = -EEXIST; |
189 | int priority = handler->priority; | 192 | int priority = handler->priority; |
190 | 193 | ||
194 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
195 | return -EINVAL; | ||
196 | |||
191 | mutex_lock(&xfrm6_protocol_mutex); | 197 | mutex_lock(&xfrm6_protocol_mutex); |
192 | 198 | ||
193 | if (!rcu_dereference_protected(*proto_handlers(protocol), | 199 | if (!rcu_dereference_protected(*proto_handlers(protocol), |
@@ -230,6 +236,9 @@ int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, | |||
230 | struct xfrm6_protocol *t; | 236 | struct xfrm6_protocol *t; |
231 | int ret = -ENOENT; | 237 | int ret = -ENOENT; |
232 | 238 | ||
239 | if (!proto_handlers(protocol) || !netproto(protocol)) | ||
240 | return -EINVAL; | ||
241 | |||
233 | mutex_lock(&xfrm6_protocol_mutex); | 242 | mutex_lock(&xfrm6_protocol_mutex); |
234 | 243 | ||
235 | for (pprev = proto_handlers(protocol); | 244 | for (pprev = proto_handlers(protocol); |