netdev
[Top] [All Lists]

[PATCH 2.6.12.2] XFRM: BEET IPsec mode for Linux

To: netdev@xxxxxxxxxxx
Subject: [PATCH 2.6.12.2] XFRM: BEET IPsec mode for Linux
From: Diego Beltrami <diego.beltrami@xxxxxxx>
Date: Mon, 25 Jul 2005 15:41:48 +0300
Cc: infrahip@xxxxxxx, gurtov@xxxxxxxxxxxxxx, jeffrey.m.ahrenholz@xxxxxxxxxx, kristian.slavov@xxxxxxxxxxxxxx, hipl-users@xxxxxxxxxxxxx, hipsec@xxxxxxxx
Organization: HIIT
Reply-to: diego.beltrami@xxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
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@xxxxxxxxxx> (InfraHIP/HIIT)
* Diego Beltrami <diego.beltrami@xxxxxxx> (InfraHIP/HIIT)
* Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx> (Ericsson)
* Miika Komu <miika@xxxxxx> (InfraHIP/HIIT)
* Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx> (Boeing)

On the behalf of the BEET development team,

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




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@xxxxxx>
+                Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+                Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+               Abhinav Pathak <abpathak@xxxxxxxxxx>
+               Diego Beltrami <diego.beltrami@xxxxxxx>
+
+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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
+ */
+
 #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@xxxxxxxxx>
  *             Add Encapsulation support
  *     
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxxxxxx>
  *     
  *     This file is derived from net/ipv4/esp.c
+ *
+ *
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
+ *
  */
 
 #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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxxxxxx>
  *             Kazunori MIYAZAWA / USAGI Project <miyazawa@xxxxxxxxxxxxxx>
  *             Derek Atkins <derek@xxxxxxxxx>
+ *
+ * Changes:     BEET support
+ *              Abhinav Pathak <abpathak@xxxxxxxxxx>
+ *              Diego Beltrami <diego.beltrami@xxxxxxx>
+ *              Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *              Miika Komu <miika@xxxxxx>
+ *              Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
+ */
+
+#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@xxxxxxxxx>          Add the post_input processor
  *     
+ * Changes: BEET support
+ *          Abhinav Pathak <abpathak@xxxxxxxxxx>
+ *          Diego Beltrami <diego.beltrami@xxxxxxx>
+ *          Kristian Slavov <kristian.slavov@xxxxxxxxxxxxxx>
+ *          Miika Komu <miika@xxxxxx>
+ *          Jeff Ahrenholz <jeffrey.m.ahrenholz@xxxxxxxxxx>
+ *
  */
 
 #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



<Prev in Thread] Current Thread [Next in Thread>