On Wed, Aug 20, 2003 at 06:26:48PM +1000, herbert wrote: > > Oops I forgot to move the MAC headers for the case where the > SAs terminate with a transport SA. Please let me fix that > before you merge it in. Thanks. OK, here is the patch which does that. Cheers, -- Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ ) Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/include/linux/skbuff.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/linux/skbuff.h,v retrieving revision 1.4 diff -u -r1.4 skbuff.h --- kernel-source-2.5/include/linux/skbuff.h 9 Aug 2003 11:29:21 -0000 1.4 +++ kernel-source-2.5/include/linux/skbuff.h 20 Aug 2003 10:48:16 -0000 @@ -201,6 +201,7 @@ struct icmphdr *icmph; struct igmphdr *igmph; struct iphdr *ipiph; + struct ipv6hdr *ipv6h; unsigned char *raw; } h; Index: kernel-source-2.5/net/ipv4/xfrm4_input.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/xfrm4_input.c,v retrieving revision 1.5 diff -u -r1.5 xfrm4_input.c --- kernel-source-2.5/net/ipv4/xfrm4_input.c 9 Aug 2003 03:42:54 -0000 1.5 +++ kernel-source-2.5/net/ipv4/xfrm4_input.c 20 Aug 2003 10:37:22 -0000 @@ -9,6 +9,7 @@ * */ +#include <linux/string.h> #include <net/inet_ecn.h> #include <net/ip.h> #include <net/xfrm.h> @@ -18,9 +19,10 @@ return xfrm4_rcv_encap(skb, 0); } -static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb) +static inline void ipip_ecn_decapsulate(struct sk_buff *skb) { - struct iphdr *inner_iph = skb->nh.iph; + struct iphdr *outer_iph = skb->nh.iph; + struct iphdr *inner_iph = skb->h.ipiph; if (INET_ECN_is_ce(outer_iph->tos) && INET_ECN_is_not_ce(inner_iph->tos)) @@ -49,6 +51,9 @@ struct xfrm_state *x; int xfrm_nr = 0; int decaps = 0; + int hhlen; + + hhlen = skb->nh.raw - skb->mac.raw; if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0) goto drop; @@ -90,16 +95,7 @@ xfrm_vec[xfrm_nr++].xvec = x; - iph = skb->nh.iph; - if (x->props.mode) { - if (iph->protocol != IPPROTO_IPIP) - goto drop; - skb->nh.raw = skb->data; - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip_ecn_decapsulate(iph, skb); - iph = skb->nh.iph; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); decaps = 1; break; } @@ -125,7 +121,19 @@ memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state)); skb->sp->len += xfrm_nr; + if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto drop; + if (decaps) { + skb->mac.raw = memmove(skb->data - hhlen, skb->mac.raw, hhlen); + if (skb->nh.iph->protocol != IPPROTO_IPIP) + goto drop; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto drop; + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip_ecn_decapsulate(skb); + skb->nh.raw = skb->data; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); if (!(skb->dev->flags&IFF_LOOPBACK)) { dst_release(skb->dst); skb->dst = NULL; @@ -133,6 +141,8 @@ netif_rx(skb); return 0; } else { + skb->mac.raw = memmove(skb->nh.raw - hhlen, skb->mac.raw, + hhlen); return -skb->nh.iph->protocol; } Index: kernel-source-2.5/net/ipv6/xfrm6_input.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/xfrm6_input.c,v retrieving revision 1.4 diff -u -r1.4 xfrm6_input.c --- kernel-source-2.5/net/ipv6/xfrm6_input.c 29 Jul 2003 11:11:34 -0000 1.4 +++ kernel-source-2.5/net/ipv6/xfrm6_input.c 20 Aug 2003 10:47:50 -0000 @@ -9,17 +9,20 @@ * IPv6 support */ +#include <linux/string.h> #include <net/inet_ecn.h> #include <net/ip.h> #include <net/ipv6.h> #include <net/xfrm.h> -static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph, - struct sk_buff *skb) +static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) { - if (INET_ECN_is_ce(ip6_get_dsfield(iph)) && - INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) - IP6_ECN_set_ce(skb->nh.ipv6h); + struct ipv6hdr *outer_iph = skb->nh.ipv6h; + struct ipv6hdr *inner_iph = skb->h.ipv6h; + + if (INET_ECN_is_ce(ip6_get_dsfield(outer_iph)) && + INET_ECN_is_not_ce(ip6_get_dsfield(inner_iph))) + IP6_ECN_set_ce(inner_iph); } int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) @@ -33,10 +36,12 @@ int decaps = 0; int nexthdr = 0; u8 *prevhdr = NULL; + int hhlen; ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; *nhoffp = prevhdr - skb->nh.raw; + hhlen = skb->nh.raw - skb->mac.raw; if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) goto drop; @@ -75,12 +80,6 @@ xfrm_vec[xfrm_nr++].xvec = x; if (x->props.mode) { /* XXX */ - if (nexthdr != IPPROTO_IPV6) - goto drop; - skb->nh.raw = skb->data; - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip6_ecn_decapsulate(iph, skb); - iph = skb->nh.ipv6h; decaps = 1; break; } @@ -107,7 +106,18 @@ skb->sp->len += xfrm_nr; skb->ip_summed = CHECKSUM_NONE; + if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto drop; + if (decaps) { + skb->mac.raw = memmove(skb->data - hhlen, skb->mac.raw, hhlen); + if (nexthdr != IPPROTO_IPV6) + goto drop; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + if (!(x->props.flags & XFRM_STATE_NOECN)) + ipip6_ecn_decapsulate(skb); + skb->nh.raw = skb->data; if (!(skb->dev->flags&IFF_LOOPBACK)) { dst_release(skb->dst); skb->dst = NULL; @@ -115,6 +125,8 @@ netif_rx(skb); return -1; } else { + skb->mac.raw = memmove(skb->nh.raw - hhlen, skb->mac.raw, + hhlen); return 1; }