[CentOS] Custom build kernel patch fails big time.

Fri Sep 12 20:46:52 UTC 2008
Robert Moskowitz <rgm at htt-consult.com>

I am trying to build a custom kernel for the HIPL code 
(infrahip.hip.fi), using the patch for the Linux 2.6.18 kernel.  I 
followed all the instructions for getting the kernel source and making a 
custom kernel provided on the wiki.  The rpmbuild fails with the 
following messages:

Get an error on this step (figured out my other problem):

Patch #40000 
(centos-5.2-hipmod-sleep-beet-and-interfamily-all-in-one.patch):
1 out of 4 hunks FAILED -- saving rejects to file 
net/ipv4/xfrm4_output.c.rej
2 out of 3 hunks FAILED -- saving rejects to file net/ipv4/esp4.c.rej
1 out of 1 hunk FAILED -- saving rejects to file net/ipv6/udp.c.rej
1 out of 1 hunk FAILED -- saving rejects to file net/ipv6/tcp_ipv6.c.rej
1 out of 1 hunk FAILED -- saving rejects to file net/ipv6/esp6.c.rej
2 out of 2 hunks FAILED -- saving rejects to file net/ipv6/icmp.c.rej
2 out of 2 hunks FAILED -- saving rejects to file net/xfrm/xfrm_state.c.rej
1 out of 2 hunks FAILED -- saving rejects to file include/net/xfrm.h.rej
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
1 out of 1 hunk ignored -- saving rejects to file include/linux/net.h.rej


I've asked for help on the hipl list, but there is no real experience 
there with Centos (FC8 and 9), and they are trying to help, put perhaps 
someone here might know what I am doing wrong?

Oh, one question was asked about how the ~/rpmbuild/BUILD/kernel-2.16.18 
directory looks like.  I think the linux-2.6.18.i386 (or i686) is not 
what the patch is expecting?

Here is the patch file 
(centos-5.2-hipmod-sleep-beet-and-interfamily-all-in-one.patch):

diff -urN  a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
--- a/net/ipv4/xfrm4_input.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/xfrm4_input.c 2007-05-25 12:21:11.000000000 +0300
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 
@@ -23,6 +24,15 @@
 
 EXPORT_SYMBOL(xfrm4_rcv);
 
+static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
+{
+    struct iphdr *outer_iph = skb->nh.iph;
+    struct iphdr *inner_iph = skb->h.ipiph;
+
+    if (INET_ECN_is_ce(outer_iph->tos))
+        IP_ECN_set_ce(inner_iph);
+}
+
 static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, 
u32 *seq)
 {
     switch (nexthdr) {
@@ -103,11 +113,11 @@
 
         xfrm_vec[xfrm_nr++] = x;
 
-        if (x->mode->input(x, skb))
+                if (x->mode->input(x, skb))
             goto drop;
-
+       
         if (x->props.mode) {
-            decaps = 1;
+                decaps = 1;
             break;
         }
 
diff -urN  a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
--- a/net/ipv4/xfrm4_output.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/xfrm4_output.c 2007-05-25 12:21:11.000000000 +0300
@@ -14,10 +14,12 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/netfilter_ipv4.h>
+#include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/icmp.h>
 
+
 static int xfrm4_tunnel_check_size(struct sk_buff *skb)
 {
     int mtu, ret = 0;
@@ -54,7 +56,7 @@
             goto error_nolock;
     }
 
-    if (x->props.mode) {
+    if (x->props.mode == XFRM_MODE_TUNNEL) {
         err = xfrm4_tunnel_check_size(skb);
         if (err)
             goto error_nolock;
@@ -66,7 +68,7 @@
         if (err)
             goto error;
 
-        err = x->mode->output(skb);
+                err = x->mode->output(skb);
         if (err)
             goto error;
 
@@ -85,6 +87,7 @@
         }
         dst = skb->dst;
         x = dst->xfrm;
+
     } while (x && !x->props.mode);
 
     IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
diff -urN  a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
--- a/net/ipv4/xfrm4_tunnel.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/xfrm4_tunnel.c 2007-05-25 12:21:11.000000000 +0300
@@ -28,13 +28,20 @@
 
 static int ipip_init_state(struct xfrm_state *x)
 {
-    if (!x->props.mode)
-        return -EINVAL;
-
     if (x->encap)
         return -EINVAL;
 
-    x->props.header_len = sizeof(struct iphdr);
+    switch (x->props.mode) {
+    case XFRM_MODE_TRANSPORT:
+        return -EINVAL;
+    default:
+    case XFRM_MODE_TUNNEL:
+        x->props.header_len = sizeof(struct iphdr);
+        break;
+    case XFRM_MODE_BEET:
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
+        break;
+    }
 
     return 0;
 }
diff -urN  a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/route.c 2007-05-25 12:21:11.000000000 +0300
@@ -108,6 +108,7 @@
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
+#include <linux/xfrm.h>
 
 #define RT_FL_TOS(oldflp) \
     ((u32)(oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK)))
@@ -2631,7 +2632,7 @@
 
 int ip_route_output_key(struct rtable **rp, struct flowi *flp)
 {
-    return ip_route_output_flow(rp, flp, NULL, 0);
+    return ip_route_output_flow(rp, flp, NULL, XFRM_LOOKUP_SLEEP);
 }
 
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
diff -urN  a/net/ipv4/ah4.c b/net/ipv4/ah4.c
--- a/net/ipv4/ah4.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/ah4.c 2007-05-25 12:21:11.000000000 +0300
@@ -253,8 +253,10 @@
         goto error;
    
     x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + 
ahp->icv_trunc_len);
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct iphdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
     x->data = ahp;
 
     return 0;
diff -urN  a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
--- a/net/ipv4/xfrm4_policy.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/xfrm4_policy.c 2007-05-25 12:21:11.000000000 +0300
@@ -16,6 +16,8 @@
 static struct dst_ops xfrm4_dst_ops;
 static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
 
