diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 1c9b283..5682505 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -130,7 +130,19 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) len = skb->len - sizeof(struct ipv6hdr); if (len > IPV6_MAXPLEN) len = 0; + +#if defined(CONFIG_INET6_IPSEC_OFFLOAD) + /* + * Since tunnel header is not added in slow path and route cache entry + * lookup is changed to perform lookup on tunnel header, dst_output() + * may reach IPv6 output for IPv4-over-IPv6 IPsec tunnel packets. Only + * update the IPv6 payload length when the skb really carries IPv6 here. + */ + if (ipv6_hdr(skb)->version == 6) + ipv6_hdr(skb)->payload_len = htons(len); +#else ipv6_hdr(skb)->payload_len = htons(len); +#endif IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); /* if egress device is enslaved to an L3 master device pass the @@ -142,6 +154,13 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) skb->protocol = htons(ETH_P_IPV6); +#if defined(CONFIG_INET6_IPSEC_OFFLOAD) + if (skb->ipsec_offload) { + dst_output(net, sk, skb); + return 0; + } +#endif + return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, NULL, skb_dst_dev(skb), dst_output);