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

Diego Beltrami <diego.beltrami@HIIT.FI> Mon, 25 July 2005 12:42 UTC

Received: from localhost.localdomain ([127.0.0.1] helo=megatron.ietf.org) by megatron.ietf.org with esmtp (Exim 4.32) id 1Dx2Hd-0005Iu-Mg; Mon, 25 Jul 2005 08:42:13 -0400
Received: from odin.ietf.org ([132.151.1.176] helo=ietf.org) by megatron.ietf.org with esmtp (Exim 4.32) id 1Dx2HZ-0005IU-I8 for hipsec@megatron.ietf.org; Mon, 25 Jul 2005 08:42:12 -0400
Received: from ietf-mx.ietf.org (ietf-mx [132.151.6.1]) by ietf.org (8.9.1a/8.9.1a) with ESMTP id IAA15375 for <hipsec@ietf.org>; Mon, 25 Jul 2005 08:42:08 -0400 (EDT)
Received: from pegasus.hiit.fi ([212.68.1.186]) by ietf-mx.ietf.org with esmtp (Exim 4.43) id 1Dx2mN-0000hR-TY for hipsec@ietf.org; Mon, 25 Jul 2005 09:14:02 -0400
Received: from [128.214.113.174] (odysse.hiit.fi [128.214.113.174]) by pegasus.hiit.fi (Postfix) with ESMTP id 1F1F1220013; Mon, 25 Jul 2005 15:41:48 +0300 (EEST)
From: Diego Beltrami <diego.beltrami@HIIT.FI>
To: netdev@oss.sgi.com
Content-Type: text/plain
Organization: HIIT
Message-Id: <1122295307.14873.37.camel@odysse>
Mime-Version: 1.0
X-Mailer: Ximian Evolution 1.4.6 (1.4.6-2)
Date: Mon, 25 Jul 2005 15:41:48 +0300
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Scan-Signature: b382e0fda7380faa630530317e47f8e4
Content-Transfer-Encoding: 7bit
Cc: hipl-users@freelists.org, hipsec@ietf.org, infrahip@HIIT.FI, kristian.slavov@nomadiclab.com
Subject: [Hipsec] [PATCH 2.6.12.2] XFRM: BEET IPsec mode for Linux
X-BeenThere: hipsec@lists.ietf.org
X-Mailman-Version: 2.1.5
Precedence: list
Reply-To: diego.beltrami@HIIT.FI
List-Id: "This is the official IETF Mailing List for the HIP Working Group." <hipsec.lists.ietf.org>
List-Unsubscribe: <https://www1.ietf.org/mailman/listinfo/hipsec>, <mailto:hipsec-request@lists.ietf.org?subject=unsubscribe>
List-Archive: <http://www1.ietf.org/pipermail/hipsec>
List-Post: <mailto:hipsec@lists.ietf.org>
List-Help: <mailto:hipsec-request@lists.ietf.org?subject=help>
List-Subscribe: <https://www1.ietf.org/mailman/listinfo/hipsec>, <mailto:hipsec-request@lists.ietf.org?subject=subscribe>
Sender: hipsec-bounces@lists.ietf.org
Errors-To: hipsec-bounces@lists.ietf.org

Hi folks,

we have been working for three months to implement a new IPsec mode,
the "BEET" mode, for Linux. Below is a link to the BEET specification
and
the abstract:

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

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.

The BEET mode is required by the Host Identity Protocol (HIP), which
provides authenticated Diffie-Hellman for end-hosts, as well as
mobility and multihoming support. The BEET mode is also useful for
other similar protocols being developed at the IETF.

Ericsson has already developed a BEET patch for *BSD. Our patch
provides the similar functionality, but using the XFRM architecture.
The patch is included at the end of this email and also at the following
URL:
http://hipl.hiit.fi/beet/beet-patch-v1.0-2.6.12.2

We have made some testing in order to assure the quality of the
patch. All the tests passed, and below is a list of them:

* Does not break transport and tunnel mode (with CONFIG_XFRM_BEET
on/off)
* All inner-outer combinations with varying test applications:
  ICMP, ICMPv6, FTP, SSH, nc, nc6
