Subject: [Hipsec] Re: [PATCH 2.6.12.2] XFRM: BEET IPsec mode for Linux

From: Diego Beltrami <[email-masked]>
Date: Tue, 02 Aug 2005 15:01:39 +0300

Folks,

after sending the first version of BEET patch and having received a
valuable feedback and after the discussion based upon the BEET design,
we now send the new BEET patch which allows for BEET to work without the
inter-family transform (i.e. inner address family different than outer
address family).

The implementation of such a patch is based on the draft you can find at
the following URL:

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

The patch is attached to the email, but, in case it gives some problems
in applying it, you may also find it at the following URL:

http://infrahip.hiit.fi/beet/beet-patch-v2.0-2.6.12.2

As it was originally designed the BEET patch at the moment works for
only ESP protocol. 
As Pekka Nikader mentioned in one reply [1]: "[...] defining BEET mode
for AH might be pretty tricky. [...] it probably would require some
careful thinking to define the exact semantics, like what addresses
(inner or outer)  are covered by the AH integrity protection, what does
the integrity  protection really assert, etc. ".

As previously written, the inter-family transform has been left out at
the moment since the xfrm architecture doesn't support it. As a result,
as soon as the xfrm architecture will be enhanced, the inter-family case
will be properly included as, for example, it can be useful for
supporting HIP over IPv4 network. But, as already mentioned, this would
require more work in properly designing the xfrm architecture (thing
which we consider necessary in order to make xfrm as generic as
possible).

On the behalf of the BEET development team,

Signed-off-by: Diego Beltrami <[email-masked]>

