Commit abf5cdb89d09ca981db10e1a85fd8531440165f2

Authored by Joakim Koskela
Committed by David S. Miller
1 parent eb49e63093

ipsec: Interfamily IPSec BEET, ipv4-inner ipv6-outer

Here's a revised version, based on Herbert's comments, of a fix for
the ipv4-inner, ipv6-outer interfamily ipsec beet mode. It fixes the
network header adjustment during interfamily, as well as makes sure
that we reserve enough room for the new ipv6 header if we might have
something else as the inner family. Also, the ipv4 pseudo header
construction was added.

Signed-off-by: Joakim Koskela <jookos@gmail.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 30 additions and 3 deletions Side-by-side Diff

... ... @@ -521,6 +521,10 @@
521 521 crypto_aead_ivsize(aead);
522 522 switch (x->props.mode) {
523 523 case XFRM_MODE_BEET:
  524 + if (x->sel.family != AF_INET6)
  525 + x->props.header_len += IPV4_BEET_PHMAXLEN +
  526 + (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
  527 + break;
524 528 case XFRM_MODE_TRANSPORT:
525 529 break;
526 530 case XFRM_MODE_TUNNEL:
net/ipv6/xfrm6_mode_beet.c
... ... @@ -40,16 +40,39 @@
40 40 static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
41 41 {
42 42 struct ipv6hdr *top_iph;
  43 + struct ip_beet_phdr *ph;
  44 + struct iphdr *iphv4;
  45 + int optlen, hdr_len;
43 46  
44   - skb_set_network_header(skb, -x->props.header_len);
  47 + iphv4 = ip_hdr(skb);
  48 + hdr_len = 0;
  49 + optlen = XFRM_MODE_SKB_CB(skb)->optlen;
  50 + if (unlikely(optlen))
  51 + hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4);
  52 +
  53 + skb_set_network_header(skb, -x->props.header_len - hdr_len);
  54 + if (x->sel.family != AF_INET6)
  55 + skb->network_header += IPV4_BEET_PHMAXLEN;
45 56 skb->mac_header = skb->network_header +
46 57 offsetof(struct ipv6hdr, nexthdr);
47 58 skb->transport_header = skb->network_header + sizeof(*top_iph);
48   - __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl);
  59 + ph = (struct ip_beet_phdr *)__skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl-hdr_len);
49 60  
50 61 xfrm6_beet_make_header(skb);
51 62  
52 63 top_iph = ipv6_hdr(skb);
  64 + if (unlikely(optlen)) {
  65 +
  66 + BUG_ON(optlen < 0);
  67 +
  68 + ph->padlen = 4 - (optlen & 4);
  69 + ph->hdrlen = optlen / 8;
  70 + ph->nexthdr = top_iph->nexthdr;
  71 + if (ph->padlen)
  72 + memset(ph + 1, IPOPT_NOP, ph->padlen);
  73 +
  74 + top_iph->nexthdr = IPPROTO_BEETPH;
  75 + }
53 76  
54 77 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
55 78 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);