+static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu);
+
 static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
 {
     return __ip_route_output_key((struct rtable**)dst, fl);
@@ -53,17 +55,20 @@
     struct dst_entry *dst, *dst_prev;
     struct rtable *rt0 = (struct rtable*)(*dst_p);
     struct rtable *rt = rt0;
-    u32 remote = fl->fl4_dst;
-    u32 local  = fl->fl4_src;
     struct flowi fl_tunnel = {
         .nl_u = {
             .ip4_u = {
-                .saddr = local,
-                .daddr = remote,
+                .saddr = fl->fl4_dst,
+                .daddr = fl->fl4_src,
                 .tos = fl->fl4_tos
             }
         }
     };
+    union {
+        struct in6_addr *in6;
+        struct in_addr *in;
+    } remote, local;
+    unsigned short outer_family = 0, beet = 0;
     int i;
     int err;
     int header_len = 0;
@@ -75,7 +80,6 @@
     for (i = 0; i < nx; i++) {
         struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
         struct xfrm_dst *xdst;
-        int tunnel = 0;
 
         if (unlikely(dst1 == NULL)) {
             err = -ENOBUFS;
@@ -96,21 +100,45 @@
 
         dst1->next = dst_prev;
         dst_prev = dst1;
-        if (xfrm[i]->props.mode) {
-            remote = xfrm[i]->id.daddr.a4;
-            local  = xfrm[i]->props.saddr.a4;
-            tunnel = 1;
+
+        if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL || 
xfrm[i]->props.mode == XFRM_MODE_BEET) {
+            outer_family = xfrm[i]->props.family;
+            beet = (xfrm[i]->props.mode == XFRM_MODE_BEET);
+
+            if(outer_family == AF_INET6){
+                remote.in6 = (struct in6_addr*)&xfrm[i]->id.daddr;
+                local.in6 = (struct in6_addr*)&xfrm[i]->props.saddr;
+            } else if(outer_family == AF_INET){
+                remote.in = (struct in_addr*)&xfrm[i]->id.daddr;
+                local.in = (struct in_addr*)&xfrm[i]->props.saddr;
+            } else
+                BUG_ON(1);
         }
         header_len += xfrm[i]->props.header_len;
         trailer_len += xfrm[i]->props.trailer_len;
 
-        if (tunnel) {
-            fl_tunnel.fl4_src = local;
-            fl_tunnel.fl4_dst = remote;
+        if (outer_family) {
+            switch(outer_family) {
+            case AF_INET:
+                fl_tunnel.fl4_dst = remote.in->s_addr;
+                fl_tunnel.fl4_src = local.in->s_addr;
+                break;
+            case AF_INET6:
+                ipv6_addr_copy(&fl_tunnel.fl6_dst, remote.in6);
+                ipv6_addr_copy(&fl_tunnel.fl6_src, local.in6);
+                break;
+            default:
+                BUG_ON(1);
+            }
             err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
-                          &fl_tunnel, AF_INET);
+                          &fl_tunnel, outer_family);
             if (err)
                 goto error;
+            /* Without this, the atomic inc below segfaults */
+            if (outer_family == AF_INET6) {
+                rt->peer = NULL;
+                rt_bind_peer(rt,1);
+            }
         } else
             dst_hold(&rt->u.dst);
     }
@@ -160,6 +188,11 @@
     }
 
     xfrm_init_pmtu(dst);
+    if (beet && outer_family == AF_INET6) {
+        int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+        u32 mtu = dst_mtu(dst);
+        xfrm4_update_pmtu(dst, mtu - delta);
+    }
     return 0;
 
 error:
diff -urN  a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
--- a/net/ipv4/xfrm4_mode_tunnel.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/xfrm4_mode_tunnel.c 2007-05-25 12:21:11.000000000 +0300
@@ -33,7 +33,7 @@
  * On exit, skb->h will be set to the start of the payload to be processed
  * by x->type->output and skb->nh will be set to the top IP header.
  */
-static int xfrm4_tunnel_output(struct sk_buff *skb)
+ static int xfrm4_tunnel_output(struct sk_buff *skb)
 {
     struct dst_entry *dst = skb->dst;
     struct xfrm_state *x = dst->xfrm;
@@ -98,6 +98,182 @@
     return err;
 }
 