Reference:
[1] http://marc.theaimsgroup.com/?l=linux-netdev&m=112265207304302&w=2
--- linux-2.6.12.2-orig/Documentation/README.BEET
+++ linux-2.6.12.2/Documentation/README.BEET
@@ -0,0 +1,296 @@
+Linux BEET-mode ESP patch
+
+Authors:        Miika Komu <[email-masked]>
+                Kristian Slavov <[email-masked]>
+                Jeff Ahrenholz <[email-masked]>
+		Abhinav Pathak <[email-masked]>
+		Diego Beltrami <[email-masked]>
+
+Changelog:      May 25, 2005 this document created
+
+
+Description
+-----------
+This patch extends the native Linux 2.6 kernel IPsec to support 
+Bound-End-to-End-Tunnel (BEET) mode for ESP:
+
+Abstract
+
+   This document specifies a new mode, called Bound End-to-End Tunnel
+   (BEET) mode, for IPsec ESP.  The new mode augments the existing ESP
+   tunnel and transport modes.  For end-to-end tunnels, the new mode
+   provides limited tunnel mode semantics without the regular tunnel
+   mode overhead.  The mode is intended to support new uses of ESP,
+   including mobility and multi-address multi-homing.
+
+http://www.ietf.org/internet-drafts/draft-nikander-esp-beet-mode-03.txt
+
+BEET mode architecture
+----------------------
+
+Below are some control flow diagrams to illustrate how BEET works.
+
+Sending (inner IPv4, outer IPv4)(4-4)
+=====================================
+inet_sendmsg
+  raw_sendmsg 
+    ip_route_output_flow
+      __ip_route_output_key
+    xfrm_lookup
+      flow_cache_lookup
+        xfrm_policy_lookup // lookup IPsec policy 
+      xfrm_find_bundle   // lookup IPsec SA
+        __xfrm_selector_match
+      xfrm_tmpl_resolve  // only if bundle was not found!
+        xfrm_state_find
+      xfrm_bundle_create // create output (dst) chain if bundle was not found
+        __xfrm4_bundle_create
+  ip_push_pending_frames
+    dst_output(skb)	//this calls skb->dst->output();	
+     xfrm4_output	//This finally returns 4 (NET_XMIT_BYPASS) to dst_output();
+       xfrm4_encap
+       esp_output
+       xfrm_beet_output	//change the ip header to outer.
+    dst_output(skb)
+     ip_output
+       ip_finish_output	Or ip_fragment 	//depending on size of packet
+          // Returns 0 to dst_output(); which makes dst_output to come out of infinite loop.
+  dev_queue_xmit
+
+
+Receiving (inner IPv4, outer IPv4)(4-4)
+===========
+
+net_rx_action()
+e1000_clean()           // dependent on network hardware
+e1000_clean_rx_irq()
+netif_receive_skb()
+  deliver_skb()
+  ret = pt_prev->func(skb, skb->dev, pt_prev);
+    ip_rcv() 
+      nf_hook()
+      ip_rcv_finish()
+        ip_route_input()
+        dst_input()->ip_forward() or ip_input()
+    ip_input // remove the IPv4 header
+      ip_input_finish 
+        ret = ipprot->handler(&skb, &nhoff); 
+          xfrm4_rcv()
+            xfrm4_rcv_encap() 
+              xfrm4_parse_spi()
+              xfrm_state_lookup() // lookup IPsec SA  
+	      xfrm_beet_input(skb, x) //To change to inner IP header.
+              nexthdr = x->type->input(x, xfrm.decap, skb) // == esp_input
+                esp_input()          // process ESP based on inner address
+                  returns 0 ;
+              /* beet handling in xfrm_rcv_spi */
+              netif_rx()
+      // ip_input_finish returns 0
+  // netif_receive_skb returns 0
+netif_receive_skb	//Now we have an IPv4 packet. So the input flow is for v4 packet.
+  deliver_skb()
+  ret = pt_prev->func(skb, skb->dev, pt_prev);
+    ip_rcv()
+      nf_hook()	//This calls ip_rcv_finish(skb)
+      ip_rcv_finish()	//Here the skb->dst is NULL and so is filled for the input side.
+        ip6_route_input()
+        dst_input()->ip_forward() or ip_input()
+    ip_input // remove the IPv4 header
+      ip_input_finish
+	...
+	 ...
+          ...  
+
+Sending (inner IPv6, outer IPv6)(6-6)
+=============
+
+(When sending the first packet!)
+
+inet_sendmsg
+  rawv6_sendmsg
+    ip6_dst_lookup
+      ip6_route_output
+    xfrm_lookup
+      flow_cache_lookup
+        xfrm_policy_lookup // lookup IPsec policy 
+      xfrm_find_bundle   // lookup IPsec SA
+        __xfrm_selector_match
+      xfrm_tmpl_resolve  // only if bundle was not found!
+        xfrm_state_find
+      xfrm_bundle_create // create output (dst) chain if bundle was not found
+        __xfrm6_bundle_create
+  rawv6_push_pending_frames
+    ip6_push_pending_frames
+      dst_output(skb)
+      	xfrm6_output
+           xfrm6_encap
+           esp6_output
+	   xfrm_beet_output
+      dst_output(skb)
+        ip6_output
+           ip6_output2
+              ip6_output_finish
+    dev_queue_xmit
+
+when are these called?
+    ip6_xmt()
+    dst_output()
+
+
+Receiving (inner IPv6, outer IPv6)(6-6)
+===========
+
+net_rx_action()
+e1000_clean()           // dependent on network hardware
+e1000_clean_rx_irq()
+netif_receive_skb()
+  deliver_skb()
+  ret = pt_prev->func(skb, skb->dev, pt_prev);
+    ipv6_rcv() // skb len = 140
+      nf_hook_slow()
+      ip6_rcv_finish()
+        ip6_route_input()
+        dst_input()->ip6_forward() or ip6_input()
+    ip6_input // remove the IPv6 header
+      ip6_input_finish // calls recursively the ->handler = xfrm6_rcv
+        ret = ipprot->handler(&skb, &nhoff); // handler = xfrm6_rcv_spi
+          xfrm6_rcv()
+            xfrm6_rcv_spi() 
+              xfrm_parse_spi()
+              xfrm_state_lookup() // lookup IPsec SA  
+	      xfrm_beet_input(skb, x) //To change to inner IP header.
+              nexthdr = x->type->input(x, xfrm.decap, skb) // == esp6_input
+                esp6_input()          // process ESP
+                  returns 58 (ICMPv6)	//returns the nexthdr in the ipv6 packet.
+              /* beet handling in xfrm_rcv_spi */
+              netif_rx()
+      // ip6_input_finish returns 0
+  // netif_receive_skb returns 0
+netif_receive_skb
+  deliver_skb()
+  ret = pt_prev->func(skb, skb->dev, pt_prev);
+    ipv6_rcv() // skb len = 104
+      nf_hook_slow()
+      ip6_rcv_finish()
+        ip6_route_input()
+        dst_input()->ip6_forward() or ip6_input()
+    ip6_input // remove the IPv6 header
+      ip6_input_finish
+        xfrm6_policy_check()
+          ..
+            __xfrm_policy_check
+        ret = ipprot->handler(&skb, &nhoff); // handler = xfrm6_rcv_spi
+tcp_v6_rcv()            // or icmpv6_rcv(), anyway, deliver to upper layer
+
+<this is Kristian's text from ARCHITECTURE, fold into above>
+output path
+ip6_datagram_connect()
+  ip6_dst_lookup() // success
+  xfrm_lookup()  // lookup policy using inner IP, matching selectors in SP and
+                    flow information 
+    xfrm_sk_policy_lookup() // success
+    flow_cache_lookup()     // success
+    xfrm_find_bundle() // check for a bundle, if found use it, or create new
+    xfrm_tmpl_resolve() // when creating new, search for SA for each transform
+                        // once valid SA found, use it to create bundle and link
+                        // to SP. modify skbuff's dst-pointer pointing to next
+                        // xfrmX_output(), after encaps/trans dst is consulted
+                        // to route the packet
+      xfrm_state_find() // 
+        xfrm_selector_match() //
+        km_query() //
+
+
+<insert some diagram here describing everything>
+          app                                           app
+           |                                             |
+          inner                                        inner
+            \                                          /
+             -<xfrm_proc>			      /	
+		     \				     /
+		      \--outer               outer--/
+			     \              /  
+			      \===<wire>===/
+
+
+Files changed
+-------------
+This is a list of changes made by the BEET patch.
+
+include/linux/ipsec.h
+ - IPSEC_MODE_BEET added
+   This is the new type of SA that may be created.
+   XXX note: are we overusing XFRM_MODE_BEET where IPSEC_MODE_BEET should be
+             used instead?
+
+include/linux/xfrm.h
+ - enum XFRM_MODE_{TRANSPORT|TUNNEL|BEET} added
+   Mode needed to distinguish from tunnel mode in xfrm code.
+
+include/net/xfrm.h
+ - u16 beet_family added to struct xfrm_state
+   For the outgoing SA, this is the family of the outer address.
+   For the incoming SA, this is the family of the inner address.
+ - unsigned short family added to struct xfrm_tmpl
+   family is required because the family may differ from the one in the selector
+ - possible change to xfrm_selector_match() (commented out)
+
+net/ipv4/xfrm4_input.c
+ - in xfrm4_rcv_encap() change the 
+   ip header to inner before going for esp test.
+ - in xfrm4_rcv_encap() check x->props.mode for XFRM_MODE_TUNNEL, _BEET
+   checks address family (x->props.beet_family), and makes final adjustments 
+   to packet before requeing it.
+
+net/ipv4/xfrm4_output.c 
+ - xfrm4_encap(), note to fix the BEET case, like xfrm6_encap
+ - xfrm4_output() changes the ip header
+
+net/ipv4/esp4.c 
+ - in esp_init_state(), check if x->props.mode == XFRM_MODE_TUNNEL,
+   then x->props.header_len += sizeof(struct ipv6hdr), not if (x->props.mode)
+
+net/ipv6/esp6.c 
+ - in esp6_init_state(), check if x->props.mode == XFRM_MODE_TUNNEL,
+   then x->props.header_len += sizeof(struct ipv6hdr), not if (x->props.mode)
+
+net/ipv6/xfrm6_input.c
+ - xfrm6-rcv_spi(), changes the 
+   inner ip header before sending to esp decapsulation.
+ - in xfrm6_rcv_spi(), handle x->props.mode = XFRM_MODE_BEET
+   checks address family (x->props.beet_family), makes final adjustments to
+   packet before requeing it.
+
+net/ipv6/xfrm6_output.c 
+ - xfrm6_encap() add ipv4 header vars, check if (x->props.mode==XFRM_MODE_BEET)
+   makes space for appropriate esp header and sends to espX_output where X depends
+   on inner family of beet.
+ - xfrm6_output() change if(x->props.mode) to (x->props.mode==XFRM_MODE_TUNNEL)
+   After esp calculations the ip header is changed
+   to outer ip header.
+
+net/ipv6/xfrm6_policy.c
+ (on output...)
+ - in __xfrm6_bundle_create() added remotebeet, localbeet vars,
+   get the IPv6 headers from xfrm[i]->id.daddr (remote) and
+   xfrm[i]->props.saddr (local)
+   copy IPv4 or IPv6 addresses from remote/localbeet to fl_tunnel.fl4/6_dst/src
+   then do xfrm_dst_lookup() passing in xfrm[i]->props.beet_family
+
+net/key/af_key.c
+ - commented-out code in pfkey_msg2xfrm_state():
+   check x->props.beet_family for x->props.family?
+
+ - parse_ipsecrequest() check if (t->mode==IPSEC_MODE_TUNNEL-1)
+   handle if (t->mode==IPSEC_MODE_BEET-1)
+   populate t->saddr.a4 or t->saddr.a6, t->family, etc
+   This supports adding a new type of beet mode SA.
+
+net/xfrm/Kconfig
+ - added XFRM_BEET config variable option and text
+   This allows you to compile BEET mode into your kernel.
+
+net/xfrm/xfrm_policy.c
+ - note from Miika - fns added just for testing, removed for BEET
+   ipv6_addr_is_hit(), hip_xfrm_handler_notify(), hip_xfrm_handler_acquire(),
+   hip_xfrm_handler_policy_notify(), hip_register_xfrm_km_handler(), etc
--- linux-2.6.12.2-orig/include/linux/ipsec.h
+++ linux-2.6.12.2/include/linux/ipsec.h
@@ -13,6 +13,9 @@
 	IPSEC_MODE_ANY		= 0,	/* We do not support this for SA */
 	IPSEC_MODE_TRANSPORT	= 1,
 	IPSEC_MODE_TUNNEL	= 2