* Works with fragmented packets
* Interoperability with HIPL
* Real machines, virtual machines (vmware)
* Tested with long data streams

The BEET development team:

* Abhinav Pathak <abpathak@iitk.ac.in> (InfraHIP/HIIT)
* Diego Beltrami <diego.beltrami@hiit.fi> (InfraHIP/HIIT)
* Kristian Slavov <kristian.slavov@nomadiclab.com> (Ericsson)
* Miika Komu <miika@iki.fi> (InfraHIP/HIIT)
* Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com> (Boeing)

On the behalf of the BEET development team,

Signed-off-by: Diego Beltrami <diego.beltrami@hiit.fi>




diff -urN linux-2.6.12.2/Documentation/README.BEET
linux-beet-2.6.12.2/Documentation/README.BEET
--- linux-2.6.12.2/Documentation/README.BEET	1970-01-01
02:00:00.000000000 +0200
+++ linux-beet-2.6.12.2/Documentation/README.BEET	2005-07-25
14:39:36.000000000 +0300
@@ -0,0 +1,465 @@
+Linux BEET-mode ESP patch
+
+Authors:        Miika Komu <miika@iki.fi>
+                Kristian Slavov <kristian.slavov@nomadiclab.com>
+                Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+		Abhinav Pathak <abpathak@iitk.ac.in>
+		Diego Beltrami <diego.beltrami@hiit.fi>
+
+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 IPv4)(6-4)
+=====================================
+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			//esp calculation is done on inner addresses
!!
+	   xfrm_beet_output		//Change the ip header to outer IP Header
+      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 IPv6, outer IPv4)(6-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() // skb len = 140
+      nf_hook()
+      ip_rcv_finish()
+        ip_route_input()
+        dst_input()->ip_forward() or ip_input()
+    ip_input // remove the IPv6 header
+      ip_input_finish // calls recursively the ->handler = xfrm6_rcv
+        ret = ipprot->handler(&skb, &nhoff); // handler = xfrm6_rcv_spi
+          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) // ==
esp6_input
+                esp6_input()          // process ESP based on inner
address
+                  returns 0 ;
+              /* 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);
+    ip6_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
+
+
+Sending (inner IPv4, outer IPv6)(4-6)
+=====================================
+
+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	
+    dst_output(skb)
+      ip6_output
+        ip6_output2
+	  ip6_output_finish	// Returns 0 to dst_output(); which makes
dst_output to come out of infinite loop.
+    dev_queue_xmit
+
+
+Receiving (inner IPv4, outer IPv6)(4-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) // ==
esp_input
+                esp_input()          // process ESP
+                  returns iph->protocol ;
+              /* beet handling in xfrm_rcv_spi */
+              netif_rx()
+      // ip6_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.
+        ip_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 Added
+--------------
+This is a list of the included files for the BEET patch
+
+net/xfrm/xfrm_beet.c
+- This file contains the functions xfrm_beet_input() and
xfrm_beet_output()
+  which deals with the incoming and the outgoing BEET packets,
respectively.
+  The purpose of these functions is to interchange the inner addresses
with 
+  the outer addresses in the IP header (in case of outgoing packets)
and viceversa
+  (in case of incoming packets).
+  The file describes two functions:
+	1. xfrm_beet_input
+		Used in receiving side, changes the ip header to inner ip header
+	2. xfrm_beet_output
+		Used in sending side, changes the ip header to outer ip header
+
+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() call is made to xfrm_beet_input(), to 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(), added a call to xfrm_beet_output() to change 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)
+ - in esp_input(), while returning, if the outer family is AF_INET6,
then return 
+   iph->protocol, else return 0.
+
+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)
+ - in esp6_input(), while returning, if the outer family is AF_INET,
then 
+   set next header field and return 0, else return ret.
+
+
+net/ipv6/xfrm6_input.c
+ - in xfrm6-rcv_spi(), call is made to xfrm_beet_input(), which changes
to 
+   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)
+   Also a call is made to xfrm_beet_output after esp calculations, to
change the
+   ip header 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
diff -urN linux-2.6.12.2/include/linux/ipsec.h
linux-beet-2.6.12.2/include/linux/ipsec.h
--- linux-2.6.12.2/include/linux/ipsec.h	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/include/linux/ipsec.h	2005-07-25
14:39:01.000000000 +0300
@@ -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 {
diff -urN linux-2.6.12.2/include/linux/xfrm.h
linux-beet-2.6.12.2/include/linux/xfrm.h
--- linux-2.6.12.2/include/linux/xfrm.h	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/include/linux/xfrm.h	2005-07-25
14:39:01.000000000 +0300
@@ -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,
diff -urN linux-2.6.12.2/include/net/xfrm.h
linux-beet-2.6.12.2/include/net/xfrm.h
--- linux-2.6.12.2/include/net/xfrm.h	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/include/net/xfrm.h	2005-07-25 15:03:01.000000000
+0300
@@ -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);
diff -urN linux-2.6.12.2/net/ipv4/esp4.c
linux-beet-2.6.12.2/net/ipv4/esp4.c
--- linux-2.6.12.2/net/ipv4/esp4.c	2005-06-30 02:00:53.000000000 +0300
+++ linux-beet-2.6.12.2/net/ipv4/esp4.c	2005-07-25 14:39:11.000000000
+0300
@@ -1,3 +1,13 @@
+/*
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
+ */
+
 #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);