+/* jk: this should be moved to the beet module! */
+static int xfrm4_beet_output(struct sk_buff *skb)
+{
+        struct dst_entry *dst = skb->dst;
+        struct xfrm_state *x = dst->xfrm;
+        int hdrlen;
+        struct iphdr *iphv4, *top_iphv4;
+        struct ipv6hdr *iphv6, *top_iphv6;
+
+        if (skb->nh.iph->version == 4) {
+               
+                int optlen;
+
+                /* 4-4 */
+
+                iphv4 = skb->nh.iph;
+                skb->h.ipiph = iphv4;
+               
+                hdrlen = x->props.header_len;
+               
+                optlen = iphv4->ihl * 4 - sizeof(*iphv4);
+                if (!optlen) {
+                        hdrlen -= IPV4_BEET_PHMAXLEN;
+                } else {
+                        skb->h.raw -= (IPV4_BEET_PHMAXLEN - (optlen & 4));
+                        hdrlen -= optlen & 4;
+                }
+               
+                skb->nh.raw = skb_push(skb, hdrlen);
+                top_iphv4 = skb->nh.iph;
+               
+                hdrlen = iphv4->ihl * 4 - optlen;
+                skb->h.raw += hdrlen;
+                memmove(top_iphv4, iphv4, hdrlen);
+               
+                if (unlikely(optlen)) {
+                        struct ip_beet_phdr *ph;
+                       
+                        BUG_ON(optlen < 0);
+                       
+                        ph = (struct ip_beet_phdr *)skb->h.raw;
+                        ph->padlen = 4 - (optlen & 4);
+                        ph->hdrlen = (optlen + ph->padlen + 
sizeof(*ph)) / 8;
+                        ph->nexthdr = iphv4->protocol;
+                        top_iphv4->protocol = IPPROTO_BEETPH;
+                        top_iphv4->ihl = sizeof(struct iphdr) / 4;
+                }
+               
+                top_iphv4->saddr = x->props.saddr.a4;
+                top_iphv4->daddr = x->id.daddr.a4;
+               
+    } else if (skb->nh.iph->version == 6) {
+               
+                u8 protocol;
+                int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+
+                /* Inner = 6, Outer = 4 : changing the external IP hdr
+                 * to the outer addresses
+                 */
+
+                hdrlen = x->props.header_len - IPV4_BEET_PHMAXLEN;
+                skb_push(skb, hdrlen);
+                iphv6 = skb->nh.ipv6h;
+               
+                skb->nh.raw = skb->data;
+                top_iphv6 = skb->nh.ipv6h;
+
+                protocol = iphv6->nexthdr;
+                skb->nh.raw = skb_pull(skb, delta);
+                top_iphv4 = skb->nh.iph;
+                skb->h.raw = skb->data + hdrlen;
+                top_iphv4->ihl = (sizeof(struct iphdr) >> 2);
+                top_iphv4->version = 4;
+                top_iphv4->id = 0;
+                top_iphv4->frag_off = htons(IP_DF);
+                top_iphv4->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);
+                top_iphv4->saddr = x->props.saddr.a4;
+                top_iphv4->daddr = x->id.daddr.a4;
+                skb->h.raw += top_iphv4->ihl*4;
+                top_iphv4->protocol = protocol;
+        
+        } else
+                BUG_ON(1);
+       
+    return 0;
+}
+
+
+/* jk: this should be moved to the beet module! */
+static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+        int err = -EINVAL;
+        int phlen = 0;
+        int optlen = 0;
+        __u8 ph_nexthdr = 0;
+        int size = (x->sel.family == AF_INET) ? sizeof(struct iphdr) : 
sizeof(struct ipv6hdr);
+        int proto = skb->nh.iph->protocol;
+        int hops = skb->nh.iph->ttl;
+        int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+     
+        if (x->sel.family == AF_INET6) {
+                /* Here, the inner family is 6, therefore I have to
+                 * substitute the IPhdr by enlarging it */
+                if (skb_tailroom(skb) <  delta){
+                        if (pskb_expand_head(skb, 0, delta, GFP_ATOMIC))
+                                goto out;        //Just returning from 
here.
+                }
+
+                skb->nh.raw -= delta;
+        } else if (x->sel.family == AF_INET) {
+                // We need to extract the PH
+                struct ip_beet_phdr *ph = (struct 
ip_beet_phdr*)(skb->nh.iph + 1);
+
+                if (proto == IPPROTO_BEETPH) {
+                        if (!pskb_may_pull(skb, sizeof(*ph)))
+                                goto out;
+                        phlen = ph->hdrlen * 8;
+                        optlen = phlen - ph->padlen - sizeof(*ph);
+
+                        if (optlen < 0 || optlen & 3 || optlen > 250)
+                                goto out;
+                        if (!pskb_may_pull(skb, phlen))
+                                goto out;
+
+                        ph_nexthdr = ph->nexthdr;
+                }
+        } else
+                BUG_ON(1);
+
+        if (skb_cloned(skb) &&
+            pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+                goto out;
+ 
+        skb_push(skb, size);
+        memmove(skb->data, skb->nh.raw, size);
+        skb->nh.raw = skb->data;
+
+        if (x->sel.family == AF_INET) {
+                struct iphdr *iph = skb->nh.iph;
+
+                if (unlikely(phlen)) {
+                        skb_pull(skb, phlen - optlen);
+                        memmove(skb->data, skb->nh.raw, sizeof(*iph));
+                        skb->nh.raw = skb->data;
+                        iph = skb->nh.iph;
+                }
+
+                iph->ihl = (sizeof(*iph) + optlen) / 4;
+                iph->tot_len = htons(skb->len);
+                iph->daddr = x->sel.daddr.a4;
+                iph->saddr = x->sel.saddr.a4;
+                if (ph_nexthdr)
+                        iph->protocol = ph_nexthdr;
+                else
+                        iph->protocol = proto;
+                ip_send_check(iph);
+        } else if (x->sel.family == AF_INET6) {
+                struct ipv6hdr *ip6h = skb->nh.ipv6h;
+
+                memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl));
+                ip6h->version = 6;
+                ip6h->priority = 0;
+                ip6h->nexthdr = proto;
+                ip6h->hop_limit = hops;
+                ip6h->payload_len = htons(skb->len - size);
+                ipv6_addr_copy(&ip6h->daddr, (struct in6_addr 
*)&x->sel.daddr.a6);
+                ipv6_addr_copy(&ip6h->saddr, (struct in6_addr 
*)&x->sel.saddr.a6);
+                skb->protocol = htons(ETH_P_IPV6);
+        }
+
+        err = 0;
+ out:
+
+        return err;
+}
+
 static struct xfrm_mode xfrm4_tunnel_mode = {
     .input = xfrm4_tunnel_input,
     .output = xfrm4_tunnel_output,
@@ -105,8 +281,19 @@
     .encap = XFRM_MODE_TUNNEL,
 };
 
+/* jk: this should be moved to the beet module! */
+static struct xfrm_mode xfrm4_beet_mode = {
+    .input = xfrm4_beet_input,
+    .output = xfrm4_beet_output,
+    .owner = THIS_MODULE,
+    .encap = XFRM_MODE_BEET,
+};
+
 static int __init xfrm4_tunnel_init(void)
 {
+        int err;
+        /* jk: this should be moved to the beet module! */
+    err = xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
     return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET);
 }
 
@@ -114,6 +301,9 @@
 {
     int err;
 
+        /* jk: this should be moved to the beet module! */
+    err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
+    BUG_ON(err);
     err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET);
     BUG_ON(err);
 }
diff -urN  a/net/ipv4/esp4.c b/net/ipv4/esp4.c
--- a/net/ipv4/esp4.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/esp4.c 2007-05-25 12:21:11.000000000 +0300
@@ -237,7 +237,8 @@
          *    as per draft-ietf-ipsec-udp-encaps-06,
          *    section 3.1.2
          */