+#ifdef CONFIG_XFRM_BEET
+	,IPSEC_MODE_BEET         = 3
+#endif
 };
 
 enum {
--- linux-2.6.12.2-orig/include/linux/xfrm.h
+++ linux-2.6.12.2/include/linux/xfrm.h
@@ -102,6 +102,15 @@
 	XFRM_SHARE_UNIQUE	/* Use once */
 };
 
+enum
+{
+	XFRM_MODE_TRANSPORT = 0,
+	XFRM_MODE_TUNNEL
+#ifdef CONFIG_XFRM_BEET
+	,XFRM_MODE_BEET
+#endif
+};
+
 /* Netlink configuration messages.  */
 enum {
 	XFRM_MSG_BASE = 0x10,
--- linux-2.6.12.2-orig/include/net/xfrm.h
+++ linux-2.6.12.2/include/net/xfrm.h
@@ -113,6 +113,14 @@
 		xfrm_address_t	saddr;
 		int		header_len;
 		int		trailer_len;
+#ifdef CONFIG_XFRM_BEET
+		/* beet_family_out = family of outer addresses
+		 * beet_family_in  = family of inner addresses
+		 */
+		u16		beet_family_in;
+		u16		beet_family_out;
+		
+#endif
 	} props;
 
 	struct xfrm_lifetime_cfg lft;
@@ -241,6 +249,12 @@
 /* Source address of tunnel. Ignored, if it is not a tunnel. */
 	xfrm_address_t		saddr;
 
+/* family of the addresses. In BEET-mode the family may differ from
+   the one in selector */
+#ifdef CONFIG_XFRM_BEET
+	unsigned short		family;
+#endif
+
 	__u32			reqid;
 
 /* Mode: transport/tunnel */
@@ -835,6 +849,12 @@
 extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
 extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
 extern int xfrm6_output(struct sk_buff *skb);
+#ifdef CONFIG_XFRM_BEET
+extern struct xfrm_state * xfrm_lookup_bydst(u8 mode, xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family);
+extern int xfrm_beet_output(struct sk_buff *skb);
+extern int xfrm_beet_input(struct sk_buff *skb, struct xfrm_state *x);
+
+#endif
 
 #ifdef CONFIG_XFRM
 extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
--- linux-2.6.12.2-orig/net/ipv4/esp4.c
+++ linux-2.6.12.2/net/ipv4/esp4.c
@@ -1,3 +1,13 @@
+/*
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
+ */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <net/ip.h>
@@ -23,7 +33,7 @@
 	struct iphdr *top_iph;
 	struct ip_esp_hdr *esph;
 	struct crypto_tfm *tfm;