@@ -238,7 +262,14 @@
 		skb->nh.iph->tot_len = htons(skb->len);
 	}
 
+#ifdef CONFIG_XFRM_BEET
+	if(x->props.mode == XFRM_MODE_BEET && x->props.beet_family_out ==
AF_INET6)
+		return iph->protocol ;
+	else
+		return 0;
+#else
 	return 0;
+#endif
 
 out:
 	return -EINVAL;
@@ -428,7 +459,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;
diff -urN linux-2.6.12.2/net/ipv4/xfrm4_input.c
linux-beet-2.6.12.2/net/ipv4/xfrm4_input.c
--- linux-2.6.12.2/net/ipv4/xfrm4_input.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv4/xfrm4_input.c	2005-07-25
14:39:11.000000000 +0300
@@ -7,6 +7,13 @@
  *	Derek Atkins <derek@ihtfp.com>
  *		Add Encapsulation support
  * 	
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #include <linux/module.h>
@@ -78,6 +85,14 @@
 			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 (xfrm_beet_input(skb, x))
+				goto drop_unlock;
+		}
+#endif
 		if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
 			goto drop_unlock;
 
@@ -96,7 +111,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 +134,69 @@
 			decaps = 1;
 			break;
 		}
+#ifdef CONFIG_XFRM_BEET
+		else if (x->props.mode == XFRM_MODE_BEET) {
+			struct iphdr *iph = skb->nh.iph;
+			struct ipv6hdr *ip6h = skb->nh.ipv6h;
+			int size = 0;
+
+			if (skb_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				goto drop;
+
+			if (x->props.beet_family_in == AF_INET)
+				size = sizeof(struct iphdr);
+			else if (x->props.beet_family_in == AF_INET6)
+				size = sizeof(struct ipv6hdr);
+			else
+				BUG_ON(1);
+
+			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;
 
-		if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) <
0)
+			switch(x->props.beet_family_in) {
+			case AF_INET:
+
+				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;
+			case AF_INET6:
+				ip6h = skb->nh.ipv6h;
+
+				skb->nh.ipv6h->payload_len =
htons(ntohs(skb->nh.ipv6h->payload_len) + size);
+				skb->protocol = htons(ETH_P_IPV6);
+
+				dst_release(skb->dst);
+				skb->dst = NULL;
+				decaps = 1;
+				break;
+			default:
+				BUG_ON(1);
+			}
+			break;
+		}
+		
+		if (x->props.mode == XFRM_MODE_BEET && x->props.beet_family_in ==
AF_INET6) {
+			if ((err = xfrm_parse_spi(skb, skb->nh.ipv6h->nexthdr, &spi, &seq))
< 0)
+				goto drop;
+		} else {
+			if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) <
0)
+				goto drop;
+		}
+#else
+	        if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi,
&seq)) < 0)
 			goto drop;
+#endif
 	} while (!err);
 
 	/* Allocate new secpath or COW existing one. */