-        if (!x->props.mode)
+        if (x->props.mode == XFRM_MODE_TRANSPORT ||
+            x->props.mode == XFRM_MODE_BEET)
             skb->ip_summed = CHECKSUM_UNNECESSARY;
     }
 
@@ -255,17 +256,27 @@
 {
     struct esp_data *esp = x->data;
     u32 blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4);
+    int enclen = 0;
 
-    if (x->props.mode) {
-        mtu = ALIGN(mtu + 2, blksize);
-    } else {
-        /* The worst case. */
+    switch (x->props.mode) {
+    default:
+    case XFRM_MODE_TUNNEL:
+        mtu = ALIGN(mtu +2, blksize);
+        break;
+    case XFRM_MODE_TRANSPORT:
+        /* The worst case */
         mtu = ALIGN(mtu + 2, 4) + blksize - 4;
+        break;
+    case XFRM_MODE_BEET:
+        /* The worst case. */
+        enclen = IPV4_BEET_PHMAXLEN;
+        mtu = ALIGN(mtu + enclen + 2, blksize);
+        break;
     }
     if (esp->conf.padlen)
         mtu = ALIGN(mtu, esp->conf.padlen);
 
-    return mtu + x->props.header_len + esp->auth.icv_trunc_len;
+    return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
@@ -368,8 +379,10 @@
     if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, 
esp->conf.key_len))
         goto error;
     x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct iphdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
     if (x->encap) {
         struct xfrm_encap_tmpl *encap = x->encap;
 
diff -urN  a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
--- a/net/ipv4/ipcomp.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv4/ipcomp.c 2007-05-25 12:21:11.000000000 +0300
@@ -176,7 +176,7 @@
     return 0;
 
 out_ok:
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         ip_send_check(iph);
     return 0;
 }
@@ -216,7 +216,7 @@
     t->id.daddr.a4 = x->id.daddr.a4;
     memcpy(&t->sel, &x->sel, sizeof(t->sel));
     t->props.family = AF_INET;
-    t->props.mode = 1;
+    t->props.mode = x->props.mode;
     t->props.saddr.a4 = x->props.saddr.a4;
     t->props.flags = x->props.flags;
 
@@ -415,8 +415,10 @@
         goto out;
 
     x->props.header_len = 0;
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct iphdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
 
     mutex_lock(&ipcomp_resource_mutex);
     if (!ipcomp_alloc_scratches())
@@ -427,7 +429,7 @@
         goto error;
     mutex_unlock(&ipcomp_resource_mutex);
 