-	struct esp_data *esp;
+	struct esp_data *esp = x->data;
 	struct sk_buff *trailer;
 	int blksize;
 	int clen;
@@ -31,7 +41,15 @@
 	int nfrags;
 
 	/* Strip IP+ESP header. */
-	__skb_pull(skb, skb->h.raw - skb->data);
+#ifdef CONFIG_XFRM_BEET
+	int hdr_len = skb->h.raw - skb->data + sizeof(*esph) + esp->conf.ivlen;
+	if (x->props.mode == XFRM_MODE_BEET)
+		__skb_pull(skb, hdr_len);
+	else
+		__skb_pull(skb, skb->h.raw - skb->data);
+#else
+        __skb_pull(skb, skb->h.raw - skb->data);
+#endif
 	/* Now skb is pure payload to encrypt */
 
 	err = -ENOMEM;
@@ -39,7 +57,6 @@
 	/* Round to block size */
 	clen = skb->len;
 
-	esp = x->data;
 	alen = esp->auth.icv_trunc_len;
 	tfm = esp->conf.tfm;
 	blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3;
@@ -59,7 +76,14 @@
 	*(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
 	pskb_put(skb, trailer, clen - skb->len);
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_BEET)
+		__skb_push(skb, hdr_len);
+	else
+		__skb_push(skb, skb->data - skb->nh.raw);
+#else
 	__skb_push(skb, skb->data - skb->nh.raw);
+#endif
 	top_iph = skb->nh.iph;
 	esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4);
 	top_iph->tot_len = htons(skb->len + alen);
@@ -428,7 +452,11 @@
 	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;
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TUNNEL)
+#else
 	if (x->props.mode)
+#endif
 		x->props.header_len += sizeof(struct iphdr);
 	if (x->encap) {
 		struct xfrm_encap_tmpl *encap = x->encap;
--- linux-2.6.12.2-orig/net/ipv4/xfrm4_input.c
+++ linux-2.6.12.2/net/ipv4/xfrm4_input.c
@@ -7,6 +7,13 @@
  *	Derek Atkins <[email-masked]>
  *		Add Encapsulation support
  * 	
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <linux/module.h>
@@ -78,6 +85,25 @@
 			goto drop_unlock;
 
 		xfrm_vec[xfrm_nr].decap.decap_type = encap_type;
+
+#ifdef CONFIG_XFRM_BEET
+		if (x->props.mode == XFRM_MODE_BEET) {
+			/* Change the outer header with the inner data */
+			if (x->props.beet_family_in == AF_INET && x->props.beet_family_out == AF_INET){
+				/* Inner = 4, Outer = 4 */
+				struct iphdr *iph = (struct iphdr *)skb->nh.iph;
+				iph->daddr = x->sel.daddr.a4;
+				iph->saddr = x->sel.saddr.a4;
+				iph->ttl--;
+				iph->tot_len = htons(skb->len);
+				iph->frag_off = htons(IP_DF);
+				iph->check = 0;
+				iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+				
+			} else
+				BUG_ON(1);
+		}
+#endif
 		if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
 			goto drop_unlock;
 
@@ -96,7 +122,11 @@
 
 		iph = skb->nh.iph;
 
+#ifdef CONFIG_XFRM_BEET
+		if (x->props.mode == XFRM_MODE_TUNNEL) {
+#else
 		if (x->props.mode) {
+#endif
 			if (iph->protocol != IPPROTO_IPIP)
 				goto drop;
 			if (!pskb_may_pull(skb, sizeof(struct iphdr)))
@@ -115,9 +145,35 @@
 			decaps = 1;
 			break;
 		}
+#ifdef CONFIG_XFRM_BEET
+		else if (x->props.mode == XFRM_MODE_BEET) {
+			struct iphdr *iph = skb->nh.iph;
+			int size = sizeof(struct iphdr);
+
+			if (skb_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				goto drop;
 
-		if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
+			skb_push(skb, size);
+
+			memmove(skb->data, skb->nh.raw, size);
+			skb->mac.raw = memmove(skb->data - skb->mac_len,
+					       skb->mac.raw, skb->mac_len);
+			skb->nh.raw = skb->data;
+			iph->tot_len = htons(skb->len);
+			iph->check = 0;
+			iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+			skb->protocol = htons(ETH_P_IP);
+			dst_release(skb->dst);
+			skb->dst = NULL;
+			decaps = 1;
+			
+			break;
+		}
+#endif
+	        if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
 			goto drop;
+
 	} while (!err);
 
 	/* Allocate new secpath or COW existing one. */
--- linux-2.6.12.2-orig/net/ipv4/xfrm4_output.c
+++ linux-2.6.12.2/net/ipv4/xfrm4_output.c
@@ -6,6 +6,14 @@
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <linux/skbuff.h>
@@ -26,7 +34,8 @@
  *	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.
+ * by x->type->output and skb->nh, as well as skb->data, will point to 
+ * the top IP header.
  */
 static void xfrm4_encap(struct sk_buff *skb)
 {
@@ -35,15 +44,36 @@
 	struct iphdr *iph, *top_iph;
 
 	iph = skb->nh.iph;
-	skb->h.ipiph = iph;
+#ifdef CONFIG_XFRM_BEET
+        /*
+         * This is because otherwise the BEET patch crashes in any case with Inner=4
+         */
+        if (x->props.mode != XFRM_MODE_BEET)
+                skb->h.ipiph = iph;
+#else
+        skb->h.ipiph = iph;
+#endif
 
 	skb->nh.raw = skb_push(skb, x->props.header_len);
 	top_iph = skb->nh.iph;
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TRANSPORT) {
+#else
 	if (!x->props.mode) {
+#endif
+
 		skb->h.raw += iph->ihl*4;
 		memmove(top_iph, iph, iph->ihl*4);
 		return;
+#ifdef CONFIG_XFRM_BEET
+	} else if (x->props.mode == XFRM_MODE_BEET) {
+
+		skb->h.raw = skb->data + sizeof(struct iphdr);
+		memmove(top_iph, iph, iph->ihl*4);
+		return;
+
+#endif /* CONFIG_XFRM_BEET */
 	}
 
 	top_iph->ihl = 5;
@@ -103,7 +133,11 @@
 			goto error_nolock;
 	}
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TUNNEL) {
+#else
 	if (x->props.mode) {
+#endif
 		err = xfrm4_tunnel_check_size(skb);
 		if (err)
 			goto error_nolock;
@@ -120,6 +154,21 @@
 	if (err)
 		goto error;
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_BEET) {
+		/* Change the outer header */
+		if (x->props.beet_family_in == AF_INET && x->props.beet_family_out == AF_INET){
+			struct iphdr *iph = (struct iphdr*)skb->data;
+			iph->saddr = x->props.saddr.a4;
+			iph->daddr = x->id.daddr.a4;
+			skb->local_df = 1;	//I am a bit unsure on how to implement this -Abi
+			iph->check = 0;
+			iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+		} else
+			BUG_ON(1);
+	}
+#endif
+
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;

--- linux-2.6.12.2-orig/net/ipv4/xfrm4_policy.c	2005-06-30 02:00:53.000000000 +0300
+++ linux-2.6.12.2/net/ipv4/xfrm4_policy.c	2005-08-01 15:05:26.000000000 +0300
@@ -6,6 +6,14 @@
  * 	YOSHIFUJI Hideaki @USAGI
  *		Split up af-specific portion
  * 	
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <asm/bug.h>
@@ -66,6 +74,12 @@
 			}
 		}
 	};