diff -urN linux-2.6.12.2/net/ipv4/xfrm4_output.c
linux-beet-2.6.12.2/net/ipv4/xfrm4_output.c
--- linux-2.6.12.2/net/ipv4/xfrm4_output.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv4/xfrm4_output.c	2005-07-25
14:39:11.000000000 +0300
@@ -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 <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #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,15 @@
 	if (err)
 		goto error;
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_BEET) {
+		/* Change the outer header */
+		err = xfrm_beet_output(skb);
+		if (err)
+			goto error;
+	}
+#endif
+
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 
diff -urN linux-2.6.12.2/net/ipv4/xfrm4_policy.c
linux-beet-2.6.12.2/net/ipv4/xfrm4_policy.c
--- linux-2.6.12.2/net/ipv4/xfrm4_policy.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv4/xfrm4_policy.c	2005-07-25
15:03:01.000000000 +0300
@@ -6,6 +6,14 @@
  * 	YOSHIFUJI Hideaki @USAGI
  *		Split up af-specific portion
  * 	
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #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,28 @@
 
 		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) {
+
+			beet_family = xfrm[i]->props.beet_family_out;
+			if(beet_family == AF_INET6){
+				remotebeet.in6 = (struct in6_addr*)&xfrm[i]->id.daddr;
+				localbeet.in6 = (struct in6_addr*)&xfrm[i]->props.saddr;
+			} else if(beet_family == AF_INET){
+				remotebeet.in = (struct in_addr*)&xfrm[i]->id.daddr;
+				localbeet.in = (struct in_addr*)&xfrm[i]->props.saddr;
+			}
+		}
+#endif
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
 
@@ -113,6 +147,28 @@
 					      &fl_tunnel, AF_INET);
 			if (err)
 				goto error;
+#ifdef CONFIG_XFRM_BEET
+		} else if (beet_family) {
+			switch(beet_family) {
+			case AF_INET:
+				fl_tunnel.fl4_dst = remotebeet.in->s_addr;
+				fl_tunnel.fl4_src = localbeet.in->s_addr;
+				break;
+			case AF_INET6:
+				ipv6_addr_copy(&fl_tunnel.fl6_dst, remotebeet.in6);
+				ipv6_addr_copy(&fl_tunnel.fl6_src, localbeet.in6);
+				break;
+			default:
+				BUG_ON(1);
+			}
+
+			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);
 	}
diff -urN linux-2.6.12.2/net/ipv6/esp6.c
linux-beet-2.6.12.2/net/ipv6/esp6.c
--- linux-2.6.12.2/net/ipv6/esp6.c	2005-06-30 02:00:53.000000000 +0300
+++ linux-beet-2.6.12.2/net/ipv6/esp6.c	2005-07-25 14:39:11.000000000
+0300
@@ -22,6 +22,16 @@
  * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  * 	
  * 	This file is derived from net/ipv4/esp.c
+ *
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
+ *
  */
 
 #include <linux/config.h>
@@ -225,6 +235,13 @@
 		memcpy(skb->nh.raw, tmp_hdr, hdr_len);
 		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct
ipv6hdr));
 		ret = nexthdr[1];
+#ifdef CONFIG_XFRM_BEET
+		if(x->props.mode == XFRM_MODE_BEET &&
+		   x->props.beet_family_out == AF_INET) {
+			skb->nh.ipv6h->nexthdr = nexthdr[1];
+			ret = 0;//This is because xfrm4_encap expects 0 if every thing is
correct
+		}
+#endif
 	}
 
 out:
@@ -365,7 +382,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;
diff -urN linux-2.6.12.2/net/ipv6/xfrm6_input.c
linux-beet-2.6.12.2/net/ipv6/xfrm6_input.c
--- linux-2.6.12.2/net/ipv6/xfrm6_input.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv6/xfrm6_input.c	2005-07-25
14:39:11.000000000 +0300
@@ -64,6 +64,12 @@
 		if (xfrm_state_check_expire(x))
 			goto drop_unlock;
 
+#ifdef CONFIG_XFRM_BEET
+		if (x->props.mode == XFRM_MODE_BEET) {
+			if (xfrm_beet_input(skb, x))
+				goto drop_unlock;
+		}
+#endif
 		nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb);
 		if (nexthdr <= 0)
 			goto drop_unlock;