-    if (x->props.mode) {
+    if (x->props.mode == XFRM_MODE_TUNNEL) {
         err = ipcomp_tunnel_attach(x);
         if (err)
             goto error_tunnel;
diff -urN  a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
--- a/net/ipv6/xfrm6_input.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/xfrm6_input.c 2007-05-25 12:21:11.000000000 +0300
@@ -13,9 +13,21 @@
 #include <linux/string.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
+#include <net/dsfield.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 sk_buff *skb)
+{
+    struct ipv6hdr *outer_iph = skb->nh.ipv6h;
+    struct ipv6hdr *inner_iph = skb->h.ipv6h;
+
+    if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
+        IP6_ECN_set_ce(inner_iph);
+}
+
 int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
 {
     int err;
@@ -33,7 +45,6 @@
     seq = 0;
     if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
         goto drop;
-   
     do {
         struct ipv6hdr *iph = skb->nh.ipv6h;
 
@@ -44,6 +55,7 @@
         if (x == NULL)
             goto drop;
         spin_lock(&x->lock);
+
         if (unlikely(x->km.state != XFRM_STATE_VALID))
             goto drop_unlock;
 
@@ -69,16 +81,17 @@
 
         xfrm_vec[xfrm_nr++] = x;
 
-        if (x->mode->input(x, skb))
+                if (x->mode->input(x, skb))
             goto drop;
-
-        if (x->props.mode) { /* XXX */
-            decaps = 1;
-            break;
+       
+        if (x->props.mode) {
+          decaps = 1;
+          break;
         }
 
         if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
             goto drop;
+
     } while (!err);
 
     /* Allocate new secpath or COW existing one. */
@@ -110,6 +123,7 @@
         netif_rx(skb);
         return -1;
     } else {
+
 #ifdef CONFIG_NETFILTER
         skb->nh.ipv6h->payload_len = htons(skb->len);
         __skb_push(skb, skb->data - skb->nh.raw);
diff -urN  a/net/ipv6/ah6.c b/net/ipv6/ah6.c
--- a/net/ipv6/ah6.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/ah6.c 2007-05-25 12:21:11.000000000 +0300
@@ -387,8 +387,10 @@
         goto error;
    
     x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + 
ahp->icv_trunc_len);
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct ipv6hdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
     x->data = ahp;
 
     return 0;
diff -urN  a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
--- a/net/ipv6/xfrm6_policy.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/xfrm6_policy.c 2007-05-25 12:21:11.000000000 +0300
@@ -22,6 +22,8 @@
 static struct dst_ops xfrm6_dst_ops;
 static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
 
+static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu);
+
 static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
 {
     int err = 0;
@@ -70,16 +72,19 @@
     struct dst_entry *dst, *dst_prev;
     struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
     struct rt6_info *rt  = rt0;
-    struct in6_addr *remote = &fl->fl6_dst;
-    struct in6_addr *local  = &fl->fl6_src;
     struct flowi fl_tunnel = {
         .nl_u = {
             .ip6_u = {
-                .saddr = *local,
-                .daddr = *remote
+                .saddr = fl->fl6_src,
+                .daddr = fl->fl6_dst
             }
         }
     };
+    union {
+        struct in6_addr *in6;
+        struct in_addr *in;
+    } remote, local;
+    unsigned short outer_family = 0, beet = 0;
     int i;
     int err = 0;
     int header_len = 0;
@@ -91,7 +96,6 @@
     for (i = 0; i < nx; i++) {
         struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
         struct xfrm_dst *xdst;
-        int tunnel = 0;
 
         if (unlikely(dst1 == NULL)) {
             err = -ENOBUFS;
@@ -114,19 +118,39 @@
 
         dst1->next = dst_prev;
         dst_prev = dst1;
-        if (xfrm[i]->props.mode) {
-            remote = (struct in6_addr*)&xfrm[i]->id.daddr;
-            local  = (struct in6_addr*)&xfrm[i]->props.saddr;
-            tunnel = 1;
+        if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL || 
xfrm[i]->props.mode == XFRM_MODE_BEET) {
+            outer_family = xfrm[i]->props.family;
+            beet = (xfrm[i]->props.mode == XFRM_MODE_BEET);
+            if (outer_family == AF_INET6) {
+                remote.in6 = (struct in6_addr*)&xfrm[i]->id.daddr;
+                local.in6 = (struct in6_addr*)&xfrm[i]->props.saddr;
+            } else if(outer_family == AF_INET){
+                remote.in = (struct in_addr*)&xfrm[i]->id.daddr;
+                local.in = (struct in_addr*)&xfrm[i]->props.saddr;
+            }
         }
         header_len += xfrm[i]->props.header_len;
         trailer_len += xfrm[i]->props.trailer_len;
 
-        if (tunnel) {
-            ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
-            ipv6_addr_copy(&fl_tunnel.fl6_src, local);
+        if (outer_family) {
+            switch(outer_family) {
+            case AF_INET:
+                fl_tunnel.fl4_dst = remote.in->s_addr;
+                fl_tunnel.fl4_src = local.in->s_addr;
+
+                fl_tunnel.fl4_tos = 0;
+                fl_tunnel.fl4_fwmark = 0;
+                fl_tunnel.fl4_scope = 0;
+                break;
+            case AF_INET6:
+                ipv6_addr_copy(&fl_tunnel.fl6_dst, remote.in6);
+                ipv6_addr_copy(&fl_tunnel.fl6_src, local.in6);
+                break;
+            default:
+                BUG_ON(1);
+            }
             err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
-                          &fl_tunnel, AF_INET6);
+                          &fl_tunnel, outer_family);
             if (err)
                 goto error;
         } else
@@ -177,6 +201,11 @@
     }
 
     xfrm_init_pmtu(dst);
+    if (beet && outer_family == AF_INET) {
+        int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+        u32 mtu = dst_mtu(dst);
+        xfrm6_update_pmtu(dst, mtu + delta);
+    }
     return 0;
 
 error:
diff -urN  a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
--- a/net/ipv6/xfrm6_output.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/xfrm6_output.c 2007-05-25 12:21:11.000000000 +0300
@@ -14,8 +14,11 @@
 #include <linux/spinlock.h>
 #include <linux/icmpv6.h>
 #include <linux/netfilter_ipv6.h>
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
 #include <net/ipv6.h>
 #include <net/xfrm.h>
+#include <net/ip.h>
 
 static int xfrm6_tunnel_check_size(struct sk_buff *skb)
 {
@@ -47,7 +50,7 @@
             goto error_nolock;
     }
 
-    if (x->props.mode) {
+    if (x->props.mode == XFRM_MODE_TUNNEL) {
         err = xfrm6_tunnel_check_size(skb);
         if (err)
             goto error_nolock;
@@ -59,7 +62,7 @@
         if (err)
             goto error;
 
-        err = x->mode->output(skb);
+                err = x->mode->output(skb);
         if (err)
             goto error;
 
diff -urN  a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/udp.c 2007-05-25 12:21:11.000000000 +0300
@@ -788,7 +788,7 @@
     if (final_p)
         ipv6_addr_copy(&fl->fl6_dst, final_p);
 
-    if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
+    if ((err = xfrm_lookup(&dst, fl, sk, XFRM_LOOKUP_SLEEP)) < 0)
         goto out;
 
     if (hlimit < 0) {
diff -urN  a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/tcp_ipv6.c 2007-05-25 12:21:11.000000000 +0300
@@ -257,7 +257,7 @@
     if (final_p)
         ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-    if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+    if ((err = xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_SLEEP)) < 0)
         goto failure;
 
     if (saddr == NULL) {
diff -urN  a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
--- a/net/ipv6/af_inet6.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/af_inet6.c 2007-05-25 12:21:11.000000000 +0300
@@ -939,4 +939,8 @@
 }
 module_exit(inet6_exit);
 
+EXPORT_SYMBOL(inet6_create);
+EXPORT_SYMBOL(inet6_stream_ops);
+EXPORT_SYMBOL(inet6_dgram_ops);
+
 MODULE_ALIAS_NETPROTO(PF_INET6);
diff -urN  a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
--- a/net/ipv6/xfrm6_mode_tunnel.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/xfrm6_mode_tunnel.c 2007-05-25 12:21:11.000000000 +0300
@@ -15,6 +15,7 @@
 #include <net/inet_ecn.h>
 #include <net/ipv6.h>
 #include <net/xfrm.h>
+#include <net/ip.h>
 
 static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
 {
@@ -95,6 +96,209 @@
     return err;
 }
 
+
+/* jk: move this to beet module! */
+static int xfrm6_beet_output(struct sk_buff *skb)
+{
+        struct dst_entry *dst = skb->dst;
+        struct xfrm_state *x = dst->xfrm;
+        int hdrlen;
+        struct iphdr *iphv4, *top_iphv4;
+        struct ipv6hdr *iphv6, *top_iphv6;
+   
+    if (skb->nh.iph->version == 6) {
+               
+        u8 *prevhdr;
+        int hdr_len;
+
+                /* 6-6 */
+
+                hdrlen = x->props.header_len - IPV4_BEET_PHMAXLEN;
+                skb_push(skb, hdrlen);
+                iphv6 = skb->nh.ipv6h;
+
+        hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
+        skb->nh.raw = prevhdr - hdrlen;
+        skb->h.raw = skb->data + hdr_len;
+        memmove(skb->data, iphv6, hdr_len);
+               
+                skb->nh.raw = skb->data;
+                top_iphv6 = skb->nh.ipv6h;
+        skb->nh.raw = &top_iphv6->nexthdr;
+        skb->h.ipv6h = top_iphv6 + 1;
+        ipv6_addr_copy(&top_iphv6->saddr, (struct in6_addr 
*)&x->props.saddr);
+        ipv6_addr_copy(&top_iphv6->daddr, (struct in6_addr *)&x->id.daddr);
+
+    } else if (skb->nh.iph->version == 4) {
+
+                int flags;
+                int optlen;
+                int dsfield;
+                u8 protocol;
+                int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+
+                /* Inner = 4, Outer = 6*/
+
+                iphv4 = skb->nh.iph;
+                skb->h.ipiph = iphv4;
+
+                hdrlen = x->props.header_len;
+
+                optlen = iphv4->ihl * 4 - sizeof(*iphv4);
+                if (!optlen) {
+                        hdrlen -= IPV4_BEET_PHMAXLEN;
+                } else {
+                        skb->h.raw -= (IPV4_BEET_PHMAXLEN - (optlen & 4));
+                        hdrlen -= optlen & 4;
+                }
+       
+                skb->nh.raw = skb_push(skb, hdrlen);
+                top_iphv4 = skb->nh.iph;
+
+                hdrlen = iphv4->ihl * 4 - optlen;
+                skb->h.raw += hdrlen;
+
+                if (unlikely(optlen)) {
+                        struct ip_beet_phdr *ph;
+               
+                        BUG_ON(optlen < 0);
+               
+                        ph = (struct ip_beet_phdr *)skb->h.raw;
+                        ph->padlen = 4 - (optlen & 4);
+                        ph->hdrlen = (optlen + ph->padlen + 
sizeof(*ph)) / 8;
+                        ph->nexthdr = iphv4->protocol;
+                        top_iphv4->protocol = IPPROTO_BEETPH;
+                        top_iphv4->ihl = sizeof(struct iphdr) / 4;
+                }
+               
+                protocol = top_iphv4->protocol;
+
+                if (unlikely(optlen))
+                        protocol = top_iphv4->protocol;
+                else
+                        protocol = iphv4->protocol;
+               
+                if (skb_headroom(skb) <=  2*delta){
+                        if (pskb_expand_head(skb, delta,0, GFP_ATOMIC))
+                                return 0;
+                }
+               
+                skb->nh.raw = skb_push(skb, delta);
+
+                top_iphv6 = skb->nh.ipv6h;
+                skb->h.ipv6h = top_iphv6 + 1;
+                /* DS disclosed */
+                top_iphv6->version = 6;
+                top_iphv6->priority = 0;
+                top_iphv6->flow_lbl[0] = 0;
+                top_iphv6->flow_lbl[1] = 0;
+                top_iphv6->flow_lbl[2] = 0;
+                dsfield = ipv6_get_dsfield(top_iphv6);
+                dsfield = INET_ECN_encapsulate(dsfield, dsfield);
+                flags = x->props.flags;
+                if (flags & XFRM_STATE_NOECN)
+                        dsfield &= ~INET_ECN_MASK;
+                ipv6_change_dsfield(top_iphv6, 0, dsfield);
+
+                top_iphv6->nexthdr = protocol;
+                top_iphv6->hop_limit = dst_metric(dst->child, 
RTAX_HOPLIMIT);
+                top_iphv6->payload_len = htons(skb->len - sizeof(struct 
ipv6hdr));
+                ipv6_addr_copy(&top_iphv6->saddr,(struct in6_addr 
*)&x->props.saddr);
+                ipv6_addr_copy(&top_iphv6->daddr, (struct in6_addr 
*)&x->id.daddr);
+                skb->nh.raw = &top_iphv6->nexthdr;
+
+    } else
+        BUG_ON(1);
+
+    return 0;
+}
+
+
+
+/* jk: move this to beet module! */
+static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{ 
+        struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(skb->h.raw);
+        int size = (x->sel.family == AF_INET) ? sizeof(struct iphdr) : 
sizeof(struct ipv6hdr);
+        int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+        __u8 proto = skb->nh.ipv6h->nexthdr, hops = 
skb->nh.ipv6h->hop_limit;
+        __u8 ph_nexthdr = 0;
+        int phlen = 0;
+        int optlen = 0;
+        int err = -EINVAL;
+
+        if (x->sel.family == AF_INET) {
+                /* Inner = IPv4, therefore the IPhdr must be shrunk */
+                /* Inner = 4, Outer = 6 */
+                if (unlikely(proto == IPPROTO_BEETPH)) {
+                        if (!pskb_may_pull(skb, sizeof(*ph)))
+                                goto out;
+                        phlen = ph->hdrlen * 8;
+                        optlen = phlen - ph->padlen - sizeof(*ph);
+
+                        if (optlen < 0 || optlen & 3 || optlen > 250)
+                                goto out;
+                        if (!pskb_may_pull(skb, phlen))
+                                goto out;
+
+                        proto = ph_nexthdr = ph->nexthdr;
+                }
+                skb->nh.raw += delta;
+        }
+
+        if (skb_cloned(skb) &&
+            pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+                goto out;
+
+        skb_push(skb, size);
+        memmove(skb->data, skb->nh.raw, size);
+        skb->nh.raw = skb->data;
+
+        skb->mac.raw = memmove(skb->data - skb->mac_len,
+                               skb->mac.raw, skb->mac_len);
+        if (unlikely(phlen)) {
+                skb_pull(skb, phlen - optlen);
+                skb->nh.raw = skb->data;
+        }
+
+        if (x->sel.family == AF_INET6) {
+                struct ipv6hdr *ip6h = skb->nh.ipv6h;
+
+                ip6h->payload_len = htons(skb->len - size);
+                ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) 
&x->sel.daddr.a6);
+                ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) 
&x->sel.saddr.a6);
+
+        } else if (x->sel.family == AF_INET) {
+
+                struct iphdr *iph = skb->nh.iph;
+
+                iph->ihl = (sizeof(*iph) + optlen) / 4;
+                iph->version = 4;
+                iph->tos = 0;
+                iph->id = 0;
+                iph->frag_off = 0;
+                iph->ttl = hops;
+                iph->protocol = proto;
+                iph->daddr = x->sel.daddr.a4;
+                iph->saddr = x->sel.saddr.a4;
+                iph->tot_len = htons(skb->len);
+                ip_send_check(iph);
+                skb->protocol = htons(ETH_P_IP);
+                if (unlikely(!optlen)) {
+                        skb->h.raw = skb->nh.raw;
+                }
+                dst_release(skb->dst);
+                skb->dst = NULL;
+        } else
+                BUG_ON(1);
+
+        err = 0;
+
+ out:
+        return err;
+}
+
+
 static struct xfrm_mode xfrm6_tunnel_mode = {
     .input = xfrm6_tunnel_input,
     .output = xfrm6_tunnel_output,
@@ -102,8 +306,20 @@
     .encap = XFRM_MODE_TUNNEL,
 };
 
+/* jk: move this to beet module! */
+static struct xfrm_mode xfrm6_beet_mode = {
+    .input = xfrm6_beet_input,
+    .output = xfrm6_beet_output,
+    .owner = THIS_MODULE,
+    .encap = XFRM_MODE_BEET,
+};
+
 static int __init xfrm6_tunnel_init(void)
 {
+ 
+  /* jk: move this to beet module! */
+  xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
+
     return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
 }
 
@@ -111,6 +327,9 @@
 {
     int err;
 
+    /* jk: move this to beet module! */
+    err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
+
     err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6);
     BUG_ON(err);
 }
diff -urN  a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
--- a/net/ipv6/ipcomp6.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/ipcomp6.c 2007-05-25 12:21:11.000000000 +0300
@@ -416,8 +416,10 @@
         goto out;
 
     x->props.header_len = 0;
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct ipv6hdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
    
     mutex_lock(&ipcomp6_resource_mutex);
     if (!ipcomp6_alloc_scratches())
@@ -428,7 +430,7 @@
         goto error;
     mutex_unlock(&ipcomp6_resource_mutex);
 
-    if (x->props.mode) {
+    if (x->props.mode == XFRM_MODE_TUNNEL) {
         err = ipcomp6_tunnel_attach(x);
         if (err)
             goto error_tunnel;
diff -urN  a/net/ipv6/esp6.c b/net/ipv6/esp6.c
--- a/net/ipv6/esp6.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/esp6.c 2007-05-25 12:21:11.000000000 +0300
@@ -344,8 +344,10 @@
     if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, 
esp->conf.key_len))
         goto error;
     x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen;
-    if (x->props.mode)
+    if (x->props.mode == XFRM_MODE_TUNNEL)
         x->props.header_len += sizeof(struct ipv6hdr);
+    else if (x->props.mode == XFRM_MODE_BEET)
+        x->props.header_len += IPV4_BEET_PHMAXLEN;
     x->data = esp;
     return 0;
 
diff -urN  a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/ipv6/icmp.c 2007-05-25 12:21:11.000000000 +0300
@@ -64,6 +64,7 @@
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/icmp.h>
+#include <linux/xfrm.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -389,7 +390,7 @@
         goto out_dst_release;
     }
 