+#ifdef CONFIG_XFRM_BEET
+	union {
+		struct in6_addr *in6;
+		struct in_addr *in;
+	} remotebeet, localbeet;
+#endif
 	int i;
 	int err;
 	int header_len = 0;
@@ -78,6 +92,9 @@
 		struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
 		struct xfrm_dst *xdst;
 		int tunnel = 0;
+#ifdef CONFIG_XFRM_BEET
+		unsigned short beet_family = 0;
+#endif
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
@@ -98,11 +115,26 @@
 
 		dst1->next = dst_prev;
 		dst_prev = dst1;
+#ifdef CONFIG_XFRM_BEET
+		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+#else
 		if (xfrm[i]->props.mode) {
+#endif
 			remote = xfrm[i]->id.daddr.a4;
 			local  = xfrm[i]->props.saddr.a4;
 			tunnel = 1;
 		}
+#ifdef CONFIG_XFRM_BEET
+		else if (xfrm[i]->props.mode == XFRM_MODE_BEET) {
+
+			if(xfrm[i]->props.beet_family_out == AF_INET){
+				remotebeet.in = (struct in_addr*)&xfrm[i]->id.daddr;
+				localbeet.in = (struct in_addr*)&xfrm[i]->props.saddr;
+				beet_family = xfrm[i]->props.beet_family_out;
+			} else
+				BUG_ON(1);
+		}
+#endif
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
 
@@ -113,6 +145,18 @@
 					      &fl_tunnel, AF_INET);
 			if (err)
 				goto error;
+#ifdef CONFIG_XFRM_BEET
+		} else if (beet_family) {
+			fl_tunnel.fl4_dst = remotebeet.in->s_addr;
+			fl_tunnel.fl4_src = localbeet.in->s_addr;
+			
+			err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
+					      &fl_tunnel, beet_family);
+			/* Without this, the BEET mode crashes
+			   indeterministically -Abi */
+			rt->peer = NULL;
+			rt_bind_peer(rt,1);
+#endif
 		} else
 			dst_hold(&rt->u.dst);
 	}
--- linux-2.6.12.2-orig/net/ipv6/esp6.c
+++ linux-2.6.12.2/net/ipv6/esp6.c
@@ -22,6 +22,16 @@
  * 	Kunihiro Ishiguro <[email-masked]>
  * 	
  * 	This file is derived from net/ipv4/esp.c
+ *
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
+ *
  */
 
 #include <linux/config.h>
@@ -365,7 +375,11 @@
 	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;
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TUNNEL)
+#else
 	if (x->props.mode)
+#endif
 		x->props.header_len += sizeof(struct ipv6hdr);
 	x->data = esp;
 	return 0;
--- linux-2.6.12.2-orig/net/ipv6/xfrm6_input.c
+++ linux-2.6.12.2/net/ipv6/xfrm6_input.c
@@ -64,6 +64,18 @@
 		if (xfrm_state_check_expire(x))
 			goto drop_unlock;
 
+#ifdef CONFIG_XFRM_BEET
+		if (x->props.mode == XFRM_MODE_BEET) {
+			if (x->props.beet_family_in == AF_INET6 && x->props.beet_family_out == AF_INET6){
+				struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->nh.raw;
+				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
+				BUG_ON(1);
+		}
+#endif
 		nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb);
 		if (nexthdr <= 0)
 			goto drop_unlock;
@@ -80,7 +92,11 @@
 
 		xfrm_vec[xfrm_nr++].xvec = x;
 
