aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_fib.c3
-rw-r--r--net/ipv6/ip6_offload.c6
-rw-r--r--net/ipv6/ip6_output.c8
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/ip6_vti.c8
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/ndisc.c7
-rw-r--r--net/ipv6/netfilter.c6
-rw-r--r--net/ipv6/netfilter/ip6t_rpfilter.c1
-rw-r--r--net/ipv6/output_core.c11
-rw-r--r--net/ipv6/route.c26
-rw-r--r--net/ipv6/tcpv6_offload.c2
-rw-r--r--net/ipv6/xfrm6_output.c22
-rw-r--r--net/ipv6/xfrm6_protocol.c11
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 }
1472skip:
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
274out_unlock: 270out_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
345static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) 345static 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:
851static void ndisc_recv_na(struct sk_buff *skb) 851static 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
953out: 950out:
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}
40EXPORT_SYMBOL(ipv6_select_ident); 35EXPORT_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. */
2241static 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
2253void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2254{
2255 fib6_clean_all(net, fib6_clean_tohost, gateway);
2256}
2257
2235struct arg_dev_net { 2258struct 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
129int xfrm6_output_finish(struct sk_buff *skb) 123int 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
166int xfrm6_output(struct sock *sk, struct sk_buff *skb) 169int 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);