-    if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+    if ((err = xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_SLEEP)) < 0)
         goto out;
 
     if (ipv6_addr_is_multicast(&fl.fl6_dst))
diff -urN  a/net/key/af_key.c b/net/key/af_key.c
--- a/net/key/af_key.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/key/af_key.c 2007-05-25 12:21:11.000000000 +0300
@@ -1166,7 +1166,8 @@
         /* Nobody uses this, but we try. */
         x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr);
         x->sel.prefixlen_s = addr->sadb_address_prefixlen;
-    }
+    } else
+        x->sel.family = x->props.family; /* Conservative */
 
     if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) {
         struct sadb_x_nat_t_type* n_type;
@@ -1763,14 +1764,13 @@
         if (!t->reqid && !(t->reqid = gen_reqid()))
             return -ENOBUFS;
     }
-
-    /* addresses present only in tunnel mode */
-    if (t->mode) {
-        switch (xp->family) {
+/* addresses present in any mode */
+    {
+        struct sockaddr *sa;
+        sa = (struct sockaddr *)(rq+1);
+        switch(sa->sa_family) {
         case AF_INET:
-            sin = (void*)(rq+1);
-            if (sin->sin_family != AF_INET)
-                return -EINVAL;
+            sin = (struct sockaddr_in *)sa;
             t->saddr.a4 = sin->sin_addr.s_addr;
             sin++;
             if (sin->sin_family != AF_INET)
@@ -1779,9 +1779,7 @@
             break;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
         case AF_INET6:
-            sin6 = (void *)(rq+1);
-            if (sin6->sin6_family != AF_INET6)
-                return -EINVAL;
+            sin6 = (struct sockaddr_in6 *)sa;
             memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
             sin6++;
             if (sin6->sin6_family != AF_INET6)
@@ -1792,6 +1790,7 @@
         default:
             return -EINVAL;
         }
+        t->outer_family = sa->sa_family;
     }
     /* No way to set this via kame pfkey */
     t->aalgos = t->ealgos = t->calgos = ~0;
diff -urN  a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
--- a/net/xfrm/xfrm_user.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/xfrm/xfrm_user.c 2007-05-25 12:21:11.000000000 +0300
@@ -173,8 +173,9 @@
 
     err = -EINVAL;
     switch (p->mode) {
-    case 0:
-    case 1:
+    case XFRM_MODE_TRANSPORT:
+    case XFRM_MODE_TUNNEL:
+    case XFRM_MODE_BEET:
         break;
 
     default:
@@ -763,6 +764,7 @@
         t->aalgos = ut->aalgos;
         t->ealgos = ut->ealgos;
         t->calgos = ut->calgos;
+        t->outer_family = ut->family;
     }
 }
 
diff -urN  a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/xfrm/xfrm_policy.c 2007-05-25 12:21:11.000000000 +0300
@@ -782,6 +782,7 @@
         if (tmpl->mode) {
             remote = &tmpl->id.daddr;
             local = &tmpl->saddr;
+            family = tmpl->outer_family;
         }
 
         x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, 
family);
diff -urN  a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
--- a/net/xfrm/xfrm_state.c 2007-05-25 12:21:11.000000000 +0300
+++ b/net/xfrm/xfrm_state.c 2007-05-25 12:21:11.000000000 +0300
@@ -366,7 +366,7 @@
                   selector.
              */
             if (x->km.state == XFRM_STATE_VALID) {
-                if (!xfrm_selector_match(&x->sel, fl, family) ||
+                if (!xfrm_selector_match(&x->sel, fl, x->sel.family) ||
                     !xfrm_sec_ctx_match(pol->security, x->security))
                     continue;
                 if (!best ||
@@ -378,7 +378,7 @@
                 acquire_in_progress = 1;
             } else if (x->km.state == XFRM_STATE_ERROR ||
                    x->km.state == XFRM_STATE_EXPIRED) {
-                 if (xfrm_selector_match(&x->sel, fl, family) &&
+                 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
                     xfrm_sec_ctx_match(pol->security, x->security))
                     error = -ESRCH;
             }
diff -urN  a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h 2007-05-25 12:21:11.000000000 +0300
+++ b/include/net/xfrm.h 2007-05-25 12:21:11.000000000 +0300
@@ -226,7 +226,7 @@
 extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo 
*afinfo);
 extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct 
km_event *c);
 extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