+#ifdef CONFIG_XFRM_BEET
+		if (x->props.mode == XFRM_MODE_TUNNEL) {
+#else
 		if (x->props.mode) { /* XXX */
+#endif
 			if (nexthdr != IPPROTO_IPV6)
 				goto drop;
 			if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
@@ -97,6 +113,33 @@
 			skb->nh.raw = skb->data;
 			decaps = 1;
 			break;
+#ifdef CONFIG_XFRM_BEET
+		} else if (x->props.mode == XFRM_MODE_BEET) {
+			struct ipv6hdr *ip6h = skb->nh.ipv6h;
+			int size = sizeof(struct ipv6hdr);
+			__u16 total = ntohs(ip6h->payload_len);
+
+			/* is the buffer a clone?
+			 * then create identical copy of header of skb */
+			if (skb_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				goto drop;
+
+			/* add data to the start of the buffer */
+			skb_push(skb, size);
+			/* move the raw header into new space */
+			memmove(skb->data, skb->nh.raw, size);
+			/* move MAC header */
+			skb->mac.raw = memmove(skb->data - skb->mac_len,
+					       skb->mac.raw, skb->mac_len);
+			skb->nh.raw = skb->data;
+
+			ip6h->payload_len = htons(total + size);
+			--ip6h->hop_limit;
+			decaps = 1;
+
+			break;
+#endif
 		}
 
 		if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
--- linux-2.6.12.2-orig/net/ipv6/xfrm6_output.c
+++ linux-2.6.12.2/net/ipv6/xfrm6_output.c
@@ -7,6 +7,14 @@
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <linux/skbuff.h>
@@ -17,6 +25,10 @@
 #include <net/ipv6.h>
 #include <net/xfrm.h>
 
+#ifdef CONFIG_XFRM_BEET
+#include <net/ip.h>
+#endif
+
 /* Add encapsulation header.
  *
  * In transport mode, the IP header and mutable extension headers will be moved
@@ -42,7 +54,12 @@
 	skb_push(skb, x->props.header_len);
 	iph = skb->nh.ipv6h;
 
+
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TRANSPORT) {
+#else
 	if (!x->props.mode) {
+#endif
 		u8 *prevhdr;
 		int hdr_len;
 
@@ -51,6 +68,16 @@
 		skb->h.raw = skb->data + hdr_len;
 		memmove(skb->data, iph, hdr_len);
 		return;
+
+#ifdef CONFIG_XFRM_BEET
+	} else if (x->props.mode == XFRM_MODE_BEET) {
+	        
+		memmove(skb->data, skb->nh.raw, sizeof(struct ipv6hdr));
+		skb->nh.raw = &((struct ipv6hdr *)skb->data)->nexthdr;
+		skb->h.ipv6h = ((struct ipv6hdr *)skb->data) + 1;
+		return;
+
+#endif /* CONFIG_XFRM_BEET */
 	}
 
 	skb->nh.raw = skb->data;
@@ -104,7 +131,11 @@
 			goto error_nolock;
 	}
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_TUNNEL) {
+#else
 	if (x->props.mode) {
+#endif
 		err = xfrm6_tunnel_check_size(skb);
 		if (err)
 			goto error_nolock;
@@ -121,6 +152,19 @@
 	if (err)
 		goto error;
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_BEET) {
+		/* Change the outer header */
+		if (x->props.beet_family_in == AF_INET6 && x->props.beet_family_out == AF_INET6){
+			/* Inner = 6, Outer = 6 */
+			struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+			ipv6_addr_copy(&iph->saddr, (struct in6_addr *)&x->props.saddr);
+			ipv6_addr_copy(&iph->daddr, (struct in6_addr *)&x->id.daddr);
+		} else
+			BUG_ON(1);
+	}
+#endif
+
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 
--- linux-2.6.12.2-orig/net/ipv6/xfrm6_policy.c
+++ linux-2.6.12.2/net/ipv6/xfrm6_policy.c
@@ -8,7 +8,14 @@
  * 		IPv6 support
  * 	YOSHIFUJI Hideaki
  * 		Split up af-specific portion
- * 
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <[email-masked]>
+ *          Diego Beltrami <[email-masked]>
+ *          Kristian Slavov <[email-masked]>
+ *          Miika Komu <[email-masked]>
+ *          Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <asm/bug.h>
@@ -84,6 +91,12 @@
 			}
 		}
 	};
+#ifdef CONFIG_XFRM_BEET
+	union {
+		struct in6_addr *in6;
+		struct in_addr *in;
+	} remotebeet, localbeet;
+#endif	
 	int i;
 	int err = 0;
 	int header_len = 0;
@@ -96,6 +109,9 @@
 		struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
 		struct xfrm_dst *xdst;
 		int tunnel = 0;
+#ifdef CONFIG_XFRM_BEET
+		unsigned short beet_family = 0;
+#endif	
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
@@ -118,11 +134,25 @@
 
 		dst1->next = dst_prev;
 		dst_prev = dst1;
+#ifdef CONFIG_XFRM_BEET
+		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
+#else
 		if (xfrm[i]->props.mode) {
+#endif
 			remote = (struct in6_addr*)&xfrm[i]->id.daddr;
 			local  = (struct in6_addr*)&xfrm[i]->props.saddr;
 			tunnel = 1;
 		}
+#ifdef CONFIG_XFRM_BEET
+		else if (xfrm[i]->props.mode == XFRM_MODE_BEET) {
+			if (xfrm[i]->props.beet_family_out == AF_INET6) {
+				beet_family = xfrm[i]->props.beet_family_out;
+				remotebeet.in6 = (struct in6_addr*)&xfrm[i]->id.daddr;
+				localbeet.in6 = (struct in6_addr*)&xfrm[i]->props.saddr;
+			} else
+				BUG_ON(1);
+		}
+#endif
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
 