@@ -80,7 +86,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 +107,64 @@
 			skb->nh.raw = skb->data;
 			decaps = 1;
 			break;
+#ifdef CONFIG_XFRM_BEET
+		} else if (x->props.mode == XFRM_MODE_BEET) {
+			struct iphdr *iph = skb->nh.iph; // miika: this masks input arg
+			struct ipv6hdr *ip6h = skb->nh.ipv6h;
+			int size=0;
+			__u8 proto=0;
+			__u8 hops=0;
+			__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;
+			if (x->props.beet_family_in == AF_INET) {
+				size = sizeof(struct iphdr);
+				proto = ip6h->nexthdr;
+				hops = ip6h->hop_limit;
+			} else if (x->props.beet_family_in == AF_INET6)
+				size = sizeof(struct ipv6hdr);
+			else
+				BUG_ON(1);
+			/* 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;
+
+			switch(x->props.beet_family_in) {
+			case AF_INET:
+
+				iph = (struct iphdr *)skb->nh.raw;
+
+				skb->protocol = htons(ETH_P_IP);
+				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);
+
+				dst_release(skb->dst);
+				skb->dst = NULL;
+
+				decaps = 1;
+				break;
+
+			case AF_INET6:
+				ip6h->payload_len = htons(total + size);
+				--ip6h->hop_limit;
+				decaps = 1;
+				break;
+			default:
+				BUG_ON(1);
+			}
+			break;
+#endif
 		}
 
 		if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
diff -urN linux-2.6.12.2/net/ipv6/xfrm6_output.c
linux-beet-2.6.12.2/net/ipv6/xfrm6_output.c
--- linux-2.6.12.2/net/ipv6/xfrm6_output.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv6/xfrm6_output.c	2005-07-25
14:39:11.000000000 +0300
@@ -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 <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #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,15 @@
 	if (err)
 		goto error;
 
+#ifdef CONFIG_XFRM_BEET
+	if (x->props.mode == XFRM_MODE_BEET) {
+		/* Change the outer header */
+		err = xfrm_beet_output(skb);
+		if (err)
+			goto error;
+	}
+#endif
+
 	x->curlft.bytes += skb->len;
 	x->curlft.packets++;
 
diff -urN linux-2.6.12.2/net/ipv6/xfrm6_policy.c
linux-beet-2.6.12.2/net/ipv6/xfrm6_policy.c
--- linux-2.6.12.2/net/ipv6/xfrm6_policy.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/ipv6/xfrm6_policy.c	2005-07-25
15:03:01.000000000 +0300
@@ -8,7 +8,14 @@
  * 		IPv6 support
  * 	YOSHIFUJI Hideaki
  * 		Split up af-specific portion
- * 
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #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,22 @@
 
 		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) {
+			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;
+		}
+#endif
 		header_len += xfrm[i]->props.header_len;
 		trailer_len += xfrm[i]->props.trailer_len;
 
@@ -133,6 +160,23 @@
 					      &fl_tunnel, AF_INET6);
 			if (err)
 				goto error;
+#ifdef CONFIG_XFRM_BEET
+		} else if (beet_family) {
+			switch(beet_family) {
+			case AF_INET:
+				fl_tunnel.fl4_dst = remotebeet.in->s_addr;
+				fl_tunnel.fl4_src = localbeet.in->s_addr;
+				break;
+			case AF_INET6:
+				ipv6_addr_copy(&fl_tunnel.fl6_dst, remotebeet.in6);
+				ipv6_addr_copy(&fl_tunnel.fl6_src, localbeet.in6);
+				break;
+			default:
+				BUG_ON(1);
+			}
+			err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
+					      &fl_tunnel, beet_family);
+#endif
 		} else
 			dst_hold(&rt->u.dst);
 	}
diff -urN linux-2.6.12.2/net/key/af_key.c
linux-beet-2.6.12.2/net/key/af_key.c
--- linux-2.6.12.2/net/key/af_key.c	2005-06-30 02:00:53.000000000 +0300
+++ linux-beet-2.6.12.2/net/key/af_key.c	2005-07-25 14:39:12.000000000
+0300
@@ -12,6 +12,14 @@
  *		Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *		Kazunori MIYAZAWA / USAGI Project <miyazawa@linux-ipv6.org>
  *		Derek Atkins <derek@ihtfp.com>