-#define XFRM_ACQ_EXPIRES    30
+#define XFRM_ACQ_EXPIRES    3
 
 struct xfrm_tmpl;
 extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct 
xfrm_policy *pol);
@@ -297,6 +297,10 @@
 /* Source address of tunnel. Ignored, if it is not a tunnel. */
     xfrm_address_t        saddr;
 
+/* family of the outer addresses. The family may differ from
+   the one in selector */
+    unsigned short        outer_family;
+
     __u32            reqid;
 
 /* Mode: transport/tunnel */
diff -urN  a/include/linux/xfrm.h b/include/linux/xfrm.h
--- a/include/linux/xfrm.h 2007-05-25 12:21:11.000000000 +0300
+++ b/include/linux/xfrm.h 2007-05-25 12:21:11.000000000 +0300
@@ -43,6 +43,12 @@
 #define XFRM_SC_ALG_RESERVED 0
 #define XFRM_SC_ALG_SELINUX 1
 
+/* Transport layer flag  passed to xfrm_lookup. If set, the userspace
+   process sleeps in a waitqueue until key management daemon has
+   finished setting up security associations. This workaround exists
+   until we have queues for outgoing IPsec packets. */
+#define XFRM_LOOKUP_SLEEP (!in_atomic() && !in_softirq())
+
 /* Selector, used as selector both on policy rules (SPD) and SAs. */
 
 struct xfrm_selector