@@ -133,6 +163,13 @@
 					      &fl_tunnel, AF_INET6);
 			if (err)
 				goto error;
+#ifdef CONFIG_XFRM_BEET
+		} else if (beet_family) {
+			ipv6_addr_copy(&fl_tunnel.fl6_dst, remotebeet.in6);
+			ipv6_addr_copy(&fl_tunnel.fl6_src, localbeet.in6);
+			err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
+					      &fl_tunnel, beet_family);
+#endif
 		} else
 			dst_hold(&rt->u.dst);
 	}
--- linux-2.6.12.2-orig/net/key/af_key.c
+++ linux-2.6.12.2/net/key/af_key.c
@@ -12,6 +12,14 @@
  *		Kunihiro Ishiguro <[email-masked]>
  *		Kazunori MIYAZAWA / USAGI Project <[email-masked]>
  *		Derek Atkins <[email-masked]>
+ *
+ * Changes:     BEET support
+ *              Abhinav Pathak <[email-masked]>
+ *              Diego Beltrami <[email-masked]>
+ *              Kristian Slavov <[email-masked]>
+ *              Miika Komu <[email-masked]>
+ *              Jeff Ahrenholz <[email-masked]>
+ *
  */
 
 #include <linux/config.h>
@@ -28,6 +36,10 @@
 #include <linux/init.h>
 #include <net/xfrm.h>
 
+#ifdef CONFIG_XFRM_BEET
+#include <linux/xfrm.h>
+#endif
+
 #include <net/sock.h>
 
 #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
@@ -1584,7 +1596,11 @@
 	}
 
 	/* addresses present only in tunnel mode */
+#ifdef CONFIG_XFRM_BEET
+	if (t->mode == IPSEC_MODE_TUNNEL-1) {
+#else
 	if (t->mode) {
+#endif
 		switch (xp->family) {
 		case AF_INET:
 			sin = (void*)(rq+1);
@@ -1612,6 +1628,40 @@
 			return -EINVAL;
 		}
 	}
+#ifdef CONFIG_XFRM_BEET
+	else if (t->mode == IPSEC_MODE_BEET-1) {
+		struct sockaddr *sa;
+
+		sa = (struct sockaddr *)(rq+1);
+		switch(sa->sa_family) {
+		case AF_INET:
+			sin = (struct sockaddr_in *)sa;
+			t->saddr.a4 = sin->sin_addr.s_addr;
+			sin++;
+			if (sin->sin_family != AF_INET)
+				return -EINVAL;
+			t->id.daddr.a4 = sin->sin_addr.s_addr;
+			t->family = AF_INET;
+
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case AF_INET6:
+			sin6 = (struct sockaddr_in6 *)sa;
+			memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
+			sin6++;
+			if (sin6->sin6_family != AF_INET6)
+				return -EINVAL;
+			memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
+			t->family = AF_INET6;
+
+			break;
+#endif /* CONFIG_IPV6 */
+		default:
+			return -EINVAL;
+		}
+	}
+#endif /* CONFIG_XFRM_BEET */
+
 	/* No way to set this via kame pfkey */
 	t->aalgos = t->ealgos = t->calgos = ~0;
 	xp->xfrm_nr++;
@@ -1935,6 +1985,48 @@
 	    (err = parse_ipsecrequests(xp, pol)) < 0)
 		goto out;
 
+#ifdef CONFIG_XFRM_BEET
+	/* lookup the SA (xfrm_state) and copy the inner addresses from
+	 * the policy (xfrm_policy) to the selector within the state
+	 */
+	if (xp->xfrm_vec[0].mode == IPSEC_MODE_BEET-1) {
+		struct xfrm_state *x;
+		if (xp->family == AF_INET6) {
+			if ((x = xfrm_lookup_bydst(XFRM_MODE_BEET, 
+						&xp->xfrm_vec[0].id.daddr,
+						&xp->xfrm_vec[0].saddr,
+						AF_INET6))) {
+				/* Inner = 6, Outer = 6 */
+				x->props.beet_family_out = AF_INET6;
+				x->props.beet_family_in = AF_INET6;
+				/* insert inner addresses into the selector */
+				memcpy(	&x->sel.daddr, &xp->selector.daddr,
+					sizeof(xfrm_address_t));
+				memcpy(	&x->sel.saddr, &xp->selector.saddr,
+					sizeof(xfrm_address_t));
+				x->type = xfrm_get_type(x->id.proto, x->props.beet_family_in);
+			}
+		} else if (xp->family == AF_INET) {
+			if ((x = xfrm_lookup_bydst(XFRM_MODE_BEET, 
+						   &xp->xfrm_vec[0].id.daddr,
+						   &xp->xfrm_vec[0].saddr, 
+						    AF_INET)))
+			{
+				/* Inner = 4, Outer = 4 */
+				x->props.beet_family_out = AF_INET;
+				x->props.beet_family_in = AF_INET;
+				/* insert inner addresses into the selector */
+				memcpy(	&x->sel.daddr, &xp->selector.daddr,
+					sizeof(xfrm_address_t));
+				memcpy(	&x->sel.saddr, &xp->selector.saddr,
+					sizeof(xfrm_address_t));
+				x->type = xfrm_get_type(x->id.proto, x->props.beet_family_in);
+			}
+		} else {
+			BUG_ON(1);
+		}
+	}
+#endif
 	out_skb = pfkey_xfrm_policy2msg_prep(xp);
 	if (IS_ERR(out_skb)) {
 		err =  PTR_ERR(out_skb);
--- linux-2.6.12.2-orig/net/xfrm/Kconfig
+++ linux-2.6.12.2/net/xfrm/Kconfig
@@ -10,3 +10,19 @@
 
 	  If unsure, say Y.
 
+config XFRM_BEET
+        bool "IPsec BEET mode"
+        depends on XFRM
+        ---help---
+          IPsec BEET mode is combination of IPsec transport and tunnel mode.
+          Currently, it is used only by HIP.
+
+          If unsure, say N.
+
+config XFRM_BEET_DEBUG
+        bool "IPsec BEET mode debugging"
+        depends on XFRM_BEET
+        ---help---
+          Enables BEET mode debugging via syslog.
+
+          If unsure, say N.
--- linux-2.6.12.2-orig/net/xfrm/xfrm_state.c
+++ linux-2.6.12.2/net/xfrm/xfrm_state.c
@@ -1036,3 +1036,31 @@
 	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
 }
 