+ *
+ * Changes:     BEET support
+ *              Abhinav Pathak <abpathak@iitk.ac.in>
+ *              Diego Beltrami <diego.beltrami@hiit.fi>
+ *              Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *              Miika Komu <miika@iki.fi>
+ *              Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #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,78 @@
 	    (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 ((x = xfrm_lookup_bydst(XFRM_MODE_BEET, 
+						&xp->xfrm_vec[0].id.daddr,
+						&xp->xfrm_vec[0].saddr,
+						AF_INET))) {
+				/* Inner = 6, Outer = 4 */
+				x->props.beet_family_out = AF_INET;
+				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 if ((x = xfrm_lookup_bydst(XFRM_MODE_BEET, 
+						   &xp->xfrm_vec[0].id.daddr,
+						   &xp->xfrm_vec[0].saddr, 
+						    AF_INET6)))
+			{
+				/* Inner = 4, Outer = 6 */
+				x->props.beet_family_out = AF_INET6;
+				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);
diff -urN linux-2.6.12.2/net/xfrm/Kconfig
linux-beet-2.6.12.2/net/xfrm/Kconfig
--- linux-2.6.12.2/net/xfrm/Kconfig	2005-06-30 02:00:53.000000000 +0300
+++ linux-beet-2.6.12.2/net/xfrm/Kconfig	2005-07-25 15:04:36.000000000
+0300
@@ -10,3 +10,11 @@
 
 	  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.
diff -urN linux-2.6.12.2/net/xfrm/Kconfig~
linux-beet-2.6.12.2/net/xfrm/Kconfig~
--- linux-2.6.12.2/net/xfrm/Kconfig~	1970-01-01 02:00:00.000000000 +0200
+++ linux-beet-2.6.12.2/net/xfrm/Kconfig~	2005-07-25 14:39:13.000000000
+0300
@@ -0,0 +1,28 @@
+#
+# XFRM configuration
+#
+config XFRM_USER
+	tristate "IPsec user configuration interface"
+	depends on INET && XFRM
+	---help---
+	  Support for IPsec user configuration interface used
+	  by native Linux tools.
+
+	  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.
diff -urN linux-2.6.12.2/net/xfrm/Makefile
linux-beet-2.6.12.2/net/xfrm/Makefile
--- linux-2.6.12.2/net/xfrm/Makefile	2005-06-30 02:00:53.000000000 +0300
+++ linux-beet-2.6.12.2/net/xfrm/Makefile	2005-07-25 14:39:13.000000000
+0300
@@ -2,6 +2,6 @@
 # Makefile for the XFRM subsystem.
 #
 
-obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o
xfrm_algo.o
+obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o
xfrm_algo.o xfrm_beet.o
 obj-$(CONFIG_XFRM_USER) += xfrm_user.o
 
diff -urN linux-2.6.12.2/net/xfrm/xfrm_beet.c
linux-beet-2.6.12.2/net/xfrm/xfrm_beet.c
--- linux-2.6.12.2/net/xfrm/xfrm_beet.c	1970-01-01 02:00:00.000000000
+0200
+++ linux-beet-2.6.12.2/net/xfrm/xfrm_beet.c	2005-07-25
15:03:01.000000000 +0300
@@ -0,0 +1,227 @@
+/*
+ * xfrm_beet.c: allows for receiving and transmitting packet in BEET
mode
+ *
+ * Authors:
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <net/xfrm.h>
+#include <linux/pfkeyv2.h>
+#include <linux/ipsec.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <net/ip.h>
+
+#ifdef CONFIG_XFRM_BEET
+
+/* xfrm_beet_output: deals with the outgoing BEET packets.
+ * It changes the outer ip header and correctly set
+ * the header fields
+ *
+ * @skb: structure sk_buff which contains the packet to be transmitted
+ *       skb->data points to the ip header
+*/
+int xfrm_beet_output(struct sk_buff *skb)
+{
+	int err = 0;
+	struct xfrm_state *x = skb->dst->xfrm;
+
+	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->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 if (x->props.beet_family_in == AF_INET &&
x->props.beet_family_out == AF_INET6){
+		/* Inner = 4, Outer = 6 */
+		struct iphdr *iph = (struct iphdr*)skb->data;
+		__u8 protocol, ttl;
+
+		protocol = iph->protocol;
+		ttl = iph->ttl;
+
+		if (skb_headroom(skb) <  sizeof(struct ipv6hdr) - sizeof(struct
iphdr)){
+			if (pskb_expand_head(skb, sizeof(struct ipv6hdr) - sizeof(struct
iphdr),0, GFP_ATOMIC))
+				return -EINVAL;		//Just returning from here.
+
+			skb->len += sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+			skb->nh.raw = skb->h.raw - sizeof(struct ipv6hdr);
+			skb->data = skb->nh.raw;
+
+		} else {
+			skb_push(skb, sizeof(struct ipv6hdr) - sizeof(struct iphdr));
+			skb->nh.raw = skb->h.raw - sizeof(struct ipv6hdr);
+			skb->data = skb->nh.raw;
+		}
+
+		skb->protocol = htons(ETH_P_IPV6);
+
+		skb->nh.ipv6h = (struct ipv6hdr*)(skb->data);
+
+		skb->nh.ipv6h->version = 6;
+		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct
ipv6hdr));
+		skb->nh.ipv6h->nexthdr =  protocol;
+		skb->nh.ipv6h->hop_limit = ttl;
+		ipv6_addr_copy(&skb->nh.ipv6h->saddr,(struct in6_addr
*)&x->props.saddr);
+		ipv6_addr_copy(&skb->nh.ipv6h->daddr, (struct in6_addr
*)&x->id.daddr);
+
+		skb->nh.ipv6h->priority    = 0;
+		skb->nh.ipv6h->flow_lbl[0] = 0;
+		skb->nh.ipv6h->flow_lbl[1] = 0;
+		skb->nh.ipv6h->flow_lbl[2] = 0;
+
+	} else if (x->props.beet_family_in == AF_INET6 &&
x->props.beet_family_out == AF_INET){
+		/* Inner = 6, Outer = 4 */
+		struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+		int delta = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+		u8 hop, proto;
+		u16 payload;
+		struct iphdr *ip4;
+		hop = iph->hop_limit;
+		proto = iph->nexthdr;
+
+		payload = ntohs(iph->payload_len) + sizeof(struct iphdr);
+
+		skb_pull(skb, delta);
+
+		skb->protocol = htons(ETH_P_IP);
+		ip4 = (struct iphdr *)skb->data;
+
+		ip4->ihl = (sizeof(struct iphdr) >> 2);
+		ip4->version = 4;
+		ip4->tos = 0;
+		ip4->tot_len = htons(payload);
+		ip4->id = 0;
+		ip4->frag_off = htons(IP_DF);
+		ip4->ttl = hop;
+		ip4->protocol = proto;
+		ip4->check = 0;
+		ip4->saddr = x->props.saddr.a4;
+		ip4->daddr = x->id.daddr.a4;
+		ip4->check = ip_fast_csum((unsigned char *)ip4, ip4->ihl);
+		/* The esp6_output assumes that skb->data points to outer IP header, 
+		 * skb->nh points eventual new ext hdrs and skb->h points to the ESP
header
+		 */
+		skb->nh.raw = skb->data; // there is no extension header
+
+	} else 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);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(xfrm_beet_output);
+
+
+/* xfrm_beet_input: deals with the incoming BEET packets.
+ * It changes the outer ip header with the corresponding inner ip
header and addresses
+ *
+ * @skb: structure sk_buff. skb->nh.raw points to the outer ip address
+ *       skb->data and skb->h.raw point to the ESP to be decapsulated
+ *
+ * @x  : struct xfrm_state containing the state information
+ *
+*/
+int xfrm_beet_input(struct sk_buff *skb, struct xfrm_state *x)
+{
+	int err = 0;
+
+	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 if (x->props.beet_family_in == AF_INET &&
x->props.beet_family_out == AF_INET6){
+		/* Inner = 4, Outer = 6 */
+		struct iphdr *iph;
+		__u8 proto = skb->nh.ipv6h->nexthdr;
+		__u8 hops = skb->nh.ipv6h->hop_limit;
+		
+		
+		skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr) - sizeof(struct
iphdr);
+		memmove(skb->h.raw, skb->data, skb->len);
+		skb->data = skb->h.raw;
+
+	
+		eth_hdr(skb)->h_proto=htons(ETH_P_IP);
+			
+		iph = (struct iphdr *)skb->nh.raw;
+		memset(iph, 0, sizeof(struct iphdr));
+		iph->daddr = x->sel.daddr.a4;
+		iph->saddr = x->sel.saddr.a4;
+		iph->ttl = hops--;
+		iph->protocol = proto;
+		iph->tot_len = htons(skb->len);
+		iph->frag_off = htons(IP_DF);
+		iph->ihl = 5;
+		iph->version = 4;
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+		skb->protocol = htons(ETH_P_IP);
+		
+	} else if (x->props.beet_family_in == AF_INET6 &&
x->props.beet_family_out == AF_INET){
+		/* Inner = 6, Outer = 4 */
+		struct ipv6hdr *ip6h;
+		int proto = skb->nh.iph->protocol;
+		int hops = skb->nh.iph->ttl;
+		int total = skb->len - sizeof(struct iphdr);
+
+		if (skb_tailroom(skb) <  sizeof(struct ipv6hdr) - sizeof(struct
iphdr)){
+			if (pskb_expand_head(skb, 0, sizeof(struct ipv6hdr) - sizeof(struct
iphdr), GFP_ATOMIC))
+				return -EINVAL;		//Just returning from here.
+		}
+
+		skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
+		memmove(skb->h.raw, skb->data, skb->len);
+		skb->data = skb->h.raw;
+		skb->tail += sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+
+		eth_hdr(skb)->h_proto=htons(ETH_P_IPV6);
+		ip6h = skb->nh.ipv6h;
+
+		memset(ip6h, 0, sizeof(struct ipv6hdr));
+		ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *)&x->sel.saddr.a6);
+		ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *)&x->sel.daddr.a6);
+		ip6h->payload_len = htons(total);
+		ip6h->hop_limit = hops-1;
+		ip6h->version = 6;
+		ip6h->nexthdr = proto;
+
+	 	skb->protocol = htons(ETH_P_IPV6);
+
+	} else if (x->props.beet_family_in == AF_INET6 &&
x->props.beet_family_out == AF_INET6){
+		/* Inner = 6, Outer = 6 */
+		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);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(xfrm_beet_input);
+
+#endif /* CONFIG_XFRM_BEET */
diff -urN linux-2.6.12.2/net/xfrm/xfrm_policy.c
linux-beet-2.6.12.2/net/xfrm/xfrm_policy.c
--- linux-2.6.12.2/net/xfrm/xfrm_policy.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/xfrm/xfrm_policy.c	2005-07-25
14:39:13.000000000 +0300
@@ -11,6 +11,13 @@
  * 		Split up af-specific portion
  *	Derek Atkins <derek@ihtfp.com>		Add the post_input processor
  * 	
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@iitk.ac.in>
+ *          Diego Beltrami <diego.beltrami@hiit.fi>
+ *          Kristian Slavov <kristian.slavov@nomadiclab.com>
+ *          Miika Komu <miika@iki.fi>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
+ *
  */
 
 #include <asm/bug.h>
@@ -643,6 +650,10 @@
 		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
 
 		if (tmpl->mode) {
+#ifdef CONFIG_XFRM_BEET
+			if(tmpl->mode == XFRM_MODE_BEET)
+				family = tmpl->family;
+#endif
 			remote = &tmpl->id.daddr;
 			local = &tmpl->saddr;
 		}
diff -urN linux-2.6.12.2/net/xfrm/xfrm_state.c
linux-beet-2.6.12.2/net/xfrm/xfrm_state.c
--- linux-2.6.12.2/net/xfrm/xfrm_state.c	2005-06-30 02:00:53.000000000
+0300
+++ linux-beet-2.6.12.2/net/xfrm/xfrm_state.c	2005-07-25
14:39:13.000000000 +0300
@@ -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
Hipsec@lists.ietf.org
https://www1.ietf.org/mailman/listinfo/hipsec