@@ -118,9 +124,13 @@
     XFRM_SHARE_UNIQUE    /* Use once */
 };
 
-#define XFRM_MODE_TRANSPORT 0
-#define XFRM_MODE_TUNNEL 1
-#define XFRM_MODE_MAX 2
+enum
+{
+    XFRM_MODE_TRANSPORT = 0,
+    XFRM_MODE_TUNNEL,
+    XFRM_MODE_BEET,
+    XFRM_MODE_MAX
+};
 
 /* Netlink configuration messages.  */
 enum {
diff -urN  a/include/linux/ipsec.h b/include/linux/ipsec.h
--- a/include/linux/ipsec.h 2007-05-25 12:21:12.000000000 +0300
+++ b/include/linux/ipsec.h 2007-05-25 12:21:12.000000000 +0300
@@ -12,7 +12,8 @@
 enum {
     IPSEC_MODE_ANY        = 0,    /* We do not support this for SA */
     IPSEC_MODE_TRANSPORT    = 1,
-    IPSEC_MODE_TUNNEL    = 2
+    IPSEC_MODE_TUNNEL    = 2,
+    IPSEC_MODE_BEET         = 3
 };
 
 enum {
diff -urN  a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h 2007-05-25 12:21:12.000000000 +0300
+++ b/include/linux/net.h 2007-05-25 12:21:12.000000000 +0300
@@ -24,7 +24,7 @@
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO        32        /* should be enough for now..    */
+#define NPROTO        33        /* should be enough for now..    */
 
 #define SYS_SOCKET    1        /* sys_socket(2)        */
 #define SYS_BIND    2        /* sys_bind(2)            */
diff -urN  a/include/linux/in.h b/include/linux/in.h
--- a/include/linux/in.h 2007-05-25 12:21:12.000000000 +0300
+++ b/include/linux/in.h 2007-05-25 12:21:12.000000000 +0300
@@ -40,6 +40,7 @@
 
   IPPROTO_ESP = 50,            /* Encapsulation Security Payload 
protocol */
   IPPROTO_AH = 51,             /* Authentication Header protocol       */
+  IPPROTO_BEETPH = 94,        /* IP option pseudo header for BEET */
   IPPROTO_PIM    = 103,        /* Protocol Independent Multicast    */
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
diff -urN  a/include/linux/ip.h b/include/linux/ip.h
--- a/include/linux/ip.h 2007-05-25 12:21:12.000000000 +0300
+++ b/include/linux/ip.h 2007-05-25 12:21:12.000000000 +0300
@@ -79,6 +79,8 @@
 #define    IPOPT_TS_TSANDADDR    1        /* timestamps and addresses */
 #define    IPOPT_TS_PRESPEC    3        /* specified modules only */
 
+#define IPV4_BEET_PHMAXLEN 8
+
 struct iphdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
     __u8    ihl:4,
@@ -122,4 +124,11 @@
     __u16 cpi;
 };
 
+struct ip_beet_phdr {
+    __u8 nexthdr;
+    __u8 hdrlen;
+    __u8 padlen;
+    __u8 reserved;
+};
+
 #endif    /* _LINUX_IP_H */