+#ifdef CONFIG_XFRM_BEET
+
+struct xfrm_state *
+xfrm_lookup_bydst(u8 mode, xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family)
+{
+	struct xfrm_state *x;
+	unsigned h = xfrm_dst_hash(daddr, family);
+
+	list_for_each_entry(x, xfrm_state_bydst+h, bydst){
+		
+		if (x->props.family == AF_INET6 &&
+		    ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
+		    mode == x->props.mode &&
+		    ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6)) {
+			return(x);
+		}
+		
+		if (x->props.family == AF_INET &&
+		    daddr->a4 == x->id.daddr.a4 &&
+		    mode == x->props.mode &&
+		    saddr->a4 == x->props.saddr.a4)
+			return(x);
+		
+	}
+	return(NULL);
+}
+
+#endif //CONFIG_XFRM_BEET
_______________________________________________
Hipsec mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/hipsec

---

From: Miika Komu <[email-masked]>
Date: Wed, 3 Aug 2005 23:57:24 +0300 (EEST)

On Tue, 2 Aug 2005, Diego Beltrami wrote:

Hi Herbert and others,

(sorry for the late comments - I am still on a holiday :)

> ...

Based on the comments from Pekka Nikander, it seems like to me that
generalizing XFRM to support AH with different inner and outer families
may not very useful (a). On the other hand, the different inner and outer
families for BEET is *extremely* useful (b). Excluding this support from
BEET restricts the HIP implementations and applications quite radically.

My own thinking logic tells me the (a) + (b) equals to supporting
different inner and outer families in BEET in the way it is implemented
currently.  Don't fix it if it ain't broken!)

We have tested that the BEET with different inner and outer addresses does
not break anything. Further, if you don't need it, you don't have to
compile it in :) Later, if AH seems really useful with different inner and
outer families, or a new XYZ header is introduced, we can refactor the
architecture for greater modularity. Even then, the XFRM/PFKEY APIs
should remain the same.

So, I'd vote for the original BEET patch, but of course it is up to you to
decide. The BEET support is the minimal support required from the kernel
in order for a usepace HIP implementation to work, and it would make both
HIP implementors and users life much more easier :) Additionally, we would
gain also more experience from using mixed inner and outer families within
the XFRM architecture.

-- 
Miika Komu              [email-masked]          http://www.iki.fi/miika/

---

From: Herbert Xu <[email-masked]>
Date: Thu, 4 Aug 2005 09:40:52 +1000

> inter-family transform (i.e. inner address family different than outer

Thanks for the new patch.  Unfortunately it really looks quite similar
to the previous patch :)

> +++ linux-2.6.12.2/net/ipv4/esp4.c

I thought getting rid of the interfamily stuff would remove the
need to touch this file, no?

Thanks,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email-masked]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

---

From: Diego Beltrami <[email-masked]>
Date: Thu, 04 Aug 2005 17:38:31 +0300

> Well to me it's more of an issue of maintainability.  BEET mode is
> more akin to transport/tunnel mode than AH/ESP/IPcomp.  As such its
> implementation would be most at home where the existing encapsulation
> and decapsulation for transport/tunnel mode is done.  That is, in
> xfrm[46]_input.c and xfrm[46]_output.c.
> 
> For instance, the reason the current patch has to touch esp4.c at
> all is really because the patch to xfrm4_output.c isn't right.
> It should do what the comment says and set skb->h to the start
> of the payload, not the start of the ESP header.  If it did that,
> then esp_output doesn't have to care about BEET at all.

This is totally true, and I agree with you but then this is somehow a 
controversial thing with respect to the esp6_output. In fact the 
esp6_output has the same purpose of esp_output, but it requires the 
skb->h to be set at the beginning of ESP header.

> 
> Also, the outer header generation should be done before
> x->type->output is called, not after.  That way, the AH
> semantics falls out quite naturally.

BEET has been designed to be compatible with HIP. This means that the 
ESP header should be computed with respect to the inner addresses.
In a very first implementation of BEET we were converting the inner 
addresses to the outer addresses before x->type->output, but we couldn't 
make interoperate BEET with HIP.
That's the reason why the outer header generation has been after 
x->type->output.

This is one of the reasons why the AH, as Pekka Nikader said, is a bit 
trickier with respect to ESP (the AH protocol protects the IP datagram 
including immutable parts of the IP header like the IP addresses whereas 
for ESP the IP header is not included in the calculation process).

--Diego

---

From: Herbert Xu <[email-masked]>
Date: Thu, 4 Aug 2005 23:15:19 +1000

Hi Miika:

> BEET restricts the HIP implementations and applications quite radically.

I agree with you wholeheartedly that this is extremely useful.
However, I also see nothing that's BEET-specific about this
feature.

So for the sake of the overall consistency of the IPsec stack
please keep the implementation generic instead of BEET-specific.
That is, please do it in a way so that it applies to plain
tunnel mode as well.

Cheers,