Hi,

as part of this email you can find a patch which introduces the BEET mode (Bound
End-to-End Tunnel) as specified by the ietf draft at the following link:

http://www.ietf.org/internet-drafts/draft-nikander-esp-beet-mode-06.txt

A BEET mode Security Associations records two pairs of IP addresses, called
inner addresses and outer addresses.  The inner addresses are what the
applications see.  The outer addresses are what appear on the wire.

The presented BEET mode allows for transformation having inner family equal to
outer family.

Signed-off-by: Diego Beltrami <[EMAIL PROTECTED]>
               Miika Komu     <[EMAIL PROTECTED]>
               Herbert Xu     <[EMAIL PROTECTED]>
               Abhinav Pathak <[EMAIL PROTECTED]>
               Jeff Ahrenholz <[EMAIL PROTECTED]>

--
Diego Beltrami


diff --git a/include/linux/in.h b/include/linux/in.h
index 94f557f..9290d99 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -40,6 +40,7 @@ enum {

   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 --git a/include/linux/ip.h b/include/linux/ip.h
index 4b55cf1..e4d8a39 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -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 @@ struct ip_comp_hdr {
        __u16 cpi;
 };

+struct ip_beet_phdr {
+       __u8 nexthdr;
+       __u8 hdrlen;
+       __u8 padlen;
+       __u8 reserved;
+};
+
 #endif /* _LINUX_IP_H */
diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
index d3c5276..d17a630 100644
--- a/include/linux/ipsec.h
+++ b/include/linux/ipsec.h
@@ -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 --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 46a15c7..6a616de 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -120,7 +120,8 @@ enum

 #define XFRM_MODE_TRANSPORT 0
 #define XFRM_MODE_TUNNEL 1
-#define XFRM_MODE_MAX 2
+#define XFRM_MODE_BEET 2
+#define XFRM_MODE_MAX 3

 /* Netlink configuration messages.  */
 enum {
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 8514106..02c5ff7 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -432,6 +432,15 @@ config INET_XFRM_MODE_TUNNEL

          If unsure, say Y.

+config INET_XFRM_MODE_BEET
+       tristate "IP: IPsec BEET mode"
+       default y
+       select XFRM
+       ---help---
+         Support for IPsec BEET mode.
+
+         If unsure, say Y.
+
 config INET_DIAG
        tristate "INET: socket monitoring interface"
        default y
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 4878fc5..ad22492 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_
 obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
 obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
 obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
+obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 1366bc6..9d6f0e7 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -253,7 +253,7 @@ static int ah_init_state(struct xfrm_sta
                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);
        x->data = ahp;

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index fc2f8ce..76722e1 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -237,7 +237,8 @@ static int esp_input(struct xfrm_state *
                 *    as per draft-ietf-ipsec-udp-encaps-06,
                 *    section 3.1.2
                 */
-               if (!x->props.mode)
+               if (x->props.mode == XFRM_MODE_TUNNEL ||
+                   x->props.mode == XFRM_MODE_BEET )
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }

@@ -255,17 +256,28 @@ static u32 esp4_get_max_size(struct xfrm
 {
        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 {
+       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. */
-               mtu = ALIGN(mtu + 2, 4) + blksize - 4;
+               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,7 +380,7 @@ static int esp_init_state(struct xfrm_st
        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);
        if (x->encap) {
                struct xfrm_encap_tmpl *encap = x->encap;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index a0c28b2..06f9f36 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -176,7 +176,7 @@ static int ipcomp_output(struct xfrm_sta
        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 @@ static struct xfrm_state *ipcomp_tunnel_
        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,7 +415,7 @@ static int ipcomp_init_state(struct xfrm
                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);

        mutex_lock(&ipcomp_resource_mutex);
@@ -427,7 +427,7 @@ static int ipcomp_init_state(struct xfrm
                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 --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
new file mode 100644
index 0000000..6950c5b
--- /dev/null
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -0,0 +1,141 @@
+/*
+ * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
+ *
+ * Copyright (c) 2006 Diego Beltrami <[EMAIL PROTECTED]>
+ *                    Miika Komu     <[EMAIL PROTECTED]>
+ *                    Herbert Xu     <[EMAIL PROTECTED]>
+ *                    Abhinav Pathak <[EMAIL PROTECTED]>
+ *                    Jeff Ahrenholz <[EMAIL PROTECTED]>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per
draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ *      tot_len
+ *      check
+ *
+ * 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_beet_output(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb->dst;
+       struct xfrm_state *x = dst->xfrm;
+       struct iphdr *iph, *top_iph = NULL;
+       int hdrlen, optlen;
+
+       iph = skb->nh.iph;
+       skb->h.ipiph = iph;
+
+       hdrlen = 0;
+       optlen = iph->ihl * 4 - sizeof(*iph);
+       if (unlikely(optlen))
+               hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
+
+       skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen);
+       top_iph = skb->nh.iph;
+       hdrlen = iph->ihl * 4 - optlen;
+       skb->h.raw += hdrlen;
+
+       memmove(top_iph, iph, 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 = top_iph->protocol;
+
+               top_iph->protocol = IPPROTO_BEETPH;
+               top_iph->ihl = sizeof(struct iphdr) / 4;
+       }
+
+       top_iph->saddr = x->props.saddr.a4;
+       top_iph->daddr = x->id.daddr.a4;
+
+       return 0;
+}
+
+static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+       int phlen = 0;
+       int optlen = 0;
+       __u8 ph_nexthdr = 0, protocol = 0;
+       int err = -EINVAL;
+
+       protocol = iph->protocol;
+
+       if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
+               struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1);
+
+               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;
+       }
+
+       skb_push(skb, sizeof(*iph) - 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 = protocol;
+       iph->check = 0;
+       iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+       err = 0;
+out:
+       return err;
+}
+
+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_beet_init(void)
+{
+       return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
+}
+
+static void __exit xfrm4_beet_exit(void)
+{
+       int err;
+
+       err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
+       BUG_ON(err);
+}
+
+module_init(xfrm4_beet_init);
+module_exit(xfrm4_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index e923d4d..4af1eaf 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -126,6 +126,16 @@ config INET6_XFRM_MODE_TUNNEL

          If unsure, say Y.

+config INET6_XFRM_MODE_BEET
+       tristate "IPv6: IPsec BEET mode"
+       depends on IPV6
+       default IPV6
+       select XFRM
+       ---help---
+         Support for IPsec BEET mode.
+
+         If unsure, say Y.
+
 config IPV6_TUNNEL
        tristate "IPv6: IPv6-in-IPv6 tunnel"
        select INET6_TUNNEL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 386e0a6..d87e8e1 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6
 obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
 obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
 obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
+obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
 obj-$(CONFIG_NETFILTER)        += netfilter/

 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 9d4831b..b085562 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -387,7 +387,7 @@ static int ah6_init_state(struct xfrm_st
                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);
        x->data = ahp;

diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index a278d5e..467a4da 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -344,7 +344,7 @@ static int esp6_init_state(struct xfrm_s
        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);
        x->data = esp;
        return 0;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 7e4d1c1..4df07cc 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -212,7 +212,7 @@ static struct xfrm_state *ipcomp6_tunnel
        memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
        memcpy(&t->sel, &x->sel, sizeof(t->sel));
        t->props.family = AF_INET6;
-       t->props.mode = 1;
+       t->props.mode = x->props.mode;
        memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));

        if (xfrm_init_state(t))
@@ -416,7 +416,7 @@ static int ipcomp6_init_state(struct xfr
                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);

        mutex_lock(&ipcomp6_resource_mutex);
@@ -428,7 +428,7 @@ static int ipcomp6_init_state(struct xfr
                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 --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
new file mode 100644
index 0000000..4e962dd
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -0,0 +1,108 @@
+/*
+ * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
+ *
+ * Copyright (c) 2006 Diego Beltrami <[EMAIL PROTECTED]>
+ *                    Miika Komu     <[EMAIL PROTECTED]>
+ *                    Herbert Xu     <[EMAIL PROTECTED]>
+ *                    Abhinav Pathak <[EMAIL PROTECTED]>
+ *                    Jeff Ahrenholz <[EMAIL PROTECTED]>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dsfield.h>
+#include <net/dst.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per
draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ *     payload_len
+ *
+ * On exit, skb->h will be set to the start of the encapsulation header to be
+ * filled in by x->type->output and skb->nh will be set to the nextheader field
+ * of the extension header directly preceding the encapsulation header, or in
+ * its absence, that of the top IP header.  The value of skb->data will always
+ * point to the top IP header.
+ */
+static int xfrm6_beet_output(struct sk_buff *skb)
+{
+       struct xfrm_state *x = skb->dst->xfrm;
+       struct ipv6hdr *iph, *top_iph;
+       u8 *prevhdr;
+       int hdr_len;
+
+       skb_push(skb, x->props.header_len);
+       iph = skb->nh.ipv6h;
+
+       hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
+       skb->nh.raw = prevhdr - x->props.header_len;
+       skb->h.raw = skb->data + hdr_len;
+       memmove(skb->data, iph, hdr_len);
+
+       skb->nh.raw = skb->data;
+       top_iph = skb->nh.ipv6h;
+       skb->nh.raw = &top_iph->nexthdr;
+       skb->h.ipv6h = top_iph + 1;
+
+       ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+       ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+
+       return 0;
+}
+
+static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+       struct ipv6hdr *ip6h;
+       int size = sizeof(struct ipv6hdr);
+       int err = -EINVAL;
+
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+               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);
+
+       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);
+       err = 0;
+out:
+       return err;
+}
+
+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_beet_init(void)
+{
+       return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
+}
+
+static void __exit xfrm6_beet_exit(void)
+{
+       int err;
+
+       err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
+       BUG_ON(err);
+}
+
+module_init(xfrm6_beet_init);
+module_exit(xfrm6_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 82891a2..d57bebe 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -173,8 +173,9 @@ static int verify_newsa_info(struct xfrm

        err = -EINVAL;
        switch (p->mode) {
-       case 0:
-       case 1:
+       case XFRM_MODE_TRANSPORT:
+       case XFRM_MODE_TUNNEL:
+       case XFRM_MODE_BEET:
                break;

        default:


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to