]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/commitdiff
Updated to a new experimental openswan.
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 16 Jul 2008 21:57:36 +0000 (21:57 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 16 Jul 2008 21:57:36 +0000 (21:57 +0000)
config/kernel/kernel.config.i586
doc/packages-list.txt
lfs/linux
lfs/openswan
make.sh
src/patches/openswan-2.6.16dr2-2.6.24-kernel.patch [new file with mode: 0644]
src/patches/openswan-2.6.16dr2-2.6.24-natt.patch [moved from src/patches/openswan-2.4.x.kernel-2.6.23-natt.patch with 100% similarity]

index c97dfa32abc177c05712346f40c9cac684e1da61..4767921c233cb5ed26df11a5d0343adfcbb9b34b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24.7
-# Mon Jul 14 10:58:23 2008
+# Linux kernel version: 2.6.24.7-ipfire
+# Wed Jul 16 20:38:30 2008
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -791,6 +791,23 @@ CONFIG_IEEE80211_SOFTMAC=m
 CONFIG_RFKILL=m
 CONFIG_RFKILL_INPUT=m
 # CONFIG_NET_9P is not set
+CONFIG_KLIPS=m
+
+#
+# KLIPS options
+#
+CONFIG_KLIPS_ESP=y
+CONFIG_KLIPS_AH=y
+CONFIG_KLIPS_AUTH_HMAC_MD5=y
+CONFIG_KLIPS_AUTH_HMAC_SHA1=y
+CONFIG_KLIPS_ALG=y
+# CONFIG_KLIPS_ENC_CRYPTOAPI is not set
+CONFIG_KLIPS_ENC_3DES=y
+CONFIG_KLIPS_ENC_AES=y
+CONFIG_KLIPS_IPCOMP=y
+# CONFIG_KLIPS_OCF is not set
+CONFIG_KLIPS_DEBUG=y
+CONFIG_KLIPS_IF_MAX=64
 
 #
 # Device Drivers
index 44cb72bbaed23892d0da93aab221f709be5f3a66..d50a76fde5c920b13988f851efa910050a4413b3 100644 (file)
@@ -39,6 +39,7 @@
 * arptables-v0.0.3-3
 * as86-0.16.17
 * asterisk-1.4.18
+* asterisk-1.4.18_old
 * atl2-2.0.4
 * autoconf-2.59
 * automake-1.9.6
 * icegenerator-0.5.5-pre2
 * igmpproxy-src-0.1-beta2
 * inetutils-1.4.2
+* initscripts_old
 * ipaddr-1.2
 * ipfireseeder-1.00
 * iproute2-2.6.16-060323
 * libxml2-2.6.26
 * libxslt-1.1.17
 * linux-2.6.24.7
+* linux-2.6.24.7-smp_old
+* linux-2.6.24.7_old
 * linux-atm-2.4.1
 * linux-libc-headers-2.6.12.0
 * linuxigd-0.95
 * openssl-0.9.8g
 * openswan-2.6.14
 * openswan-2.6.14-kmod
+* openswan-2.6.16dr2
 * openvpn-2.0.9
 * pam_mysql-0.7RC1
 * patch-2.5.4
 * tcptrack-1.3.0
 * teamspeak-2.0.24.1
 * texinfo-4.8
+* tftp-hpa-0.48
+* tftp-hpa-0.48_old
 * tiff-3.8.2
 * traceroute-1.4a12
 * tripwire-2.4.1.2
index 78e4468d08de99e21fce6804f641b87e5c09fbae..d89d44157472e32a0970fcb7693a5dbacc2510f4 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
@@ -100,8 +100,9 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        # Add USB ID of US-Robotics USR805423 to ZD1211 driver
 #      cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-2.6.20.21-zd1211-usrobotics-usbid.patch
 
-       # Openswan nat-t
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openswan-2.4.x.kernel-2.6.23-natt.patch
+       # Openswan
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openswan-2.6.16dr2-2.6.24-kernel.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/openswan-2.6.16dr2-2.6.24-natt.patch
 
        # Reiser4
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/reiser4-for-2.6.24.patch
index c1d2fdd7cd719fbf6f1c14d42f81f3a5732d3000..36084a90a64193a5dc110c5db3f78a0235e12535 100644 (file)
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 2.6.14
+VER        = 2.6.16dr2
 
 THISAPP    = openswan-$(VER)
 DL_FILE    = $(THISAPP).tar.gz
@@ -48,8 +48,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-#$(DL_FILE)_MD5 = 0c2505cf2639a7de051e815f41e8e1f4
-$(DL_FILE)_MD5 = 44dc3cb98b9cb4e3fa03b82967d08b78
+$(DL_FILE)_MD5 = 8bf347f1d2219dd9277adb2b34720bf9
 
 install : $(TARGET)
 
@@ -81,15 +80,11 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
        cd $(DIR_APP) && sed -i \
                -e 's%^INC_USRLOCAL.*$$%INC_USRLOCAL=/usr%' \
-               -e 's%^USERCOMPILE.*$$%USERCOMPILE=$(CFLAGS)%' \
-               -e 's%^KLIPSCOMPILE.*$$%KLIPSCOMPILE=$(CFLAGS)%' Makefile.inc
-       cd $(DIR_APP) && sed -i \
-               -e 's/-Werror//g' programs/Makefile.program
+               -e 's%^USERCOMPILE.*$$%USERCOMPILE=$(CFLAGS)%' Makefile.inc
+
+       cd $(DIR_APP) && sed -e 's/-Werror//g' -i programs/Makefile.program
+       cd $(DIR_APP) && sed -e 's/-Werror//g' -i lib/liblwres/Makefile
 
-ifeq "$(KMOD)" "1"
-       cd $(DIR_APP) && make KERNELSRC=/usr/src/linux module
-       cd $(DIR_APP) && make minstall
-else
        cd $(DIR_APP) && make programs
        cd $(DIR_APP) && make install
        
@@ -108,6 +103,5 @@ else
        cd /usr/lib/ipsec && patch -Np0 < $(DIR_SRC)/src/patches/openswan-2.6.14-updown-1.patch
 #      cd /usr/lib/ipsec && patch -Np0 < $(DIR_SRC)/src/patches/openswan-2.4.9-updown_x509-1.patch
 #      cd /etc/ipsec.d/policies && patch -Np0 < $(DIR_SRC)/src/patches/openswan-2.4.9-clear-1.patch
-endif  
        #@rm -rf $(DIR_APP)
        @$(POSTBUILD)
diff --git a/make.sh b/make.sh
index daeb45444ce0c0abd58fe2422ab9de8ffc8faafa..a4337a41d9e31747ece624d759f56c48b5a0e000 100755 (executable)
--- a/make.sh
+++ b/make.sh
@@ -343,7 +343,6 @@ buildipfire() {
   ipfiremake v4l-dvb                   SMP=1
   ipfiremake madwifi                    SMP=1
   ipfiremake sane              KMOD=1  SMP=1
-  ipfiremake openswan          KMOD=1  SMP=1
   ipfiremake linux
 #  ipfiremake linux-fusion
 #  ipfiremake ipp2p
@@ -355,7 +354,6 @@ buildipfire() {
   ipfiremake v4l-dvb
   ipfiremake madwifi
   ipfiremake sane              KMOD=1
-  ipfiremake openswan          KMOD=1
   ipfiremake pkg-config
   ipfiremake linux-atm
   ipfiremake cpio
diff --git a/src/patches/openswan-2.6.16dr2-2.6.24-kernel.patch b/src/patches/openswan-2.6.16dr2-2.6.24-kernel.patch
new file mode 100644 (file)
index 0000000..faf66e7
--- /dev/null
@@ -0,0 +1,56013 @@
+packaging/utils/kernelpatch 2.6
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/README.openswan-2     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,112 @@
++*
++* RCSID $Id: README.openswan-2,v 1.1 2003/12/10 01:07:49 mcr Exp $
++*
++
++               ****************************************
++               * IPSEC for Linux, Release 2.xx series *
++               ****************************************
++
++
++
++1. Files
++
++The contents of linux/net/ipsec/ (see below) join the linux kernel source tree.
++as provided for higher up.
++
++The programs/ directory contains the user-level utilities which you need
++to run IPSEC.  See the top-level top/INSTALL to compile and install them.
++
++The testing/ directory contains test scripts.
++
++The doc/ directory contains -- what else -- documentation. 
++
++1.1. Kernel files
++
++The following are found in net/ipsec/:
++
++Makefile                      The Makefile
++Config.in                     The configuration script for make menuconfig
++defconfig                     Configuration defaults for first time.
++
++radij.c                               General-purpose radix-tree operations
++
++ipsec_ipcomp.c           IPCOMP encapsulate/decapsulate code.
++ipsec_ah.c       Authentication Header (AH) encapsulate/decapsulate code.
++ipsec_esp.c      Encapsulated Security Payload (ESP) encap/decap code.
++
++pfkey_v2.c                    PF_KEYv2 socket interface code.
++pfkey_v2_parser.c             PF_KEYv2 message parsing and processing code.
++
++ipsec_init.c                  Initialization code, /proc interface.
++ipsec_radij.c                 Interface with the radix tree code.
++ipsec_netlink.c                       Interface with the netlink code.
++ipsec_xform.c                 Routines and structures common to transforms.
++ipsec_tunnel.c                        The outgoing packet processing code.
++ipsec_rcv.c                   The incoming packet processing code.
++ipsec_md5c.c                  Somewhat modified RSADSI MD5 C code.
++ipsec_sha1.c                  Somewhat modified Steve Reid SHA-1 C code.
++
++sysctl_net_ipsec.c            /proc/sys/net/ipsec/* variable definitions.
++
++version.c                     symbolic link to project version.
++
++radij.h                               Headers for radij.c
++
++ipcomp.h                      Headers used by IPCOMP code.
++
++ipsec_radij.h                 Interface with the radix tree code.
++ipsec_netlink.h                       Headers used by the netlink interface.
++ipsec_encap.h                 Headers defining encapsulation structures.
++ipsec_xform.h                 Transform headers.
++ipsec_tunnel.h                        Headers used by tunneling code.
++ipsec_ipe4.h                  Headers for the IP-in-IP code.
++ipsec_ah.h                    Headers common to AH transforms.
++ipsec_md5h.h                  RSADSI MD5 headers.
++ipsec_sha1.h                  SHA-1 headers.
++ipsec_esp.h                   Headers common to ESP transfroms.
++ipsec_rcv.h                   Headers for incoming packet processing code.
++
++1.2. User-level files.
++
++The following are found in utils/:
++
++eroute.c      Create an "extended route" source code
++spi.c         Set up Security Associations source code
++spigrp.c        Link SPIs together source code.
++tncfg.c         Configure the tunneling features of the virtual interface
++              source code
++klipsdebug.c  Set/reset klips debugging features source code.
++version.c     symbolic link to project version.
++
++eroute.8      Create an "extended route" manual page
++spi.8         Set up Security Associations manual page
++spigrp.8        Link SPIs together manual page
++tncfg.8         Configure the tunneling features of the virtual interface
++              manual page
++klipsdebug.8  Set/reset klips debugging features manual page
++
++eroute.5      /proc/net/ipsec_eroute format manual page
++spi.5         /proc/net/ipsec_spi format manual page
++spigrp.5      /proc/net/ipsec_spigrp format manual page
++tncfg.5               /proc/net/ipsec_tncfg format manual page
++klipsdebug.5  /proc/net/ipsec_klipsdebug format manual page
++version.5     /proc/net/ipsec_version format manual page
++pf_key.5      /proc/net/pf_key format manual page
++
++Makefile      Utilities makefile.
++
++*.8           Manpages for the respective utils.
++
++
++1.3. Test files
++
++The test scripts are locate in testing/ and and documentation is found
++at doc/src/umltesting.html. Automated testing via "make check" is available
++provided that the User-Mode-Linux patches are available.
++
++*
++* $Log: README.openswan-2,v $
++* Revision 1.1  2003/12/10 01:07:49  mcr
++*     documentation for additions.
++*
++*
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/des/des_locl.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,511 @@
++/* crypto/des/des_locl.org */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
++ *
++ * Always modify des_locl.org since des_locl.h is automatically generated from
++ * it during SSLeay configuration.
++ *
++ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
++ */
++
++#ifndef HEADER_DES_LOCL_H
++#define HEADER_DES_LOCL_H
++
++#if defined(WIN32) || defined(WIN16)
++#ifndef MSDOS
++#define MSDOS
++#endif
++#endif
++
++#include "klips-crypto/des.h"
++#ifdef OCF_ASSIST
++#include "klips-crypto/ocf_assist.h"
++#endif
++
++#ifndef DES_DEFAULT_OPTIONS
++/* the following is tweaked from a config script, that is why it is a
++ * protected undef/define */
++#ifndef DES_PTR
++#define DES_PTR
++#endif
++
++/* This helps C compiler generate the correct code for multiple functional
++ * units.  It reduces register dependancies at the expense of 2 more
++ * registers */
++#ifndef DES_RISC1
++#define DES_RISC1
++#endif
++
++#ifndef DES_RISC2
++#undef DES_RISC2
++#endif
++
++#if defined(DES_RISC1) && defined(DES_RISC2)
++YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
++#endif
++
++/* Unroll the inner loop, this sometimes helps, sometimes hinders.
++ * Very mucy CPU dependant */
++#ifndef DES_UNROLL
++#define DES_UNROLL
++#endif
++
++/* These default values were supplied by
++ * Peter Gutman <pgut001@cs.auckland.ac.nz>
++ * They are only used if nothing else has been defined */
++#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
++/* Special defines which change the way the code is built depending on the
++   CPU and OS.  For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
++   even newer MIPS CPU's, but at the moment one size fits all for
++   optimization options.  Older Sparc's work better with only UNROLL, but
++   there's no way to tell at compile time what it is you're running on */
++ 
++#if defined( sun )            /* Newer Sparc's */
++  #define DES_PTR
++  #define DES_RISC1
++  #define DES_UNROLL
++#elif defined( __ultrix )     /* Older MIPS */
++  #define DES_PTR
++  #define DES_RISC2
++  #define DES_UNROLL
++#elif defined( __osf1__ )     /* Alpha */
++  #define DES_PTR
++  #define DES_RISC2
++#elif defined ( _AIX )                /* RS6000 */
++  /* Unknown */
++#elif defined( __hpux )               /* HP-PA */
++  /* Unknown */
++#elif defined( __aux )                /* 68K */
++  /* Unknown */
++#elif defined( __dgux )               /* 88K (but P6 in latest boxes) */
++  #define DES_UNROLL
++#elif defined( __sgi )                /* Newer MIPS */
++  #define DES_PTR
++  #define DES_RISC2
++  #define DES_UNROLL
++#elif defined( i386 )         /* x86 boxes, should be gcc */
++  #define DES_PTR
++  #define DES_RISC1
++  #define DES_UNROLL
++#endif /* Systems-specific speed defines */
++#endif
++
++#endif /* DES_DEFAULT_OPTIONS */
++
++#ifdef MSDOS          /* Visual C++ 2.1 (Windows NT/95) */
++#include <stdlib.h>
++#include <errno.h>
++#include <time.h>
++#include <io.h>
++#ifndef RAND
++#define RAND
++#endif
++#undef NOPROTO
++#endif
++
++#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)
++#ifndef __KERNEL__
++#include <string.h>
++#else
++#include <linux/string.h>
++#endif
++#endif
++
++#ifndef RAND
++#define RAND
++#endif
++
++#ifdef linux
++#undef RAND
++#endif
++
++#ifdef MSDOS
++#define getpid() 2
++#define RAND
++#undef NOPROTO
++#endif
++
++#if defined(NOCONST)
++#define const
++#endif
++
++#ifdef __STDC__
++#undef NOPROTO
++#endif
++
++#define ITERATIONS 16
++#define HALF_ITERATIONS 8
++
++/* used in des_read and des_write */
++#define MAXWRITE      (1024*16)
++#define BSIZE         (MAXWRITE+4)
++
++#define c2l(c,l)      (l =((DES_LONG)(*((c)++)))    , \
++                       l|=((DES_LONG)(*((c)++)))<< 8L, \
++                       l|=((DES_LONG)(*((c)++)))<<16L, \
++                       l|=((DES_LONG)(*((c)++)))<<24L)
++
++/* NOTE - c is not incremented as per c2l */
++#define c2ln(c,l1,l2,n)       { \
++                      c+=n; \
++                      l1=l2=0; \
++                      switch (n) { \
++                      case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
++                      case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
++                      case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
++                      case 5: l2|=((DES_LONG)(*(--(c))));     \
++                      case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
++                      case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
++                      case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
++                      case 1: l1|=((DES_LONG)(*(--(c))));     \
++                              } \
++                      }
++
++#define l2c(l,c)      (*((c)++)=(unsigned char)(((l)     )&0xff), \
++                       *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                       *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                       *((c)++)=(unsigned char)(((l)>>24L)&0xff))
++
++/* replacements for htonl and ntohl since I have no idea what to do
++ * when faced with machines with 8 byte longs. */
++#define HDRSIZE 4
++
++#define n2l(c,l)      (l =((DES_LONG)(*((c)++)))<<24L, \
++                       l|=((DES_LONG)(*((c)++)))<<16L, \
++                       l|=((DES_LONG)(*((c)++)))<< 8L, \
++                       l|=((DES_LONG)(*((c)++))))
++
++#define l2n(l,c)      (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
++                       *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
++                       *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
++                       *((c)++)=(unsigned char)(((l)     )&0xff))
++
++/* NOTE - c is not incremented as per l2c */
++#define l2cn(l1,l2,c,n)       { \
++                      c+=n; \
++                      switch (n) { \
++                      case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
++                      case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
++                      case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
++                      case 5: *(--(c))=(unsigned char)(((l2)     )&0xff); \
++                      case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
++                      case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
++                      case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
++                      case 1: *(--(c))=(unsigned char)(((l1)     )&0xff); \
++                              } \
++                      }
++
++#define       ROTATE(a,n)     (((a)>>(n))+((a)<<(32-(n))))
++
++/* Don't worry about the LOAD_DATA() stuff, that is used by
++ * fcrypt() to add it's little bit to the front */
++
++#ifdef DES_FCRYPT
++
++#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
++      { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
++
++#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
++      t=R^(R>>16L); \
++      u=t&E0; t&=E1; \
++      tmp=(u<<16); u^=R^s[S  ]; u^=tmp; \
++      tmp=(t<<16); t^=R^s[S+1]; t^=tmp
++#else
++#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
++#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
++      u=R^s[S  ]; \
++      t=R^s[S+1]
++#endif
++
++/* The changes to this macro may help or hinder, depending on the
++ * compiler and the achitecture.  gcc2 always seems to do well :-).
++ * Inspired by Dana How <how@isl.stanford.edu>
++ * DO NOT use the alternative version on machines with 8 byte longs.
++ * It does not seem to work on the Alpha, even when DES_LONG is 4
++ * bytes, probably an issue of accessing non-word aligned objects :-( */
++#ifdef DES_PTR
++
++/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there
++ * is no reason to not xor all the sub items together.  This potentially
++ * saves a register since things can be xored directly into L */
++
++#if defined(DES_RISC1) || defined(DES_RISC2)
++#ifdef DES_RISC1
++#define D_ENCRYPT(LL,R,S) { \
++      unsigned int u1,u2,u3; \
++      LOAD_DATA(R,S,u,t,E0,E1,u1); \
++      u2=(int)u>>8L; \
++      u1=(int)u&0xfc; \
++      u2&=0xfc; \
++      t=ROTATE(t,4); \
++      u>>=16L; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP      +u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
++      u3=(int)(u>>8L); \
++      u1=(int)u&0xfc; \
++      u3&=0xfc; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \
++      u2=(int)t>>8L; \
++      u1=(int)t&0xfc; \
++      u2&=0xfc; \
++      t>>=16L; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
++      u3=(int)t>>8L; \
++      u1=(int)t&0xfc; \
++      u3&=0xfc; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); }
++#endif
++#ifdef DES_RISC2
++#define D_ENCRYPT(LL,R,S) { \
++      unsigned int u1,u2,s1,s2; \
++      LOAD_DATA(R,S,u,t,E0,E1,u1); \
++      u2=(int)u>>8L; \
++      u1=(int)u&0xfc; \
++      u2&=0xfc; \
++      t=ROTATE(t,4); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP      +u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
++      s1=(int)(u>>16L); \
++      s2=(int)(u>>24L); \
++      s1&=0xfc; \
++      s2&=0xfc; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \
++      u2=(int)t>>8L; \
++      u1=(int)t&0xfc; \
++      u2&=0xfc; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
++      s1=(int)(t>>16L); \
++      s2=(int)(t>>24L); \
++      s1&=0xfc; \
++      s2&=0xfc; \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \
++      LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); }
++#endif
++#else
++#define D_ENCRYPT(LL,R,S) { \
++      LOAD_DATA_tmp(R,S,u,t,E0,E1); \
++      t=ROTATE(t,4); \
++      LL^= \
++      *(DES_LONG *)((unsigned char *)des_SP      +((u     )&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x100+((t     )&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \
++      *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); }
++#endif
++
++#else /* original version */
++
++#if defined(DES_RISC1) || defined(DES_RISC2)
++#ifdef DES_RISC1
++#define D_ENCRYPT(LL,R,S) {\
++      unsigned int u1,u2,u3; \
++      LOAD_DATA(R,S,u,t,E0,E1,u1); \
++      u>>=2L; \
++      t=ROTATE(t,6); \
++      u2=(int)u>>8L; \
++      u1=(int)u&0x3f; \
++      u2&=0x3f; \
++      u>>=16L; \
++      LL^=des_SPtrans[0][u1]; \
++      LL^=des_SPtrans[2][u2]; \
++      u3=(int)u>>8L; \
++      u1=(int)u&0x3f; \
++      u3&=0x3f; \
++      LL^=des_SPtrans[4][u1]; \
++      LL^=des_SPtrans[6][u3]; \
++      u2=(int)t>>8L; \
++      u1=(int)t&0x3f; \
++      u2&=0x3f; \
++      t>>=16L; \
++      LL^=des_SPtrans[1][u1]; \
++      LL^=des_SPtrans[3][u2]; \
++      u3=(int)t>>8L; \
++      u1=(int)t&0x3f; \
++      u3&=0x3f; \
++      LL^=des_SPtrans[5][u1]; \
++      LL^=des_SPtrans[7][u3]; }
++#endif
++#ifdef DES_RISC2
++#define D_ENCRYPT(LL,R,S) {\
++      unsigned int u1,u2,s1,s2; \
++      LOAD_DATA(R,S,u,t,E0,E1,u1); \
++      u>>=2L; \
++      t=ROTATE(t,6); \
++      u2=(int)u>>8L; \
++      u1=(int)u&0x3f; \
++      u2&=0x3f; \
++      LL^=des_SPtrans[0][u1]; \
++      LL^=des_SPtrans[2][u2]; \
++      s1=(int)u>>16L; \
++      s2=(int)u>>24L; \
++      s1&=0x3f; \
++      s2&=0x3f; \
++      LL^=des_SPtrans[4][s1]; \
++      LL^=des_SPtrans[6][s2]; \
++      u2=(int)t>>8L; \
++      u1=(int)t&0x3f; \
++      u2&=0x3f; \
++      LL^=des_SPtrans[1][u1]; \
++      LL^=des_SPtrans[3][u2]; \
++      s1=(int)t>>16; \
++      s2=(int)t>>24L; \
++      s1&=0x3f; \
++      s2&=0x3f; \
++      LL^=des_SPtrans[5][s1]; \
++      LL^=des_SPtrans[7][s2]; }
++#endif
++
++#else
++
++#define D_ENCRYPT(LL,R,S) {\
++      LOAD_DATA_tmp(R,S,u,t,E0,E1); \
++      t=ROTATE(t,4); \
++      LL^=\
++              des_SPtrans[0][(u>> 2L)&0x3f]^ \
++              des_SPtrans[2][(u>>10L)&0x3f]^ \
++              des_SPtrans[4][(u>>18L)&0x3f]^ \
++              des_SPtrans[6][(u>>26L)&0x3f]^ \
++              des_SPtrans[1][(t>> 2L)&0x3f]^ \
++              des_SPtrans[3][(t>>10L)&0x3f]^ \
++              des_SPtrans[5][(t>>18L)&0x3f]^ \
++              des_SPtrans[7][(t>>26L)&0x3f]; }
++#endif
++#endif
++
++      /* IP and FP
++       * The problem is more of a geometric problem that random bit fiddling.
++       0  1  2  3  4  5  6  7      62 54 46 38 30 22 14  6
++       8  9 10 11 12 13 14 15      60 52 44 36 28 20 12  4
++      16 17 18 19 20 21 22 23      58 50 42 34 26 18 10  2
++      24 25 26 27 28 29 30 31  to  56 48 40 32 24 16  8  0
++
++      32 33 34 35 36 37 38 39      63 55 47 39 31 23 15  7
++      40 41 42 43 44 45 46 47      61 53 45 37 29 21 13  5
++      48 49 50 51 52 53 54 55      59 51 43 35 27 19 11  3
++      56 57 58 59 60 61 62 63      57 49 41 33 25 17  9  1
++
++      The output has been subject to swaps of the form
++      0 1 -> 3 1 but the odd and even bits have been put into
++      2 3    2 0
++      different words.  The main trick is to remember that
++      t=((l>>size)^r)&(mask);
++      r^=t;
++      l^=(t<<size);
++      can be used to swap and move bits between words.
++
++      So l =  0  1  2  3  r = 16 17 18 19
++              4  5  6  7      20 21 22 23
++              8  9 10 11      24 25 26 27
++             12 13 14 15      28 29 30 31
++      becomes (for size == 2 and mask == 0x3333)
++         t =   2^16  3^17 -- --   l =  0  1 16 17  r =  2  3 18 19
++               6^20  7^21 -- --        4  5 20 21       6  7 22 23
++              10^24 11^25 -- --        8  9 24 25      10 11 24 25
++              14^28 15^29 -- --       12 13 28 29      14 15 28 29
++
++      Thanks for hints from Richard Outerbridge - he told me IP&FP
++      could be done in 15 xor, 10 shifts and 5 ands.
++      When I finally started to think of the problem in 2D
++      I first got ~42 operations without xors.  When I remembered
++      how to use xors :-) I got it to its final state.
++      */
++#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
++      (b)^=(t),\
++      (a)^=((t)<<(n)))
++
++#define IP(l,r) \
++      { \
++      register DES_LONG tt; \
++      PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
++      PERM_OP(l,r,tt,16,0x0000ffffL); \
++      PERM_OP(r,l,tt, 2,0x33333333L); \
++      PERM_OP(l,r,tt, 8,0x00ff00ffL); \
++      PERM_OP(r,l,tt, 1,0x55555555L); \
++      }
++
++#define FP(l,r) \
++      { \
++      register DES_LONG tt; \
++      PERM_OP(l,r,tt, 1,0x55555555L); \
++      PERM_OP(r,l,tt, 8,0x00ff00ffL); \
++      PERM_OP(l,r,tt, 2,0x33333333L); \
++      PERM_OP(r,l,tt,16,0x0000ffffL); \
++      PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
++      }
++
++extern const DES_LONG des_SPtrans[8][64];
++
++#ifndef NO_FCRYPT
++#ifndef NOPROTO
++void fcrypt_body(DES_LONG *out,des_key_schedule ks,
++      DES_LONG Eswap0, DES_LONG Eswap1);
++#else
++void fcrypt_body();
++#endif
++#endif /* NO_FCRYPT */
++
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/des/des_ver.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,60 @@
++/* crypto/des/des_ver.h */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++extern char *DES_version;     /* SSLeay version string */
++extern char *libdes_version;  /* old libdes version string */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/des/podd.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,75 @@
++/* crypto/des/podd.h */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++static const unsigned char odd_parity[256]={
++  1,  1,  2,  2,  4,  4,  7,  7,  8,  8, 11, 11, 13, 13, 14, 14,
++ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
++ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
++ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
++ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
++ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
++ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
++112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
++128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
++145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
++161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
++176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
++193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
++208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
++224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
++241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/des/sk.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,204 @@
++/* crypto/des/sk.h */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++static const DES_LONG des_skb[8][64]={
++{
++/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
++0x00000000L,0x00000010L,0x20000000L,0x20000010L,
++0x00010000L,0x00010010L,0x20010000L,0x20010010L,
++0x00000800L,0x00000810L,0x20000800L,0x20000810L,
++0x00010800L,0x00010810L,0x20010800L,0x20010810L,
++0x00000020L,0x00000030L,0x20000020L,0x20000030L,
++0x00010020L,0x00010030L,0x20010020L,0x20010030L,
++0x00000820L,0x00000830L,0x20000820L,0x20000830L,
++0x00010820L,0x00010830L,0x20010820L,0x20010830L,
++0x00080000L,0x00080010L,0x20080000L,0x20080010L,
++0x00090000L,0x00090010L,0x20090000L,0x20090010L,
++0x00080800L,0x00080810L,0x20080800L,0x20080810L,
++0x00090800L,0x00090810L,0x20090800L,0x20090810L,
++0x00080020L,0x00080030L,0x20080020L,0x20080030L,
++0x00090020L,0x00090030L,0x20090020L,0x20090030L,
++0x00080820L,0x00080830L,0x20080820L,0x20080830L,
++0x00090820L,0x00090830L,0x20090820L,0x20090830L,
++},{
++/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
++0x00000000L,0x02000000L,0x00002000L,0x02002000L,
++0x00200000L,0x02200000L,0x00202000L,0x02202000L,
++0x00000004L,0x02000004L,0x00002004L,0x02002004L,
++0x00200004L,0x02200004L,0x00202004L,0x02202004L,
++0x00000400L,0x02000400L,0x00002400L,0x02002400L,
++0x00200400L,0x02200400L,0x00202400L,0x02202400L,
++0x00000404L,0x02000404L,0x00002404L,0x02002404L,
++0x00200404L,0x02200404L,0x00202404L,0x02202404L,
++0x10000000L,0x12000000L,0x10002000L,0x12002000L,
++0x10200000L,0x12200000L,0x10202000L,0x12202000L,
++0x10000004L,0x12000004L,0x10002004L,0x12002004L,
++0x10200004L,0x12200004L,0x10202004L,0x12202004L,
++0x10000400L,0x12000400L,0x10002400L,0x12002400L,
++0x10200400L,0x12200400L,0x10202400L,0x12202400L,
++0x10000404L,0x12000404L,0x10002404L,0x12002404L,
++0x10200404L,0x12200404L,0x10202404L,0x12202404L,
++},{
++/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
++0x00000000L,0x00000001L,0x00040000L,0x00040001L,
++0x01000000L,0x01000001L,0x01040000L,0x01040001L,
++0x00000002L,0x00000003L,0x00040002L,0x00040003L,
++0x01000002L,0x01000003L,0x01040002L,0x01040003L,
++0x00000200L,0x00000201L,0x00040200L,0x00040201L,
++0x01000200L,0x01000201L,0x01040200L,0x01040201L,
++0x00000202L,0x00000203L,0x00040202L,0x00040203L,
++0x01000202L,0x01000203L,0x01040202L,0x01040203L,
++0x08000000L,0x08000001L,0x08040000L,0x08040001L,
++0x09000000L,0x09000001L,0x09040000L,0x09040001L,
++0x08000002L,0x08000003L,0x08040002L,0x08040003L,
++0x09000002L,0x09000003L,0x09040002L,0x09040003L,
++0x08000200L,0x08000201L,0x08040200L,0x08040201L,
++0x09000200L,0x09000201L,0x09040200L,0x09040201L,
++0x08000202L,0x08000203L,0x08040202L,0x08040203L,
++0x09000202L,0x09000203L,0x09040202L,0x09040203L,
++},{
++/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
++0x00000000L,0x00100000L,0x00000100L,0x00100100L,
++0x00000008L,0x00100008L,0x00000108L,0x00100108L,
++0x00001000L,0x00101000L,0x00001100L,0x00101100L,
++0x00001008L,0x00101008L,0x00001108L,0x00101108L,
++0x04000000L,0x04100000L,0x04000100L,0x04100100L,
++0x04000008L,0x04100008L,0x04000108L,0x04100108L,
++0x04001000L,0x04101000L,0x04001100L,0x04101100L,
++0x04001008L,0x04101008L,0x04001108L,0x04101108L,
++0x00020000L,0x00120000L,0x00020100L,0x00120100L,
++0x00020008L,0x00120008L,0x00020108L,0x00120108L,
++0x00021000L,0x00121000L,0x00021100L,0x00121100L,
++0x00021008L,0x00121008L,0x00021108L,0x00121108L,
++0x04020000L,0x04120000L,0x04020100L,0x04120100L,
++0x04020008L,0x04120008L,0x04020108L,0x04120108L,
++0x04021000L,0x04121000L,0x04021100L,0x04121100L,
++0x04021008L,0x04121008L,0x04021108L,0x04121108L,
++},{
++/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
++0x00000000L,0x10000000L,0x00010000L,0x10010000L,
++0x00000004L,0x10000004L,0x00010004L,0x10010004L,
++0x20000000L,0x30000000L,0x20010000L,0x30010000L,
++0x20000004L,0x30000004L,0x20010004L,0x30010004L,
++0x00100000L,0x10100000L,0x00110000L,0x10110000L,
++0x00100004L,0x10100004L,0x00110004L,0x10110004L,
++0x20100000L,0x30100000L,0x20110000L,0x30110000L,
++0x20100004L,0x30100004L,0x20110004L,0x30110004L,
++0x00001000L,0x10001000L,0x00011000L,0x10011000L,
++0x00001004L,0x10001004L,0x00011004L,0x10011004L,
++0x20001000L,0x30001000L,0x20011000L,0x30011000L,
++0x20001004L,0x30001004L,0x20011004L,0x30011004L,
++0x00101000L,0x10101000L,0x00111000L,0x10111000L,
++0x00101004L,0x10101004L,0x00111004L,0x10111004L,
++0x20101000L,0x30101000L,0x20111000L,0x30111000L,
++0x20101004L,0x30101004L,0x20111004L,0x30111004L,
++},{
++/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
++0x00000000L,0x08000000L,0x00000008L,0x08000008L,
++0x00000400L,0x08000400L,0x00000408L,0x08000408L,
++0x00020000L,0x08020000L,0x00020008L,0x08020008L,
++0x00020400L,0x08020400L,0x00020408L,0x08020408L,
++0x00000001L,0x08000001L,0x00000009L,0x08000009L,
++0x00000401L,0x08000401L,0x00000409L,0x08000409L,
++0x00020001L,0x08020001L,0x00020009L,0x08020009L,
++0x00020401L,0x08020401L,0x00020409L,0x08020409L,
++0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
++0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
++0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
++0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
++0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
++0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
++0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
++0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
++},{
++/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
++0x00000000L,0x00000100L,0x00080000L,0x00080100L,
++0x01000000L,0x01000100L,0x01080000L,0x01080100L,
++0x00000010L,0x00000110L,0x00080010L,0x00080110L,
++0x01000010L,0x01000110L,0x01080010L,0x01080110L,
++0x00200000L,0x00200100L,0x00280000L,0x00280100L,
++0x01200000L,0x01200100L,0x01280000L,0x01280100L,
++0x00200010L,0x00200110L,0x00280010L,0x00280110L,
++0x01200010L,0x01200110L,0x01280010L,0x01280110L,
++0x00000200L,0x00000300L,0x00080200L,0x00080300L,
++0x01000200L,0x01000300L,0x01080200L,0x01080300L,
++0x00000210L,0x00000310L,0x00080210L,0x00080310L,
++0x01000210L,0x01000310L,0x01080210L,0x01080310L,
++0x00200200L,0x00200300L,0x00280200L,0x00280300L,
++0x01200200L,0x01200300L,0x01280200L,0x01280300L,
++0x00200210L,0x00200310L,0x00280210L,0x00280310L,
++0x01200210L,0x01200310L,0x01280210L,0x01280310L,
++},{
++/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
++0x00000000L,0x04000000L,0x00040000L,0x04040000L,
++0x00000002L,0x04000002L,0x00040002L,0x04040002L,
++0x00002000L,0x04002000L,0x00042000L,0x04042000L,
++0x00002002L,0x04002002L,0x00042002L,0x04042002L,
++0x00000020L,0x04000020L,0x00040020L,0x04040020L,
++0x00000022L,0x04000022L,0x00040022L,0x04040022L,
++0x00002020L,0x04002020L,0x00042020L,0x04042020L,
++0x00002022L,0x04002022L,0x00042022L,0x04042022L,
++0x00000800L,0x04000800L,0x00040800L,0x04040800L,
++0x00000802L,0x04000802L,0x00040802L,0x04040802L,
++0x00002800L,0x04002800L,0x00042800L,0x04042800L,
++0x00002802L,0x04002802L,0x00042802L,0x04042802L,
++0x00000820L,0x04000820L,0x00040820L,0x04040820L,
++0x00000822L,0x04000822L,0x00040822L,0x04040822L,
++0x00002820L,0x04002820L,0x00042820L,0x04042820L,
++0x00002822L,0x04002822L,0x00042822L,0x04042822L,
++}};
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/des/spr.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,204 @@
++/* crypto/des/spr.h */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++const DES_LONG des_SPtrans[8][64]={
++{
++/* nibble 0 */
++0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
++0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
++0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
++0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
++0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
++0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
++0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
++0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
++0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
++0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
++0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
++0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
++0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
++0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
++0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
++0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
++},{
++/* nibble 1 */
++0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
++0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
++0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
++0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
++0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
++0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
++0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
++0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
++0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
++0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
++0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
++0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
++0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
++0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
++0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
++0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
++},{
++/* nibble 2 */
++0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
++0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
++0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
++0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
++0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
++0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
++0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
++0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
++0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
++0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
++0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
++0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
++0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
++0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
++0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
++0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
++},{
++/* nibble 3 */
++0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
++0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
++0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
++0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
++0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
++0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
++0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
++0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
++0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
++0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
++0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
++0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
++0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
++0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
++0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
++0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
++},{
++/* nibble 4 */
++0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
++0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
++0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
++0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
++0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
++0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
++0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
++0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
++0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
++0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
++0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
++0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
++0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
++0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
++0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
++0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
++},{
++/* nibble 5 */
++0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
++0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
++0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
++0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
++0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
++0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
++0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
++0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
++0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
++0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
++0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
++0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
++0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
++0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
++0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
++0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
++},{
++/* nibble 6 */
++0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
++0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
++0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
++0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
++0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
++0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
++0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
++0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
++0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
++0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
++0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
++0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
++0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
++0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
++0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
++0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
++},{
++/* nibble 7 */
++0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
++0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
++0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
++0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
++0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
++0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
++0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
++0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
++0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
++0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
++0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
++0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
++0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
++0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
++0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
++0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
++}};
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/aes.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,97 @@
++// I retain copyright in this code but I encourage its free use provided
++// that I don't carry any responsibility for the results. I am especially 
++// happy to see it used in free and open source software. If you do use 
++// it I would appreciate an acknowledgement of its origin in the code or
++// the product that results and I would also appreciate knowing a little
++// about the use to which it is being put. I am grateful to Frank Yellin
++// for some ideas that are used in this implementation.
++//
++// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
++//
++// This is an implementation of the AES encryption algorithm (Rijndael)
++// designed by Joan Daemen and Vincent Rijmen. This version is designed
++// to provide both fixed and dynamic block and key lengths and can also 
++// run with either big or little endian internal byte order (see aes.h). 
++// It inputs block and key lengths in bytes with the legal values being 
++// 16, 24 and 32.
++
++/*
++ * Modified by Jari Ruusu,  May 1 2001
++ *  - Fixed some compile warnings, code was ok but gcc warned anyway.
++ *  - Changed basic types: byte -> unsigned char, word -> u_int32_t
++ *  - Major name space cleanup: Names visible to outside now begin
++ *    with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
++ *  - Removed C++ and DLL support as part of name space cleanup.
++ *  - Eliminated unnecessary recomputation of tables. (actual bug fix)
++ *  - Merged precomputed constant tables to aes.c file.
++ *  - Removed data alignment restrictions for portability reasons.
++ *  - Made block and key lengths accept bit count (128/192/256)
++ *    as well byte count (16/24/32).
++ *  - Removed all error checks. This change also eliminated the need
++ *    to preinitialize the context struct to zero.
++ *  - Removed some totally unused constants.
++ */
++
++#ifndef _AES_H
++#define _AES_H
++
++#if defined(__linux__) && defined(__KERNEL__)
++#  include <linux/types.h>
++#else 
++#  include <sys/types.h>
++#endif
++
++// CONFIGURATION OPTIONS (see also aes.c)
++//
++// Define AES_BLOCK_SIZE to set the cipher block size (16, 24 or 32) or
++// leave this undefined for dynamically variable block size (this will
++// result in much slower code).
++// IMPORTANT NOTE: AES_BLOCK_SIZE is in BYTES (16, 24, 32 or undefined). If
++// left undefined a slower version providing variable block length is compiled
++
++#define AES_BLOCK_SIZE  16
++
++// The number of key schedule words for different block and key lengths
++// allowing for method of computation which requires the length to be a
++// multiple of the key length
++//
++// Nk =       4   6   8
++//        -------------
++// Nb = 4 |  60  60  64
++//      6 |  96  90  96
++//      8 | 120 120 120
++
++#if !defined(AES_BLOCK_SIZE) || (AES_BLOCK_SIZE == 32)
++#define AES_KS_LENGTH   120
++#define AES_RC_LENGTH    29
++#else
++#define AES_KS_LENGTH   4 * AES_BLOCK_SIZE
++#define AES_RC_LENGTH   (9 * AES_BLOCK_SIZE) / 8 - 8
++#endif
++
++typedef struct
++{
++    u_int32_t    aes_Nkey;      // the number of words in the key input block
++    u_int32_t    aes_Nrnd;      // the number of cipher rounds
++    u_int32_t    aes_e_key[AES_KS_LENGTH];   // the encryption key schedule
++    u_int32_t    aes_d_key[AES_KS_LENGTH];   // the decryption key schedule
++#if !defined(AES_BLOCK_SIZE)
++    u_int32_t    aes_Ncol;      // the number of columns in the cipher state
++#endif
++} aes_context;
++
++// THE CIPHER INTERFACE
++
++#if !defined(AES_BLOCK_SIZE)
++extern void aes_set_blk(aes_context *, const int);
++#endif
++extern void aes_set_key(aes_context *, const unsigned char [], const int, const int);
++extern void aes_encrypt(const aes_context *, const unsigned char [], unsigned char []);
++extern void aes_decrypt(const aes_context *, const unsigned char [], unsigned char []);
++
++// The block length inputs to aes_set_block and aes_set_key are in numbers
++// of bytes or bits.  The calls to subroutines must be made in the above
++// order but multiple calls can be made without repeating earlier calls
++// if their parameters have not changed.
++
++#endif  // _AES_H
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/aes_cbc.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,4 @@
++/* Glue header */
++#include "aes.h"
++int AES_set_key(aes_context *aes_ctx, const u_int8_t * key, int keysize);
++int AES_cbc_encrypt(aes_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/aes_xcbc_mac.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,12 @@
++#ifndef _AES_XCBC_MAC_H
++#define _AES_XCBC_MAC_H
++
++typedef u_int32_t aes_block[4];
++typedef struct {
++      aes_context ctx_k1;
++      aes_block k2;
++      aes_block k3;
++} aes_context_mac;
++int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen);
++int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]);
++#endif /* _AES_XCBC_MAC_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/cbc_generic.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,110 @@
++#ifndef _CBC_GENERIC_H
++#define _CBC_GENERIC_H
++/*
++ * CBC macro helpers
++ *
++ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++/*
++ *    Heavily inspired in loop_AES
++ */
++#define CBC_IMPL_BLK16(name, ctx_type, addr_type, enc_func, dec_func) \
++int name(ctx_type *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
++      int ret=ilen, pos; \
++      const u_int32_t *iv_i; \
++      if ((ilen) % 16) return 0; \
++      if (encrypt) { \
++              pos=0; \
++              while(pos<ilen) { \
++                      if (pos==0) \
++                              iv_i=(const u_int32_t*) iv; \
++                      else \
++                              iv_i=(const u_int32_t*) (out-16); \
++                      *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
++                      *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
++                      *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8])); \
++                      *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12])); \
++                      enc_func(ctx, (addr_type) out, (addr_type) out); \
++                      in+=16; \
++                      out+=16; \
++                      pos+=16; \
++              } \
++      } else { \
++              pos=ilen-16; \
++              in+=pos; \
++              out+=pos; \
++              while(pos>=0) { \
++                      dec_func(ctx, (const addr_type) in, (addr_type) out); \
++                      if (pos==0) \
++                              iv_i=(const u_int32_t*) (iv); \
++                      else \
++                              iv_i=(const u_int32_t*) (in-16); \
++                      *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
++                      *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
++                      *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; \
++                      *((u_int32_t *)(&out[12])) ^= iv_i[3]; \
++                      in-=16; \
++                      out-=16; \
++                      pos-=16; \
++              } \
++      } \
++      return ret; \
++} 
++#define CBC_IMPL_BLK8(name, ctx_type, addr_type,  enc_func, dec_func) \
++int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
++      int ret=ilen, pos; \
++      const u_int32_t *iv_i; \
++      if ((ilen) % 8) return 0; \
++      if (encrypt) { \
++              pos=0; \
++              while(pos<ilen) { \
++                      if (pos==0) \
++                              iv_i=(const u_int32_t*) iv; \
++                      else \
++                              iv_i=(const u_int32_t*) (out-8); \
++                      *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
++                      *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
++                      enc_func(ctx, (addr_type)out, (addr_type)out); \
++                      in+=8; \
++                      out+=8; \
++                      pos+=8; \
++              } \
++      } else { \
++              pos=ilen-8; \
++              in+=pos; \
++              out+=pos; \
++              while(pos>=0) { \
++                      dec_func(ctx, (const addr_type)in, (addr_type)out); \
++                      if (pos==0) \
++                              iv_i=(const u_int32_t*) (iv); \
++                      else \
++                              iv_i=(const u_int32_t*) (in-8); \
++                      *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
++                      *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
++                      in-=8; \
++                      out-=8; \
++                      pos-=8; \
++              } \
++      } \
++      return ret; \
++} 
++#define CBC_DECL(name, ctx_type) \
++int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt)
++/*
++Eg.:
++CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
++CBC_DECL(AES_cbc_encrypt, aes_context);
++*/
++#endif /* _CBC_GENERIC_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/des.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,286 @@
++/* crypto/des/des.org */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 
++ *
++ * Always modify des.org since des.h is automatically generated from
++ * it during SSLeay configuration.
++ *
++ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
++ */
++
++#ifndef HEADER_DES_H
++#define HEADER_DES_H
++
++#ifdef  __cplusplus
++extern "C" {
++#endif
++
++
++/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
++ * %20 speed up (longs are 8 bytes, int's are 4). */
++/* Must be unsigned int on ia64/Itanium or DES breaks badly */
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#else
++#include <sys/types.h>
++#endif
++
++#ifndef DES_LONG
++#define DES_LONG u_int32_t
++#endif
++
++typedef unsigned char des_cblock[8];
++typedef struct { des_cblock ks; } des_key_schedule[16];
++
++#define DES_KEY_SZ    (sizeof(des_cblock))
++#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
++
++#define DES_ENCRYPT   1
++#define DES_DECRYPT   0
++
++#define DES_CBC_MODE  0
++#define DES_PCBC_MODE 1
++
++#define des_ecb2_encrypt(i,o,k1,k2,e) \
++      des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
++
++#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
++      des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
++
++#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
++      des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
++
++#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
++      des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
++
++#define C_Block des_cblock
++#define Key_schedule des_key_schedule
++#ifdef KERBEROS
++#define ENCRYPT DES_ENCRYPT
++#define DECRYPT DES_DECRYPT
++#endif
++#define KEY_SZ DES_KEY_SZ
++#define string_to_key des_string_to_key
++#define read_pw_string des_read_pw_string
++#define random_key des_random_key
++#define pcbc_encrypt des_pcbc_encrypt
++#define set_key des_set_key
++#define key_sched des_key_sched
++#define ecb_encrypt des_ecb_encrypt
++#define cbc_encrypt des_cbc_encrypt
++#define ncbc_encrypt des_ncbc_encrypt
++#define xcbc_encrypt des_xcbc_encrypt
++#define cbc_cksum des_cbc_cksum
++#define quad_cksum des_quad_cksum
++
++/* For compatibility with the MIT lib - eay 20/05/92 */
++typedef des_key_schedule bit_64;
++#define des_fixup_key_parity des_set_odd_parity
++#define des_check_key_parity check_parity
++
++extern int des_check_key;     /* defaults to false */
++extern int des_rw_mode;               /* defaults to DES_PCBC_MODE */
++
++/* The next line is used to disable full ANSI prototypes, if your
++ * compiler has problems with the prototypes, make sure this line always
++ * evaluates to true :-) */
++#if defined(MSDOS) || defined(__STDC__)
++#undef NOPROTO
++#endif
++#ifndef NOPROTO
++char *des_options(void);
++void des_ecb3_encrypt(des_cblock *input,des_cblock *output,
++      des_key_schedule ks1,des_key_schedule ks2,
++      des_key_schedule ks3, int enc);
++DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
++      long length,des_key_schedule schedule,des_cblock *ivec);
++void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
++      des_key_schedule schedule,des_cblock *ivec,int enc);
++void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length,
++      des_key_schedule schedule,des_cblock *ivec,int enc);
++void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
++      des_key_schedule schedule,des_cblock *ivec,
++      des_cblock *inw,des_cblock *outw,int enc);
++void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
++      long length,des_key_schedule schedule,des_cblock *ivec,int enc);
++void des_ecb_encrypt(des_cblock *input,des_cblock *output,
++      des_key_schedule ks,int enc);
++void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc);
++void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc);
++void des_encrypt3(DES_LONG *data, des_key_schedule ks1,
++      des_key_schedule ks2, des_key_schedule ks3);
++void des_decrypt3(DES_LONG *data, des_key_schedule ks1,
++      des_key_schedule ks2, des_key_schedule ks3);
++void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, 
++      long length, des_key_schedule ks1, des_key_schedule ks2, 
++      des_key_schedule ks3, des_cblock *ivec, int enc);
++void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
++      long length, des_key_schedule ks1, des_key_schedule ks2,
++      des_key_schedule ks3, des_cblock *ivec, int *num, int enc);
++void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
++      long length, des_key_schedule ks1, des_key_schedule ks2,
++      des_key_schedule ks3, des_cblock *ivec, int *num);
++
++void des_xwhite_in2out(des_cblock (*des_key), des_cblock (*in_white),
++      des_cblock (*out_white));
++
++int des_enc_read(int fd,char *buf,int len,des_key_schedule sched,
++      des_cblock *iv);
++int des_enc_write(int fd,char *buf,int len,des_key_schedule sched,
++      des_cblock *iv);
++char *des_fcrypt(const char *buf,const char *salt, char *ret);
++
++void des_ofb_encrypt(unsigned char *in,unsigned char *out,
++      int numbits,long length,des_key_schedule schedule,des_cblock *ivec);
++void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length,
++      des_key_schedule schedule,des_cblock *ivec,int enc);
++DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output,
++      long length,int out_count,des_cblock *seed);
++void des_random_seed(des_cblock key);
++void des_random_key(des_cblock ret);
++int des_read_password(des_cblock *key,char *prompt,int verify);
++int des_read_2passwords(des_cblock *key1,des_cblock *key2,
++      char *prompt,int verify);
++int des_read_pw_string(char *buf,int length,char *prompt,int verify);
++void des_set_odd_parity(des_cblock *key);
++int des_is_weak_key(des_cblock *key);
++int des_set_key(des_cblock *key,des_key_schedule schedule);
++int des_key_sched(des_cblock *key,des_key_schedule schedule);
++void des_string_to_key(char *str,des_cblock *key);
++void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2);
++void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
++      des_key_schedule schedule, des_cblock *ivec, int *num, int enc);
++void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
++      des_key_schedule schedule, des_cblock *ivec, int *num);
++int des_read_pw(char *buf, char *buff, int size, char *prompt, int verify);
++
++/* Extra functions from Mark Murray <mark@grondar.za> */
++/* The following functions are not in the normal unix build or the
++ * SSLeay build.  When using the SSLeay build, use RAND_seed()
++ * and RAND_bytes() instead. */
++int des_new_random_key(des_cblock *key);
++void des_init_random_number_generator(des_cblock *key);
++void des_set_random_generator_seed(des_cblock *key);
++void des_set_sequence_number(des_cblock new_sequence_number);
++void des_generate_random_block(des_cblock *block);
++
++#else
++
++char *des_options();
++void des_ecb3_encrypt();
++DES_LONG des_cbc_cksum();
++void des_cbc_encrypt();
++void des_ncbc_encrypt();
++void des_xcbc_encrypt();
++void des_cfb_encrypt();
++void des_ede3_cfb64_encrypt();
++void des_ede3_ofb64_encrypt();
++void des_ecb_encrypt();
++void des_encrypt();
++void des_encrypt2();
++void des_encrypt3();
++void des_decrypt3();
++void des_ede3_cbc_encrypt();
++int des_enc_read();
++int des_enc_write();
++char *des_fcrypt();
++#ifdef PERL5
++char *des_crypt();
++#else
++char *crypt();
++#endif
++void des_ofb_encrypt();
++void des_pcbc_encrypt();
++DES_LONG des_quad_cksum();
++void des_random_seed();
++void des_random_key();
++int des_read_password();
++int des_read_2passwords();
++int des_read_pw_string();
++void des_set_odd_parity();
++int des_is_weak_key();
++int des_set_key();
++int des_key_sched();
++void des_string_to_key();
++void des_string_to_2keys();
++void des_cfb64_encrypt();
++void des_ofb64_encrypt();
++int des_read_pw();
++void des_xwhite_in2out();
++
++/* Extra functions from Mark Murray <mark@grondar.za> */
++/* The following functions are not in the normal unix build or the
++ * SSLeay build.  When using the SSLeay build, use RAND_seed()
++ * and RAND_bytes() instead. */
++#ifdef FreeBSD
++int des_new_random_key();
++void des_init_random_number_generator();
++void des_set_random_generator_seed();
++void des_set_sequence_number();
++void des_generate_random_block();
++#endif
++
++#endif
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/klips-crypto/ocf_assist.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,63 @@
++#ifndef _OCF_ASSIST_H
++#define _OCF_ASSIST_H 1
++/****************************************************************************/
++/* The various hw_assist functions return these bits */
++
++#define OCF_PROVIDES_AES              0x0001
++#define OCF_PROVIDES_DES_3DES 0x0002
++
++/****************************************************************************/
++#if !defined(OCF_ASSIST)
++/****************************************************************************/
++/*
++ *    stub it all out just in case
++ */
++
++#define ocf_aes_assist() (0)
++#define ocf_aes_set_key(a1,a2,a3,a4) 
++#define ocf_aes_cbc_encrypt(a1,a2,a3,a4,a5,a6)
++
++#define ocf_des_assist() (0)
++#define ocf_des_set_key(a, b)
++#define ocf_des_cbc_encrypt(a1,a2,a3,a4,a5,a6)
++#define ocf_des_encrypt(a1,a2,a3)
++#define ocf_des_ede3_cbc_encrypt(a1,a2,a3,a4,a5,a6,a7,a8)
++#define ocf_des_ncbc_encrypt(a1,a2,a3,a4,a5,a6)
++#define ocf_des_ecb_encrypt(a1,a2,a3,a4)
++
++/****************************************************************************/
++#else
++/****************************************************************************/
++
++#include <sys/types.h>
++#include "aes.h"
++#include "des.h"
++
++extern int    ocf_aes_assist(void);
++extern void   ocf_aes_set_key(aes_context *cx, const unsigned char in_key[],
++                                                              int n_bytes, const int f);
++extern int    ocf_aes_cbc_encrypt(aes_context *ctx, const u_int8_t *input,
++                                  u_int8_t *output,
++                                  long length,
++                                  const u_int8_t *ivec, int enc);
++
++extern int    ocf_des_assist(void);
++extern int    ocf_des_set_key(des_cblock *key, des_key_schedule schedule);
++extern void   ocf_des_cbc_encrypt(des_cblock *input, des_cblock *output,
++                                                              long length, des_key_schedule schedule,
++                                                              des_cblock *ivec, int enc);
++extern void   ocf_des_encrypt(DES_LONG *data, des_key_schedule ks, int enc);
++extern void   ocf_des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
++                                                              long length, des_key_schedule ks1,
++                                                              des_key_schedule ks2, des_key_schedule ks3,
++                                                              des_cblock *ivec, int enc);
++extern void   ocf_des_ncbc_encrypt(des_cblock *input, des_cblock *output,
++                                                              long length, des_key_schedule schedule,
++                                                              des_cblock *ivec, int enc);
++extern void   ocf_des_ecb_encrypt(des_cblock *input, des_cblock *output,
++                                                              des_key_schedule ks, int enc);
++
++/****************************************************************************/
++#endif /* !defined(OCF_ASSIST) */
++/****************************************************************************/
++#endif /* _OCF_ASSIST_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,569 @@
++#ifndef _OPENSWAN_H
++/*
++ * header file for FreeS/WAN library functions
++ * Copyright (C) 1998, 1999, 2000  Henry Spencer.
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: openswan.h,v 1.95 2005/08/25 01:24:40 paul Exp $
++ */
++#define       _OPENSWAN_H     /* seen it, no need to see it again */
++
++/* you'd think this should be builtin to compiler... */
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++/*
++ * When using uclibc, malloc(0) returns NULL instead of success. This is
++ * to make it use the inbuilt work-around.
++ * See: http://osdir.com/ml/network.freeswan.devel/2003-11/msg00009.html
++ */
++#ifdef __UCLIBC__
++# if !defined(__MALLOC_GLIBC_COMPAT__) && !defined(MALLOC_GLIBC_COMPAT)
++#  warning Please compile uclibc with GLIBC_COMPATIBILITY defined
++# endif
++#endif
++
++
++/*
++ * We've just got to have some datatypes defined...  And annoyingly, just
++ * where we get them depends on whether we're in userland or not.
++ */
++/* things that need to come from one place or the other, depending */
++#if defined(linux) 
++#if defined(__KERNEL__)
++#include <linux/types.h>
++#include <linux/socket.h>
++#include <linux/in.h>
++#include <linux/in6.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <openswan/ipsec_kversion.h>
++#include <openswan/ipsec_param.h>
++#define user_assert(foo)  /*nothing*/
++
++#else /* NOT in kernel */
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++#define user_assert(foo) assert(foo)
++#include <stdio.h>
++
++#  define uint8_t u_int8_t
++#  define uint16_t u_int16_t 
++#  define uint32_t u_int32_t 
++#  define uint64_t u_int64_t 
++
++
++
++#endif /* __KERNEL__ */
++
++#endif /* linux */
++
++#define DEBUG_NO_STATIC static
++
++/*
++ * Yes Virginia, we have started a windows port.
++ */
++#if defined(__CYGWIN32__)
++#if !defined(WIN32_KERNEL) 
++/* get windows equivalents */
++#include <stdio.h>
++#include <string.h>
++#include <win32/types.h>
++#include <netinet/in.h>
++#include <cygwin/socket.h>
++#include <assert.h>
++#define user_assert(foo) assert(foo)
++#endif /* _KERNEL */
++#endif /* WIN32 */
++
++/*
++ * Kovacs? A macosx port?
++ */
++#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
++#include <TargetConditionals.h>
++#include <AvailabilityMacros.h>
++#include <machine/types.h>
++#include <machine/endian.h>
++#include <stdint.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <time.h>
++#include <sys/time.h>
++#include <string.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <tcpd.h>
++#include <assert.h>
++#define user_assert(foo) assert(foo)
++#define __u32  unsigned int
++#define __u8  unsigned char
++#define s6_addr16 __u6_addr.__u6_addr16
++#define DEBUG_NO_STATIC static
++#endif
++
++/*
++ * FreeBSD
++ */
++#if defined(__FreeBSD__)
++#  define DEBUG_NO_STATIC static
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <string.h>
++#include <assert.h>
++#define user_assert(foo) assert(foo)
++/* apparently this way to deal with an IPv6 address is not standard. */
++#define s6_addr16 __u6_addr.__u6_addr16
++#endif
++
++
++#ifndef IPPROTO_COMP
++#  define IPPROTO_COMP 108
++#endif /* !IPPROTO_COMP */
++
++#ifndef IPPROTO_INT
++#  define IPPROTO_INT 61
++#endif /* !IPPROTO_INT */
++
++#if !defined(ESPINUDP_WITH_NON_IKE)
++#define ESPINUDP_WITH_NON_IKE   1  /* draft-ietf-ipsec-nat-t-ike-00/01 */
++#define ESPINUDP_WITH_NON_ESP   2  /* draft-ietf-ipsec-nat-t-ike-02    */
++#endif
++
++/*
++ * Basic data types for the address-handling functions.
++ * ip_address and ip_subnet are supposed to be opaque types; do not
++ * use their definitions directly, they are subject to change!
++ */
++
++/* first, some quick fakes in case we're on an old system with no IPv6 */
++#if !defined(s6_addr16) && defined(__CYGWIN32__)
++struct in6_addr {
++      union 
++      {
++              u_int8_t        u6_addr8[16];
++              u_int16_t       u6_addr16[8];
++              u_int32_t       u6_addr32[4];
++      } in6_u;
++#define s6_addr                       in6_u.u6_addr8
++#define s6_addr16             in6_u.u6_addr16
++#define s6_addr32             in6_u.u6_addr32
++};
++struct sockaddr_in6 {
++      unsigned short int      sin6_family;    /* AF_INET6 */
++      __u16                   sin6_port;      /* Transport layer port # */
++      __u32                   sin6_flowinfo;  /* IPv6 flow information */
++      struct in6_addr         sin6_addr;      /* IPv6 address */
++      __u32                   sin6_scope_id;  /* scope id (new in RFC2553) */
++};
++#endif        /* !s6_addr16 */
++
++/* then the main types */
++typedef struct {
++      union {
++              struct sockaddr_in v4;
++              struct sockaddr_in6 v6;
++      } u;
++} ip_address;
++typedef struct {
++      ip_address addr;
++      int maskbits;
++} ip_subnet;
++
++/* and the SA ID stuff */
++#ifdef __KERNEL__
++typedef __u32 ipsec_spi_t;
++#else
++typedef u_int32_t ipsec_spi_t;
++#endif
++typedef struct {              /* to identify an SA, we need: */
++        ip_address dst;               /* A. destination host */
++        ipsec_spi_t spi;      /* B. 32-bit SPI, assigned by dest. host */
++#             define  SPI_PASS        256     /* magic values... */
++#             define  SPI_DROP        257     /* ...for use... */
++#             define  SPI_REJECT      258     /* ...with SA_INT */
++#             define  SPI_HOLD        259
++#             define  SPI_TRAP        260
++#             define  SPI_TRAPSUBNET  261
++      int proto;              /* C. protocol */
++#             define  SA_ESP  50      /* IPPROTO_ESP */
++#             define  SA_AH   51      /* IPPROTO_AH */
++#             define  SA_IPIP 4       /* IPPROTO_IPIP */
++#             define  SA_COMP 108     /* IPPROTO_COMP */
++#             define  SA_INT  61      /* IANA reserved for internal use */
++} ip_said;
++
++/* misc */
++typedef const char *err_t;    /* error message, or NULL for success */
++struct prng {                 /* pseudo-random-number-generator guts */
++      unsigned char sbox[256];
++      int i, j;
++      unsigned long count;
++};
++
++
++/*
++ * definitions for user space, taken from freeswan/ipsec_sa.h
++ */
++typedef uint32_t IPsecSAref_t;
++
++/* Translation to/from nfmark.
++ *
++ * use bits 16-31. Leave bit 32 as a indicate that IPsec processing
++ * has already been done.
++ */
++#define IPSEC_SA_REF_TABLE_IDX_WIDTH 15
++#define IPSEC_SA_REF_TABLE_OFFSET    16
++#define IPSEC_SA_REF_MAASK           ((1<<IPSEC_SA_REF_TABLE_IDX_WIDTH)-1)
++
++#define IPsecSAref2NFmark(x) (((x)&IPSEC_SA_REF_MASK) << IPSEC_SA_REF_TABLE_OFFSET)
++#define NFmark2IPsecSAref(x) (((x) >> IPSEC_SA_REF_TABLE_OFFSET)&IPSEC_SA_REF_MASK)
++
++#define IPSEC_SAREF_NULL ((IPsecSAref_t)0)
++#define IPSEC_SAREF_NA   ((IPsecSAref_t)0xffff0001)
++
++/* GCC magic for use in function definitions! */
++#ifdef GCC_LINT
++# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
++# define NEVER_RETURNS __attribute__ ((noreturn))
++# define UNUSED __attribute__ ((unused))
++# define BLANK_FORMAT " "     /* GCC_LINT whines about empty formats */
++#else
++# define PRINTF_LIKE(n)       /* ignore */
++# define NEVER_RETURNS /* ignore */
++# define UNUSED /* ignore */
++# define BLANK_FORMAT ""
++#endif
++
++
++/*
++ * function to log stuff from libraries that may be used in multiple
++ * places.
++ */
++typedef int (*openswan_keying_debug_func_t)(const char *message, ...);
++
++
++
++/*
++ * new IPv6-compatible functions
++ */
++
++/* text conversions */
++err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst);
++size_t ultot(unsigned long src, int format, char *buf, size_t buflen);
++#define       ULTOT_BUF       (22+1)  /* holds 64 bits in octal */
++
++/* looks up names in DNS */
++err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst);
++
++/* does not look up names in DNS */
++err_t ttoaddr_num(const char *src, size_t srclen, int af, ip_address *dst);
++
++err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst);
++size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen);
++/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */
++#define       ADDRTOT_BUF     (32*2 + 3 + 1 + 3 + 1 + 1)
++err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst);
++size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen);
++#define       SUBNETTOT_BUF   (ADDRTOT_BUF + 1 + 3)
++size_t subnetporttot(const ip_subnet *src, int format, char *buf, size_t buflen);
++#define       SUBNETPROTOTOT_BUF      (SUBNETTOTO_BUF + ULTOT_BUF)
++err_t ttosa(const char *src, size_t srclen, ip_said *dst);
++size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen);
++#define       SATOT_BUF       (5 + ULTOA_BUF + 1 + ADDRTOT_BUF)
++err_t ttodata(const char *src, size_t srclen, int base, char *buf,
++                                              size_t buflen, size_t *needed);
++err_t ttodatav(const char *src, size_t srclen, int base,
++             char *buf,  size_t buflen, size_t *needed,
++             char *errp, size_t errlen, unsigned int flags);
++#define       TTODATAV_BUF    40      /* ttodatav's largest non-literal message */
++#define TTODATAV_IGNORESPACE  (1<<1)  /* ignore spaces in base64 encodings*/
++#define TTODATAV_SPACECOUNTS  0       /* do not ignore spaces in base64   */
++
++size_t datatot(const unsigned char *src, size_t srclen, int format
++             , char *buf, size_t buflen);
++size_t keyblobtoid(const unsigned char *src, size_t srclen, char *dst,
++                                                              size_t dstlen);
++size_t splitkeytoid(const unsigned char *e, size_t elen, const unsigned char *m,
++                                      size_t mlen, char *dst, size_t dstlen);
++#define       KEYID_BUF       10      /* up to 9 text digits plus NUL */
++err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port,
++                                                       int *has_port_wildcard);
++
++/* initializations */
++void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst);
++err_t loopbackaddr(int af, ip_address *dst);
++err_t unspecaddr(int af, ip_address *dst);
++err_t anyaddr(int af, ip_address *dst);
++err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst);
++err_t add_port(int af, ip_address *addr, unsigned short port);
++err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst);
++err_t addrtosubnet(const ip_address *addr, ip_subnet *dst);
++
++/* misc. conversions and related */
++err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst);
++int addrtypeof(const ip_address *src);
++int subnettypeof(const ip_subnet *src);
++size_t addrlenof(const ip_address *src);
++size_t addrbytesptr(const ip_address *src, const unsigned char **dst);
++size_t addrbytesptr_write(ip_address *src, unsigned char **dst);
++size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen);
++int masktocount(const ip_address *src);
++void networkof(const ip_subnet *src, ip_address *dst);
++void maskof(const ip_subnet *src, ip_address *dst);
++
++/* tests */
++int sameaddr(const ip_address *a, const ip_address *b);
++int addrcmp(const ip_address *a, const ip_address *b);
++int samesubnet(const ip_subnet *a, const ip_subnet *b);
++int addrinsubnet(const ip_address *a, const ip_subnet *s);
++int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);
++int subnetishost(const ip_subnet *s);
++int samesaid(const ip_said *a, const ip_said *b);
++int sameaddrtype(const ip_address *a, const ip_address *b);
++int samesubnettype(const ip_subnet *a, const ip_subnet *b);
++int isvalidsubnet(const ip_subnet *a);
++int isanyaddr(const ip_address *src);
++int isunspecaddr(const ip_address *src);
++int isloopbackaddr(const ip_address *src);
++
++/* low-level grot */
++int portof(const ip_address *src);
++void setportof(int port, ip_address *dst);
++struct sockaddr *sockaddrof(ip_address *src);
++size_t sockaddrlenof(const ip_address *src);
++
++/* PRNG */
++void prng_init(struct prng *prng, const unsigned char *key, size_t keylen);
++void prng_bytes(struct prng *prng, unsigned char *dst, size_t dstlen);
++unsigned long prng_count(struct prng *prng);
++void prng_final(struct prng *prng);
++
++/* odds and ends */
++const char *ipsec_version_code(void);
++const char *ipsec_version_string(void);
++const char **ipsec_copyright_notice(void);
++
++const char *dns_string_rr(int rr, char *buf, int bufsize);
++const char *dns_string_datetime(time_t seconds,
++                              char *buf,
++                              int bufsize);
++
++
++/*
++ * old functions, to be deleted eventually
++ */
++
++/* unsigned long */
++const char *                  /* NULL for success, else string literal */
++atoul(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      int base,               /* 0 means figure it out */
++      unsigned long *resultp
++);
++size_t                                /* space needed for full conversion */
++ultoa(
++      unsigned long n,
++      int base,
++      char *dst,
++      size_t dstlen
++);
++#define       ULTOA_BUF       21      /* just large enough for largest result, */
++                              /* assuming 64-bit unsigned long! */
++
++/* Internet addresses */
++const char *                  /* NULL for success, else string literal */
++atoaddr(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      struct in_addr *addr
++);
++size_t                                /* space needed for full conversion */
++addrtoa(
++      struct in_addr addr,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++#define       ADDRTOA_BUF     16      /* just large enough for largest result */
++
++/* subnets */
++const char *                  /* NULL for success, else string literal */
++atosubnet(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      struct in_addr *addr,
++      struct in_addr *mask
++);
++size_t                                /* space needed for full conversion */
++subnettoa(
++      struct in_addr addr,
++      struct in_addr mask,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++#define       SUBNETTOA_BUF   32      /* large enough for worst case result */
++
++/* ranges */
++const char *                  /* NULL for success, else string literal */
++atoasr(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      char *type,             /* 'a', 's', 'r' */
++      struct in_addr *addrs   /* two-element array */
++);
++size_t                                /* space needed for full conversion */
++rangetoa(
++      struct in_addr *addrs,  /* two-element array */
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++#define       RANGETOA_BUF    34      /* large enough for worst case result */
++
++/* data types for SA conversion functions */
++
++/* generic data, e.g. keys */
++const char *                  /* NULL for success, else string literal */
++atobytes(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      char *dst,
++      size_t dstlen,
++      size_t *lenp            /* NULL means don't bother telling me */
++);
++size_t                                /* 0 failure, else true size */
++bytestoa(
++      const unsigned char *src,
++      size_t srclen,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++
++/* old versions of generic-data functions; deprecated */
++size_t                                /* 0 failure, else true size */
++atodata(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      char *dst,
++      size_t dstlen
++);
++size_t                                /* 0 failure, else true size */
++datatoa(
++      const unsigned char *src,
++      size_t srclen,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++
++/* part extraction and special addresses */
++struct in_addr
++subnetof(
++      struct in_addr addr,
++      struct in_addr mask
++);
++struct in_addr
++hostof(
++      struct in_addr addr,
++      struct in_addr mask
++);
++struct in_addr
++broadcastof(
++      struct in_addr addr,
++      struct in_addr mask
++);
++
++/* mask handling */
++int
++goodmask(
++      struct in_addr mask
++);
++extern int masktobits(struct in_addr mask);
++extern struct in_addr  bitstomask(int n);
++extern struct in6_addr bitstomask6(int n);
++
++
++
++/*
++ * ENUM of klips debugging values. Not currently used in klips.
++ * debug flag is actually 32 -bits, but only one bit is ever used,
++ * so we can actually pack it all into a single 32-bit word.
++ */
++enum klips_debug_flags {
++    KDF_VERBOSE     = 0,
++    KDF_XMIT        = 1,
++    KDF_NETLINK     = 2, /* obsolete */
++    KDF_XFORM       = 3,
++    KDF_EROUTE      = 4,
++    KDF_SPI         = 5,
++    KDF_RADIJ       = 6,
++    KDF_ESP         = 7,
++    KDF_AH          = 8, /* obsolete */
++    KDF_RCV         = 9,
++    KDF_TUNNEL      = 10,
++    KDF_PFKEY       = 11,
++    KDF_COMP        = 12,
++    KDF_NATT        = 13,
++};
++
++
++/*
++ * Debugging levels for pfkey_lib_debug
++ */
++#define PF_KEY_DEBUG_PARSE_NONE    0
++#define PF_KEY_DEBUG_PARSE_PROBLEM 1
++#define PF_KEY_DEBUG_PARSE_STRUCT  2
++#define PF_KEY_DEBUG_PARSE_FLOW    4
++#define PF_KEY_DEBUG_BUILD         8
++#define PF_KEY_DEBUG_PARSE_MAX    15
++
++extern unsigned int pfkey_lib_debug;  /* bits selecting what to report */
++
++/*
++ * pluto and lwdnsq need to know the maximum size of the commands to,
++ * and replies from lwdnsq. 
++ */
++
++#define LWDNSQ_CMDBUF_LEN      1024
++#define LWDNSQ_RESULT_LEN_MAX  4096
++
++
++/* syntax for passthrough SA */
++#ifndef PASSTHROUGHNAME
++#define       PASSTHROUGHNAME "%passthrough"
++#define       PASSTHROUGH4NAME        "%passthrough4"
++#define       PASSTHROUGH6NAME        "%passthrough6"
++#define       PASSTHROUGHIS   "tun0@0.0.0.0"
++#define       PASSTHROUGH4IS  "tun0@0.0.0.0"
++#define       PASSTHROUGH6IS  "tun0@::"
++#define       PASSTHROUGHTYPE "tun"
++#define       PASSTHROUGHSPI  0
++#define       PASSTHROUGHDST  0
++#endif
++
++
++
++#endif /* _OPENSWAN_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipcomp.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,58 @@
++/*
++ * IPCOMP zlib interface code.
++ * Copyright (C) 2000  Svenning Soerensen <svenning@post5.tele.dk>
++ * Copyright (C) 2000, 2001  Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++
++ RCSID $Id: ipcomp.h,v 1.14 2004/07/10 19:08:41 mcr Exp $
++
++ */
++
++/* SSS */
++
++#ifndef _IPCOMP_H
++#define _IPCOMP_H
++
++/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
++#ifndef IPCOMP_PREFIX
++#define IPCOMP_PREFIX
++#endif /* IPCOMP_PREFIX */
++
++#ifndef IPPROTO_COMP
++#define IPPROTO_COMP 108
++#endif /* IPPROTO_COMP */
++
++#include "openswan/ipsec_sysctl.h"
++
++struct ipcomphdr {                    /* IPCOMP header */
++    __u8    ipcomp_nh;                /* Next header (protocol) */
++    __u8    ipcomp_flags;     /* Reserved, must be 0 */
++    __u16   ipcomp_cpi;               /* Compression Parameter Index */
++};
++
++extern struct inet_protocol comp_protocol;
++
++#define IPCOMP_UNCOMPRESSABLE     0x000000001
++#define IPCOMP_COMPRESSIONERROR   0x000000002
++#define IPCOMP_PARMERROR          0x000000004
++#define IPCOMP_DECOMPRESSIONERROR 0x000000008
++
++#define IPCOMP_ADAPT_INITIAL_TRIES    8
++#define IPCOMP_ADAPT_INITIAL_SKIP     4
++#define IPCOMP_ADAPT_SUBSEQ_TRIES     2
++#define IPCOMP_ADAPT_SUBSEQ_SKIP      8
++
++/* Function prototypes */
++struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
++struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
++
++#endif /* _IPCOMP_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_ah.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,201 @@
++/*
++ * Authentication Header declarations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_ah.h,v 1.26 2004/09/13 02:22:10 mcr Exp $
++ */
++
++#include "ipsec_md5h.h"
++#include "ipsec_sha1.h"
++
++#ifndef IPPROTO_AH
++#define IPPROTO_AH 51
++#endif /* IPPROTO_AH */
++
++#include "ipsec_auth.h"
++
++#ifdef __KERNEL__
++
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++extern struct inet_protocol ah_protocol;
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++
++struct options;
++
++struct ahhdr                          /* Generic AH header */
++{
++      __u8    ah_nh;                  /* Next header (protocol) */
++      __u8    ah_hl;                  /* AH length, in 32-bit words */
++      __u16   ah_rv;                  /* reserved, must be 0 */
++      __u32   ah_spi;                 /* Security Parameters Index */
++        __u32   ah_rpl;                 /* Replay prevention */
++      __u8    ah_data[AHHMAC_HASHLEN];/* Authentication hash */
++};
++#define AH_BASIC_LEN 8      /* basic AH header is 8 bytes, nh,hl,rv,spi
++                           * and the ah_hl, says how many bytes after that
++                           * to cover. */
++
++extern struct xform_functions ah_xform_funcs[];
++
++#include "openswan/ipsec_sysctl.h"
++
++#endif /* __KERNEL__ */
++
++/*
++ * $Log: ipsec_ah.h,v $
++ * Revision 1.26  2004/09/13 02:22:10  mcr
++ *    #define inet_protocol if necessary.
++ *
++ * Revision 1.25  2004/09/06 18:35:41  mcr
++ *    2.6.8.1 gets rid of inet_protocol->net_protocol compatibility,
++ *    so adjust for that.
++ *
++ * Revision 1.24  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.23  2004/04/05 19:55:04  mcr
++ * Moved from linux/include/freeswan/ipsec_ah.h,v
++ *
++ * Revision 1.22  2004/04/05 19:41:05  mcr
++ *    merged alg-branch code.
++ *
++ * Revision 1.21  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.22  2003/12/11 20:14:58  mcr
++ *    refactored the xmit code, to move all encapsulation
++ *    code into protocol functions. Note that all functions
++ *    are essentially done by a single function, which is probably
++ *    wrong.
++ *    the rcv_functions structures are renamed xform_functions.
++ *
++ * Revision 1.21  2003/12/06 21:21:19  mcr
++ *    split up receive path into per-transform files, for
++ *    easier later removal.
++ *
++ * Revision 1.20.8.1  2003/12/22 15:25:52  jjo
++ *      Merged algo-0.8.1-rc11-test1 into alg-branch
++ *
++ * Revision 1.20  2003/02/06 02:21:34  rgb
++ *
++ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
++ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
++ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
++ *
++ * Revision 1.19  2002/09/16 21:19:13  mcr
++ *    fixes for west-ah-icmp-01 - length of AH header must be
++ *    calculated properly, and next_header field properly copied.
++ *
++ * Revision 1.18  2002/05/14 02:37:02  rgb
++ * Change reference from _TDB to _IPSA.
++ *
++ * Revision 1.17  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_ah.h,v
++ *
++ * Revision 1.16  2002/02/20 01:27:06  rgb
++ * Ditched a pile of structs only used by the old Netlink interface.
++ *
++ * Revision 1.15  2001/12/11 02:35:57  rgb
++ * Change "struct net_device" to "struct device" for 2.2 compatibility.
++ *
++ * Revision 1.14  2001/11/26 09:23:47  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.13.2.1  2001/09/25 02:18:24  mcr
++ *    replace "struct device" with "struct netdevice"
++ *
++ * Revision 1.13  2001/06/14 19:35:08  rgb
++ * Update copyright date.
++ *
++ * Revision 1.12  2000/09/12 03:21:20  rgb
++ * Cleared out unused htonq.
++ *
++ * Revision 1.11  2000/09/08 19:12:55  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.10  2000/01/21 06:13:10  rgb
++ * Tidied up spacing.
++ * Added macros for HMAC padding magic numbers.(kravietz)
++ *
++ * Revision 1.9  1999/12/07 18:16:23  rgb
++ * Fixed comments at end of #endif lines.
++ *
++ * Revision 1.8  1999/04/11 00:28:56  henry
++ * GPL boilerplate
++ *
++ * Revision 1.7  1999/04/06 04:54:25  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.6  1999/01/26 02:06:01  rgb
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ *
++ * Revision 1.5  1999/01/22 06:17:49  rgb
++ * Updated macro comments.
++ * Added context types to support algorithm switch code.
++ * 64-bit clean-up -- converting 'u long long' to __u64.
++ *
++ * Revision 1.4  1998/07/14 15:54:56  rgb
++ * Add #ifdef __KERNEL__ to protect kernel-only structures.
++ *
++ * Revision 1.3  1998/06/30 18:05:16  rgb
++ * Comment out references to htonq.
++ *
++ * Revision 1.2  1998/06/25 19:33:46  rgb
++ * Add prototype for protocol receive function.
++ * Rearrange for more logical layout.
++ *
++ * Revision 1.1  1998/06/18 21:27:43  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.4  1998/05/18 22:28:43  rgb
++ * Disable key printing facilities from /proc/net/ipsec_*.
++ *
++ * Revision 1.3  1998/04/21 21:29:07  rgb
++ * Rearrange debug switches to change on the fly debug output from user
++ * space.  Only kernel changes checked in at this time.  radij.c was also
++ * changed to temporarily remove buggy debugging code in rj_delete causing
++ * an OOPS and hence, netlink device open errors.
++ *
++ * Revision 1.2  1998/04/12 22:03:17  rgb
++ * Updated ESP-3DES-HMAC-MD5-96,
++ *    ESP-DES-HMAC-MD5-96,
++ *    AH-HMAC-MD5-96,
++ *    AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
++ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
++ *
++ * Fixed eroute references in /proc/net/ipsec*.
++ *
++ * Started to patch module unloading memory leaks in ipsec_netlink and
++ * radij tree unloading.
++ *
++ * Revision 1.1  1998/04/09 03:05:55  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:02  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Added definitions for new AH transforms.
++ *
++ * Revision 0.3  1996/11/20 14:35:48  ji
++ * Minor Cleanup.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_alg.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,248 @@
++/*
++ * Modular extensions service and registration functions interface
++ *
++ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ *
++ * ipsec_alg.h,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ *
++ */
++/*
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++#ifndef IPSEC_ALG_H
++#define IPSEC_ALG_H
++
++/* 
++ *   gcc >= 3.2 has removed __FUNCTION__, replaced by C99 __func__
++ *   *BUT* its a compiler variable.
++ */
++#if (__GNUC__ >= 3)
++#ifndef __FUNCTION__
++#define __FUNCTION__ __func__
++#endif
++#endif
++
++/*    Version 0.8.1-0 */
++#define IPSEC_ALG_VERSION     0x00080100
++
++#include <linux/types.h>
++#include <linux/list.h>
++#include <asm/atomic.h>
++#include <openswan/pfkey.h>
++
++/*    
++ *    The following structs are used via pointers in ipsec_alg object to
++ *    avoid ipsec_alg.h coupling with freeswan headers, thus simplifying
++ *    module development
++ */
++struct ipsec_sa;
++struct esp;
++
++/**************************************
++ *
++ *    Main registration object 
++ *
++ *************************************/
++#define IPSEC_ALG_VERSION_QUAD(v)     \
++      (v>>24),((v>>16)&0xff),((v>>8)&0xff),(v&0xff)
++/*    
++ *    Main ipsec_alg objects: "OOPrograming wannabe"
++ *    Hierachy (carefully handled with _minimal_ cast'ing):
++ *
++ *      ipsec_alg+
++ *             +->ipsec_alg_enc  (ixt_alg_type=SADB_EXT_SUPPORTED_ENCRYPT)
++ *             +->ipsec_alg_auth (ixt_alg_type=SADB_EXT_SUPPORTED_AUTH)
++ */
++
++/***************************************************************
++ *
++ *    INTERFACE object: struct ipsec_alg
++ *
++ ***************************************************************/
++
++#define ixt_alg_type ixt_support.ias_exttype
++#define ixt_alg_id   ixt_support.ias_id
++
++#define IPSEC_ALG_ST_SUPP     0x01
++#define IPSEC_ALG_ST_REGISTERED 0x02
++#define IPSEC_ALG_ST_EXCL     0x04
++struct ipsec_alg {
++      unsigned ixt_version;   /* only allow this version (or 'near')*/ \
++      struct list_head ixt_list;      /* dlinked list */ \
++      struct module *ixt_module;      /* THIS_MODULE */ \
++      unsigned ixt_state;             /* state flags */ \
++      atomic_t ixt_refcnt;    /* ref. count when pointed from ipsec_sa */ \
++      char ixt_name[16];      /* descriptive short name, eg. "3des" */ \
++      void *ixt_data;         /* private for algo implementation */ \
++      uint8_t  ixt_blocksize; /* blocksize in bytes */ \
++
++      struct ipsec_alg_supported ixt_support;
++};
++/* 
++ *    Note the const in cbc_encrypt IV arg:
++ *    some ciphers like to toast passed IV (eg. 3DES): make a local IV copy
++ */
++struct ipsec_alg_enc {
++      struct ipsec_alg ixt_common;
++      unsigned ixt_e_keylen;          /* raw key length in bytes          */
++      unsigned ixt_e_ctx_size;        /* sa_p->key_e_size */
++      int (*ixt_e_set_key)(struct ipsec_alg_enc *alg, __u8 *key_e, const __u8 *key, size_t keysize);
++      __u8 *(*ixt_e_new_key)(struct ipsec_alg_enc *alg, const __u8 *key, size_t keysize);
++      void (*ixt_e_destroy_key)(struct ipsec_alg_enc *alg, __u8 *key_e);
++      int (*ixt_e_cbc_encrypt)(struct ipsec_alg_enc *alg, __u8 *key_e, __u8 *in, int ilen, __u8 *iv, int encrypt);
++};
++struct ipsec_alg_auth {
++      struct ipsec_alg ixt_common;
++      unsigned ixt_a_keylen;          /* raw key length in bytes          */
++      unsigned ixt_a_ctx_size;        /* sa_p->key_a_size */
++      unsigned ixt_a_authlen;         /* 'natural' auth. hash len (bytes) */
++      int (*ixt_a_hmac_set_key)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *key, int keylen);
++      int (*ixt_a_hmac_hash)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *dat, int len, __u8 *hash, int hashlen);
++};
++/*    
++ *    These are _copies_ of SADB_EXT_SUPPORTED_{AUTH,ENCRYPT}, 
++ *    to avoid header coupling for true constants
++ *    about headers ... "cp is your friend" --Linus
++ */
++#define IPSEC_ALG_TYPE_AUTH   14
++#define IPSEC_ALG_TYPE_ENCRYPT        15
++
++/***************************************************************
++ *
++ *    INTERFACE for module loading,testing, and unloading
++ *
++ ***************************************************************/
++/*    -  registration calls   */
++int register_ipsec_alg(struct ipsec_alg *);
++int unregister_ipsec_alg(struct ipsec_alg *);
++/*    -  optional (simple test) for algos     */
++int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int testparm);
++/*    inline wrappers (usefull for type validation */
++static inline int register_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
++      return register_ipsec_alg((struct ipsec_alg*)ixt);
++}
++static inline int unregister_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
++      return unregister_ipsec_alg((struct ipsec_alg*)ixt);
++}
++static inline int register_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
++      return register_ipsec_alg((struct ipsec_alg*)ixt);
++}
++static inline int unregister_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
++      return unregister_ipsec_alg((struct ipsec_alg*)ixt);
++}
++
++/*****************************************************************
++ *
++ *    INTERFACE for ENC services: key creation, encrypt function
++ *
++ *****************************************************************/
++
++#define IPSEC_ALG_ENCRYPT 1
++#define IPSEC_ALG_DECRYPT 0
++
++/*    encryption key context creation function */
++int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p);
++/* 
++ *    ipsec_alg_esp_encrypt(): encrypt ilen bytes in idat returns
++ *    0 or ERR<0
++ */
++int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 *idat, int ilen, __u8 *iv, int action);
++
++/***************************************************************
++ *
++ *    INTERFACE for AUTH services: key creation, hash functions
++ *
++ ***************************************************************/
++int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p);
++int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) ;
++#define ipsec_alg_sa_esp_update(c,k,l) ipsec_alg_sa_esp_hash(c,k,l,NULL,0)
++
++/* only called from ipsec_init.c */
++int ipsec_alg_init(void);
++
++/* algo module glue for static algos */
++void ipsec_alg_static_init(void);
++typedef int (*ipsec_alg_init_func_t) (void);
++
++/**********************************************
++ *
++ *    INTERFACE for ipsec_sa init and wipe
++ *
++ **********************************************/
++
++/* returns true if ipsec_sa has ipsec_alg obj attached */
++/* 
++ * Initializes ipsec_sa's ipsec_alg object, using already loaded
++ * proto, authalg, encalg.; links ipsec_alg objects (enc, auth)
++ */
++int ipsec_alg_sa_init(struct ipsec_sa *sa_p);
++/* 
++ * Destroys ipsec_sa's ipsec_alg object
++ * unlinking ipsec_alg objects
++ */
++int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p);
++
++#define IPSEC_ALG_MODULE_INIT_MOD( func_name )        \
++      static int func_name(void);             \
++      module_init(func_name);                 \
++      static int __init func_name(void)
++#define IPSEC_ALG_MODULE_EXIT_MOD( func_name )        \
++      static void func_name(void);            \
++      module_exit(func_name);                 \
++      static void __exit func_name(void)
++
++#define IPSEC_ALG_MODULE_INIT_STATIC( func_name )     \
++      extern int func_name(void);             \
++      int func_name(void)
++#define IPSEC_ALG_MODULE_EXIT_STATIC( func_name )     \
++      extern void func_name(void);            \
++      void func_name(void)
++
++/**********************************************
++ *
++ *    2.2 backport for some 2.4 useful module stuff
++ *
++ **********************************************/
++#ifdef MODULE
++#ifndef THIS_MODULE
++#define THIS_MODULE          (&__this_module)
++#endif
++#ifndef module_init
++typedef int (*__init_module_func_t)(void);
++typedef void (*__cleanup_module_func_t)(void);
++
++#define module_init(x) \
++        int init_module(void) __attribute__((alias(#x))); \
++        static inline __init_module_func_t __init_module_inline(void) \
++        { return x; }
++#define module_exit(x) \
++        void cleanup_module(void) __attribute__((alias(#x))); \
++        static inline __cleanup_module_func_t __cleanup_module_inline(void) \
++        { return x; }
++#endif
++#define IPSEC_ALG_MODULE_INIT( func_name )    IPSEC_ALG_MODULE_INIT_MOD( func_name )  
++#define IPSEC_ALG_MODULE_EXIT( func_name )    IPSEC_ALG_MODULE_EXIT_MOD( func_name )
++
++#else /* not MODULE */
++#ifndef THIS_MODULE
++#define THIS_MODULE          NULL
++#endif
++/*    
++ *    I only want module_init() magic 
++ *    when algo.c file *is THE MODULE*, in all other
++ *    cases, initialization is called explicitely from ipsec_alg_init()
++ */
++#define IPSEC_ALG_MODULE_INIT( func_name )      IPSEC_ALG_MODULE_INIT_STATIC(func_name)
++#define IPSEC_ALG_MODULE_EXIT( func_name )    IPSEC_ALG_MODULE_EXIT_STATIC(func_name)
++#endif
++
++#endif /* IPSEC_ALG_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_alg_3des.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,12 @@
++struct TripleDES_context {
++  des_key_schedule s1;
++  des_key_schedule s2;
++  des_key_schedule s3;
++};
++typedef struct TripleDES_context TripleDES_context;
++
++#define ESP_3DES_KEY_SZ       3*(sizeof(des_cblock))
++#define ESP_3DES_CBC_BLK_LEN    8
++
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_auth.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,100 @@
++/*
++ * Authentication Header declarations
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_auth.h,v 1.3 2004/04/06 02:49:08 mcr Exp $
++ */
++
++#include "ipsec_md5h.h"
++#include "ipsec_sha1.h"
++
++#ifndef IPSEC_AUTH_H
++#define IPSEC_AUTH_H
++
++#define AH_FLENGTH            12              /* size of fixed part */
++#define AHMD5_KMAX            64              /* MD5 max 512 bits key */
++#define AHMD5_AMAX            12              /* MD5 96 bits of authenticator */
++
++#define AHMD596_KLEN          16              /* MD5 128 bits key */
++#define AHSHA196_KLEN         20              /* SHA1 160 bits key */
++
++#define AHMD596_ALEN          16              /* MD5 128 bits authentication length */
++#define AHSHA196_ALEN         20              /* SHA1 160 bits authentication length */
++
++#define AHMD596_BLKLEN        64              /* MD5 block length */
++#define AHSHA196_BLKLEN       64              /* SHA1 block length */
++#define AHSHA2_256_BLKLEN     64              /* SHA2-256 block length */
++#define AHSHA2_384_BLKLEN     128             /* SHA2-384 block length (?) */
++#define AHSHA2_512_BLKLEN     128             /* SHA2-512 block length */
++
++#define AH_BLKLEN_MAX                 128             /* keep up to date! */
++
++
++#define AH_AMAX               AHSHA196_ALEN   /* keep up to date! */
++#define AHHMAC_HASHLEN        12              /* authenticator length of 96bits */
++#define AHHMAC_RPLLEN         4               /* 32 bit replay counter */
++
++#define DB_AH_PKTRX           0x0001
++#define DB_AH_PKTRX2          0x0002
++#define DB_AH_DMP             0x0004
++#define DB_AH_IPSA            0x0010
++#define DB_AH_XF              0x0020
++#define DB_AH_INAU            0x0040
++#define DB_AH_REPLAY          0x0100
++
++#ifdef __KERNEL__
++
++/* General HMAC algorithm is described in RFC 2104 */
++
++#define               HMAC_IPAD       0x36
++#define               HMAC_OPAD       0x5C
++
++struct md5_ctx {
++      MD5_CTX ictx;           /* context after H(K XOR ipad) */
++      MD5_CTX octx;           /* context after H(K XOR opad) */
++};
++
++struct sha1_ctx {
++      SHA1_CTX ictx;          /* context after H(K XOR ipad) */
++      SHA1_CTX octx;          /* context after H(K XOR opad) */
++};
++
++struct auth_alg {
++      void (*init)(void *ctx);
++      void (*update)(void *ctx, unsigned char *bytes, __u32 len);
++      void (*final)(unsigned char *hash, void *ctx);
++      int hashlen;
++};
++
++struct options;
++
++#endif /* __KERNEL__ */
++#endif /* IPSEC_AUTH_H */
++
++/*
++ * $Log: ipsec_auth.h,v $
++ * Revision 1.3  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.2  2004/04/05 19:55:04  mcr
++ * Moved from linux/include/freeswan/ipsec_auth.h,v
++ *
++ * Revision 1.1  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.1  2003/12/06 21:21:19  mcr
++ *    split up receive path into per-transform files, for
++ *    easier later removal.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_encap.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,149 @@
++/*
++ * declarations relevant to encapsulation-like operations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_encap.h,v 1.19 2004/04/05 19:55:04 mcr Exp $
++ */
++
++#ifndef _IPSEC_ENCAP_H_
++
++#define SENT_IP4      16      /* data is two struct in_addr + proto + ports*/
++                      /* (2 * sizeof(struct in_addr)) */
++                      /* sizeof(struct sockaddr_encap)
++                         - offsetof(struct sockaddr_encap, Sen.Sip4.Src) */
++
++struct sockaddr_encap
++{
++      __u8    sen_len;                /* length */
++      __u8    sen_family;             /* AF_ENCAP */
++      __u16   sen_type;               /* see SENT_* */
++      union
++      {
++              struct                  /* SENT_IP4 */
++              {
++                      struct in_addr Src;
++                      struct in_addr Dst;
++                      __u8 Proto;
++                      __u16 Sport;
++                      __u16 Dport;
++              } Sip4;
++      } Sen;
++};
++
++#define sen_ip_src    Sen.Sip4.Src
++#define sen_ip_dst    Sen.Sip4.Dst
++#define sen_proto       Sen.Sip4.Proto
++#define sen_sport       Sen.Sip4.Sport
++#define sen_dport       Sen.Sip4.Dport
++
++#ifndef AF_ENCAP
++#define AF_ENCAP 26
++#endif /* AF_ENCAP */
++
++#define _IPSEC_ENCAP_H_
++#endif /* _IPSEC_ENCAP_H_ */
++
++/*
++ * $Log: ipsec_encap.h,v $
++ * Revision 1.19  2004/04/05 19:55:04  mcr
++ * Moved from linux/include/freeswan/ipsec_encap.h,v
++ *
++ * Revision 1.18  2003/10/31 02:27:05  mcr
++ *    pulled up port-selector patches and sa_id elimination.
++ *
++ * Revision 1.17.30.1  2003/09/21 13:59:38  mcr
++ *    pre-liminary X.509 patch - does not yet pass tests.
++ *
++ * Revision 1.17  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_encap.h,v
++ *
++ * Revision 1.16  2001/11/26 09:23:47  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.15.2.1  2001/09/25 02:18:54  mcr
++ *    struct eroute moved to ipsec_eroute.h
++ *
++ * Revision 1.15  2001/09/14 16:58:36  rgb
++ * Added support for storing the first and last packets through a HOLD.
++ *
++ * Revision 1.14  2001/09/08 21:13:31  rgb
++ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
++ *
++ * Revision 1.13  2001/06/14 19:35:08  rgb
++ * Update copyright date.
++ *
++ * Revision 1.12  2001/05/27 06:12:10  rgb
++ * Added structures for pid, packet count and last access time to eroute.
++ * Added packet count to beginning of /proc/net/ipsec_eroute.
++ *
++ * Revision 1.11  2000/09/08 19:12:56  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.10  2000/03/22 16:15:36  rgb
++ * Fixed renaming of dev_get (MB).
++ *
++ * Revision 1.9  2000/01/21 06:13:26  rgb
++ * Added a macro for AF_ENCAP
++ *
++ * Revision 1.8  1999/12/31 14:56:55  rgb
++ * MB fix for 2.3 dev-use-count.
++ *
++ * Revision 1.7  1999/11/18 04:09:18  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.6  1999/09/24 00:34:13  rgb
++ * Add Marc Boucher's support for 2.3.xx+.
++ *
++ * Revision 1.5  1999/04/11 00:28:57  henry
++ * GPL boilerplate
++ *
++ * Revision 1.4  1999/04/06 04:54:25  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.3  1998/10/19 14:44:28  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.2  1998/07/14 18:19:33  rgb
++ * Added #ifdef __KERNEL__ directives to restrict scope of header.
++ *
++ * Revision 1.1  1998/06/18 21:27:44  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.2  1998/04/21 21:29:10  rgb
++ * Rearrange debug switches to change on the fly debug output from user
++ * space.  Only kernel changes checked in at this time.  radij.c was also
++ * changed to temporarily remove buggy debugging code in rj_delete causing
++ * an OOPS and hence, netlink device open errors.
++ *
++ * Revision 1.1  1998/04/09 03:05:58  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:02  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Minor cosmetic changes.
++ *
++ * Revision 0.3  1996/11/20 14:35:48  ji
++ * Minor Cleanup.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_eroute.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,112 @@
++/*
++ * @(#) declarations of eroute structures
++ *
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs <rgb@freeswan.org>
++ * Copyright (C) 2001                    Michael Richardson <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_eroute.h,v 1.5 2004/04/05 19:55:05 mcr Exp $
++ *
++ * derived from ipsec_encap.h 1.15 on 2001/9/18 by mcr.
++ *
++ */
++
++#ifndef _IPSEC_EROUTE_H_
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++
++/*
++ * The "type" is really part of the address as far as the routing
++ * system is concerned. By using only one bit in the type field
++ * for each type, we sort-of make sure that different types of
++ * encapsulation addresses won't be matched against the wrong type.
++ */
++
++/*
++ * An entry in the radix tree 
++ */
++
++struct rjtentry
++{
++      struct  radij_node rd_nodes[2]; /* tree glue, and other values */
++#define       rd_key(r)       ((struct sockaddr_encap *)((r)->rd_nodes->rj_key))
++#define       rd_mask(r)      ((struct sockaddr_encap *)((r)->rd_nodes->rj_mask))
++      short   rd_flags;
++      short   rd_count;
++};
++
++struct ident
++{
++      __u16   type;   /* identity type */
++      __u64   id;     /* identity id */
++      __u8    len;    /* identity len */
++      caddr_t data;   /* identity data */
++};
++
++/*
++ * An encapsulation route consists of a pointer to a 
++ * radix tree entry and a SAID (a destination_address/SPI/protocol triple).
++ */
++
++struct eroute
++{
++      struct rjtentry er_rjt;
++      ip_said er_said;
++      uint32_t er_pid;
++      uint32_t er_count;
++      uint64_t er_lasttime;
++      struct sockaddr_encap er_eaddr; /* MCR get rid of _encap, it is silly*/
++      struct sockaddr_encap er_emask;
++        struct ident er_ident_s;
++        struct ident er_ident_d;
++      struct sk_buff* er_first;
++      struct sk_buff* er_last;
++};
++
++#define er_dst er_said.dst
++#define er_spi er_said.spi
++
++#define _IPSEC_EROUTE_H_
++#endif /* _IPSEC_EROUTE_H_ */
++
++/*
++ * $Log: ipsec_eroute.h,v $
++ * Revision 1.5  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_eroute.h,v
++ *
++ * Revision 1.4  2003/10/31 02:27:05  mcr
++ *    pulled up port-selector patches and sa_id elimination.
++ *
++ * Revision 1.3.30.2  2003/10/29 01:10:19  mcr
++ *    elimited "struct sa_id"
++ *
++ * Revision 1.3.30.1  2003/09/21 13:59:38  mcr
++ *    pre-liminary X.509 patch - does not yet pass tests.
++ *
++ * Revision 1.3  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_eroute.h,v
++ *
++ * Revision 1.2  2001/11/26 09:16:13  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.1.2.1  2001/09/25 02:18:54  mcr
++ *    struct eroute moved to ipsec_eroute.h
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_errs.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,53 @@
++/*
++ * @(#) definition of ipsec_errs structure
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_errs.h,v 1.4 2004/04/05 19:55:05 mcr Exp $
++ *
++ */
++
++/* 
++ * This file describes the errors/statistics that FreeSWAN collects.
++ *
++ */
++
++struct ipsec_errs {
++      __u32           ips_alg_errs;          /* number of algorithm errors */
++      __u32           ips_auth_errs;         /* # of authentication errors */
++      __u32           ips_encsize_errs;      /* # of encryption size errors*/
++      __u32           ips_encpad_errs;       /* # of encryption pad  errors*/
++      __u32           ips_replaywin_errs;    /* # of pkt sequence errors */
++};
++
++/*
++ * $Log: ipsec_errs.h,v $
++ * Revision 1.4  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_errs.h,v
++ *
++ * Revision 1.3  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_errs.h,v
++ *
++ * Revision 1.2  2001/11/26 09:16:13  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.1.2.1  2001/09/25 02:25:57  mcr
++ *    lifetime structure created and common functions created.
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_esp.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,161 @@
++/*
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_esp.h,v 1.28 2004/09/13 02:22:10 mcr Exp $
++ */
++
++#include "openswan/ipsec_md5h.h"
++#include "openswan/ipsec_sha1.h"
++
++#include "klips-crypto/des.h"
++
++#ifndef IPPROTO_ESP
++#define IPPROTO_ESP 50
++#endif /* IPPROTO_ESP */
++
++#define ESP_HEADER_LEN                8       /* 64 bits header (spi+rpl)*/
++
++#define EMT_ESPDESCBC_ULEN    20      /* coming from user mode */
++#define EMT_ESPDES_KMAX               64      /* 512 bit secret key enough? */
++#define EMT_ESPDES_KEY_SZ     8       /* 56 bit secret key with parity = 64 bits */
++#define EMT_ESP3DES_KEY_SZ    24      /* 168 bit secret key with parity = 192 bits */
++#define EMT_ESPDES_IV_SZ      8       /* IV size */
++#define ESP_DESCBC_BLKLEN       8       /* DES-CBC block size */
++
++#define ESP_IV_MAXSZ          16      /* This is _critical_ */
++#define ESP_IV_MAXSZ_INT      (ESP_IV_MAXSZ/sizeof(int))
++
++#define DB_ES_PKTRX   0x0001
++#define DB_ES_PKTRX2  0x0002
++#define DB_ES_IPSA    0x0010
++#define DB_ES_XF      0x0020
++#define DB_ES_IPAD    0x0040
++#define DB_ES_INAU    0x0080
++#define DB_ES_OINFO   0x0100
++#define DB_ES_OINFO2  0x0200
++#define DB_ES_OH      0x0400
++#define DB_ES_REPLAY  0x0800
++
++#ifdef __KERNEL__
++struct des_eks {
++      des_key_schedule ks;
++};
++
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++extern struct inet_protocol esp_protocol;
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++
++struct options;
++
++struct esphdr
++{
++      __u32   esp_spi;                /* Security Parameters Index */
++        __u32   esp_rpl;                /* Replay counter */
++      __u8    esp_iv[8];              /* iv */
++};
++
++extern struct xform_functions esp_xform_funcs[];
++
++extern enum ipsec_rcv_value ipsec_rcv_esp_post_decrypt(struct ipsec_rcv_state *irs);
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int debug_esp;
++#endif /* CONFIG_KLIPS_DEBUG */
++#endif /* __KERNEL__ */
++
++/*
++ * $Log: ipsec_esp.h,v $
++ * Revision 1.28  2004/09/13 02:22:10  mcr
++ *    #define inet_protocol if necessary.
++ *
++ * Revision 1.27  2004/09/06 18:35:41  mcr
++ *    2.6.8.1 gets rid of inet_protocol->net_protocol compatibility,
++ *    so adjust for that.
++ *
++ * Revision 1.26  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.25  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.24  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_esp.h,v
++ *
++ * Revision 1.23  2004/04/05 19:41:05  mcr
++ *    merged alg-branch code.
++ *
++ * Revision 1.22  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.23  2003/12/11 20:14:58  mcr
++ *    refactored the xmit code, to move all encapsulation
++ *    code into protocol functions. Note that all functions
++ *    are essentially done by a single function, which is probably
++ *    wrong.
++ *    the rcv_functions structures are renamed xform_functions.
++ *
++ * Revision 1.22  2003/12/06 21:21:19  mcr
++ *    split up receive path into per-transform files, for
++ *    easier later removal.
++ *
++ * Revision 1.21.8.1  2003/12/22 15:25:52  jjo
++ *      Merged algo-0.8.1-rc11-test1 into alg-branch
++ *
++ * Revision 1.21  2003/02/06 02:21:34  rgb
++ *
++ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
++ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
++ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
++ *
++ * Revision 1.20  2002/05/14 02:37:02  rgb
++ * Change reference from _TDB to _IPSA.
++ *
++ * Revision 1.19  2002/04/24 07:55:32  mcr
++ *    #include patches and Makefiles for post-reorg compilation.
++ *
++ * Revision 1.18  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_esp.h,v
++ *
++ * Revision 1.17  2002/02/20 01:27:07  rgb
++ * Ditched a pile of structs only used by the old Netlink interface.
++ *
++ * Revision 1.16  2001/12/11 02:35:57  rgb
++ * Change "struct net_device" to "struct device" for 2.2 compatibility.
++ *
++ * Revision 1.15  2001/11/26 09:23:48  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.14.2.3  2001/10/23 04:16:42  mcr
++ *    get definition of des_key_schedule from des.h
++ *
++ * Revision 1.14.2.2  2001/10/22 20:33:13  mcr
++ *    use "des_key_schedule" structure instead of cooking our own.
++ *
++ * Revision 1.14.2.1  2001/09/25 02:18:25  mcr
++ *    replace "struct device" with "struct netdevice"
++ *
++ * Revision 1.14  2001/06/14 19:35:08  rgb
++ * Update copyright date.
++ *
++ * Revision 1.13  2000/09/08 19:12:56  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.12  2000/08/01 14:51:50  rgb
++ * Removed _all_ remaining traces of DES.
++ *
++ * Revision 1.11  2000/01/10 16:36:20  rgb
++ * Ditch last of EME option flags, including initiator.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_ipcomp.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,97 @@
++/*
++ * IP compression header declations
++ *
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_ipcomp.h,v 1.4 2004/07/10 19:08:41 mcr Exp $
++ */
++
++#ifndef IPSEC_IPCOMP_H
++#define IPSEC_IPCOMP_H
++
++#include "openswan/ipsec_auth.h"
++
++/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
++#ifndef IPCOMP_PREFIX
++#define IPCOMP_PREFIX
++#endif /* IPCOMP_PREFIX */
++
++#ifndef IPPROTO_COMP
++#define IPPROTO_COMP 108
++#endif /* IPPROTO_COMP */
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int sysctl_ipsec_debug_ipcomp;
++#endif /* CONFIG_KLIPS_DEBUG */
++
++struct ipcomphdr {                    /* IPCOMP header */
++    __u8    ipcomp_nh;                /* Next header (protocol) */
++    __u8    ipcomp_flags;     /* Reserved, must be 0 */
++    __u16   ipcomp_cpi;               /* Compression Parameter Index */
++};
++
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++extern struct inet_protocol comp_protocol;
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++
++extern int sysctl_ipsec_debug_ipcomp;
++
++#define IPCOMP_UNCOMPRESSABLE     0x000000001
++#define IPCOMP_COMPRESSIONERROR   0x000000002
++#define IPCOMP_PARMERROR          0x000000004
++#define IPCOMP_DECOMPRESSIONERROR 0x000000008
++
++#define IPCOMP_ADAPT_INITIAL_TRIES    8
++#define IPCOMP_ADAPT_INITIAL_SKIP     4
++#define IPCOMP_ADAPT_SUBSEQ_TRIES     2
++#define IPCOMP_ADAPT_SUBSEQ_SKIP      8
++
++/* Function prototypes */
++struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
++struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
++
++extern struct xform_functions ipcomp_xform_funcs[];
++
++#endif /* IPSEC_IPCOMP_H */
++
++/*
++ * $Log: ipsec_ipcomp.h,v $
++ * Revision 1.4  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.3  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.2  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_ipcomp.h,v
++ *
++ * Revision 1.1  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.2  2003/12/11 20:14:58  mcr
++ *    refactored the xmit code, to move all encapsulation
++ *    code into protocol functions. Note that all functions
++ *    are essentially done by a single function, which is probably
++ *    wrong.
++ *    the rcv_functions structures are renamed xform_functions.
++ *
++ * Revision 1.1  2003/12/06 21:21:19  mcr
++ *    split up receive path into per-transform files, for
++ *    easier later removal.
++ *
++ *
++ *
++ */
++
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_ipe4.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,68 @@
++/*
++ * IP-in-IP Header declarations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_ipe4.h,v 1.6 2004/04/05 19:55:05 mcr Exp $
++ */
++
++/* The packet header is an IP header! */
++
++struct ipe4_xdata                     /* transform table data */
++{
++      struct in_addr  i4_src;
++      struct in_addr  i4_dst;
++};
++
++#define EMT_IPE4_ULEN 8       /* coming from user mode */
++ 
++
++/*
++ * $Log: ipsec_ipe4.h,v $
++ * Revision 1.6  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_ipe4.h,v
++ *
++ * Revision 1.5  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_ipe4.h,v
++ *
++ * Revision 1.4  2001/06/14 19:35:08  rgb
++ * Update copyright date.
++ *
++ * Revision 1.3  1999/04/11 00:28:57  henry
++ * GPL boilerplate
++ *
++ * Revision 1.2  1999/04/06 04:54:25  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.1  1998/06/18 21:27:47  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.1  1998/04/09 03:06:07  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:03  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:48:53  ji
++ * Release update only.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_ipip.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_ipip.h,v 1.2 2004/04/05 19:55:05 mcr Exp $
++ */
++
++#ifndef _IPSEC_IPIP_H_
++
++#ifndef IPPROTO_IPIP
++#define IPPROTO_IPIP 4
++#endif /* IPPROTO_ESP */
++
++extern struct xform_functions ipip_xform_funcs[];
++
++#define _IPSEC_IPIP_H_
++
++#endif /* _IPSEC_IPIP_H_ */
++
++/*
++ * $Log: ipsec_ipip.h,v $
++ * Revision 1.2  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_ipip.h,v
++ *
++ * Revision 1.1  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.1  2003/12/11 20:14:58  mcr
++ *    refactored the xmit code, to move all encapsulation
++ *    code into protocol functions. Note that all functions
++ *    are essentially done by a single function, which is probably
++ *    wrong.
++ *    the rcv_functions structures are renamed xform_functions.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_kern24.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,92 @@
++/*
++ * @(#) routines to makes kernel 2.4 compatible with 2.6 usage.
++ *
++ * Copyright (C) 2004 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ * Copyright (C) 2005 - 2008 Paul Wouters <paul@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++#ifndef _IPSEC_KERN24_H
++
++
++#ifdef NETDEV_23
++#if 0
++#ifndef NETDEV_25
++#define device net_device
++#endif
++#endif
++
++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#  define __ipsec_dev_get(x) __dev_get_by_name(&init_net, x)
++#  define ipsec_dev_get(x) dev_get_by_name(&init_net, x)
++# else
++#  define ipsec_dev_get(x) __dev_get_by_name(x)
++#  define __ipsec_dev_get(x) __dev_get_by_name(x)
++# endif
++
++# define ipsec_dev_put(x) dev_put(x)
++# define __ipsec_dev_put(x) __dev_put(x)
++# define ipsec_dev_hold(x) dev_hold(x)
++#else /* NETDEV_23 */
++# define ipsec_dev_get dev_get
++# define __ipsec_dev_put(x) 
++# define ipsec_dev_put(x)
++# define ipsec_dev_hold(x) 
++#endif /* NETDEV_23 */
++
++#ifndef HAVE_NETDEV_PRINTK
++#define netdev_printk(sevlevel, netdev, msglevel, format, arg...) \
++      printk(sevlevel "%s: " format , netdev->name , ## arg)
++#endif
++
++#ifndef NET_26
++#define sk_receive_queue  receive_queue
++#define sk_destruct       destruct
++#define sk_reuse          reuse
++#define sk_zapped         zapped
++#define sk_family         family
++#define sk_protocol       protocol
++#define sk_protinfo       protinfo
++#define sk_sleep          sleep
++#define sk_state_change   state_change
++#define sk_shutdown       shutdown
++#define sk_err            err
++#define sk_stamp          stamp
++#define sk_socket         socket
++#define sk_sndbuf         sndbuf
++#define sock_flag(sk, flag)  sk->dead
++#define sk_for_each(sk, node, plist) for(sk=*plist; sk!=NULL; sk = sk->next)
++#endif
++
++/* deal with 2.4 vs 2.6 issues with module counts */
++
++/* in 2.6, all refcounts are maintained *outside* of the
++ * module to deal with race conditions.
++ */
++
++#ifdef NET_26
++#define KLIPS_INC_USE /* nothing */
++#define KLIPS_DEC_USE /* nothing */
++
++#else
++#define KLIPS_INC_USE MOD_INC_USE_COUNT
++#define KLIPS_DEC_USE MOD_DEC_USE_COUNT
++#endif
++
++extern int printk_ratelimit(void);
++
++
++#define _IPSEC_KERN24_H 1
++
++#endif /* _IPSEC_KERN24_H */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_kversion.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,441 @@
++#ifndef _OPENSWAN_KVERSIONS_H
++/*
++ * header file for Openswan library functions
++ * Copyright (C) 1998, 1999, 2000  Henry Spencer.
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs
++ * Copyright (C) 2003 - 2008  Paul Wouters <paul@xelerance.com>
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ */
++#define       _OPENSWAN_KVERSIONS_H   /* seen it, no need to see it again */
++
++/*
++ * this file contains a series of atomic defines that depend upon
++ * kernel version numbers. The kernel versions are arranged
++ * in version-order number (which is often not chronological)
++ * and each clause enables or disables a feature.
++ */
++
++/*
++ * First, assorted kernel-version-dependent trickery.
++ */
++#include <linux/version.h>
++#ifndef KERNEL_VERSION
++# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
++# define HEADER_CACHE_BIND_21
++# error "KLIPS is no longer supported on Linux 2.0. Sorry"
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
++# define SPINLOCK
++# define PROC_FS_21
++# define NETLINK_SOCK
++# define NET_21
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,19)
++# define net_device_stats enet_statistics
++#endif                                                                         
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++# define SPINLOCK_23
++# define NETDEV_23
++# ifndef CONFIG_IP_ALIAS
++#  define CONFIG_IP_ALIAS
++# endif
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,25)
++# define PROC_FS_2325
++# undef  PROC_FS_21
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
++# define PROC_NO_DUMMY
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,35)
++# define SKB_COPY_EXPAND
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,37)
++# define IP_SELECT_IDENT
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,2)
++# define IP_SELECT_IDENT_NEW
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
++# define IPH_is_SKB_PULLED
++# define SKB_COW_NEW
++# define PROTO_HANDLER_SINGLE_PARM
++# define IP_FRAGMENT_LINEARIZE 1
++#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
++#  ifdef REDHAT_BOGOSITY
++#  define IP_SELECT_IDENT_NEW
++#  define IPH_is_SKB_PULLED
++#  define SKB_COW_NEW
++#  define PROTO_HANDLER_SINGLE_PARM
++#  endif /* REDHAT_BOGOSITY */
++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
++# define MALLOC_SLAB
++# define LINUX_KERNEL_HAS_SNPRINTF
++#endif                                                                         
++
++/* API changes are documented at: http://lwn.net/Articles/2.6-kernel-api/ */
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++# define HAVE_NETDEV_PRINTK 1
++# define NET_26
++# define NETDEV_25
++# define NEED_SPINLOCK_TYPES
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
++# define NEED_INET_PROTOCOL
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
++# define HAVE_SOCK_ZAPPED
++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#  define NET_26_24_SKALLOC
++# else
++#  define NET_26_12_SKALLOC
++# endif
++#endif
++#endif
++
++/* see <linux/security.h> */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
++# define HAVE_SOCK_SECURITY
++/* skb->nf_debug disappared completely in 2.6.13 */
++# define ipsec_nf_debug_reset(skb)    ((skb)->nf_debug = 0)
++#else
++# define ipsec_nf_debug_reset(skb)
++#endif
++
++/* how to reset an skb we are reusing after encrpytion/decryption etc */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++# define ipsec_nf_reset(skb)  nf_reset((skb))
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,50) && defined(CONFIG_NETFILTER)
++# define ipsec_nf_reset(skb)  do { \
++                                                                      nf_conntrack_put((skb)->nfct); \
++                                                                      (skb)->nfct=NULL; \
++                                                                      ipsec_nf_debug_reset(skb); \
++                                                              } while(0)
++#else
++# define ipsec_nf_reset(skb)  /**/
++#endif
++
++/* skb->stamp changed to skb->tstamp in 2.6.14 */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
++# define HAVE_TSTAMP
++# define HAVE_INET_SK_SPORT
++#else
++# define HAVE_SKB_LIST 
++#endif
++
++/* it seems 2.6.14 accidentally removed sysctl_ip_default_ttl */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
++# define SYSCTL_IPSEC_DEFAULT_TTL IPSEC_DEFAULT_TTL
++#else
++# define SYSCTL_IPSEC_DEFAULT_TTL sysctl_ip_default_ttl                      
++#endif
++
++/*
++   The obsolete MODULE_PARM() macro is gone forevermore [in 2.6.17+]
++    It was introduced in 2.6.0
++   Zero-filled memory can now be allocated from slab caches with
++    kmem_cache_zalloc(). There is also a new slab debugging option
++    to produce a /proc/slab_allocators file with detailed allocation
++    information.
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++# define module_param(a,b,c)  MODULE_PARM(#a,"i")
++/* note below is only true for our current calls to module_param_array */
++# define module_param_array(a,b,c,d)  MODULE_PARM(#a,"1-2i")
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
++/*
++   The skb_linearize() function has been reworked, and no longer has a
++    GFP flags argument. There is also a new skb_linearize_cow() function
++    which ensures that the resulting SKB is writable.
++   Network drivers should no longer manipulate the xmit_lock  spinlock
++    in the net_device structure; instead, the following new functions
++    should be used:
++     int netif_tx_lock(struct net_device *dev);
++     int netif_tx_lock_bh(struct net_device *dev);
++     void netif_tx_unlock(struct net_device *dev);
++     void netif_tx_unlock_bh(struct net_device *dev);
++     int netif_tx_trylock(struct net_device *dev);
++   A number of crypto API changes have been merged, the biggest being
++    a change to most algorithm-specific functions to take a pointer to
++    the crypto_tfm structure, rather than the old "context" pointer. This
++    change was necessary to support parameterized algorithms.
++*/
++
++# define HAVE_NEW_SKB_LINEARIZE
++#endif
++
++/* this is the best we can do to detect XEN, which makes
++ * patches to linux/skbuff.h, making it look like 2.6.18 version 
++ */
++#ifdef CONFIG_XEN
++# define HAVE_NEW_SKB_LINEARIZE
++#endif
++
++/* And the same for SuSe kernels who have it before it got into the
++ * linus kernel.
++ */
++#ifdef SLE_VERSION_CODE
++# if SLE_VERSION_CODE >= 655616
++#  define HAVE_NEW_SKB_LINEARIZE
++# else
++#  warning "A Suse kernel was detected, but we are unsure if it requires HAVE_NEW_SKB_LINEARIZE"
++# endif
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++# define VOID_SOCK_UNREGISTER
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++/* skb->nfmark changed to skb->mark in 2.6.20 */
++# define nfmark mark
++#else
++# define HAVE_KMEM_CACHE_T
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++/*
++   Significant changes have been made to the crypto support interface.
++   The sysctl code has been heavily reworked, leading to a number of
++    internal API changes. 
++*/
++# define ipsec_register_sysctl_table(a,b) register_sysctl_table(a)
++# define CTL_TABLE_PARENT
++#else
++# define ipsec_register_sysctl_table(a,b) register_sysctl_table(a,b)
++#endif
++ 
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++/*
++   The eth_type_trans() function now sets the skb->dev field, consistent
++    with how similar functions for other link types operate. As a result,
++    many Ethernet drivers have been changed to remove the (now) redundant
++    assignment.
++   The header fields in the sk_buff structure have been renamed
++    and are no longer unions. Networking code and drivers can
++    now just use skb->transport_header, skb->network_header, and
++    skb->skb_mac_header. There are new functions for finding specific
++    headers within packets: tcp_hdr(), udp_hdr(), ipip_hdr(), and
++    ipipv6_hdr().
++   The crypto API has a new set of functions for use with asynchronous
++    block ciphers. There is also a new cryptd kernel thread which can
++    run any synchronous cipher in an asynchronous mode.
++   A new macro has been added to make the creation of slab caches easier:
++    struct kmem_cache KMEM_CACHE(struct-type, flags);
++    The result is the creation of a cache holding objects of the given
++     struct_type, named after that type, and with the additional slab
++     flags (if any). 
++*/
++
++/* need to include ip.h early, no longer pick it up in skbuff.h */
++# include <linux/ip.h>
++# define HAVE_KERNEL_TSTAMP
++/* type of sock.sk_stamp changed from timeval to ktime  */
++# define grab_socket_timeval(tv, sock)  { (tv) = ktime_to_timeval((sock).sk_stamp); }
++#else
++# define grab_socket_timeval(tv, sock)  { (tv) = (sock).sk_stamp; }
++/* internals of struct skbuff changed */
++# define        HAVE_DEV_NEXT
++# define ip_hdr(skb)  ((skb)->nh.iph)
++# define skb_tail_pointer(skb)  ((skb)->tail)
++# define skb_end_pointer(skb)  ((skb)->end)
++# define skb_network_header(skb)  ((skb)->nh.raw)
++# define skb_set_network_header(skb,off)  ((skb)->nh.raw = (skb)->data + (off))
++# define tcp_hdr(skb)  ((skb)->h.th)
++# define udp_hdr(skb)  ((skb)->h.uh)
++# define skb_transport_header(skb)  ((skb)->h.raw)
++# define skb_set_transport_header(skb,off)  ((skb)->h.raw = (skb)->data + (off))
++# define skb_mac_header(skb)  ((skb)->mac.raw)
++# define skb_set_mac_header(skb,off)  ((skb)->mac.raw = (skb)->data + (off))
++#endif
++/* turn a pointer into an offset for above macros */
++#define ipsec_skb_offset(skb, ptr) (((unsigned char *)(ptr)) - (skb)->data)
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
++/* 
++ * The macro got introduced in 2,6,22 but it does not work properly, and
++ * still uses the old number of arguments. 
++ */
++ /*
++    The destructor argument has been removed from kmem_cache_create(), as
++    destructors are no longer supported. All in-kernel callers have been
++    updated
++  */
++# define HAVE_KMEM_CACHE_MACRO
++
++/* Try using the new kernel encaps hook for nat-t, instead of udp.c */
++# ifdef NOT_YET_FINISHED
++#  define HAVE_UDP_ENCAP_CONVERT
++# endif
++
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++/*
++ * We can switch on earlier kernels, but from here on we have no choice
++ * but to abandon the old style proc_net and use seq_file
++ * The hard_header() method has been removed from struct net_device;
++    it has been replaced by a per-protocol header_ops structure pointer. 
++
++   The prototype for slab constructor callbacks has changed to:
++    void (*ctor)(struct kmem_cache *cache, void *object);
++   The unused flags argument has been removed and the order of the other
++    two arguments has been reversed to match other slab functions. 
++ */
++# define HAVE_PROC_DIR_ENTRY
++# define        PROC_NET        init_net.proc_net
++
++# define __ipsec_dev_get(x) __dev_get_by_name(&init_net, x)
++# define ipsec_dev_get(x) dev_get_by_name(&init_net, x)
++#else
++
++# define        PROC_NET        proc_net
++
++# define ipsec_dev_get(x) __dev_get_by_name(x)
++# define __ipsec_dev_get(x) __dev_get_by_name(x)
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
++# define ip_chk_addr(a) inet_addr_type(&init_net, a)
++
++# define l_inet_addr_type(a)  inet_addr_type(&init_net, a)
++
++#else
++# define ip_chk_addr inet_addr_type
++
++#define l_inet_addr_type      inet_addr_type
++
++#endif
++
++#ifndef NETDEV_TX_BUSY
++# ifdef NETDEV_XMIT_CN
++#  define NETDEV_TX_BUSY NETDEV_XMIT_CN
++# else
++#  define NETDEV_TX_BUSY 1
++# endif
++#endif
++
++
++#ifdef NET_21
++# define ipsec_kfree_skb(a) kfree_skb(a)
++#else /* NET_21 */
++# define ipsec_kfree_skb(a) kfree_skb(a, FREE_WRITE)
++#endif /* NET_21 */
++
++#ifdef NETDEV_23
++
++#ifndef SPINLOCK
++#  include <linux/bios32.h>
++     /* simulate spin locks and read/write locks */
++     typedef struct {
++       volatile char lock;
++     } spinlock_t;
++
++     typedef struct {
++       volatile unsigned int lock;
++     } rwlock_t;                                                                     
++
++#  define spin_lock_init(x) { (x)->lock = 0;}
++#  define rw_lock_init(x) { (x)->lock = 0; }
++
++#  define spin_lock(x) { while ((x)->lock) barrier(); (x)->lock=1;}
++#  define spin_lock_irq(x) { cli(); spin_lock(x);}
++#  define spin_lock_irqsave(x,flags) { save_flags(flags); spin_lock_irq(x);}
++
++#  define spin_unlock(x) { (x)->lock=0;}
++#  define spin_unlock_irq(x) { spin_unlock(x); sti();}
++#  define spin_unlock_irqrestore(x,flags) { spin_unlock(x); restore_flags(flags);}
++
++#  define read_lock(x) spin_lock(x)
++#  define read_lock_irq(x) spin_lock_irq(x)
++#  define read_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
++
++#  define read_unlock(x) spin_unlock(x)
++#  define read_unlock_irq(x) spin_unlock_irq(x)
++#  define read_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
++
++#  define write_lock(x) spin_lock(x)
++#  define write_lock_irq(x) spin_lock_irq(x)
++#  define write_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
++
++#  define write_unlock(x) spin_unlock(x)
++#  define write_unlock_irq(x) spin_unlock_irq(x)
++#  define write_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
++#endif /* !SPINLOCK */
++
++#ifndef SPINLOCK_23
++#  define spin_lock_bh(x)  spin_lock_irq(x)
++#  define spin_unlock_bh(x)  spin_unlock_irq(x)
++
++#  define read_lock_bh(x)  read_lock_irq(x)
++#  define read_unlock_bh(x)  read_unlock_irq(x)
++
++#  define write_lock_bh(x)  write_lock_irq(x)
++#  define write_unlock_bh(x)  write_unlock_irq(x)
++#endif /* !SPINLOCK_23 */
++
++#ifndef HAVE_NETDEV_PRINTK
++#define netdev_printk(sevlevel, netdev, msglevel, format, arg...) \
++      printk(sevlevel "%s: " format , netdev->name , ## arg)
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#define       PROC_NET        init_net.proc_net
++#define       PROC_EOF_DATA
++#else
++#define       PROC_NET        proc_net
++#endif
++
++#ifdef NET_21
++# include <linux/in6.h>
++#else
++     /* old kernel in.h has some IPv6 stuff, but not quite enough */
++# define      s6_addr16       s6_addr
++# define      AF_INET6        10
++# define uint8_t __u8
++# define uint16_t __u16 
++# define uint32_t __u32 
++# define uint64_t __u64 
++#endif
++
++#if __KERNEL__
++# if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)
++#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) 
++#   include "openswan/ipsec_kern24.h"
++#  else
++#   error "kernels before 2.4 are not supported at this time"
++#  endif
++# endif
++#endif
++
++#endif /* _OPENSWAN_KVERSIONS_H */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_life.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,112 @@
++/*
++ * Definitions relevant to IPSEC lifetimes
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_life.h,v 1.4 2004/04/05 19:55:05 mcr Exp $
++ *
++ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
++ *
++ */
++
++/* 
++ * This file describes the book keeping fields for the 
++ *   IPsec Security Association Structure. ("ipsec_sa")
++ *
++ * This structure is never allocated directly by kernel code,
++ * (it is always a static/auto or is part of a structure)
++ * so it does not have a reference count.
++ *
++ */
++
++#ifndef _IPSEC_LIFE_H_
++
++/*
++ *  _count is total count.
++ *  _hard is hard limit (kill SA after this number)
++ *  _soft is soft limit (try to renew SA after this number)
++ *  _last is used in some special cases.
++ *
++ */
++
++struct ipsec_lifetime64
++{
++      __u64           ipl_count;
++      __u64           ipl_soft;
++      __u64           ipl_hard;
++      __u64           ipl_last;  
++};
++
++struct ipsec_lifetimes
++{
++      /* number of bytes processed */
++      struct ipsec_lifetime64 ipl_bytes;
++
++      /* number of packets processed */
++      struct ipsec_lifetime64 ipl_packets;
++
++      /* time since SA was added */
++      struct ipsec_lifetime64 ipl_addtime;
++
++      /* time since SA was first used */
++      struct ipsec_lifetime64 ipl_usetime;
++
++      /* from rfc2367:  
++         *         For CURRENT, the number of different connections,
++         *         endpoints, or flows that the association has been
++         *          allocated towards. For HARD and SOFT, the number of
++         *          these the association may be allocated towards
++         *          before it expires. The concept of a connection,
++         *          flow, or endpoint is system specific.
++       *
++       * mcr(2001-9-18) it is unclear what purpose these serve for FreeSWAN.
++       *          They are maintained for PF_KEY compatibility. 
++       */
++      struct ipsec_lifetime64 ipl_allocations;
++};
++
++enum ipsec_life_alive {
++      ipsec_life_harddied = -1,
++      ipsec_life_softdied = 0,
++      ipsec_life_okay     = 1
++};
++
++enum ipsec_life_type {
++      ipsec_life_timebased = 1,
++      ipsec_life_countbased= 0
++};
++
++#define _IPSEC_LIFE_H_
++#endif /* _IPSEC_LIFE_H_ */
++
++
++/*
++ * $Log: ipsec_life.h,v $
++ * Revision 1.4  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_life.h,v
++ *
++ * Revision 1.3  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_life.h,v
++ *
++ * Revision 1.2  2001/11/26 09:16:14  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.1.2.1  2001/09/25 02:25:58  mcr
++ *    lifetime structure created and common functions created.
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_mast.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,59 @@
++#ifndef _IPSEC_MAST_H
++#define _IPSEC_MAST_H
++
++#ifdef CONFIG_KLIPS_DEBUG
++#define DB_MAST_INIT  0x0001
++#define DB_MAST_PROCFS        0x0002
++#define DB_MAST_XMIT  0x0010
++#define DB_MAST_OHDR  0x0020
++#define DB_MAST_CROUT 0x0040
++#define DB_MAST_OXFS  0x0080
++#define DB_MAST_REVEC 0x0100
++#define DB_MAST_ENCAP   0x0200
++#endif /* CONFIG_KLIPS_DEBUG */
++
++struct ipsecmastconf {
++      __u32   cf_cmd;
++      union
++      {
++              char    cfu_name[12];
++      } cf_u;
++#define cf_name cf_u.cfu_name
++};
++
++struct mastpriv
++{
++      struct sk_buff_head sendq;
++      struct wait_queue *wait_queue;
++      int  (*hard_header) (struct sk_buff *skb,
++                           struct net_device *dev,
++                           unsigned short type,
++                           void *daddr,
++                           void *saddr,
++                           unsigned len);
++#if 0
++      char locked;
++      int  (*hard_start_xmit) (struct sk_buff *skb,
++                               struct net_device *dev);
++      int  (*rebuild_header)(struct sk_buff *skb);
++      int  (*set_mac_address)(struct net_device *dev, void *addr);
++      void (*header_cache_bind)(struct hh_cache **hhp, struct net_device *dev,
++                                unsigned short htype, __u32 daddr);
++      void (*header_cache_update)(struct hh_cache *hh,
++                                  struct net_device *dev,
++                                  unsigned char *  haddr);
++      struct net_device_stats *(*get_stats)(struct net_device *dev);
++#endif
++      struct net_device_stats mystats;
++      int mtu;        /* What is the desired MTU? */
++};
++
++extern int ipsec_mast_init_devices(void);
++extern int ipsec_mast_deletenum(int vifnum);
++extern int ipsec_mast_createnum(int vifnum);
++extern struct net_device *ipsec_mast_get_device(int vifnum);
++extern unsigned int ipsec_mast_is_transport(int vifnum);
++
++
++
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_md5h.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,143 @@
++/*
++ * RCSID $Id: ipsec_md5h.h,v 1.10 2004/09/08 17:21:35 ken Exp $
++ */
++
++/*
++ * The rest of this file is Copyright RSA DSI. See the following comments
++ * for the full Copyright notice.
++ */
++
++#ifndef _IPSEC_MD5H_H_
++#define _IPSEC_MD5H_H_
++
++/* GLOBAL.H - RSAREF types and constants
++ */
++
++/* PROTOTYPES should be set to one if and only if the compiler supports
++     function argument prototyping.
++   The following makes PROTOTYPES default to 0 if it has not already
++     been defined with C compiler flags.
++ */
++#ifndef PROTOTYPES
++#define PROTOTYPES 1
++#endif /* !PROTOTYPES */
++
++/* POINTER defines a generic pointer type */
++typedef __u8 *POINTER;
++
++/* UINT2 defines a two byte word */
++typedef __u16 UINT2;
++
++/* UINT4 defines a four byte word */
++typedef __u32 UINT4;
++
++/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
++   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
++     returns an empty list.
++ */
++
++#if PROTOTYPES
++#define PROTO_LIST(list) list
++#else /* PROTOTYPES */
++#define PROTO_LIST(list) ()
++#endif /* PROTOTYPES */
++
++
++/* MD5.H - header file for MD5C.C
++ */
++
++/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
++rights reserved.
++
++License to copy and use this software is granted provided that it
++is identified as the "RSA Data Security, Inc. MD5 Message-Digest
++Algorithm" in all material mentioning or referencing this software
++or this function.
++
++License is also granted to make and use derivative works provided
++that such works are identified as "derived from the RSA Data
++Security, Inc. MD5 Message-Digest Algorithm" in all material
++mentioning or referencing the derived work.
++
++RSA Data Security, Inc. makes no representations concerning either
++the merchantability of this software or the suitability of this
++software for any particular purpose. It is provided "as is"
++without express or implied warranty of any kind.
++
++These notices must be retained in any copies of any part of this
++documentation and/or software.
++ */
++
++/* MD5 context. */
++typedef struct {
++  UINT4 state[4];                                   /* state (ABCD) */
++  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
++  unsigned char buffer[64];                         /* input buffer */
++} MD5_CTX;
++
++void osMD5Init PROTO_LIST ((void *));
++void osMD5Update PROTO_LIST
++  ((void *, unsigned char *, __u32));
++void osMD5Final PROTO_LIST ((unsigned char [16], void *));
++ 
++#endif /* _IPSEC_MD5H_H_ */
++
++/*
++ * $Log: ipsec_md5h.h,v $
++ * Revision 1.10  2004/09/08 17:21:35  ken
++ * Rename MD5* -> osMD5 functions to prevent clashes with other symbols exported by kernel modules (CIFS in 2.6 initiated this)
++ *
++ * Revision 1.9  2004/04/05 19:55:05  mcr
++ * Moved from linux/include/freeswan/ipsec_md5h.h,v
++ *
++ * Revision 1.8  2002/09/10 01:45:09  mcr
++ *    changed type of MD5_CTX and SHA1_CTX to void * so that
++ *    the function prototypes would match, and could be placed
++ *    into a pointer to a function.
++ *
++ * Revision 1.7  2002/04/24 07:36:46  mcr
++ * Moved from ./klips/net/ipsec/ipsec_md5h.h,v
++ *
++ * Revision 1.6  1999/12/13 13:59:13  rgb
++ * Quick fix to argument size to Update bugs.
++ *
++ * Revision 1.5  1999/12/07 18:16:23  rgb
++ * Fixed comments at end of #endif lines.
++ *
++ * Revision 1.4  1999/04/06 04:54:26  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.3  1999/01/22 06:19:58  rgb
++ * 64-bit clean-up.
++ *
++ * Revision 1.2  1998/11/30 13:22:54  rgb
++ * Rationalised all the klips kernel file headers.  They are much shorter
++ * now and won't conflict under RH5.2.
++ *
++ * Revision 1.1  1998/06/18 21:27:48  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.2  1998/04/23 20:54:03  rgb
++ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
++ * verified.
++ *
++ * Revision 1.1  1998/04/09 03:04:21  henry
++ * sources moved up from linux/net/ipsec
++ * these two include files modified not to include others except in kernel
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:03  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:48:53  ji
++ * Release update only.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_param.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,268 @@
++/*
++ * @(#) Openswan tunable paramaters
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * Copyright (C) 2004  Michael Richardson  <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ *
++ */
++
++/* 
++ * This file provides a set of #define's which may be tuned by various
++ * people/configurations. It keeps all compile-time tunables in one place.
++ *
++ * This file should be included before all other IPsec kernel-only files.
++ *
++ */
++
++#ifndef _IPSEC_PARAM_H_
++
++#ifdef __KERNEL__
++
++#include "openswan/ipsec_kversion.h"
++
++/* Set number of ipsecX virtual devices here. */
++/* This must be < exp(field width of IPSEC_DEV_FORMAT) */
++/* It must also be reasonable so as not to overload the memory and CPU */
++/* constraints of the host. */
++#ifdef CONFIG_KLIPS_IF_MAX
++#define IPSEC_NUM_IFMAX CONFIG_KLIPS_IF_MAX
++#endif
++#ifndef IPSEC_NUM_IFMAX
++#define IPSEC_NUM_IFMAX       64
++#endif
++
++/* default number of ipsecX devices to create */
++#define IPSEC_NUM_IF  2
++
++/* The field width must be < IF_NAM_SIZ - strlen("ipsec") - 1. */
++/* With "ipsec" being 5 characters, that means 10 is the max field width */
++/* but machine memory and CPU constraints are not likely to tollerate */
++/* more than 3 digits.  The default is one digit. */
++/* Update: userland scripts get upset if they can't find "ipsec0", so */
++/* for now, no "0"-padding should be used (which would have been helpful */
++/* to make text-searches work */
++#define IPSEC_DEV_FORMAT "ipsec%d"
++#define MAST_DEV_FORMAT "mast%d"
++
++/* For, say, 500 virtual ipsec devices, I would recommend: */
++/* #define IPSEC_NUM_IF       500 */
++/* #define IPSEC_DEV_FORMAT "ipsec%03d" */
++/* Note that the "interfaces=" line in /etc/ipsec.conf would be, um, challenging. */
++
++/* use dynamic ipsecX device allocation */
++#ifndef CONFIG_KLIPS_DYNDEV
++#define CONFIG_KLIPS_DYNDEV 1
++#endif /* CONFIG_KLIPS_DYNDEV */
++
++
++#ifdef CONFIG_KLIPS_BIGGATE
++# define SADB_HASHMOD   8069
++#else /* CONFIG_KLIPS_BIGGATE */
++# define SADB_HASHMOD 257
++#endif /* CONFIG_KLIPS_BIGGATE */
++
++#endif /* __KERNEL__ */
++
++/*
++ * This is for the SA reference table. This number is related to the
++ * maximum number of SAs that KLIPS can concurrently deal with, plus enough
++ * space for keeping expired SAs around.
++ *
++ * TABLE_IDX_WIDTH is the number of bits that we will use.
++ * MAIN_TABLE_WIDTH is the number of bits used for the primary index table.
++ *
++ */
++#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 
++# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4 
++#endif
++
++#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES 
++# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256
++#endif
++
++#ifndef IPSEC_SA_REF_CODE 
++# define IPSEC_SA_REF_CODE 1 
++#endif
++
++#ifdef __KERNEL__
++/* This is defined for 2.4, but not 2.2.... */
++#ifndef ARPHRD_VOID
++# define ARPHRD_VOID 0xFFFF
++#endif
++
++/* always turn on IPIP mode */
++#ifndef CONFIG_KLIPS_IPIP 
++#define CONFIG_KLIPS_IPIP 1
++#endif
++
++/*
++ * Worry about PROC_FS stuff
++ */
++#if defined(PROC_FS_2325)
++/* kernel 2.4 */
++# define IPSEC_PROC_LAST_ARG ,int *eof,void *data
++# define IPSEC_PROCFS_DEBUG_NO_STATIC
++# define IPSEC_PROC_SUBDIRS
++#else
++/* kernel <2.4 */
++# define IPSEC_PROCFS_DEBUG_NO_STATIC DEBUG_NO_STATIC
++
++# ifndef PROC_NO_DUMMY
++#  define IPSEC_PROC_LAST_ARG , int dummy
++# else
++#  define IPSEC_PROC_LAST_ARG
++# endif /* !PROC_NO_DUMMY */
++#endif /* PROC_FS_2325 */
++
++#if !defined(LINUX_KERNEL_HAS_SNPRINTF)
++/* GNU CPP specific! */
++# define snprintf(buf, len, fmt...) sprintf(buf, ##fmt)
++#endif /* !LINUX_KERNEL_HAS_SNPRINTF */
++
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#ifndef KLIPS_FIXES_DES_PARITY
++# define KLIPS_FIXES_DES_PARITY 1
++#endif /* !KLIPS_FIXES_DES_PARITY */
++
++/* we don't really want to print these unless there are really big problems */
++#ifndef KLIPS_DIVULGE_CYPHER_KEY
++# define KLIPS_DIVULGE_CYPHER_KEY 0
++#endif /* !KLIPS_DIVULGE_CYPHER_KEY */
++
++#ifndef KLIPS_DIVULGE_HMAC_KEY
++# define KLIPS_DIVULGE_HMAC_KEY 0
++#endif /* !KLIPS_DIVULGE_HMAC_KEY */
++
++#ifndef IPSEC_DISALLOW_IPOPTIONS
++# define IPSEC_DISALLOW_IPOPTIONS 1
++#endif /* !KLIPS_DIVULGE_HMAC_KEY */
++
++/* extra toggles for regression testing */
++#ifdef CONFIG_KLIPS_REGRESS
++
++/* 
++ * should pfkey_acquire() become 100% lossy?
++ *
++ */
++extern int sysctl_ipsec_regress_pfkey_lossage;
++#ifndef KLIPS_PFKEY_ACQUIRE_LOSSAGE
++# ifdef CONFIG_KLIPS_PFKEY_ACQUIRE_LOSSAGE
++#  define KLIPS_PFKEY_ACQUIRE_LOSSAGE 100
++# else /* CONFIG_KLIPS_PFKEY_ACQUIRE_LOSSAGE */
++/* not by default! */
++#  define KLIPS_PFKEY_ACQUIRE_LOSSAGE 0
++# endif /* CONFIG_KLIPS_PFKEY_ACQUIRE_LOSSAGE */
++#endif /* KLIPS_PFKEY_ACQUIRE_LOSSAGE */
++
++#endif /* CONFIG_KLIPS_REGRESS */
++
++
++/*
++ * debugging routines.
++ */
++#ifdef CONFIG_KLIPS_DEBUG
++        #define KLIPS_ERROR(flag, format, args...) if(printk_ratelimit() || flag) printk(KERN_ERR "KLIPS " format, ## args)
++      #define KLIPS_PRINT(flag, format, args...) \
++              ((flag) ? printk(KERN_INFO format , ## args) : 0)
++      #define KLIPS_PRINTMORE(flag, format, args...) \
++              ((flag) ? printk(format , ## args) : 0)
++      #define KLIPS_IP_PRINT(flag, ip) \
++              ((flag) ? ipsec_print_ip(ip) : 0)
++      #define KLIPS_SATOT(flag, sa, format, dst, dstlen) \
++              ((flag) ? satot(sa, format, dst, dstlen) : 0)
++#else /* CONFIG_KLIPS_DEBUG */
++        #define KLIPS_ERROR(flag, format, args...) if(printk_ratelimit()) printk(KERN_ERR "KLIPS " format, ## args)
++      #define KLIPS_PRINT(flag, format, args...) do ; while(0)
++      #define KLIPS_PRINTMORE(flag, format, args...) do ; while(0)
++      #define KLIPS_IP_PRINT(flag, ip) do ; while(0)
++      #define KLIPS_SATOT(flag, sa, format, dst, dstlen) (0)
++#endif /* CONFIG_KLIPS_DEBUG */
++
++
++/* 
++ * Stupid kernel API differences in APIs. Not only do some
++ * kernels not have ip_select_ident, but some have differing APIs,
++ * and SuSE has one with one parameter, but no way of checking to
++ * see what is really what.
++ */
++
++#ifdef SUSE_LINUX_2_4_19_IS_STUPID
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
++#else
++
++/* simplest case, nothing */
++#if !defined(IP_SELECT_IDENT)
++#define KLIPS_IP_SELECT_IDENT(iph, skb)  do { iph->id = htons(ip_id_count++); } while(0)
++#endif
++
++/* kernels > 2.3.37-ish */
++#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
++#endif
++
++/* kernels > 2.4.2 */
++#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
++#endif
++
++#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
++
++/*
++ * make klips fail test:east-espiv-01.
++ * exploit is at testing/attacks/espiv
++ *
++ */
++#define KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK 0
++
++
++/* IP_FRAGMENT_LINEARIZE is set in freeswan.h if Kernel > 2.4.4 */
++#ifndef IP_FRAGMENT_LINEARIZE
++# define IP_FRAGMENT_LINEARIZE 0
++#endif /* IP_FRAGMENT_LINEARIZE */
++#endif /* __KERNEL__ */
++
++#ifdef NEED_INET_PROTOCOL
++#define inet_protocol net_protocol
++#endif
++
++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && CONFIG_IPSEC_NAT_TRAVERSAL
++#define NAT_TRAVERSAL 1
++#else
++/* let people either #undef, or #define = 0 it */
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#undef CONFIG_IPSEC_NAT_TRAVERSAL
++#endif
++#endif
++
++#ifndef IPSEC_DEFAULT_TTL
++#define IPSEC_DEFAULT_TTL 64
++#endif
++
++#define _IPSEC_PARAM_H_
++#endif /* _IPSEC_PARAM_H_ */
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_policy.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,239 @@
++#ifndef _IPSEC_POLICY_H
++/*
++ * policy interface file between pluto and applications
++ * Copyright (C) 2003              Michael Richardson <mcr@freeswan.org>
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: ipsec_policy.h,v 1.8 2005/07/26 01:12:38 mcr Exp $
++ */
++#define       _IPSEC_POLICY_H         /* seen it, no need to see it again */
++
++
++/*
++ * this file defines an interface between an application (or rather an
++ * application library) and a key/policy daemon. It provides for inquiries
++ * as to the current state of a connected socket, as well as for general
++ * questions.
++ *
++ * In general, the interface is defined as a series of functional interfaces,
++ * and the policy messages should be internal. However, because this is in
++ * fact an ABI between pieces of the system that may get compiled and revised
++ * seperately, this ABI must be public and revision controlled.
++ *
++ * It is expected that the daemon will always support previous versions.
++ */
++
++#define IPSEC_POLICY_MSG_REVISION (unsigned)200305061
++
++enum ipsec_policy_command {
++  IPSEC_CMD_QUERY_FD       = 1,
++  IPSEC_CMD_QUERY_HOSTPAIR = 2,
++  IPSEC_CMD_QUERY_DSTONLY  = 3,
++};
++
++struct ipsec_policy_msg_head {
++  u_int32_t ipm_version;
++  u_int32_t ipm_msg_len;  
++  u_int32_t ipm_msg_type;
++  u_int32_t ipm_msg_seq;
++};
++
++enum ipsec_privacy_quality {
++  IPSEC_PRIVACY_NONE     = 0,
++  IPSEC_PRIVACY_INTEGRAL = 4,   /* not private at all. AH-like */
++  IPSEC_PRIVACY_UNKNOWN  = 8,   /* something is claimed, but details unavail */
++  IPSEC_PRIVACY_ROT13    = 12,  /* trivially breakable, i.e. 1DES */
++  IPSEC_PRIVACY_GAK      = 16,  /* known eavesdroppers */
++  IPSEC_PRIVACY_PRIVATE  = 32,  /* secure for at least a decade */
++  IPSEC_PRIVACY_STRONG   = 64,  /* ridiculously secure */
++  IPSEC_PRIVACY_TORTOISE = 192, /* even stronger, but very slow */
++  IPSEC_PRIVACY_OTP      = 224, /* some kind of *true* one time pad */
++};
++
++enum ipsec_bandwidth_quality {
++  IPSEC_QOS_UNKNOWN = 0,       /* unknown bandwidth */
++  IPSEC_QOS_INTERACTIVE = 16,  /* reasonably moderate jitter, moderate fast.
++                                Good enough for telnet/ssh. */
++  IPSEC_QOS_VOIP        = 32,  /* faster crypto, predicable jitter */
++  IPSEC_QOS_FTP         = 64,  /* higher throughput crypto, perhaps hardware
++                                offloaded, but latency/jitter may be bad */
++  IPSEC_QOS_WIRESPEED   = 128, /* expect to be able to fill your pipe */
++};
++
++/* moved from programs/pluto/constants.h */
++/* IPsec AH transform values
++ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3
++ * and in http://www.iana.org/assignments/isakmp-registry
++ */
++enum ipsec_authentication_algo {
++  AH_NONE=0,
++  AH_MD5=2,
++  AH_SHA=3,
++  AH_DES=4,
++  AH_SHA2_256=5,
++  AH_SHA2_384=6,
++  AH_SHA2_512=7,
++  AH_RIPEMD=8,
++  AH__AES_XCBC_MAC=9,
++  AH_RSA=10
++};
++
++/* IPsec ESP transform values
++ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4
++ * and from http://www.iana.org/assignments/isakmp-registry
++ */
++
++enum ipsec_cipher_algo {
++  ESP_reserved=0,
++  ESP_DES_IV64=1,
++  ESP_DES=2,
++  ESP_3DES=3,
++  ESP_RC5=4,
++  ESP_IDEA=5,
++  ESP_CAST=6,
++  ESP_BLOWFISH=7,
++  ESP_3IDEA=8,
++  ESP_DES_IV32=9,
++  ESP_RC4=10,
++  ESP_NULL=11,
++  ESP_AES=12,         /* 128 bit AES */
++  ESP_AES_CTR=13,
++  ESP_AES_CCM_8=14,
++  ESP_AES_CCM_12=15,
++  ESP_AES_CCM_16=16,
++  /* unassigned=17 */
++  ESP_AES_GCM_8=18,
++  ESP_AES_GCM_12=19,
++  ESP_AES_GCM_16=20,
++  ESP_SEED_CBC=21,
++  ESP_CAMELLIA=22,
++  /* 249-255 reserved for private use */
++};
++
++/* IPCOMP transform values
++ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5
++ */
++
++enum ipsec_comp_algo {
++  IPCOMP_OUI=               1,
++  IPCOMP_DEFLATE=           2,
++  IPCOMP_LZS=               3,
++  IPCOMP_V42BIS=            4
++};
++
++/* Identification type values
++ * RFC 2407 The Internet IP security Domain of Interpretation for
++ * ISAKMP 4.6.2.1
++ *
++ * Also for RFC4306. 
++ *
++ * enum ident_names;
++ */
++
++enum ipsec_id_type {
++      ID_FROMCERT=         (-3),      /* taken from certificate */
++  ID_IMPOSSIBLE=             (-2),    /* private to Pluto */
++  ID_MYID=                   (-1),    /* private to Pluto */
++  ID_NONE=                     0,     /* private to Pluto */
++  ID_IPV4_ADDR=                1,
++  ID_FQDN=                     2,
++  ID_USER_FQDN=                3,
++  ID_RFC822_ADDR = ID_USER_FQDN,        /* RFC4306 */
++  ID_IPV4_ADDR_SUBNET=         4,
++  ID_IPV6_ADDR=                5,
++  ID_IPV6_ADDR_SUBNET=         6,
++  ID_IPV4_ADDR_RANGE=          7,
++  ID_IPV6_ADDR_RANGE=          8,
++  ID_DER_ASN1_DN=              9,
++  ID_DER_ASN1_GN=              10,
++  ID_KEY_ID=                   11
++};
++
++/* Certificate type values
++ * RFC 2408 ISAKMP, chapter 3.9
++ */
++enum ipsec_cert_type {
++  CERT_NONE=                  0,  /* none, or guess from file contents */
++  CERT_PKCS7_WRAPPED_X509=    1,  /* self-signed certificate from disk */
++  CERT_PGP=                   2,
++  CERT_DNS_SIGNED_KEY=                3,  /* KEY RR from DNS */
++  CERT_X509_SIGNATURE=                4,
++  CERT_X509_KEY_EXCHANGE=     5,
++  CERT_KERBEROS_TOKENS=               6,
++  CERT_CRL=                   7,
++  CERT_ARL=                   8,
++  CERT_SPKI=                  9,
++  CERT_X509_ATTRIBUTE=                10,
++  CERT_RAW_RSA=                 11, /* raw RSA from config file */ 
++};
++
++/* a SIG record in ASCII */
++struct ipsec_dns_sig {
++  char fqdn[256];
++  char dns_sig[768];     /* empty string if not signed */
++};
++
++struct ipsec_raw_key {
++  char id_name[256];
++  char fs_keyid[8];
++};
++
++struct ipsec_identity {
++  enum ipsec_id_type     ii_type;
++  enum ipsec_cert_type   ii_format;
++  union {
++    struct ipsec_dns_sig ipsec_dns_signed;
++    /* some thing for PGP */
++    /* some thing for PKIX */
++    struct ipsec_raw_key ipsec_raw_key;
++  } ii_credential;
++};
++
++#define IPSEC_MAX_CREDENTIALS 32
++
++struct ipsec_policy_cmd_query {
++  struct ipsec_policy_msg_head head;
++
++  /* Query section */
++  ip_address query_local;     /* us   */
++  ip_address query_remote;    /* them */
++  u_int8_t proto;             /* TCP, ICMP, etc. */
++  u_short src_port, dst_port;
++
++  /* Answer section */
++  enum ipsec_privacy_quality     strength;
++  enum ipsec_bandwidth_quality   bandwidth;
++  enum ipsec_authentication_algo auth_detail;  
++  enum ipsec_cipher_algo         esp_detail;
++  enum ipsec_comp_algo           comp_detail;
++
++  int                            credential_count;
++
++  struct ipsec_identity credentials[IPSEC_MAX_CREDENTIALS];
++};
++
++#define IPSEC_POLICY_SOCKET "/var/run/pluto/pluto.info"
++
++/* prototypes */
++extern err_t ipsec_policy_lookup(int fd, struct ipsec_policy_cmd_query *result);
++extern err_t ipsec_policy_init(void);
++extern err_t ipsec_policy_final(void);
++extern err_t ipsec_policy_readmsg(int policysock,
++                                unsigned char *buf, size_t buflen);
++extern err_t ipsec_policy_sendrecv(unsigned char *buf, size_t buflen);
++extern err_t ipsec_policy_cgilookup(struct ipsec_policy_cmd_query *result);
++
++
++extern const char *ipsec_policy_version_code(void);
++extern const char *ipsec_policy_version_string(void);
++
++#endif /* _IPSEC_POLICY_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_proto.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,195 @@
++/*
++ * @(#) prototypes for FreeSWAN functions 
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_proto.h,v 1.14 2005/04/29 04:50:03 mcr Exp $
++ *
++ */
++
++#ifndef _IPSEC_PROTO_H_
++
++#include "ipsec_param.h"
++
++/* 
++ * This file is a kernel only file that declares prototypes for
++ * all intra-module function calls and global data structures.
++ *
++ * Include this file last.
++ *
++ */
++
++/* forward references */
++enum ipsec_direction;
++enum ipsec_life_type;
++struct ipsec_lifetime64;
++struct ident;
++struct sockaddr_encap;
++struct ipsec_sa;
++
++/* ipsec_init.c */
++extern struct prng ipsec_prng;
++
++/* ipsec_sa.c */
++extern struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
++extern spinlock_t       tdb_lock;
++extern int ipsec_sadb_init(void);
++extern int ipsec_sadb_cleanup(__u8);
++
++extern struct ipsec_sa *ipsec_sa_alloc(int*error); 
++
++
++extern struct ipsec_sa *ipsec_sa_getbyid(ip_said *);
++extern /* void */ int ipsec_sa_add(struct ipsec_sa *);
++
++extern int ipsec_sa_init(struct ipsec_sa *ipsp);
++
++/* debug declarations */
++
++/* ipsec_proc.c */
++extern int  ipsec_proc_init(void);
++extern void ipsec_proc_cleanup(void);
++
++/* ipsec_rcv.c */
++extern int ipsec_rcv(struct sk_buff *skb);
++extern int klips26_rcv_encap(struct sk_buff *skb, __u16 encap_type);
++
++/* ipsec_xmit.c */
++struct ipsec_xmit_state;
++extern enum ipsec_xmit_value ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs);
++extern enum ipsec_xmit_value ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs);
++extern void ipsec_print_ip(struct iphdr *ip);
++
++
++
++/* ipsec_radij.c */
++extern int ipsec_makeroute(struct sockaddr_encap *ea,
++                         struct sockaddr_encap *em,
++                         ip_said said,
++                         uint32_t pid,
++                         struct sk_buff *skb,
++                         struct ident *ident_s,
++                         struct ident *ident_d);
++
++extern int ipsec_breakroute(struct sockaddr_encap *ea,
++                          struct sockaddr_encap *em,
++                          struct sk_buff **first,
++                          struct sk_buff **last);
++
++int ipsec_radijinit(void);
++int ipsec_cleareroutes(void);
++int ipsec_radijcleanup(void);
++
++/* ipsec_life.c */
++extern enum ipsec_life_alive ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
++                                                const char *lifename,
++                                                const char *saname,
++                                                enum ipsec_life_type ilt,
++                                                enum ipsec_direction idir,
++                                                struct ipsec_sa *ips);
++
++
++extern int ipsec_lifetime_format(char *buffer,
++                               int   buflen,
++                               char *lifename,
++                               enum ipsec_life_type timebaselife,
++                               struct ipsec_lifetime64 *lifetime);
++
++extern void ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
++                                     __u64 newvalue);
++
++extern void ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
++                                     __u64 newvalue);
++
++/* ipsec_snprintf.c */
++extern int ipsec_snprintf(char * buf, ssize_t size, const char *fmt, ...);
++extern void ipsec_dmp_block(char *s, caddr_t bb, int len);
++
++
++/* ipsec_alg.c */
++extern int ipsec_alg_init(void);
++
++
++#ifdef CONFIG_KLIPS_DEBUG
++
++extern int debug_xform;
++extern int debug_eroute;
++extern int debug_spi;
++extern int debug_netlink;
++
++#endif /* CONFIG_KLIPS_DEBUG */
++
++
++
++
++#define _IPSEC_PROTO_H
++#endif /* _IPSEC_PROTO_H_ */
++
++/*
++ * $Log: ipsec_proto.h,v $
++ * Revision 1.14  2005/04/29 04:50:03  mcr
++ *    prototypes for xmit and alg code.
++ *
++ * Revision 1.13  2005/04/17 03:46:07  mcr
++ *    added prototypes for ipsec_rcv() routines.
++ *
++ * Revision 1.12  2005/04/14 20:28:37  mcr
++ *    added additional prototypes.
++ *
++ * Revision 1.11  2005/04/14 01:16:28  mcr
++ *    add prototypes for snprintf.
++ *
++ * Revision 1.10  2005/04/13 22:47:28  mcr
++ *    make sure that forward references are available.
++ *
++ * Revision 1.9  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.8  2004/04/05 19:55:06  mcr
++ * Moved from linux/include/freeswan/ipsec_proto.h,v
++ *
++ * Revision 1.7  2003/10/31 02:27:05  mcr
++ *    pulled up port-selector patches and sa_id elimination.
++ *
++ * Revision 1.6.30.1  2003/10/29 01:10:19  mcr
++ *    elimited "struct sa_id"
++ *
++ * Revision 1.6  2002/05/23 07:13:48  rgb
++ * Added ipsec_sa_put() for releasing an ipsec_sa refcount.
++ *
++ * Revision 1.5  2002/05/14 02:36:40  rgb
++ * Converted reference from ipsec_sa_put to ipsec_sa_add to avoid confusion
++ * with "put" usage in the kernel.
++ *
++ * Revision 1.4  2002/04/24 07:36:47  mcr
++ * Moved from ./klips/net/ipsec/ipsec_proto.h,v
++ *
++ * Revision 1.3  2002/04/20 00:12:25  rgb
++ * Added esp IV CBC attack fix, disabled.
++ *
++ * Revision 1.2  2001/11/26 09:16:15  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.1.2.1  2001/09/25 02:21:01  mcr
++ *    ipsec_proto.h created to keep prototypes rather than deal with
++ *    cyclic dependancies of structures and prototypes in .h files.
++ *
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_radij.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,179 @@
++/*
++ * @(#) Definitions relevant to the IPSEC <> radij tree interfacing
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_radij.h,v 1.22 2004/07/10 19:08:41 mcr Exp $
++ */
++
++#ifndef _IPSEC_RADIJ_H
++
++#include <openswan.h>
++
++int ipsec_walk(char *);
++
++int ipsec_rj_walker_procprint(struct radij_node *, void *);
++int ipsec_rj_walker_delete(struct radij_node *, void *);
++
++/* This structure is used to pass information between
++ * ipsec_eroute_get_info and ipsec_rj_walker_procprint
++ * (through rj_walktree) and between calls of ipsec_rj_walker_procprint.
++ */
++struct wsbuf
++{
++       /* from caller of ipsec_eroute_get_info: */
++       char *const buffer;     /* start of buffer provided */
++       const int length;       /* length of buffer provided */
++       const off_t offset;     /* file position of first character of interest */
++       /* accumulated by ipsec_rj_walker_procprint: */
++       int len;        /* number of character filled into buffer */
++       off_t begin;    /* file position contained in buffer[0] (<=offset) */
++};
++
++extern struct radij_node_head *rnh;
++extern spinlock_t eroute_lock;
++
++struct eroute * ipsec_findroute(struct sockaddr_encap *);
++
++#define O1(x) (int)(((x)>>24)&0xff)
++#define O2(x) (int)(((x)>>16)&0xff)
++#define O3(x) (int)(((x)>>8)&0xff)
++#define O4(x) (int)(((x))&0xff)
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int debug_radij;
++void rj_dumptrees(void);
++
++#define DB_RJ_DUMPTREES       0x0001
++#define DB_RJ_FINDROUTE 0x0002
++#endif /* CONFIG_KLIPS_DEBUG */
++
++#define _IPSEC_RADIJ_H
++#endif
++
++/*
++ * $Log: ipsec_radij.h,v $
++ * Revision 1.22  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.21  2004/04/29 11:06:42  ken
++ * Last bits from 2.06 procfs updates
++ *
++ * Revision 1.20  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.19  2004/04/05 19:55:06  mcr
++ * Moved from linux/include/freeswan/ipsec_radij.h,v
++ *
++ * Revision 1.18  2002/04/24 07:36:47  mcr
++ * Moved from ./klips/net/ipsec/ipsec_radij.h,v
++ *
++ * Revision 1.17  2001/11/26 09:23:49  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.16.2.1  2001/09/25 02:21:17  mcr
++ *    ipsec_proto.h created to keep prototypes rather than deal with
++ *    cyclic dependancies of structures and prototypes in .h files.
++ *
++ * Revision 1.16  2001/09/15 16:24:04  rgb
++ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
++ *
++ * Revision 1.15  2001/09/14 16:58:37  rgb
++ * Added support for storing the first and last packets through a HOLD.
++ *
++ * Revision 1.14  2001/09/08 21:13:32  rgb
++ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
++ *
++ * Revision 1.13  2001/06/14 19:35:09  rgb
++ * Update copyright date.
++ *
++ * Revision 1.12  2001/05/27 06:12:11  rgb
++ * Added structures for pid, packet count and last access time to eroute.
++ * Added packet count to beginning of /proc/net/ipsec_eroute.
++ *
++ * Revision 1.11  2000/09/08 19:12:56  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.10  1999/11/17 15:53:39  rgb
++ * Changed all occurrences of #include "../../../lib/freeswan.h"
++ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
++ * klips/net/ipsec/Makefile.
++ *
++ * Revision 1.9  1999/10/01 00:01:23  rgb
++ * Added eroute structure locking.
++ *
++ * Revision 1.8  1999/04/11 00:28:59  henry
++ * GPL boilerplate
++ *
++ * Revision 1.7  1999/04/06 04:54:26  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.6  1999/01/22 06:23:26  rgb
++ * Cruft clean-out.
++ *
++ * Revision 1.5  1998/10/25 02:42:08  rgb
++ * Change return type on ipsec_breakroute and ipsec_makeroute and add an
++ * argument to be able to transmit more infomation about errors.
++ *
++ * Revision 1.4  1998/10/19 14:44:29  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.3  1998/07/28 00:03:31  rgb
++ * Comment out temporary inet_nto4u() kluge.
++ *
++ * Revision 1.2  1998/07/14 18:22:00  rgb
++ * Add function to clear the eroute table.
++ *
++ * Revision 1.1  1998/06/18 21:27:49  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.5  1998/05/25 20:30:38  rgb
++ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
++ *
++ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
++ * add ipsec_rj_walker_delete.
++ *
++ * Revision 1.4  1998/05/21 13:02:56  rgb
++ * Imported definitions from ipsec_radij.c and radij.c to support /proc 3k
++ * limit fix.
++ *
++ * Revision 1.3  1998/04/21 21:29:09  rgb
++ * Rearrange debug switches to change on the fly debug output from user
++ * space.  Only kernel changes checked in at this time.  radij.c was also
++ * changed to temporarily remove buggy debugging code in rj_delete causing
++ * an OOPS and hence, netlink device open errors.
++ *
++ * Revision 1.2  1998/04/14 17:30:39  rgb
++ * Fix up compiling errors for radij tree memory reclamation.
++ *
++ * Revision 1.1  1998/04/09 03:06:10  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:04  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:39:04  ji
++ * Minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_rcv.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,261 @@
++/*
++ * 
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_rcv.h,v 1.28.2.1 2006/07/10 15:52:20 paul Exp $
++ */
++
++#ifndef IPSEC_RCV_H
++#define IPSEC_RCV_H
++
++#include "openswan/ipsec_auth.h"
++
++#define DB_RX_PKTRX   0x0001
++#define DB_RX_PKTRX2  0x0002
++#define DB_RX_DMP     0x0004
++#define DB_RX_IPSA    0x0010
++#define DB_RX_XF      0x0020
++#define DB_RX_IPAD    0x0040
++#define DB_RX_INAU    0x0080
++#define DB_RX_OINFO   0x0100
++#define DB_RX_OINFO2  0x0200
++#define DB_RX_OH      0x0400
++#define DB_RX_REPLAY  0x0800
++
++#ifdef __KERNEL__
++/* struct options; */
++
++#define __NO_VERSION__
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif        /* for CONFIG_IP_FORWARD */
++#ifdef CONFIG_MODULES
++#include <linux/module.h>
++#endif
++#include <linux/version.h>
++#include <openswan.h>
++
++#ifdef CONFIG_KLIPS_OCF
++#include <cryptodev.h>
++#endif
++
++#define IPSEC_BIRTH_TEMPLATE_MAXLEN 256
++
++struct ipsec_birth_reply {
++  int            packet_template_len;
++  unsigned char  packet_template[IPSEC_BIRTH_TEMPLATE_MAXLEN];
++};
++
++extern struct ipsec_birth_reply ipsec_ipv4_birth_packet;
++extern struct ipsec_birth_reply ipsec_ipv6_birth_packet;
++
++enum ipsec_rcv_value {
++      IPSEC_RCV_PENDING=2,
++      IPSEC_RCV_LASTPROTO=1,
++      IPSEC_RCV_OK=0,
++      IPSEC_RCV_BADPROTO=-1,
++      IPSEC_RCV_BADLEN=-2,
++      IPSEC_RCV_ESP_BADALG=-3,
++      IPSEC_RCV_3DES_BADBLOCKING=-4,
++      IPSEC_RCV_ESP_DECAPFAIL=-5,
++      IPSEC_RCV_DECAPFAIL=-6,
++      IPSEC_RCV_SAIDNOTFOUND=-7,
++      IPSEC_RCV_IPCOMPALONE=-8,
++      IPSEC_RCV_IPCOMPFAILED=-10,
++      IPSEC_RCV_SAIDNOTLIVE=-11,
++      IPSEC_RCV_FAILEDINBOUND=-12,
++      IPSEC_RCV_LIFETIMEFAILED=-13,
++      IPSEC_RCV_BADAUTH=-14,
++      IPSEC_RCV_REPLAYFAILED=-15,
++      IPSEC_RCV_AUTHFAILED=-16,
++      IPSEC_RCV_REPLAYROLLED=-17,
++      IPSEC_RCV_BAD_DECRYPT=-18,
++      IPSEC_RCV_REALLYBAD=-19
++};
++
++/*
++ * state machine states
++ */
++
++#define IPSEC_RSM_INIT                        0       /* make it easy, starting state is 0 */
++#define       IPSEC_RSM_DECAP_INIT    1
++#define       IPSEC_RSM_DECAP_LOOKUP  2
++#define       IPSEC_RSM_AUTH_INIT             3
++#define       IPSEC_RSM_AUTH_DECAP    4
++#define       IPSEC_RSM_AUTH_CALC             5
++#define       IPSEC_RSM_AUTH_CHK              6
++#define       IPSEC_RSM_DECRYPT               7
++#define       IPSEC_RSM_DECAP_CONT    8       /* do we restart at IPSEC_RSM_DECAP_INIT */
++#define       IPSEC_RSM_CLEANUP               9
++#define       IPSEC_RSM_IPCOMP                10
++#define       IPSEC_RSM_COMPLETE              11
++#define IPSEC_RSM_DONE                        100
++
++struct ipsec_rcv_state {
++      struct sk_buff *skb;
++      struct net_device_stats *stats;
++      struct iphdr    *ipp;          /* the IP header */
++      struct ipsec_sa *ipsp;         /* current SA being processed */
++      struct ipsec_sa *lastipsp;     /* last SA that was processed */
++      int len;                       /* length of packet */
++      int ilen;                      /* length of inner payload (-authlen) */
++      int authlen;                   /* how big is the auth data at end */
++      int hard_header_len;           /* layer 2 size */
++      int iphlen;                    /* how big is IP header */
++      unsigned int   transport_direct:1;
++      struct auth_alg *authfuncs;
++      ip_said said;
++      char   sa[SATOT_BUF];
++      size_t sa_len;
++      __u8 next_header;
++      __u8 hash[AH_AMAX];
++      char ipsaddr_txt[ADDRTOA_BUF];
++      char ipdaddr_txt[ADDRTOA_BUF];
++      __u8 *octx;
++      __u8 *ictx;
++      int ictx_len;
++      int octx_len;
++      union {
++              struct {
++                      struct esphdr *espp;
++              } espstuff;
++              struct {
++                      struct ahhdr *ahp;
++              } ahstuff;
++              struct {
++                      struct ipcomphdr *compp;
++              } ipcompstuff;
++      } protostuff;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      __u8            natt_type;
++      __u16           natt_sport;
++      __u16           natt_dport;
++      int             natt_len; 
++#endif  
++
++      /*
++       * rcv state machine use
++       */
++      int             state;
++      int             next_state;
++      int             auth_checked;
++
++#ifdef CONFIG_KLIPS_OCF
++      struct work_struct      workq;
++#ifdef DECLARE_TASKLET
++      struct tasklet_struct   tasklet;
++#endif
++#endif
++#ifndef NET_21
++      struct net_device *devp;
++      struct inet_protocol *protop;
++#endif
++      struct xform_functions *proto_funcs;
++      __u8 proto;
++      int replay;
++      unsigned char *authenticator;
++      int esphlen;
++#ifdef CONFIG_KLIPS_ALG
++      struct ipsec_alg_auth *ixt_a;
++#endif
++      __u8 ttl, tos;
++      __u16 frag_off, check;
++};
++
++extern void ipsec_rsm(struct ipsec_rcv_state *irs);
++#ifdef HAVE_KMEM_CACHE_T
++extern kmem_cache_t *ipsec_irs_cache;
++#else
++extern struct kmem_cache *ipsec_irs_cache;
++#endif
++extern int ipsec_irs_max;
++extern atomic_t ipsec_irs_cnt;
++
++extern int
++#ifdef PROTO_HANDLER_SINGLE_PARM
++ipsec_rcv(struct sk_buff *skb);
++#else /* PROTO_HANDLER_SINGLE_PARM */
++ipsec_rcv(struct sk_buff *skb,
++        unsigned short xlen);
++#endif /* PROTO_HANDLER_SINGLE_PARM */
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int debug_rcv;
++#define ipsec_rcv_dmp(_x,_y, _z) if (debug_rcv && sysctl_ipsec_debug_verbose) ipsec_dmp_block(_x,_y,_z)
++#else
++#define ipsec_rcv_dmp(_x,_y, _z) do {} while(0)
++#endif /* CONFIG_KLIPS_DEBUG */
++
++extern int sysctl_ipsec_inbound_policy_check;
++#endif /* __KERNEL__ */
++
++extern int klips26_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
++extern int klips26_rcv_encap(struct sk_buff *skb, __u16 encap_type);
++
++// manage ipsec rcv state objects
++extern int ipsec_rcv_state_cache_init (void);
++extern void ipsec_rcv_state_cache_cleanup (void);
++
++#endif /* IPSEC_RCV_H */
++
++/*
++ * $Log: ipsec_rcv.h,v $
++ * Revision 1.28.2.1  2006/07/10 15:52:20  paul
++ * Fix for bug #642 by Bart Trojanowski
++ *
++ * Revision 1.28  2005/05/11 00:59:45  mcr
++ *    do not call debug routines if !defined KLIPS_DEBUG.
++ *
++ * Revision 1.27  2005/04/29 04:59:46  mcr
++ *    use ipsec_dmp_block.
++ *
++ * Revision 1.26  2005/04/13 22:48:35  mcr
++ *    added comments, and removed some log.
++ *    removed Linux 2.0 support.
++ *
++ * Revision 1.25  2005/04/08 18:25:37  mcr
++ *    prototype klips26 encap receive function
++ *
++ * Revision 1.24  2004/08/20 21:45:37  mcr
++ *    CONFIG_KLIPS_NAT_TRAVERSAL is not used in an attempt to
++ *    be 26sec compatible. But, some defines where changed.
++ *
++ * Revision 1.23  2004/08/03 18:17:40  mcr
++ *    in 2.6, use "net_device" instead of #define device->net_device.
++ *    this probably breaks 2.0 compiles.
++ *
++ * Revision 1.22  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.21  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.20  2004/04/05 19:55:06  mcr
++ * Moved from linux/include/freeswan/ipsec_rcv.h,v
++ *
++ * Revision 1.19  2003/12/15 18:13:09  mcr
++ *    when compiling with NAT traversal, don't assume that the
++ *    kernel has been patched, unless CONFIG_IPSEC_NAT_NON_ESP
++ *    is set.
++ *
++ * history elided 2005-04-12.
++ *
++ * Local Variables:
++ * c-basic-offset:8
++ * c-style:linux
++ * End:
++ *
++ */
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_sa.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,280 @@
++/*
++ * @(#) Definitions of IPsec Security Association (ipsec_sa)
++ *
++ * Copyright (C) 2001, 2002, 2003
++ *                      Richard Guy Briggs  <rgb@freeswan.org>
++ *                  and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_sa.h,v 1.23.2.1 2007/09/05 02:31:15 paul Exp $
++ *
++ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
++ *
++ */
++
++/* 
++ * This file describes the IPsec Security Association Structure.
++ *
++ * This structure keeps track of a single transform that may be done
++ * to a set of packets. It can describe applying the transform or
++ * apply the reverse. (e.g. compression vs expansion). However, it
++ * only describes one at a time. To describe both, two structures would
++ * be used, but since the sides of the transform are performed 
++ * on different machines typically it is usual to have only one side
++ * of each association.
++ * 
++ */
++
++#ifndef _IPSEC_SA_H_
++
++#ifdef __KERNEL__
++#include "openswan/ipsec_stats.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_eroute.h"
++#endif /* __KERNEL__ */
++#include "openswan/ipsec_param.h"
++
++#include "openswan/pfkeyv2.h"
++
++
++/* SAs are held in a table.
++ * Entries in this table are referenced by IPsecSAref_t values.
++ * IPsecSAref_t values are conceptually subscripts.  Because
++ * we want to allocate the table piece-meal, the subscripting
++ * is implemented with two levels, a bit like paged virtual memory.
++ * This representation mechanism is known as an Iliffe Vector.
++ *
++ * The Main table (AKA the refTable) consists of 2^IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
++ * pointers to subtables.
++ * Each subtable has 2^IPSEC_SA_REF_SUBTABLE_IDX_WIDTH entries, each of which
++ * is a pointer to an SA.
++ *
++ * An IPsecSAref_t contains either an exceptional value (signified by the
++ * high-order bit being on) or a reference to a table entry.  A table entry
++ * reference has the subtable subscript in the low-order
++ * IPSEC_SA_REF_SUBTABLE_IDX_WIDTH bits and the Main table subscript
++ * in the next lowest IPSEC_SA_REF_MAINTABLE_IDX_WIDTH bits.
++ *
++ * The Maintable entry for an IPsecSAref_t x, a pointer to its subtable, is
++ * IPsecSAref2table(x).  It is of type struct IPsecSArefSubTable *.
++ *
++ * The pointer to the SA for x is IPsecSAref2SA(x).  It is of type
++ * struct ipsec_sa*.  The macro definition clearly shows the two-level
++ * access needed to find the SA pointer.
++ *
++ * The Maintable is allocated when IPsec is initialized.
++ * Each subtable is allocated when needed, but the first is allocated
++ * when IPsec is initialized.
++ *
++ * IPsecSAref_t is designed to be smaller than an NFmark so that
++ * they can be stored in NFmarks and still leave a few bits for other
++ * purposes.  The spare bits are in the low order of the NFmark
++ * but in the high order of the IPsecSAref_t, so conversion is required.
++ * We pick the upper bits of NFmark on the theory that they are less likely to
++ * interfere with more pedestrian uses of nfmark.
++ */
++
++
++typedef unsigned short int IPsecRefTableUnusedCount;
++
++#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH)
++
++#ifdef __KERNEL__
++#if ((IPSEC_SA_REF_TABLE_IDX_WIDTH - (1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) < 0)
++#error "IPSEC_SA_REF_TABLE_IDX_WIDTH("IPSEC_SA_REF_TABLE_IDX_WIDTH") MUST be < 1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH("IPSEC_SA_REF_MAINTABLE_IDX_WIDTH")"
++#endif
++
++#define IPSEC_SA_REF_SUBTABLE_IDX_WIDTH (IPSEC_SA_REF_TABLE_IDX_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
++
++#define IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
++#define IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
++
++#ifdef CONFIG_NETFILTER
++#define IPSEC_SA_REF_HOST_FIELD(x) ((struct sk_buff*)(x))->nfmark
++#define IPSEC_SA_REF_HOST_FIELD_TYPE typeof(IPSEC_SA_REF_HOST_FIELD(NULL))
++#else /* CONFIG_NETFILTER */
++/* just make it work for now, it doesn't matter, since there is no nfmark */
++#define IPSEC_SA_REF_HOST_FIELD_TYPE unsigned long
++#endif /* CONFIG_NETFILTER */
++#define IPSEC_SA_REF_HOST_FIELD_WIDTH (8 * sizeof(IPSEC_SA_REF_HOST_FIELD_TYPE))
++#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
++
++#define IPSEC_SA_REF_MAX         (~IPSEC_SAREF_NULL)
++#define IPSEC_SAREF_FIRST        1
++#define IPSEC_SA_REF_MASK        (IPSEC_SA_REF_MAX >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
++#define IPSEC_SA_REF_TABLE_MASK ((IPSEC_SA_REF_MAX >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
++#define IPSEC_SA_REF_ENTRY_MASK  (IPSEC_SA_REF_MAX >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_SUBTABLE_IDX_WIDTH))
++
++#define IPsecSAref2table(x) (((x) & IPSEC_SA_REF_TABLE_MASK) >> IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
++#define IPsecSAref2entry(x) ((x) & IPSEC_SA_REF_ENTRY_MASK)
++#define IPsecSArefBuild(x,y) (((x) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH) + (y))
++
++#define IPsecSAref2SA(x) (ipsec_sadb.refTable[IPsecSAref2table(x)]->entry[IPsecSAref2entry(x)])
++#define IPsecSA2SAref(x) ((x)->ips_ref)
++
++#define EMT_INBOUND   0x01    /* SA direction, 1=inbound */
++
++/* 'struct ipsec_sa' should be 64bit aligned when allocated. */
++struct ipsec_sa                               
++{
++      atomic_t        ips_refcount;   /* reference count for this struct */
++        int             ips_marked_deleted;     /* used with reference counting */
++      IPsecSAref_t    ips_ref;        /* reference table entry number */
++      IPsecSAref_t    ips_refhim;     /* ref of paired SA, if any */
++      struct ipsec_sa *ips_next;              /* pointer to next xform */
++
++      struct ipsec_sa *ips_hnext;             /* next in hash chain */
++
++      struct ifnet    *ips_rcvif;             /* related rcv encap interface */
++
++      struct xform_functions *ips_xformfuncs; /* pointer to routines to process this SA */
++
++      struct net_device *ips_out;             /* what interface to emerge on */
++      __u8            ips_transport_direct;   /* if true, punt directly to
++                                               * the protocol layer */
++      struct socket  *ips_sock;               /* cache of transport socket */
++
++      ip_said         ips_said;               /* SA ID */
++
++      __u32           ips_seq;                /* seq num of msg that initiated this SA */
++      __u32           ips_pid;                /* PID of process that initiated this SA */
++      __u8            ips_authalg;            /* auth algorithm for this SA */
++      __u8            ips_encalg;             /* enc algorithm for this SA */
++
++      struct ipsec_stats ips_errs;
++
++      __u8            ips_replaywin;          /* replay window size */
++      enum sadb_sastate ips_state;            /* state of SA */
++      __u32           ips_replaywin_lastseq;  /* last pkt sequence num */
++      __u64           ips_replaywin_bitmap;   /* bitmap of received pkts */
++      __u32           ips_replaywin_maxdiff;  /* max pkt sequence difference */
++
++      __u32           ips_flags;              /* generic xform flags */
++
++
++      struct ipsec_lifetimes ips_life;        /* lifetime records */
++
++      /* selector information */
++        __u8            ips_transport_protocol; /* protocol for this SA, if ports are involved */
++      struct sockaddr*ips_addr_s;             /* src sockaddr */
++      struct sockaddr*ips_addr_d;             /* dst sockaddr */
++      struct sockaddr*ips_addr_p;             /* proxy sockaddr */
++      __u16           ips_addr_s_size;
++      __u16           ips_addr_d_size;
++      __u16           ips_addr_p_size;
++      ip_address      ips_flow_s;
++      ip_address      ips_flow_d;
++      ip_address      ips_mask_s;
++      ip_address      ips_mask_d;
++
++      __u16           ips_key_bits_a;         /* size of authkey in bits */
++      __u16           ips_auth_bits;          /* size of authenticator in bits */
++      __u16           ips_key_bits_e;         /* size of enckey in bits */
++      __u16           ips_iv_bits;            /* size of IV in bits */
++      __u8            ips_iv_size;
++      __u16           ips_key_a_size;
++      __u16           ips_key_e_size;
++
++      caddr_t         ips_key_a;              /* authentication key */
++      caddr_t         ips_key_e;              /* encryption key */
++      caddr_t         ips_iv;                 /* Initialisation Vector */
++
++      struct ident    ips_ident_s;            /* identity src */
++      struct ident    ips_ident_d;            /* identity dst */
++
++        /* these are included even if CONFIG_KLIPS_IPCOMP is off */
++      __u16           ips_comp_adapt_tries;   /* ipcomp self-adaption tries */
++      __u16           ips_comp_adapt_skip;    /* ipcomp self-adaption to-skip */
++      __u64           ips_comp_ratio_cbytes;  /* compressed bytes */
++      __u64           ips_comp_ratio_dbytes;  /* decompressed (or uncompressed) bytes */
++
++        /* these are included even if CONFIG_IPSEC_NAT_TRAVERSAL is off */
++      __u8            ips_natt_type;
++      __u8            ips_natt_reserved[3];
++      __u16           ips_natt_sport;
++      __u16           ips_natt_dport;
++
++      struct sockaddr *ips_natt_oa;
++      __u16           ips_natt_oa_size;
++      __u16           ips_natt_reserved2;
++
++#if 0
++      __u32           ips_sens_dpd;
++      __u8            ips_sens_sens_level;
++      __u8            ips_sens_sens_len;
++      __u64*          ips_sens_sens_bitmap;
++      __u8            ips_sens_integ_level;
++      __u8            ips_sens_integ_len;
++      __u64*          ips_sens_integ_bitmap;
++#endif
++      struct ipsec_alg_enc *ips_alg_enc;
++      struct ipsec_alg_auth *ips_alg_auth;
++
++      int             ocf_in_use;
++      int64_t         ocf_cryptoid;
++};
++
++struct IPsecSArefSubTable
++{
++      struct ipsec_sa* entry[IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES];
++};
++
++struct ipsec_sadb {
++      struct IPsecSArefSubTable* refTable[IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES];
++      IPsecSAref_t refFreeList[IPSEC_SA_REF_FREELIST_NUM_ENTRIES];
++      int refFreeListHead;
++      int refFreeListTail;
++      IPsecSAref_t refFreeListCont;
++      IPsecSAref_t said_hash[SADB_HASHMOD];
++      spinlock_t sadb_lock;
++};
++
++extern struct ipsec_sadb ipsec_sadb;
++
++extern int ipsec_SAref_recycle(void);
++extern int ipsec_SArefSubTable_alloc(unsigned table);
++extern int ipsec_saref_freelist_init(void);
++extern int ipsec_sadb_init(void);
++extern struct ipsec_sa *ipsec_sa_alloc(int*error); /* pass in error var by pointer */
++extern IPsecSAref_t ipsec_SAref_alloc(int*erorr); /* pass in error var by pointer */
++extern int ipsec_sa_free(struct ipsec_sa* ips);
++
++#define ipsec_sa_get(ips) __ipsec_sa_get(ips, __FUNCTION__, __LINE__)
++extern struct ipsec_sa * __ipsec_sa_get(struct ipsec_sa *ips, const char *func, int line);
++
++#define ipsec_sa_put(ips) __ipsec_sa_put(ips, __FUNCTION__, __LINE__)
++extern void __ipsec_sa_put(struct ipsec_sa *ips, const char *func, int line);
++extern int ipsec_sa_add(struct ipsec_sa *ips);
++extern void ipsec_sa_rm(struct ipsec_sa *ips);
++extern int ipsec_sadb_cleanup(__u8 proto);
++extern int ipsec_sadb_free(void);
++extern int ipsec_sa_wipe(struct ipsec_sa *ips);
++extern int ipsec_sa_intern(struct ipsec_sa *ips);
++extern struct ipsec_sa *ipsec_sa_getbyref(IPsecSAref_t ref);
++
++extern void ipsec_sa_untern(struct ipsec_sa *ips);
++#endif /* __KERNEL__ */
++
++enum ipsec_direction {
++      ipsec_incoming = 1,
++      ipsec_outgoing = 2
++};
++
++#define _IPSEC_SA_H_
++#endif /* _IPSEC_SA_H_ */
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_sha1.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,79 @@
++/*
++ * RCSID $Id: ipsec_sha1.h,v 1.8 2004/04/05 19:55:07 mcr Exp $
++ */
++
++/*
++ * Here is the original comment from the distribution:
++
++SHA-1 in C
++By Steve Reid <steve@edmweb.com>
++100% Public Domain
++
++ * Adapted for use by the IPSEC code by John Ioannidis
++ */
++
++
++#ifndef _IPSEC_SHA1_H_
++#define _IPSEC_SHA1_H_
++
++typedef struct
++{
++      __u32   state[5];
++      __u32   count[2];
++      __u8    buffer[64];
++} SHA1_CTX;
++
++void SHA1Transform(__u32 state[5], __u8 buffer[64]);
++void SHA1Init(void *context);
++void SHA1Update(void *context, unsigned char *data, __u32 len);
++void SHA1Final(unsigned char digest[20], void *context);
++
++ 
++#endif /* _IPSEC_SHA1_H_ */
++
++/*
++ * $Log: ipsec_sha1.h,v $
++ * Revision 1.8  2004/04/05 19:55:07  mcr
++ * Moved from linux/include/freeswan/ipsec_sha1.h,v
++ *
++ * Revision 1.7  2002/09/10 01:45:09  mcr
++ *    changed type of MD5_CTX and SHA1_CTX to void * so that
++ *    the function prototypes would match, and could be placed
++ *    into a pointer to a function.
++ *
++ * Revision 1.6  2002/04/24 07:36:47  mcr
++ * Moved from ./klips/net/ipsec/ipsec_sha1.h,v
++ *
++ * Revision 1.5  1999/12/13 13:59:13  rgb
++ * Quick fix to argument size to Update bugs.
++ *
++ * Revision 1.4  1999/12/07 18:16:23  rgb
++ * Fixed comments at end of #endif lines.
++ *
++ * Revision 1.3  1999/04/06 04:54:27  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.2  1998/11/30 13:22:54  rgb
++ * Rationalised all the klips kernel file headers.  They are much shorter
++ * now and won't conflict under RH5.2.
++ *
++ * Revision 1.1  1998/06/18 21:27:50  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.2  1998/04/23 20:54:05  rgb
++ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
++ * verified.
++ *
++ * Revision 1.1  1998/04/09 03:04:21  henry
++ * sources moved up from linux/net/ipsec
++ * these two include files modified not to include others except in kernel
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:04  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * New transform
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_stats.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,76 @@
++/*
++ * @(#) definition of ipsec_stats structure
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_stats.h,v 1.7 2005/04/14 01:17:45 mcr Exp $
++ *
++ */
++
++/* 
++ * This file describes the errors/statistics that FreeSWAN collects.
++ */
++
++#ifndef _IPSEC_STATS_H_
++
++struct ipsec_stats {
++      __u32           ips_alg_errs;          /* number of algorithm errors */
++      __u32           ips_auth_errs;         /* # of authentication errors */
++      __u32           ips_encsize_errs;      /* # of encryption size errors*/
++      __u32           ips_encpad_errs;       /* # of encryption pad  errors*/
++      __u32           ips_replaywin_errs;    /* # of pkt sequence errors */
++};
++
++#define _IPSEC_STATS_H_
++#endif /* _IPSEC_STATS_H_ */
++
++/*
++ * $Log: ipsec_stats.h,v $
++ * Revision 1.7  2005/04/14 01:17:45  mcr
++ *    add prototypes for snprintf.
++ *
++ * Revision 1.6  2004/04/05 19:55:07  mcr
++ * Moved from linux/include/freeswan/ipsec_stats.h,v
++ *
++ * Revision 1.5  2004/04/05 19:41:05  mcr
++ *    merged alg-branch code.
++ *
++ * Revision 1.4  2004/03/28 20:27:19  paul
++ * Included tested and confirmed fixes mcr made and dhr verified for
++ * snprint statements. Changed one other snprintf to use ipsec_snprintf
++ * so it wouldnt break compatibility with 2.0/2.2 kernels. Verified with
++ * dhr. (thanks dhr!)
++ *
++ * Revision 1.4  2004/03/24 01:58:31  mcr
++ *     sprintf->snprintf for formatting into proc buffer.
++ *
++ * Revision 1.3.34.1  2004/04/05 04:30:46  mcr
++ *    patches for alg-branch to compile/work with 2.x openswan
++ *
++ * Revision 1.3  2002/04/24 07:36:47  mcr
++ * Moved from ./klips/net/ipsec/ipsec_stats.h,v
++ *
++ * Revision 1.2  2001/11/26 09:16:16  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.1.2.1  2001/09/25 02:27:00  mcr
++ *    statistics moved to seperate structure.
++ *
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_sysctl.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,20 @@
++#ifndef OPENSWAN_SYSCTL_H
++#define OPENSWAN_SYSCTL_H
++
++extern int debug_ah;
++extern int debug_esp;
++extern int debug_xform;
++extern int debug_eroute;
++extern int debug_spi;
++extern int debug_netlink;
++extern int debug_radij;
++extern int debug_rcv;
++extern int debug_tunnel;
++extern int debug_xmit;
++extern int debug_mast;
++
++extern int sysctl_ip_default_ttl;
++extern int sysctl_ipsec_inbound_policy_check;
++extern int sysctl_ipsec_debug_ipcomp;
++extern int sysctl_ipsec_debug_verbose;
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_tunnel.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,286 @@
++/*
++ * IPSEC tunneling code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Richard Guy Briggs.
++ * Copyright (C) 2006        Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++
++# define DEV_QUEUE_XMIT(skb, device, pri) {\
++      skb->dev = device; \
++      neigh_compat_output(skb); \
++      /* skb->dst->output(skb); */ \
++ }
++# define ICMP_SEND(skb_in, type, code, info, dev) \
++      icmp_send(skb_in, type, code, htonl(info))
++# define IP_SEND(skb, dev) \
++      ip_send(skb);
++
++
++#if defined(KLIPS)
++/*
++ * Heavily based on drivers/net/new_tunnel.c.  Lots
++ * of ideas also taken from the 2.1.x version of drivers/net/shaper.c
++ */
++
++struct ipsectunnelconf
++{
++      uint32_t        cf_cmd;
++      union
++      {
++              char    cfu_name[12];
++      } cf_u;
++#define cf_name cf_u.cfu_name
++};
++
++#define IPSEC_SET_DEV (SIOCDEVPRIVATE)
++#define IPSEC_DEL_DEV (SIOCDEVPRIVATE + 1)
++#define IPSEC_CLR_DEV (SIOCDEVPRIVATE + 2)
++#define IPSEC_UDP_ENCAP_CONVERT       (SIOCDEVPRIVATE + 3)
++#endif
++
++#ifdef __KERNEL__
++#include <linux/version.h>
++#ifndef KERNEL_VERSION
++#  define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
++#endif
++struct ipsecpriv
++{
++      struct sk_buff_head sendq;
++      struct net_device *dev;
++      struct wait_queue *wait_queue;
++      int  vifnum;
++      char locked;
++      int  (*hard_start_xmit) (struct sk_buff *skb,
++              struct net_device *dev);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      const struct header_ops *header_ops;
++#else
++
++      int  (*hard_header) (struct sk_buff *skb,
++              struct net_device *dev,
++              unsigned short type,
++              void *daddr,
++              void *saddr,
++              unsigned len);
++#ifdef NET_21
++      int  (*rebuild_header)(struct sk_buff *skb);
++#else /* NET_21 */
++      int  (*rebuild_header)(void *buff, struct net_device *dev,
++                      unsigned long raddr, struct sk_buff *skb);
++#endif /* NET_21 */
++#ifndef NET_21
++      void (*header_cache_bind)(struct hh_cache **hhp, struct net_device *dev,
++                               unsigned short htype, __u32 daddr);
++#endif /* !NET_21 */
++      void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char *  haddr);
++#endif
++      int  (*set_mac_address)(struct net_device *dev, void *addr);
++      struct net_device_stats *(*get_stats)(struct net_device *dev);
++      struct net_device_stats mystats;
++      int mtu;        /* What is the desired MTU? */
++};
++
++extern char ipsec_tunnel_c_version[];
++
++extern struct net_device *ipsecdevices[IPSEC_NUM_IFMAX];
++extern int ipsecdevices_max;
++
++int ipsec_tunnel_init_devices(void);
++
++/* void */ int ipsec_tunnel_cleanup_devices(void);
++
++extern /* void */ int ipsec_init(void);
++
++extern int ipsec_tunnel_start_xmit(struct sk_buff *skb, struct net_device *dev);
++extern struct net_device *ipsec_get_device(int inst);
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int debug_tunnel;
++extern int sysctl_ipsec_debug_verbose;
++#endif /* CONFIG_KLIPS_DEBUG */
++#endif /* __KERNEL__ */
++
++#ifdef CONFIG_KLIPS_DEBUG
++#define DB_TN_INIT    0x0001
++#define DB_TN_PROCFS  0x0002
++#define DB_TN_XMIT    0x0010
++#define DB_TN_OHDR    0x0020
++#define DB_TN_CROUT   0x0040
++#define DB_TN_OXFS    0x0080
++#define DB_TN_REVEC   0x0100
++#define DB_TN_ENCAP     0x0200
++#endif /* CONFIG_KLIPS_DEBUG */
++
++extern int ipsec_tunnel_deletenum(int vifnum);
++extern int ipsec_tunnel_createnum(int vifnum);
++extern struct net_device *ipsec_tunnel_get_device(int vifnum);
++
++
++/* manage ipsec xmit state objects */
++extern int ipsec_xmit_state_cache_init (void);
++extern void ipsec_xmit_state_cache_cleanup (void);
++struct ipsec_xmit_state *ipsec_xmit_state_new (void);
++void ipsec_xmit_state_delete (struct ipsec_xmit_state *ixs);
++
++/*
++ * $Log: ipsec_tunnel.h,v $
++ * Revision 1.33  2005/06/04 16:06:05  mcr
++ *    better patch for nat-t rcv-device code.
++ *
++ * Revision 1.32  2005/05/21 03:18:35  mcr
++ *    added additional debug flag tunnelling.
++ *
++ * Revision 1.31  2004/08/03 18:18:02  mcr
++ *    in 2.6, use "net_device" instead of #define device->net_device.
++ *    this probably breaks 2.0 compiles.
++ *
++ * Revision 1.30  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.29  2004/04/05 19:55:07  mcr
++ * Moved from linux/include/freeswan/ipsec_tunnel.h,v
++ *
++ * Revision 1.28  2003/06/24 20:22:32  mcr
++ *    added new global: ipsecdevices[] so that we can keep track of
++ *    the ipsecX devices. They will be referenced with dev_hold(),
++ *    so 2.2 may need this as well.
++ *
++ * Revision 1.27  2003/04/03 17:38:09  rgb
++ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
++ *
++ * Revision 1.26  2003/02/12 19:32:20  rgb
++ * Updated copyright year.
++ *
++ * Revision 1.25  2002/05/27 18:56:07  rgb
++ * Convert to dynamic ipsec device allocation.
++ *
++ * Revision 1.24  2002/04/24 07:36:48  mcr
++ * Moved from ./klips/net/ipsec/ipsec_tunnel.h,v
++ *
++ * Revision 1.23  2001/11/06 19:50:44  rgb
++ * Moved IP_SEND, ICMP_SEND, DEV_QUEUE_XMIT macros to ipsec_tunnel.h for
++ * use also by pfkey_v2_parser.c
++ *
++ * Revision 1.22  2001/09/15 16:24:05  rgb
++ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
++ *
++ * Revision 1.21  2001/06/14 19:35:10  rgb
++ * Update copyright date.
++ *
++ * Revision 1.20  2000/09/15 11:37:02  rgb
++ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
++ * IPCOMP zlib deflate code.
++ *
++ * Revision 1.19  2000/09/08 19:12:56  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.18  2000/07/28 13:50:54  rgb
++ * Changed enet_statistics to net_device_stats and added back compatibility
++ * for pre-2.1.19.
++ *
++ * Revision 1.17  1999/11/19 01:12:15  rgb
++ * Purge unneeded proc_info prototypes, now that static linking uses
++ * dynamic proc_info registration.
++ *
++ * Revision 1.16  1999/11/18 18:51:00  rgb
++ * Changed all device registrations for static linking to
++ * dynamic to reduce the number and size of patches.
++ *
++ * Revision 1.15  1999/11/18 04:14:21  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
++ * Added Marc Boucher's 2.3.25 proc patches.
++ *
++ * Revision 1.14  1999/05/25 02:50:10  rgb
++ * Fix kernel version macros for 2.0.x static linking.
++ *
++ * Revision 1.13  1999/05/25 02:41:06  rgb
++ * Add ipsec_klipsdebug support for static linking.
++ *
++ * Revision 1.12  1999/05/05 22:02:32  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.11  1999/04/29 15:19:50  rgb
++ * Add return values to init and cleanup functions.
++ *
++ * Revision 1.10  1999/04/16 16:02:39  rgb
++ * Bump up macro to 4 ipsec I/Fs.
++ *
++ * Revision 1.9  1999/04/15 15:37:25  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.5.2.1  1999/04/02 04:26:14  rgb
++ * Backcheck from HEAD, pre1.0.
++ *
++ * Revision 1.8  1999/04/11 00:29:01  henry
++ * GPL boilerplate
++ *
++ * Revision 1.7  1999/04/06 04:54:28  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.6  1999/03/31 05:44:48  rgb
++ * Keep PMTU reduction private.
++ *
++ * Revision 1.5  1999/02/10 22:31:20  rgb
++ * Change rebuild_header member to reflect generality of link layer.
++ *
++ * Revision 1.4  1998/12/01 13:22:04  rgb
++ * Added support for debug printing of version info.
++ *
++ * Revision 1.3  1998/07/29 20:42:46  rgb
++ * Add a macro for clearing all tunnel devices.
++ * Rearrange structures and declarations for sharing with userspace.
++ *
++ * Revision 1.2  1998/06/25 20:01:45  rgb
++ * Make prototypes available for ipsec_init and ipsec proc_dir_entries
++ * for static linking.
++ *
++ * Revision 1.1  1998/06/18 21:27:50  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.3  1998/05/18 21:51:50  rgb
++ * Added macros for num of I/F's and a procfs debug switch.
++ *
++ * Revision 1.2  1998/04/21 21:29:09  rgb
++ * Rearrange debug switches to change on the fly debug output from user
++ * space.  Only kernel changes checked in at this time.  radij.c was also
++ * changed to temporarily remove buggy debugging code in rj_delete causing
++ * an OOPS and hence, netlink device open errors.
++ *
++ * Revision 1.1  1998/04/09 03:06:13  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:05  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.5  1997/06/03 04:24:48  ji
++ * Added transport mode.
++ * Changed the way routing is done.
++ * Lots of bug fixes.
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:39:04  ji
++ * Minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_xform.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,278 @@
++/*
++ * Definitions relevant to IPSEC transformations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * COpyright (C) 2003  Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_xform.h,v 1.42 2005/08/05 08:50:45 mcr Exp $
++ */
++
++#ifndef _IPSEC_XFORM_H_
++
++#include <openswan.h>
++
++#define XF_NONE                       0       /* No transform set */
++#define XF_IP4                        1       /* IPv4 inside IPv4 */
++#define XF_AHMD5              2       /* AH MD5 */
++#define XF_AHSHA              3       /* AH SHA */
++#define XF_ESP3DES            5       /* ESP DES3-CBC */
++#define XF_AHHMACMD5          6       /* AH-HMAC-MD5 with opt replay prot */
++#define XF_AHHMACSHA1         7       /* AH-HMAC-SHA1 with opt replay prot */
++#define XF_ESP3DESMD5         9       /* triple DES, HMAC-MD-5, 128-bits of authentication */
++#define       XF_ESP3DESMD596         10      /* triple DES, HMAC-MD-5, 96-bits of authentication */
++#define       XF_ESPNULLMD596         12      /* NULL, HMAC-MD-5 with 96-bits of authentication */
++#define       XF_ESPNULLSHA196        13      /* NULL, HMAC-SHA-1 with 96-bits of authentication */
++#define       XF_ESP3DESSHA196        14      /* triple DES, HMAC-SHA-1, 96-bits of authentication */
++#define XF_IP6                        15      /* IPv6 inside IPv6 */
++#define XF_COMPDEFLATE                16      /* IPCOMP deflate */
++
++#define XF_CLR                        126     /* Clear SA table */
++#define XF_DEL                        127     /* Delete SA */
++
++/* IPsec AH transform values
++ * RFC 2407
++ * draft-ietf-ipsec-doi-tc-mib-02.txt
++ */
++
++/* why are these hardcoded here? See ipsec_policy.h for their enums -- Paul*/
++/* ---------- These really need to go from here ------------------ */
++#define AH_NONE                       0
++#define AH_MD5                        2
++#define AH_SHA                        3
++/* draft-ietf-ipsec-ciph-aes-cbc-03.txt */
++#define AH_SHA2_256           5
++#define AH_SHA2_384           6
++#define AH_SHA2_512           7
++#define AH_RIPEMD             8
++#define AH_AES                        9
++#define AH_NULL                       251
++#define AH_MAX                        251
++
++/* IPsec ESP transform values */
++
++#define ESP_NONE              0
++#define ESP_DES                       2
++#define ESP_3DES              3
++#define ESP_RC5                       4
++#define ESP_IDEA              5
++#define ESP_CAST              6
++#define ESP_BLOWFISH          7
++#define ESP_3IDEA             8
++#define ESP_RC4                       10
++#define ESP_NULL              11
++#define ESP_AES                       12
++#define ESP_AES_CTR           13
++#define ESP_AES_CCM_A         14
++#define ESP_AES_CCM_B         15
++#define ESP_AES_CCM_C         16
++#define ESP_ID17              17
++#define ESP_AES_GCM_A         18
++#define ESP_AES_GCM_B         19
++#define ESP_AES_GCM_C         20
++#define ESP_SEED_CBC          21
++#define ESP_CAMELLIA          22
++
++/* as draft-ietf-ipsec-ciph-aes-cbc-02.txt */
++#define ESP_MARS              249
++#define       ESP_RC6                 250
++#define ESP_SERPENT           252
++#define ESP_TWOFISH           253
++                       
++/* IPCOMP transform values */
++
++#define IPCOMP_NONE           0
++#define IPCOMP_OUI            1
++#define IPCOMP_DEFLAT         2
++#define IPCOMP_LZS            3
++#define IPCOMP_V42BIS         4
++
++#define XFT_AUTH              0x0001
++#define XFT_CONF              0x0100
++
++/* available if CONFIG_KLIPS_DEBUG is defined */
++#define DB_XF_INIT            0x0001
++
++#define PROTO2TXT(x) \
++      (x) == IPPROTO_AH ? "AH" : \
++      (x) == IPPROTO_ESP ? "ESP" : \
++      (x) == IPPROTO_IPIP ? "IPIP" : \
++      (x) == IPPROTO_COMP ? "COMP" : \
++      "UNKNOWN_proto"
++static inline const char *enc_name_id (unsigned id) {
++      static char buf[16];
++      snprintf(buf, sizeof(buf), "_ID%d", id);
++      return buf;
++}
++static inline const char *auth_name_id (unsigned id) {
++      static char buf[16];
++      snprintf(buf, sizeof(buf), "_ID%d", id);
++      return buf;
++}
++#define IPS_XFORM_NAME(x) \
++      PROTO2TXT((x)->ips_said.proto), \
++      (x)->ips_said.proto == IPPROTO_COMP ? \
++              ((x)->ips_encalg == SADB_X_CALG_DEFLATE ? \
++               "_DEFLATE" : "_UNKNOWN_comp") : \
++      (x)->ips_encalg == ESP_NONE ? "" : \
++      (x)->ips_encalg == ESP_3DES ? "_3DES" : \
++      (x)->ips_encalg == ESP_AES ? "_AES" : \
++      (x)->ips_encalg == ESP_SERPENT ? "_SERPENT" : \
++      (x)->ips_encalg == ESP_TWOFISH ? "_TWOFISH" : \
++      enc_name_id(x->ips_encalg)/* "_UNKNOWN_encr" */, \
++      (x)->ips_authalg == AH_NONE ? "" : \
++      (x)->ips_authalg == AH_MD5 ? "_HMAC_MD5" : \
++      (x)->ips_authalg == AH_SHA ? "_HMAC_SHA1" : \
++      (x)->ips_authalg == AH_SHA2_256 ? "_HMAC_SHA2_256" : \
++      (x)->ips_authalg == AH_SHA2_384 ? "_HMAC_SHA2_384" : \
++      (x)->ips_authalg == AH_SHA2_512 ? "_HMAC_SHA2_512" : \
++      auth_name_id(x->ips_authalg) /* "_UNKNOWN_auth" */ \
++
++#ifdef __KERNEL__
++#include <linux/skbuff.h>
++
++struct ipsec_rcv_state;
++struct ipsec_xmit_state;
++
++struct xform_functions {
++      u8   protocol;
++      enum ipsec_rcv_value (*rcv_checks)(struct ipsec_rcv_state *irs,
++                                     struct sk_buff *skb);
++        enum ipsec_rcv_value (*rcv_decrypt)(struct ipsec_rcv_state *irs);
++
++      enum ipsec_rcv_value (*rcv_setup_auth)(struct ipsec_rcv_state *irs,
++                                         struct sk_buff *skb,
++                                         __u32          *replay,
++                                         unsigned char **authenticator);
++      enum ipsec_rcv_value (*rcv_calc_auth)(struct ipsec_rcv_state *irs,
++                                      struct sk_buff *skb);
++
++      enum ipsec_xmit_value (*xmit_setup)(struct ipsec_xmit_state *ixs);
++        enum ipsec_xmit_value (*xmit_encrypt)(struct ipsec_xmit_state *ixs);
++
++      enum ipsec_xmit_value (*xmit_setup_auth)(struct ipsec_xmit_state *ixs,
++                                         struct sk_buff *skb,
++                                         __u32          *replay,
++                                         unsigned char **authenticator);
++      enum ipsec_xmit_value (*xmit_calc_auth)(struct ipsec_xmit_state *ixs,
++                                      struct sk_buff *skb);
++        int  xmit_headroom;
++      int  xmit_needtailroom;
++};
++
++#endif /* __KERNEL__ */
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern void ipsec_dmp(char *s, caddr_t bb, int len);
++#else /* CONFIG_KLIPS_DEBUG */
++#define ipsec_dmp(_x, _y, _z) 
++#endif /* CONFIG_KLIPS_DEBUG */
++
++
++#define _IPSEC_XFORM_H_
++#endif /* _IPSEC_XFORM_H_ */
++
++/*
++ * $Log: ipsec_xform.h,v $
++ * Revision 1.42  2005/08/05 08:50:45  mcr
++ *    move #include of skbuff.h to a place where
++ *    we know it will be kernel only code.
++ *
++ * Revision 1.41  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.40  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.39  2004/04/05 19:55:07  mcr
++ * Moved from linux/include/freeswan/ipsec_xform.h,v
++ *
++ * Revision 1.38  2004/04/05 19:41:05  mcr
++ *    merged alg-branch code.
++ *
++ * Revision 1.37  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.36.34.1  2003/12/22 15:25:52  jjo
++ *      Merged algo-0.8.1-rc11-test1 into alg-branch
++ *
++ * Revision 1.36  2002/04/24 07:36:48  mcr
++ * Moved from ./klips/net/ipsec/ipsec_xform.h,v
++ *
++ * Revision 1.35  2001/11/26 09:23:51  rgb
++ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
++ *
++ * Revision 1.33.2.1  2001/09/25 02:24:58  mcr
++ *    struct tdb -> struct ipsec_sa.
++ *    sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
++ *    ipsec_xform.c removed. header file still contains useful things.
++ *
++ * Revision 1.34  2001/11/06 19:47:17  rgb
++ * Changed lifetime_packets to uint32 from uint64.
++ *
++ * Revision 1.33  2001/09/08 21:13:34  rgb
++ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
++ *
++ * Revision 1.32  2001/07/06 07:40:01  rgb
++ * Reformatted for readability.
++ * Added inbound policy checking fields for use with IPIP SAs.
++ *
++ * Revision 1.31  2001/06/14 19:35:11  rgb
++ * Update copyright date.
++ *
++ * Revision 1.30  2001/05/30 08:14:03  rgb
++ * Removed vestiges of esp-null transforms.
++ *
++ * Revision 1.29  2001/01/30 23:42:47  rgb
++ * Allow pfkey msgs from pid other than user context required for ACQUIRE
++ * and subsequent ADD or UDATE.
++ *
++ * Revision 1.28  2000/11/06 04:30:40  rgb
++ * Add Svenning's adaptive content compression.
++ *
++ * Revision 1.27  2000/09/19 00:38:25  rgb
++ * Fixed algorithm name bugs introduced for ipcomp.
++ *
++ * Revision 1.26  2000/09/17 21:36:48  rgb
++ * Added proto2txt macro.
++ *
++ * Revision 1.25  2000/09/17 18:56:47  rgb
++ * Added IPCOMP support.
++ *
++ * Revision 1.24  2000/09/12 19:34:12  rgb
++ * Defined XF_IP6 from Gerhard for ipv6 tunnel support.
++ *
++ * Revision 1.23  2000/09/12 03:23:14  rgb
++ * Cleaned out now unused tdb_xform and tdb_xdata members of struct tdb.
++ *
++ * Revision 1.22  2000/09/08 19:12:56  rgb
++ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
++ *
++ * Revision 1.21  2000/09/01 18:32:43  rgb
++ * Added (disabled) sensitivity members to tdb struct.
++ *
++ * Revision 1.20  2000/08/30 05:31:01  rgb
++ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
++ * Kill remainder of tdb_xform, tdb_xdata, xformsw.
++ *
++ * Revision 1.19  2000/08/01 14:51:52  rgb
++ * Removed _all_ remaining traces of DES.
++ *
++ * Revision 1.18  2000/01/21 06:17:45  rgb
++ * Tidied up spacing.
++ *
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/ipsec_xmit.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,267 @@
++/*
++ * IPSEC tunneling code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_xmit.h,v 1.14 2005/05/11 01:00:26 mcr Exp $
++ */
++
++#include "openswan/ipsec_sa.h"
++
++#ifdef CONFIG_KLIPS_OCF
++#include <cryptodev.h>
++#endif
++
++enum ipsec_xmit_value
++{
++      IPSEC_XMIT_STOLEN=2,
++      IPSEC_XMIT_PASS=1,
++      IPSEC_XMIT_OK=0,
++      IPSEC_XMIT_ERRMEMALLOC=-1,
++      IPSEC_XMIT_ESP_BADALG=-2,
++      IPSEC_XMIT_BADPROTO=-3,
++      IPSEC_XMIT_ESP_PUSHPULLERR=-4,
++      IPSEC_XMIT_BADLEN=-5,
++      IPSEC_XMIT_AH_BADALG=-6,
++      IPSEC_XMIT_SAIDNOTFOUND=-7,
++      IPSEC_XMIT_SAIDNOTLIVE=-8,
++      IPSEC_XMIT_REPLAYROLLED=-9,
++      IPSEC_XMIT_LIFETIMEFAILED=-10,
++      IPSEC_XMIT_CANNOTFRAG=-11,
++      IPSEC_XMIT_MSSERR=-12,
++      IPSEC_XMIT_ERRSKBALLOC=-13,
++      IPSEC_XMIT_ENCAPFAIL=-14,
++      IPSEC_XMIT_NODEV=-15,
++      IPSEC_XMIT_NOPRIVDEV=-16,
++      IPSEC_XMIT_NOPHYSDEV=-17,
++      IPSEC_XMIT_NOSKB=-18,
++      IPSEC_XMIT_NOIPV6=-19,
++      IPSEC_XMIT_NOIPOPTIONS=-20,
++      IPSEC_XMIT_TTLEXPIRED=-21,
++      IPSEC_XMIT_BADHHLEN=-22,
++      IPSEC_XMIT_PUSHPULLERR=-23,
++      IPSEC_XMIT_ROUTEERR=-24,
++      IPSEC_XMIT_RECURSDETECT=-25,
++      IPSEC_XMIT_IPSENDFAILURE=-26,
++      IPSEC_XMIT_ESPUDP=-27,
++      IPSEC_XMIT_ESPUDP_BADTYPE=-28,
++      IPSEC_XMIT_PENDING=-29,
++};
++
++
++/*
++ * state machine states
++ */
++
++#define IPSEC_XSM_INIT1                       0       /* make it easy, starting state is 0 */
++#define IPSEC_XSM_INIT2                       1
++#define IPSEC_XSM_ENCAP_INIT  2
++#define IPSEC_XSM_ENCAP_SELECT        3
++#define IPSEC_XSM_ESP                 4
++#define IPSEC_XSM_ESP_AH              5
++#define IPSEC_XSM_AH                  6
++#define IPSEC_XSM_IPIP                        7
++#define IPSEC_XSM_IPCOMP              8
++#define IPSEC_XSM_CONT                        9
++#define IPSEC_XSM_DONE                        100
++
++
++struct ipsec_xmit_state
++{
++      struct sk_buff *skb;            /* working skb pointer */
++      struct net_device *dev;         /* working dev pointer */
++      struct ipsecpriv *prv;          /* Our device' private space */
++      struct sk_buff *oskb;           /* Original skb pointer */
++      struct net_device_stats *stats; /* This device's statistics */
++      struct iphdr  *iph;             /* Our new IP header */
++      __u32   newdst;                 /* The other SG's IP address */
++      __u32   orgdst;                 /* Original IP destination address */
++      __u32   orgedst;                /* 1st SG's IP address */
++      __u32   newsrc;                 /* The new source SG's IP address */
++      __u32   orgsrc;                 /* Original IP source address */
++      __u32   innersrc;               /* Innermost IP source address */
++      int     iphlen;                 /* IP header length */
++      int     pyldsz;                 /* upper protocol payload size */
++      int     headroom;
++      int     tailroom;
++        int     authlen;
++      int     max_headroom;           /* The extra header space needed */
++      int     max_tailroom;           /* The extra stuffing needed */
++      int     ll_headroom;            /* The extra link layer hard_header space needed */
++      int     tot_headroom;           /* The total header space needed */
++      int     tot_tailroom;           /* The totalstuffing needed */
++      __u8    *saved_header;          /* saved copy of the hard header */
++      unsigned short   sport, dport;
++
++      struct sockaddr_encap matcher;  /* eroute search key */
++      struct eroute *eroute;
++        struct ipsec_sa *ipsp;                /* ipsec_sa pointers */
++  //struct ipsec_sa *ipsp_outer;    /* last SA applied by encap_bundle */
++      char sa_txt[SATOT_BUF];
++      size_t sa_len;
++      int hard_header_stripped;       /* has the hard header been removed yet? */
++      int hard_header_len;
++      struct net_device *physdev;
++/*    struct device *virtdev; */
++      short physmtu;
++      short cur_mtu;          /* copy of prv->mtu, cause prv may == NULL */
++      short mtudiff;
++#ifdef NET_21
++      struct rtable *route;
++#endif /* NET_21 */
++      ip_said outgoing_said;
++#ifdef NET_21
++      int pass;
++#endif /* NET_21 */
++      uint32_t eroute_pid;
++      struct ipsec_sa ips;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      uint8_t natt_type;
++      uint8_t natt_head;
++      uint16_t natt_sport;
++      uint16_t natt_dport;
++#endif
++
++      /*
++       * xmit state machine use
++       */
++      void (*xsm_complete)(struct ipsec_xmit_state *ixs,
++                      enum ipsec_xmit_value stat);
++      int             state;
++      int             next_state;
++#ifdef CONFIG_KLIPS_OCF
++      struct work_struct      workq;
++#ifdef DECLARE_TASKLET
++      struct tasklet_struct   tasklet;
++#endif
++#endif
++#ifdef CONFIG_KLIPS_ALG
++      struct ipsec_alg_auth *ixt_a;
++      struct ipsec_alg_enc *ixt_e;
++#endif
++#ifdef CONFIG_KLIPS_ESP
++      struct esphdr *espp;
++      unsigned char *idat;
++#endif /* !CONFIG_KLIPS_ESP */
++      int blocksize;
++      int ilen, len;
++      unsigned char *dat;
++      __u8 frag_off, tos;
++      __u16 ttl, check;
++};
++
++enum ipsec_xmit_value
++ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs);
++
++enum ipsec_xmit_value
++ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs);
++
++enum ipsec_xmit_value
++ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs);
++
++extern void ipsec_xsm(struct ipsec_xmit_state *ixs);
++#ifdef HAVE_KMEM_CACHE_T
++extern kmem_cache_t *ipsec_ixs_cache;
++#else
++extern struct kmem_cache *ipsec_ixs_cache;
++#endif
++extern int ipsec_ixs_max;
++extern atomic_t ipsec_ixs_cnt;
++
++extern void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er);
++
++extern enum ipsec_xmit_value
++ipsec_xmit_send(struct ipsec_xmit_state*ixs, struct flowi *fl);
++
++extern enum ipsec_xmit_value
++ipsec_nat_encap(struct ipsec_xmit_state*ixs);
++
++extern enum ipsec_xmit_value
++ipsec_tunnel_send(struct ipsec_xmit_state *ixs);
++
++extern void ipsec_xmit_cleanup(struct ipsec_xmit_state*ixs);
++
++
++extern int ipsec_xmit_trap_count;
++extern int ipsec_xmit_trap_sendcount;
++
++#ifdef CONFIG_KLIPS_DEBUG
++extern int debug_xmit;
++extern int debug_mast;
++
++#define ipsec_xmit_dmp(_x,_y, _z) if (debug_xmit && sysctl_ipsec_debug_verbose) ipsec_dmp_block(_x,_y,_z)
++#else
++#define ipsec_xmit_dmp(_x,_y, _z) do {} while(0)
++
++#endif /* CONFIG_KLIPS_DEBUG */
++
++extern int sysctl_ipsec_debug_verbose;
++extern int sysctl_ipsec_icmp;
++extern int sysctl_ipsec_tos;
++
++
++/*
++ * $Log: ipsec_xmit.h,v $
++ * Revision 1.14  2005/05/11 01:00:26  mcr
++ *    do not call debug routines if !defined KLIPS_DEBUG.
++ *
++ * Revision 1.13  2005/04/29 05:01:38  mcr
++ *    use ipsec_dmp_block.
++ *    added cur_mtu to ixs instead of using ixs->dev.
++ *
++ * Revision 1.12  2004/08/20 21:45:37  mcr
++ *    CONFIG_KLIPS_NAT_TRAVERSAL is not used in an attempt to
++ *    be 26sec compatible. But, some defines where changed.
++ *
++ * Revision 1.11  2004/08/03 18:18:21  mcr
++ *    in 2.6, use "net_device" instead of #define device->net_device.
++ *    this probably breaks 2.0 compiles.
++ *
++ * Revision 1.10  2004/07/10 19:08:41  mcr
++ *    CONFIG_IPSEC -> CONFIG_KLIPS.
++ *
++ * Revision 1.9  2004/04/06 02:49:08  mcr
++ *    pullup of algo code from alg-branch.
++ *
++ * Revision 1.8  2004/04/05 19:55:07  mcr
++ * Moved from linux/include/freeswan/ipsec_xmit.h,v
++ *
++ * Revision 1.7  2004/02/03 03:11:40  mcr
++ *    new xmit type if the UDP encapsulation is wrong.
++ *
++ * Revision 1.6  2003/12/13 19:10:16  mcr
++ *    refactored rcv and xmit code - same as FS 2.05.
++ *
++ * Revision 1.5  2003/12/10 01:20:06  mcr
++ *    NAT-traversal patches to KLIPS.
++ *
++ * Revision 1.4  2003/12/06 16:37:04  mcr
++ *    1.4.7a X.509 patch applied.
++ *
++ * Revision 1.3  2003/10/31 02:27:05  mcr
++ *    pulled up port-selector patches and sa_id elimination.
++ *
++ * Revision 1.2.4.2  2003/10/29 01:10:19  mcr
++ *    elimited "struct sa_id"
++ *
++ * Revision 1.2.4.1  2003/09/21 13:59:38  mcr
++ *    pre-liminary X.509 patch - does not yet pass tests.
++ *
++ * Revision 1.2  2003/06/20 01:42:13  mcr
++ *    added counters to measure how many ACQUIREs we send to pluto,
++ *    and how many are successfully sent.
++ *
++ * Revision 1.1  2003/02/12 19:31:03  rgb
++ * Refactored from ipsec_tunnel.c
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/mast.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,33 @@
++struct mast_callbacks {
++  int (*packet_encap)(struct device *mast, void *context,
++                    struct sk_buff *skb, int flowref);
++  int (*link_inquire)(struct device *mast, void *context);
++};
++
++
++struct device *mast_init (int family,
++                        struct mast_callbacks *callbacks,
++                        unsigned int flags,
++                        unsigned int desired_unit,
++                        unsigned int max_flowref,
++                        void *context);
++
++int mast_destroy(struct device *mast);
++
++int mast_recv(struct device *mast, struct sk_buff *skb, int flowref);
++
++/* free this skb as being useless, increment failure count. */
++int mast_toast(struct device *mast, struct sk_buff *skb, int flowref);
++
++int mast_linkstat (struct device *mast, int flowref,
++                 int status);
++
++int mast_setreference (struct device *mast,
++                     int defaultSA);
++
++int mast_setneighbor (struct device *mast,
++                    struct sockaddr *source,
++                    struct sockaddr *destination,
++                    int flowref);
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/passert.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,75 @@
++/*
++ * sanitize a string into a printable format.
++ *
++ * Copyright (C) 1998-2002  D. Hugh Redelmeier.
++ * Copyright (C) 2003  Michael Richardson <mcr@freeswan.org>
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: passert.h,v 1.7.8.1 2007/09/05 02:32:24 paul Exp $
++ */
++
++#include "openswan.h"
++
++#ifndef _OPENSWAN_PASSERT_H
++#define _OPENSWAN_PASSERT_H
++/* our versions of assert: log result */
++
++#ifdef DEBUG
++
++typedef void (*openswan_passert_fail_t)(const char *pred_str,
++                                      const char *file_str,
++                                      unsigned long line_no) NEVER_RETURNS;
++
++extern openswan_passert_fail_t openswan_passert_fail;
++
++extern void pexpect_log(const char *pred_str
++                      , const char *file_str, unsigned long line_no);
++
++# define impossible() do { \
++    if(openswan_passert_fail) {                                       \
++      (*openswan_passert_fail)("impossible", __FILE__, __LINE__); \
++    }} while(0)
++
++extern void openswan_switch_fail(int n
++    , const char *file_str, unsigned long line_no) NEVER_RETURNS;
++
++# define bad_case(n) openswan_switch_fail((int) n, __FILE__, __LINE__)
++
++# define passert(pred) do { \
++      if (!(pred)) \
++        if(openswan_passert_fail) { \
++          (*openswan_passert_fail)(#pred, __FILE__, __LINE__);        \
++        } \
++  } while(0)
++
++# define pexpect(pred) do { \
++      if (!(pred)) \
++          pexpect_log(#pred, __FILE__, __LINE__); \
++  } while(0)
++
++/* assert that an err_t is NULL; evaluate exactly once */
++# define happy(x) { \
++      err_t ugh = x; \
++      if (ugh != NULL) \
++        if(openswan_passert_fail) { (*openswan_passert_fail)(ugh, __FILE__, __LINE__); }  \
++    }
++
++#else /*!DEBUG*/
++
++# define impossible() abort()
++# define bad_case(n) abort()
++# define passert(pred)  { }   /* do nothing */
++# define happy(x)  { (void) x; }      /* evaluate non-judgementally */
++
++#endif /*!DEBUG*/
++
++#endif /* _OPENSWAN_PASSERT_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/pfkey.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,384 @@
++/*
++ * Openswan specific PF_KEY headers
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs.
++ * Copyright (C) 2006-2007 Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: pfkey.h,v 1.52 2005/11/09 00:30:37 mcr Exp $
++ */
++
++#ifndef __NET_IPSEC_PF_KEY_H
++#define __NET_IPSEC_PF_KEY_H
++
++#include "pfkeyv2.h"
++#ifdef __KERNEL__
++extern struct proto_ops pfkey_proto_ops;
++typedef struct sock pfkey_sock;
++extern int debug_pfkey;
++
++extern /* void */ int pfkey_init(void);
++extern /* void */ int pfkey_cleanup(void);
++
++struct socket_list
++{
++      struct socket *socketp;
++      struct socket_list *next;
++};
++extern int pfkey_list_insert_socket(struct socket*, struct socket_list**);
++extern int pfkey_list_remove_socket(struct socket*, struct socket_list**);
++extern struct socket_list *pfkey_open_sockets;
++extern struct socket_list *pfkey_registered_sockets[];
++
++struct ipsec_alg_supported
++{
++      uint16_t ias_exttype;
++      uint8_t  ias_id;
++      uint8_t  ias_ivlen;
++      uint16_t ias_keyminbits;
++      uint16_t ias_keymaxbits;
++        const char    *ias_name;
++};
++
++extern struct supported_list *pfkey_supported_list[];
++struct supported_list
++{
++      struct ipsec_alg_supported *supportedp;
++      struct supported_list *next;
++};
++extern int pfkey_list_insert_supported(struct ipsec_alg_supported*, struct supported_list**);
++extern int pfkey_list_remove_supported(struct ipsec_alg_supported*, struct supported_list**);
++
++struct sockaddr_key
++{
++      uint16_t        key_family;     /* PF_KEY */
++      uint16_t        key_pad;        /* not used */
++      uint32_t        key_pid;        /* process ID */
++};
++
++struct pfkey_extracted_data
++{
++      struct ipsec_sa* ips;
++      struct ipsec_sa* ips2;
++      struct eroute *eroute;
++      int            outif;
++      IPsecSAref_t   sarefme;
++      IPsecSAref_t   sarefhim;
++};
++
++/* forward reference */
++struct sadb_ext;
++struct sadb_msg;
++struct sockaddr;
++struct sadb_comb;
++struct sadb_sadb;
++struct sadb_alg;
++
++extern int
++pfkey_alloc_eroute(struct eroute** eroute);
++
++extern int
++pfkey_sa_process(struct sadb_ext *pfkey_ext,
++               struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_lifetime_process(struct sadb_ext *pfkey_ext,
++                     struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_address_process(struct sadb_ext *pfkey_ext,
++                    struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_key_process(struct sadb_ext *pfkey_ext,
++                struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_ident_process(struct sadb_ext *pfkey_ext,
++                  struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_sens_process(struct sadb_ext *pfkey_ext,
++                 struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_prop_process(struct sadb_ext *pfkey_ext,
++                 struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_supported_process(struct sadb_ext *pfkey_ext,
++                      struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_spirange_process(struct sadb_ext *pfkey_ext,
++                     struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext,
++                        struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_x_satype_process(struct sadb_ext *pfkey_ext,
++                     struct pfkey_extracted_data* extr);
++
++extern int
++pfkey_x_debug_process(struct sadb_ext *pfkey_ext,
++                    struct pfkey_extracted_data* extr);
++
++extern int pfkey_upmsg(struct socket *, struct sadb_msg *);
++extern int pfkey_upmsgsk(struct sock *, struct sadb_msg *);
++extern int pfkey_expire(struct ipsec_sa *, int);
++extern int pfkey_acquire(struct ipsec_sa *);
++#else /* ! __KERNEL__ */
++
++extern openswan_keying_debug_func_t pfkey_debug_func;
++extern openswan_keying_debug_func_t pfkey_error_func;
++extern void pfkey_print(struct sadb_msg *msg, FILE *out);
++
++
++#endif /* __KERNEL__ */
++
++extern uint8_t satype2proto(uint8_t satype);
++extern uint8_t proto2satype(uint8_t proto);
++extern char* satype2name(uint8_t satype);
++extern char* proto2name(uint8_t proto);
++
++struct key_opt
++{
++      uint32_t        key_pid;        /* process ID */
++      struct sock     *sk;
++};
++
++#define key_pid(sk) ((struct key_opt*)&((sk)->sk_protinfo))->key_pid
++
++/* XXX-mcr this is not an alignment, this is because the count is in 64-bit
++ * words.
++ */
++#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
++#define BITS_PER_OCTET 8
++#define OCTETBITS 8
++#define PFKEYBITS 64
++#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
++#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
++
++#define IPSEC_PFKEYv2_LEN(x)   ((x) * IPSEC_PFKEYv2_ALIGN)
++#define IPSEC_PFKEYv2_WORDS(x) (DIVUP(x,IPSEC_PFKEYv2_ALIGN))
++
++
++#define PFKEYv2_MAX_MSGSIZE 4096
++
++/*
++ * PF_KEYv2 permitted and required extensions in and out bitmaps
++ */
++struct pf_key_ext_parsers_def {
++      int  (*parser)(struct sadb_ext*);
++      char  *parser_name;
++};
++
++enum pfkey_ext_required {
++      EXT_BITS_IN=0,
++      EXT_BITS_OUT=1
++};
++
++enum pfkey_ext_perm {
++      EXT_BITS_PERM=0,
++      EXT_BITS_REQ=1
++};
++
++
++typedef uint64_t pfkey_ext_track;
++static inline void pfkey_mark_extension(enum sadb_extension_t exttype,
++                                      pfkey_ext_track *exten_track)
++{
++      *exten_track |= (1 << exttype);
++}
++      
++extern int pfkey_extensions_missing(enum pfkey_ext_required inout,
++                                  enum sadb_msg_t sadb_operation,
++                                  pfkey_ext_track extensions_seen);
++extern int pfkey_required_extension(enum pfkey_ext_required inout,
++                                  enum sadb_msg_t sadb_operation,
++                                  enum sadb_extension_t exttype);
++extern int pfkey_permitted_extension(enum pfkey_ext_required inout,
++                                  enum sadb_msg_t sadb_operation,
++                                  enum sadb_extension_t exttype);
++
++
++extern void pfkey_extensions_init(struct sadb_ext *extensions[]);
++extern void pfkey_extensions_free(struct sadb_ext *extensions[]);
++extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
++
++extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
++                         struct pf_key_ext_parsers_def *ext_parsers[],
++                         struct sadb_ext **extensions,
++                         int dir);
++
++extern int pfkey_register_reply(int satype, struct sadb_msg *sadb_msg);
++
++/*
++ * PF_KEYv2 build function prototypes
++ */
++
++int
++pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
++                  uint8_t             msg_type,
++                  uint8_t             satype,
++                  uint8_t             msg_errno,
++                  uint32_t            seq,
++                  uint32_t            pid);
++
++int
++pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
++             uint16_t                 exttype,
++             uint32_t                 spi, /* in network order */
++             uint8_t                  replay_window,
++             uint8_t                  sa_state,
++             uint8_t                  auth,
++             uint8_t                  encrypt,
++             uint32_t                 flags,
++             uint32_t/*IPsecSAref_t*/ ref);
++
++int
++pfkey_sa_build(struct sadb_ext **     pfkey_ext,
++             uint16_t                 exttype,
++             uint32_t                 spi, /* in network order */
++             uint8_t                  replay_window,
++             uint8_t                  sa_state,
++             uint8_t                  auth,
++             uint8_t                  encrypt,
++             uint32_t                 flags);
++
++extern int
++pfkey_saref_build(struct sadb_ext **pfkey_ext,
++                IPsecSAref_t in, IPsecSAref_t out);
++
++int
++pfkey_lifetime_build(struct sadb_ext **       pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           allocations,
++                   uint64_t           bytes,
++                   uint64_t           addtime,
++                   uint64_t           usetime,
++                   uint32_t           packets);
++
++int
++pfkey_address_build(struct sadb_ext** pfkey_ext,
++                  uint16_t            exttype,
++                  uint8_t             proto,
++                  uint8_t             prefixlen,
++                  struct sockaddr*    address);
++
++int
++pfkey_key_build(struct sadb_ext**     pfkey_ext,
++              uint16_t                exttype,
++              uint16_t                key_bits,
++              unsigned char          *key);
++
++int
++pfkey_ident_build(struct sadb_ext**   pfkey_ext,
++                uint16_t              exttype,
++                uint16_t              ident_type,
++                uint64_t              ident_id,
++                uint8_t               ident_len,
++                char*                 ident_string);
++
++#ifdef __KERNEL__
++extern int pfkey_nat_t_new_mapping(struct ipsec_sa *, struct sockaddr *, __u16);
++extern int pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
++extern int pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
++#endif /* __KERNEL__ */
++int
++pfkey_x_nat_t_type_build(struct sadb_ext**  pfkey_ext,
++            uint8_t         type);
++int
++pfkey_x_nat_t_port_build(struct sadb_ext**  pfkey_ext,
++            uint16_t         exttype,
++            uint16_t         port);
++
++int
++pfkey_sens_build(struct sadb_ext**    pfkey_ext,
++               uint32_t               dpd,
++               uint8_t                sens_level,
++               uint8_t                sens_len,
++               uint64_t*              sens_bitmap,
++               uint8_t                integ_level,
++               uint8_t                integ_len,
++               uint64_t*              integ_bitmap);
++
++int pfkey_x_protocol_build(struct sadb_ext **, uint8_t);
++
++
++int
++pfkey_prop_build(struct sadb_ext**    pfkey_ext,
++               uint8_t                replay,
++               unsigned int           comb_num,
++               struct sadb_comb*      comb);
++
++int
++pfkey_supported_build(struct sadb_ext**       pfkey_ext,
++                    uint16_t          exttype,
++                    unsigned int      alg_num,
++                    struct sadb_alg*  alg);
++
++int
++pfkey_spirange_build(struct sadb_ext**        pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           min,
++                   uint32_t           max);
++
++int
++pfkey_x_kmprivate_build(struct sadb_ext**     pfkey_ext);
++
++int
++pfkey_x_satype_build(struct sadb_ext**        pfkey_ext,
++                   uint8_t            satype);
++
++int
++pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
++                  uint32_t            tunnel,
++                  uint32_t            netlink,
++                  uint32_t            xform,
++                  uint32_t            eroute,
++                  uint32_t            spi,
++                  uint32_t            radij,
++                  uint32_t            esp,
++                  uint32_t            ah,
++                  uint32_t            rcv,
++                  uint32_t            pfkey,
++                  uint32_t            ipcomp,
++                  uint32_t            verbose);
++
++int
++pfkey_msg_build(struct sadb_msg**     pfkey_msg,
++              struct sadb_ext*        extensions[],
++              int                     dir);
++
++/* in pfkey_v2_debug.c - routines to decode numbers -> strings */
++const char *
++pfkey_v2_sadb_ext_string(int extnum);
++
++const char *
++pfkey_v2_sadb_type_string(int sadb_type);
++
++struct sadb_builds {
++      struct k_sadb_sa       sa_base;
++};
++
++int
++pfkey_sa_builds(struct sadb_ext **pfkey_ext,
++              struct sadb_builds sab);
++
++extern int
++pfkey_outif_build(struct sadb_ext **pfkey_ext,
++                uint16_t outif);
++
++#endif /* __NET_IPSEC_PF_KEY_H */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/pfkey_debug.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,54 @@
++/*
++ * sanitize a string into a printable format.
++ *
++ * Copyright (C) 1998-2002  D. Hugh Redelmeier.
++ * Copyright (C) 2003  Michael Richardson <mcr@freeswan.org>
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: pfkey_debug.h,v 1.3 2004/04/05 19:55:07 mcr Exp $
++ */
++
++#ifndef _FREESWAN_PFKEY_DEBUG_H
++#define _FREESWAN_PFKEY_DEBUG_H
++
++#ifdef __KERNEL__
++
++/* note, kernel version ignores pfkey levels */
++# define DEBUGGING(level,args...) \
++         KLIPS_PRINT(debug_pfkey, "klips_debug:" args)
++
++# define ERROR(args...) printk(KERN_ERR "klips:" args)
++
++#else
++
++extern unsigned int pfkey_lib_debug;
++
++extern int (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
++extern int (*pfkey_error_func)(const char *message, ...) PRINTF_LIKE(1);
++
++#define DEBUGGING(level,args...)  if(pfkey_lib_debug & level) { \
++                              if(pfkey_debug_func != NULL) { \
++                                (*pfkey_debug_func)("pfkey_lib_debug:" args); \
++                              } else { \
++                                printf("pfkey_lib_debug:" args); \
++                              } }
++
++#define ERROR(args...)      if(pfkey_error_func != NULL) { \
++                                (*pfkey_error_func)("pfkey_lib_debug:" args); \
++                              } 
++
++# define MALLOC(size) malloc(size)
++# define FREE(obj) free(obj)
++
++#endif
++
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/pfkeyv2.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,347 @@
++/*
++ * RCSID $Id: pfkeyv2.h,v 1.31 2005/04/14 01:14:54 mcr Exp $
++ */
++
++/*
++RFC 2367               PF_KEY Key Management API               July 1998
++
++
++Appendix D: Sample Header File
++
++This file defines structures and symbols for the PF_KEY Version 2
++key management interface. It was written at the U.S. Naval Research
++Laboratory. This file is in the public domain. The authors ask that
++you leave this credit intact on any copies of this file.
++*/
++
++#ifndef __PFKEY_V2_H
++#define __PFKEY_V2_H 1
++
++#include <linux/pfkeyv2.h>
++
++#define PF_KEY_V2               2
++#define PFKEYV2_REVISION        199806L
++
++enum sadb_msg_t {
++      K_SADB_RESERVED=SADB_RESERVED,
++      K_SADB_GETSPI=SADB_GETSPI,
++      K_SADB_UPDATE=SADB_UPDATE,
++      K_SADB_ADD=SADB_ADD,
++      K_SADB_DELETE=SADB_DELETE,
++      K_SADB_GET=SADB_GET,
++      K_SADB_ACQUIRE=SADB_ACQUIRE,
++      K_SADB_REGISTER=SADB_REGISTER,
++      K_SADB_EXPIRE=SADB_EXPIRE,
++      K_SADB_FLUSH=SADB_FLUSH,
++      K_SADB_DUMP=SADB_DUMP,
++      K_SADB_X_PROMISC=SADB_X_PROMISC,
++      K_SADB_X_PCHANGE=SADB_X_PCHANGE,
++      K_SADB_X_GRPSA=13,
++      K_SADB_X_ADDFLOW=14,
++      K_SADB_X_DELFLOW=15,
++      K_SADB_X_DEBUG=16,
++      K_SADB_X_NAT_T_NEW_MAPPING=17,
++      K_SADB_X_PLUMBIF=18,
++      K_SADB_X_UNPLUMBIF=19,
++      K_SADB_MAX=19
++};
++
++#define SADB_X_GRPSA      K_SADB_X_GRPSA                  
++#define SADB_X_ADDFLOW            K_SADB_X_ADDFLOW        
++#define SADB_X_DELFLOW            K_SADB_X_DELFLOW        
++#define SADB_X_DEBUG      K_SADB_X_DEBUG                  
++#define SADB_X_PLUMBIF            K_SADB_X_PLUMBIF        
++#define SADB_X_UNPLUMBIF    K_SADB_X_UNPLUMBIF            
++
++struct k_sadb_sa {
++      uint16_t sadb_sa_len;
++      uint16_t sadb_sa_exttype;
++      uint32_t sadb_sa_spi;
++      uint8_t sadb_sa_replay;
++      uint8_t sadb_sa_state;
++      uint8_t sadb_sa_auth;
++      uint8_t sadb_sa_encrypt;
++      uint32_t sadb_sa_flags;
++      uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */
++      uint8_t sadb_x_reserved[4];
++} __attribute__((packed));
++
++struct sadb_sa_v1 {
++  uint16_t sadb_sa_len;
++  uint16_t sadb_sa_exttype;
++  uint32_t sadb_sa_spi;
++  uint8_t sadb_sa_replay;
++  uint8_t sadb_sa_state;
++  uint8_t sadb_sa_auth;
++  uint8_t sadb_sa_encrypt;
++  uint32_t sadb_sa_flags;
++} __attribute__((packed));
++
++struct sadb_x_satype {
++  uint16_t sadb_x_satype_len;
++  uint16_t sadb_x_satype_exttype;
++  uint8_t sadb_x_satype_satype;
++  uint8_t sadb_x_satype_reserved[3];
++} __attribute__((packed));
++  
++struct sadb_x_debug {
++  uint16_t sadb_x_debug_len;
++  uint16_t sadb_x_debug_exttype;
++  uint32_t sadb_x_debug_tunnel;
++  uint32_t sadb_x_debug_netlink;
++  uint32_t sadb_x_debug_xform;
++  uint32_t sadb_x_debug_eroute;
++  uint32_t sadb_x_debug_spi;
++  uint32_t sadb_x_debug_radij;
++  uint32_t sadb_x_debug_esp;
++  uint32_t sadb_x_debug_ah;
++  uint32_t sadb_x_debug_rcv;
++  uint32_t sadb_x_debug_pfkey;
++  uint32_t sadb_x_debug_ipcomp;
++  uint32_t sadb_x_debug_verbose;
++  uint8_t sadb_x_debug_reserved[4];
++} __attribute__((packed));
++
++/*
++ * a plumbif extension can appear in
++ *          - a plumbif message to create the interface.
++ *          - a unplumbif message to delete the interface.
++ *          - a sadb add/replace to indicate which interface
++ *                   a decrypted packet should emerge on.
++ *
++ * the create/delete part could/should be replaced with netlink equivalents,
++ * or better yet, FORCES versions of same.
++ * 
++ */
++struct sadb_x_plumbif {
++      uint16_t sadb_x_outif_len;
++      uint16_t sadb_x_outif_exttype;
++      uint16_t sadb_x_outif_ifnum;
++} __attribute__((packed));
++
++/*
++ * the ifnum describes a device that you wish to create refer to.
++ *
++ * devices 0-40959 are mastXXX devices.
++ * devices 40960-49141 are mastXXX devices with transport set.
++ * devices 49152-65536 are deprecated ipsecXXX devices.
++ */
++#define IPSECDEV_OFFSET       (48*1024)
++#define MASTTRANSPORT_OFFSET  (40*1024)
++
++/*
++ * an saref extension sets the SA's reference number, and
++ * may also set the paired SA's reference number.
++ *
++ */
++struct sadb_x_saref {
++      uint16_t sadb_x_saref_len;
++      uint16_t sadb_x_saref_exttype;
++      uint32_t sadb_x_saref_me;       
++      uint32_t sadb_x_saref_him;
++} __attribute__((packed));
++
++/*
++ * A protocol structure for passing through the transport level
++ * protocol.  It contains more fields than are actually used/needed
++ * but it is this way to be compatible with the structure used in
++ * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h)
++ */
++struct sadb_protocol {
++  uint16_t sadb_protocol_len;
++  uint16_t sadb_protocol_exttype;
++  uint8_t  sadb_protocol_proto;
++  uint8_t  sadb_protocol_direction;
++  uint8_t  sadb_protocol_flags;
++  uint8_t  sadb_protocol_reserved2;
++} __attribute__((packed));
++
++/*
++ * NOTE that there is a limit of 31 extensions due to current implementation
++ * in pfkeyv2_ext_bits.c
++ */
++enum sadb_extension_t {
++      K_SADB_EXT_RESERVED=SADB_RESERVED,
++      K_SADB_EXT_SA=              SADB_EXT_SA,
++      K_SADB_EXT_LIFETIME_CURRENT=SADB_EXT_LIFETIME_CURRENT,
++      K_SADB_EXT_LIFETIME_HARD=   SADB_EXT_LIFETIME_HARD,
++      K_SADB_EXT_LIFETIME_SOFT=   SADB_EXT_LIFETIME_SOFT,
++      K_SADB_EXT_ADDRESS_SRC=     SADB_EXT_ADDRESS_SRC,
++      K_SADB_EXT_ADDRESS_DST=     SADB_EXT_ADDRESS_DST,
++      K_SADB_EXT_ADDRESS_PROXY=   SADB_EXT_ADDRESS_PROXY,
++      K_SADB_EXT_KEY_AUTH=        SADB_EXT_KEY_AUTH,
++      K_SADB_EXT_KEY_ENCRYPT=     SADB_EXT_KEY_ENCRYPT,
++      K_SADB_EXT_IDENTITY_SRC=    SADB_EXT_IDENTITY_SRC,
++      K_SADB_EXT_IDENTITY_DST=    SADB_EXT_IDENTITY_DST,
++      K_SADB_EXT_SENSITIVITY=     SADB_EXT_SENSITIVITY,
++      K_SADB_EXT_PROPOSAL=        SADB_EXT_PROPOSAL,
++      K_SADB_EXT_SUPPORTED_AUTH=  SADB_EXT_SUPPORTED_AUTH,
++      K_SADB_EXT_SUPPORTED_ENCRYPT=SADB_EXT_SUPPORTED_ENCRYPT,
++      K_SADB_EXT_SPIRANGE=        SADB_EXT_SPIRANGE,
++      K_SADB_X_EXT_KMPRIVATE=     SADB_X_EXT_KMPRIVATE,
++      K_SADB_X_EXT_SATYPE2=       18,
++      K_SADB_X_EXT_POLICY=        SADB_X_EXT_POLICY,
++      K_SADB_X_EXT_SA2=           SADB_X_EXT_SA2,
++      K_SADB_X_EXT_ADDRESS_DST2=  20,
++      K_SADB_X_EXT_ADDRESS_SRC_FLOW=21,
++      K_SADB_X_EXT_ADDRESS_DST_FLOW=22,
++      K_SADB_X_EXT_ADDRESS_SRC_MASK=23,
++      K_SADB_X_EXT_ADDRESS_DST_MASK=24,
++      K_SADB_X_EXT_DEBUG=         25,
++      K_SADB_X_EXT_PROTOCOL=      26,
++      K_SADB_X_EXT_NAT_T_TYPE=    27,
++      K_SADB_X_EXT_NAT_T_SPORT=   28,
++      K_SADB_X_EXT_NAT_T_DPORT=   29,
++      K_SADB_X_EXT_NAT_T_OA=      30,
++      K_SADB_X_EXT_PLUMBIF=       31,
++      K_SADB_X_EXT_SAREF=         32,
++      K_SADB_EXT_MAX=             32,
++};
++
++
++#define SADB_X_EXT_SATYPE2            K_SADB_X_EXT_SATYPE2            
++#define SADB_X_EXT_ADDRESS_DST2               K_SADB_X_EXT_ADDRESS_DST2       
++#define SADB_X_EXT_ADDRESS_SRC_FLOW   K_SADB_X_EXT_ADDRESS_SRC_FLOW   
++#define SADB_X_EXT_ADDRESS_DST_FLOW   K_SADB_X_EXT_ADDRESS_DST_FLOW   
++#define SADB_X_EXT_ADDRESS_SRC_MASK   K_SADB_X_EXT_ADDRESS_SRC_MASK   
++#define SADB_X_EXT_ADDRESS_DST_MASK   K_SADB_X_EXT_ADDRESS_DST_MASK   
++#define SADB_X_EXT_DEBUG              K_SADB_X_EXT_DEBUG              
++#define SADB_X_EXT_PROTOCOL           K_SADB_X_EXT_PROTOCOL           
++
++#undef SADB_X_EXT_NAT_T_TYPE          
++#undef SADB_X_EXT_NAT_T_SPORT         
++#undef SADB_X_EXT_NAT_T_DPORT         
++#undef SADB_X_EXT_NAT_T_OA            
++#define SADB_X_EXT_PLUMBIF            K_SADB_X_EXT_PLUMBIF            
++
++
++
++/* K_SADB_X_DELFLOW required over and above K_SADB_X_SAFLAGS_CLEARFLOW */
++#define K_SADB_X_EXT_ADDRESS_DELFLOW \
++      ( (1<<K_SADB_X_EXT_ADDRESS_SRC_FLOW) \
++      | (1<<K_SADB_X_EXT_ADDRESS_DST_FLOW) \
++      | (1<<K_SADB_X_EXT_ADDRESS_SRC_MASK) \
++      | (1<<K_SADB_X_EXT_ADDRESS_DST_MASK))
++
++enum sadb_satype {
++      K_SADB_SATYPE_UNSPEC=SADB_SATYPE_UNSPEC,
++      K_SADB_SATYPE_AH=SADB_SATYPE_AH,
++      K_SADB_SATYPE_ESP=SADB_SATYPE_ESP,
++      K_SADB_SATYPE_RSVP=SADB_SATYPE_RSVP,
++      K_SADB_SATYPE_OSPFV2=SADB_SATYPE_OSPFV2,
++      K_SADB_SATYPE_RIPV2=SADB_SATYPE_RIPV2,
++      K_SADB_SATYPE_MIP=SADB_SATYPE_MIP,
++      K_SADB_X_SATYPE_IPIP=9,
++      K_SADB_X_SATYPE_COMP=10,
++      K_SADB_X_SATYPE_INT=11
++};
++#define K_SADB_SATYPE_MAX       11
++
++enum sadb_sastate {
++  K_SADB_SASTATE_LARVAL=0,
++  K_SADB_SASTATE_MATURE=1,
++  K_SADB_SASTATE_DYING=2,
++  K_SADB_SASTATE_DEAD=3
++};
++#undef  SADB_SASTATE_LARVAL
++#undef  SADB_SASTATE_MATURE
++#undef  SADB_SASTATE_DYING
++#undef  SADB_SASTATE_DEAD
++#define K_SADB_SASTATE_MAX 3
++
++#define SADB_SAFLAGS_PFS              1
++#define SADB_X_SAFLAGS_REPLACEFLOW    2
++#define SADB_X_SAFLAGS_CLEARFLOW      4
++#define SADB_X_SAFLAGS_INFLOW         8
++
++/* not obvious, but these are the same values as used in isakmp,
++ * and in freeswan/ipsec_policy.h. If you need to add any, they
++ * should be added as according to 
++ *   http://www.iana.org/assignments/isakmp-registry
++ * 
++ * and if not, then please try to use a private-use value, and
++ * consider asking IANA to assign a value.
++ */
++#define SADB_AALG_NONE                  0
++#define SADB_AALG_MD5HMAC               2
++#define SADB_AALG_SHA1HMAC              3
++#define SADB_X_AALG_SHA2_256HMAC      5
++#define SADB_X_AALG_SHA2_384HMAC      6
++#define SADB_X_AALG_SHA2_512HMAC      7
++#define SADB_X_AALG_RIPEMD160HMAC     8
++#define SADB_X_AALG_NULL              251     /* kame */
++enum sadb_aalg {
++      K_SADB_AALG_NONE=          SADB_AALG_NONE,              
++      K_SADB_AALG_MD5HMAC=       SADB_AALG_MD5HMAC,           
++      K_SADB_AALG_SHA1HMAC=      SADB_AALG_SHA1HMAC,          
++      K_SADB_X_AALG_SHA2_256HMAC=SADB_X_AALG_SHA2_256HMAC,
++      K_SADB_X_AALG_SHA2_384HMAC=SADB_X_AALG_SHA2_384HMAC,
++      K_SADB_X_AALG_SHA2_512HMAC=SADB_X_AALG_SHA2_512HMAC,
++      K_SADB_X_AALG_RIPEMD160HMAC=SADB_X_AALG_RIPEMD160HMAC,
++};
++#define K_SADB_AALG_MAX                       251
++
++#define SADB_EALG_NONE                  0
++#define SADB_EALG_DESCBC                2
++#define SADB_EALG_3DESCBC               3
++#define SADB_X_EALG_CASTCBC           6
++#define SADB_X_EALG_BLOWFISHCBC               7
++#define SADB_EALG_NULL                        11
++#define SADB_X_EALG_AESCBC            12
++#define SADB_X_EALG_AESCTR            13
++#define SADB_X_EALG_AES_CCM_ICV8      14
++#define SADB_X_EALG_AES_CCM_ICV12     15
++#define SADB_X_EALG_AES_CCM_ICV16     16
++#define SADB_X_EALG_AES_GCM_ICV8      18
++#define SADB_X_EALG_AES_GCM_ICV12     19
++#define SADB_X_EALG_AES_GCM_ICV16     20
++#define SADB_X_EALG_CAMELLIACBC               22
++
++enum sadb_ealg {
++      K_SADB_EALG_NONE=SADB_EALG_NONE,                 
++      K_SADB_EALG_DESCBC=SADB_EALG_DESCBC,     
++      K_SADB_EALG_3DESCBC=SADB_EALG_3DESCBC,   
++      K_SADB_X_EALG_CASTCBC=SADB_X_EALG_CASTCBC,       
++      K_SADB_X_EALG_BLOWFISHCBC=SADB_X_EALG_BLOWFISHCBC, 
++      K_SADB_EALG_NULL=SADB_EALG_NULL,                 
++      K_SADB_X_EALG_AESCBC=SADB_X_EALG_AESCBC,    
++      K_SADB_X_EALG_AESCTR=SADB_X_EALG_AESCTR,
++      K_SADB_X_EALG_AES_CCM_ICV8=SADB_X_EALG_AES_CCM_ICV8,
++      K_SADB_X_EALG_AES_CCM_ICV12=SADB_X_EALG_AES_CCM_ICV12,
++      K_SADB_X_EALG_AES_CCM_ICV16=SADB_X_EALG_AES_CCM_ICV16,
++      K_SADB_X_EALG_AES_GCM_ICV8=SADB_X_EALG_AES_GCM_ICV8,
++      K_SADB_X_EALG_AES_GCM_ICV12=SADB_X_EALG_AES_GCM_ICV12,
++      K_SADB_X_EALG_AES_GCM_ICV16=SADB_X_EALG_AES_GCM_ICV16,
++      K_SADB_X_EALG_CAMELLIACBC=SADB_X_EALG_CAMELLIACBC
++};
++
++#undef SADB_EALG_MAX
++#define K_SADB_EALG_MAX                       255
++
++#define SADB_X_CALG_NONE          0
++#define SADB_X_CALG_OUI           1
++#define SADB_X_CALG_DEFLATE       2
++#define SADB_X_CALG_LZS           3
++#define SADB_X_CALG_LZJH          4
++#define SADB_X_CALG_MAX           4
++
++enum sadb_talg {
++      K_SADB_X_TALG_NONE=0,
++      K_SADB_X_TALG_IPv4_in_IPv4=1,
++      K_SADB_X_TALG_IPv6_in_IPv4=2,
++      K_SADB_X_TALG_IPv4_in_IPv6=3,
++      K_SADB_X_TALG_IPv6_in_IPv6=4,
++};
++#define SADB_X_TALG_MAX         4
++
++
++#define SADB_IDENTTYPE_RESERVED   0
++#define SADB_IDENTTYPE_PREFIX     1
++#define SADB_IDENTTYPE_FQDN       2
++#define SADB_IDENTTYPE_USERFQDN   3
++#define SADB_X_IDENTTYPE_CONNECTION 4
++#define K_SADB_IDENTTYPE_MAX        4
++
++#define K_SADB_KEY_FLAGS_MAX     0
++#endif /* __PFKEY_V2_H */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/openswan/radij.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,280 @@
++/*
++ * RCSID $Id: radij.h,v 1.13 2004/04/05 19:55:08 mcr Exp $
++ */
++
++/*
++ * This file is defived from ${SRC}/sys/net/radix.h of BSD 4.4lite
++ *
++ * Variable and procedure names have been modified so that they don't
++ * conflict with the original BSD code, as a small number of modifications
++ * have been introduced and we may want to reuse this code in BSD.
++ * 
++ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
++ * chi or a German ch sound (as `doch', not as in `milch'), or even a 
++ * spanish j as in Juan.  It is not as far back in the throat like
++ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
++ * It has nothing to do with the Dutch ij sound.
++ * 
++ * Here is the appropriate copyright notice:
++ */
++
++/*
++ * Copyright (c) 1988, 1989, 1993
++ *    The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by the University of
++ *    California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ *    @(#)radix.h     8.1 (Berkeley) 6/10/93
++ */
++
++#ifndef _RADIJ_H_
++#define       _RADIJ_H_
++
++/* 
++#define RJ_DEBUG
++*/
++
++#ifdef __KERNEL__
++
++#ifndef __P
++#ifdef __STDC__
++#define __P(x)  x
++#else
++#define __P(x)  ()
++#endif
++#endif
++
++/*
++ * Radix search tree node layout.
++ */
++
++struct radij_node
++{
++      struct  radij_mask *rj_mklist;  /* list of masks contained in subtree */
++      struct  radij_node *rj_p;       /* parent */
++      short   rj_b;                   /* bit offset; -1-index(netmask) */
++      char    rj_bmask;               /* node: mask for bit test*/
++      u_char  rj_flags;               /* enumerated next */
++#define RJF_NORMAL    1               /* leaf contains normal route */
++#define RJF_ROOT      2               /* leaf is root leaf for tree */
++#define RJF_ACTIVE    4               /* This node is alive (for rtfree) */
++      union {
++              struct {                        /* leaf only data: */
++                      caddr_t rj_Key; /* object of search */
++                      caddr_t rj_Mask;        /* netmask, if present */
++                      struct  radij_node *rj_Dupedkey;
++              } rj_leaf;
++              struct {                        /* node only data: */
++                      int     rj_Off;         /* where to start compare */
++                      struct  radij_node *rj_L;/* progeny */
++                      struct  radij_node *rj_R;/* progeny */
++              }rj_node;
++      }               rj_u;
++#ifdef RJ_DEBUG
++      int rj_info;
++      struct radij_node *rj_twin;
++      struct radij_node *rj_ybro;
++#endif
++};
++
++#define rj_dupedkey rj_u.rj_leaf.rj_Dupedkey
++#define rj_key rj_u.rj_leaf.rj_Key
++#define rj_mask rj_u.rj_leaf.rj_Mask
++#define rj_off rj_u.rj_node.rj_Off
++#define rj_l rj_u.rj_node.rj_L
++#define rj_r rj_u.rj_node.rj_R
++
++/*
++ * Annotations to tree concerning potential routes applying to subtrees.
++ */
++
++extern struct radij_mask {
++      short   rm_b;                   /* bit offset; -1-index(netmask) */
++      char    rm_unused;              /* cf. rj_bmask */
++      u_char  rm_flags;               /* cf. rj_flags */
++      struct  radij_mask *rm_mklist;  /* more masks to try */
++      caddr_t rm_mask;                /* the mask */
++      int     rm_refs;                /* # of references to this struct */
++} *rj_mkfreelist;
++
++#define MKGet(m) {\
++      if (rj_mkfreelist) {\
++              m = rj_mkfreelist; \
++              rj_mkfreelist = (m)->rm_mklist; \
++      } else \
++              R_Malloc(m, struct radij_mask *, sizeof (*(m))); }\
++
++#define MKFree(m) { (m)->rm_mklist = rj_mkfreelist; rj_mkfreelist = (m);}
++
++struct radij_node_head {
++      struct  radij_node *rnh_treetop;
++      int     rnh_addrsize;           /* permit, but not require fixed keys */
++      int     rnh_pktsize;            /* permit, but not require fixed keys */
++#if 0
++      struct  radij_node *(*rnh_addaddr)      /* add based on sockaddr */
++              __P((void *v, void *mask,
++                   struct radij_node_head *head, struct radij_node nodes[]));
++#endif
++      int (*rnh_addaddr)      /* add based on sockaddr */
++              __P((void *v, void *mask,
++                   struct radij_node_head *head, struct radij_node nodes[]));
++      struct  radij_node *(*rnh_addpkt)       /* add based on packet hdr */
++              __P((void *v, void *mask,
++                   struct radij_node_head *head, struct radij_node nodes[]));
++#if 0
++      struct  radij_node *(*rnh_deladdr)      /* remove based on sockaddr */
++              __P((void *v, void *mask, struct radij_node_head *head));
++#endif
++      int (*rnh_deladdr)      /* remove based on sockaddr */
++              __P((void *v, void *mask, struct radij_node_head *head, struct radij_node **node));
++      struct  radij_node *(*rnh_delpkt)       /* remove based on packet hdr */
++              __P((void *v, void *mask, struct radij_node_head *head));
++      struct  radij_node *(*rnh_matchaddr)    /* locate based on sockaddr */
++              __P((void *v, struct radij_node_head *head));
++      struct  radij_node *(*rnh_matchpkt)     /* locate based on packet hdr */
++              __P((void *v, struct radij_node_head *head));
++      int     (*rnh_walktree)                 /* traverse tree */
++              __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
++      struct  radij_node rnh_nodes[3];        /* empty tree for common case */
++};
++
++
++#define Bcmp(a, b, n) memcmp(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
++#define Bcopy(a, b, n) memmove(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
++#define Bzero(p, n) memset((caddr_t)(p), 0, (unsigned)(n))
++#define R_Malloc(p, t, n) ((p = (t) kmalloc((size_t)(n), GFP_ATOMIC)), Bzero((p),(n)))
++#define Free(p) kfree((caddr_t)p);
++
++void   rj_init __P((void));
++int    rj_inithead __P((void **, int));
++int    rj_refines __P((void *, void *));
++int    rj_walktree __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
++struct radij_node
++       *rj_addmask __P((void *, int, int)) /* , rgb */ ;
++int /* * */ rj_addroute __P((void *, void *, struct radij_node_head *,
++                      struct radij_node [2])) /* , rgb */ ;
++int /* * */ rj_delete __P((void *, void *, struct radij_node_head *, struct radij_node **)) /* , rgb */ ;
++struct radij_node /* rgb */
++       *rj_insert __P((void *, struct radij_node_head *, int *,
++                      struct radij_node [2])),
++       *rj_match __P((void *, struct radij_node_head *)),
++       *rj_newpair __P((void *, int, struct radij_node[2])),
++       *rj_search __P((void *, struct radij_node *)),
++       *rj_search_m __P((void *, struct radij_node *, void *));
++
++void rj_deltree(struct radij_node_head *);
++void rj_delnodes(struct radij_node *);
++void rj_free_mkfreelist(void);
++int radijcleartree(void);
++int radijcleanup(void);
++
++extern struct radij_node_head *mask_rjhead;
++extern int maj_keylen;
++#endif /* __KERNEL__ */
++
++#endif /* _RADIJ_H_ */
++
++
++/*
++ * $Log: radij.h,v $
++ * Revision 1.13  2004/04/05 19:55:08  mcr
++ * Moved from linux/include/freeswan/radij.h,v
++ *
++ * Revision 1.12  2002/04/24 07:36:48  mcr
++ * Moved from ./klips/net/ipsec/radij.h,v
++ *
++ * Revision 1.11  2001/09/20 15:33:00  rgb
++ * Min/max cleanup.
++ *
++ * Revision 1.10  1999/11/18 04:09:20  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.9  1999/05/05 22:02:33  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.8  1999/04/29 15:24:58  rgb
++ * Add check for existence of macros min/max.
++ *
++ * Revision 1.7  1999/04/11 00:29:02  henry
++ * GPL boilerplate
++ *
++ * Revision 1.6  1999/04/06 04:54:29  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ * Revision 1.5  1999/01/22 06:30:32  rgb
++ * 64-bit clean-up.
++ *
++ * Revision 1.4  1998/11/30 13:22:55  rgb
++ * Rationalised all the klips kernel file headers.  They are much shorter
++ * now and won't conflict under RH5.2.
++ *
++ * Revision 1.3  1998/10/25 02:43:27  rgb
++ * Change return type on rj_addroute and rj_delete and add and argument
++ * to the latter to be able to transmit more infomation about errors.
++ *
++ * Revision 1.2  1998/07/14 18:09:51  rgb
++ * Add a routine to clear eroute table.
++ * Added #ifdef __KERNEL__ directives to restrict scope of header.
++ *
++ * Revision 1.1  1998/06/18 21:30:22  henry
++ * move sources from klips/src to klips/net/ipsec to keep stupid kernel
++ * build scripts happier about symlinks
++ *
++ * Revision 1.4  1998/05/25 20:34:16  rgb
++ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
++ *
++ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
++ * add ipsec_rj_walker_delete.
++ *
++ * Recover memory for eroute table on unload of module.
++ *
++ * Revision 1.3  1998/04/22 16:51:37  rgb
++ * Tidy up radij debug code from recent rash of modifications to debug code.
++ *
++ * Revision 1.2  1998/04/14 17:30:38  rgb
++ * Fix up compiling errors for radij tree memory reclamation.
++ *
++ * Revision 1.1  1998/04/09 03:06:16  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:04  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:44:45  ji
++ * Release update only.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/zlib/zconf.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,309 @@
++/* zconf.h -- configuration of the zlib compression library
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* @(#) $Id: zconf.h,v 1.4 2004/07/10 07:48:40 mcr Exp $ */
++
++#ifndef _ZCONF_H
++#define _ZCONF_H
++
++/*
++ * If you *really* need a unique prefix for all types and library functions,
++ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
++ */
++#ifdef IPCOMP_PREFIX
++#  define deflateInit_        ipcomp_deflateInit_
++#  define deflate     ipcomp_deflate
++#  define deflateEnd  ipcomp_deflateEnd
++#  define inflateInit_        ipcomp_inflateInit_
++#  define inflate     ipcomp_inflate
++#  define inflateEnd  ipcomp_inflateEnd
++#  define deflateInit2_       ipcomp_deflateInit2_
++#  define deflateSetDictionary ipcomp_deflateSetDictionary
++#  define deflateCopy ipcomp_deflateCopy
++#  define deflateReset        ipcomp_deflateReset
++#  define deflateParams       ipcomp_deflateParams
++#  define inflateInit2_       ipcomp_inflateInit2_
++#  define inflateSetDictionary ipcomp_inflateSetDictionary
++#  define inflateSync ipcomp_inflateSync
++#  define inflateSyncPoint ipcomp_inflateSyncPoint
++#  define inflateReset        ipcomp_inflateReset
++#  define compress    ipcomp_compress
++#  define compress2   ipcomp_compress2
++#  define uncompress  ipcomp_uncompress
++#  define adler32     ipcomp_adler32
++#  define crc32               ipcomp_crc32
++#  define get_crc_table ipcomp_get_crc_table
++/* SSS: these also need to be prefixed to avoid clash with ppp_deflate and ext2compression */
++#  define inflate_blocks ipcomp_deflate_blocks
++#  define inflate_blocks_free ipcomp_deflate_blocks_free
++#  define inflate_blocks_new ipcomp_inflate_blocks_new
++#  define inflate_blocks_reset ipcomp_inflate_blocks_reset
++#  define inflate_blocks_sync_point ipcomp_inflate_blocks_sync_point
++#  define inflate_set_dictionary ipcomp_inflate_set_dictionary
++#  define inflate_codes ipcomp_inflate_codes
++#  define inflate_codes_free ipcomp_inflate_codes_free
++#  define inflate_codes_new ipcomp_inflate_codes_new
++#  define inflate_fast ipcomp_inflate_fast
++#  define inflate_trees_bits ipcomp_inflate_trees_bits
++#  define inflate_trees_dynamic ipcomp_inflate_trees_dynamic
++#  define inflate_trees_fixed ipcomp_inflate_trees_fixed
++#  define inflate_flush ipcomp_inflate_flush
++#  define inflate_mask ipcomp_inflate_mask
++#  define _dist_code _ipcomp_dist_code
++#  define _length_code _ipcomp_length_code
++#  define _tr_align _ipcomp_tr_align
++#  define _tr_flush_block _ipcomp_tr_flush_block
++#  define _tr_init _ipcomp_tr_init
++#  define _tr_stored_block _ipcomp_tr_stored_block
++#  define _tr_tally _ipcomp_tr_tally
++#  define zError ipcomp_zError
++#  define z_errmsg ipcomp_z_errmsg
++#  define zlibVersion ipcomp_zlibVersion
++#  define match_init ipcomp_match_init
++#  define longest_match ipcomp_longest_match
++#endif
++
++#ifdef Z_PREFIX
++#  define Byte                z_Byte
++#  define uInt                z_uInt
++#  define uLong               z_uLong
++#  define Bytef               z_Bytef
++#  define charf               z_charf
++#  define intf                z_intf
++#  define uIntf               z_uIntf
++#  define uLongf      z_uLongf
++#  define voidpf      z_voidpf
++#  define voidp               z_voidp
++#endif
++
++#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
++#  define WIN32
++#endif
++#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
++#  ifndef __32BIT__
++#    define __32BIT__
++#  endif
++#endif
++#if defined(__MSDOS__) && !defined(MSDOS)
++#  define MSDOS
++#endif
++
++/*
++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
++ * than 64k bytes at a time (needed on systems with 16-bit int).
++ */
++#if defined(MSDOS) && !defined(__32BIT__)
++#  define MAXSEG_64K
++#endif
++#ifdef MSDOS
++#  define UNALIGNED_OK
++#endif
++
++#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
++#  define STDC
++#endif
++#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
++#  ifndef STDC
++#    define STDC
++#  endif
++#endif
++
++#ifndef STDC
++#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
++#    define const
++#  endif
++#endif
++
++/* Some Mac compilers merge all .h files incorrectly: */
++#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
++#  define NO_DUMMY_DECL
++#endif
++
++/* Old Borland C incorrectly complains about missing returns: */
++#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
++#  define NEED_DUMMY_RETURN
++#endif
++
++
++/* Maximum value for memLevel in deflateInit2 */
++#ifndef MAX_MEM_LEVEL
++#  ifdef MAXSEG_64K
++#    define MAX_MEM_LEVEL 8
++#  else
++#    define MAX_MEM_LEVEL 9
++#  endif
++#endif
++
++/* Maximum value for windowBits in deflateInit2 and inflateInit2.
++ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
++ * created by gzip. (Files created by minigzip can still be extracted by
++ * gzip.)
++ */
++#ifndef MAX_WBITS
++#  define MAX_WBITS   15 /* 32K LZ77 window */
++#endif
++
++/* The memory requirements for deflate are (in bytes):
++            (1 << (windowBits+2)) +  (1 << (memLevel+9))
++ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
++ plus a few kilobytes for small objects. For example, if you want to reduce
++ the default memory requirements from 256K to 128K, compile with
++     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
++ Of course this will generally degrade compression (there's no free lunch).
++
++   The memory requirements for inflate are (in bytes) 1 << windowBits
++ that is, 32K for windowBits=15 (default value) plus a few kilobytes
++ for small objects.
++*/
++
++                        /* Type declarations */
++
++#ifndef OF /* function prototypes */
++#  ifdef STDC
++#    define OF(args)  args
++#  else
++#    define OF(args)  ()
++#  endif
++#endif
++
++/* The following definitions for FAR are needed only for MSDOS mixed
++ * model programming (small or medium model with some far allocations).
++ * This was tested only with MSC; for other MSDOS compilers you may have
++ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
++ * just define FAR to be empty.
++ */
++#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
++   /* MSC small or medium model */
++#  define SMALL_MEDIUM
++#  ifdef _MSC_VER
++#    define FAR _far
++#  else
++#    define FAR far
++#  endif
++#endif
++#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
++#  ifndef __32BIT__
++#    define SMALL_MEDIUM
++#    define FAR _far
++#  endif
++#endif
++
++/* Compile with -DZLIB_DLL for Windows DLL support */
++#if defined(ZLIB_DLL)
++#  if defined(_WINDOWS) || defined(WINDOWS)
++#    ifdef FAR
++#      undef FAR
++#    endif
++#    include <windows.h>
++#    define ZEXPORT  WINAPI
++#    ifdef WIN32
++#      define ZEXPORTVA  WINAPIV
++#    else
++#      define ZEXPORTVA  FAR _cdecl _export
++#    endif
++#  endif
++#  if defined (__BORLANDC__)
++#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
++#      include <windows.h>
++#      define ZEXPORT __declspec(dllexport) WINAPI
++#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
++#    else
++#      if defined (_Windows) && defined (__DLL__)
++#        define ZEXPORT _export
++#        define ZEXPORTVA _export
++#      endif
++#    endif
++#  endif
++#endif
++
++#if defined (__BEOS__)
++#  if defined (ZLIB_DLL)
++#    define ZEXTERN extern __declspec(dllexport)
++#  else
++#    define ZEXTERN extern __declspec(dllimport)
++#  endif
++#endif
++
++#ifndef ZEXPORT
++#  define ZEXPORT
++#endif
++#ifndef ZEXPORTVA
++#  define ZEXPORTVA
++#endif
++#ifndef ZEXTERN
++#  define ZEXTERN extern
++#endif
++
++#ifndef FAR
++#   define FAR
++#endif
++
++#if !defined(MACOS) && !defined(TARGET_OS_MAC)
++typedef unsigned char  Byte;  /* 8 bits */
++#endif
++typedef unsigned int   uInt;  /* 16 bits or more */
++typedef unsigned long  uLong; /* 32 bits or more */
++
++#ifdef SMALL_MEDIUM
++   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
++#  define Bytef Byte FAR
++#else
++   typedef Byte  FAR Bytef;
++#endif
++typedef char  FAR charf;
++typedef int   FAR intf;
++typedef uInt  FAR uIntf;
++typedef uLong FAR uLongf;
++
++#ifdef STDC
++   typedef void FAR *voidpf;
++   typedef void     *voidp;
++#else
++   typedef Byte FAR *voidpf;
++   typedef Byte     *voidp;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#  include <sys/types.h> /* for off_t */
++#  include <unistd.h>    /* for SEEK_* and off_t */
++#  define z_off_t  off_t
++#endif
++#ifndef SEEK_SET
++#  define SEEK_SET        0       /* Seek from beginning of file.  */
++#  define SEEK_CUR        1       /* Seek from current position.  */
++#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
++#endif
++#ifndef z_off_t
++#  define  z_off_t long
++#endif
++
++/* MVS linker does not support external names larger than 8 bytes */
++#if defined(__MVS__)
++#   pragma map(deflateInit_,"DEIN")
++#   pragma map(deflateInit2_,"DEIN2")
++#   pragma map(deflateEnd,"DEEND")
++#   pragma map(inflateInit_,"ININ")
++#   pragma map(inflateInit2_,"ININ2")
++#   pragma map(inflateEnd,"INEND")
++#   pragma map(inflateSync,"INSY")
++#   pragma map(inflateSetDictionary,"INSEDI")
++#   pragma map(inflate_blocks,"INBL")
++#   pragma map(inflate_blocks_new,"INBLNE")
++#   pragma map(inflate_blocks_free,"INBLFR")
++#   pragma map(inflate_blocks_reset,"INBLRE")
++#   pragma map(inflate_codes_free,"INCOFR")
++#   pragma map(inflate_codes,"INCO")
++#   pragma map(inflate_fast,"INFA")
++#   pragma map(inflate_flush,"INFLU")
++#   pragma map(inflate_mask,"INMA")
++#   pragma map(inflate_set_dictionary,"INSEDI2")
++#   pragma map(ipcomp_inflate_copyright,"INCOPY")
++#   pragma map(inflate_trees_bits,"INTRBI")
++#   pragma map(inflate_trees_dynamic,"INTRDY")
++#   pragma map(inflate_trees_fixed,"INTRFI")
++#   pragma map(inflate_trees_free,"INTRFR")
++#endif
++
++#endif /* _ZCONF_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/zlib/zlib.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,893 @@
++/* zlib.h -- interface of the 'zlib' general purpose compression library
++  version 1.1.4, March 11th, 2002
++
++  Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
++
++  This software is provided 'as-is', without any express or implied
++  warranty.  In no event will the authors be held liable for any damages
++  arising from the use of this software.
++
++  Permission is granted to anyone to use this software for any purpose,
++  including commercial applications, and to alter it and redistribute it
++  freely, subject to the following restrictions:
++
++  1. The origin of this software must not be misrepresented; you must not
++     claim that you wrote the original software. If you use this software
++     in a product, an acknowledgment in the product documentation would be
++     appreciated but is not required.
++  2. Altered source versions must be plainly marked as such, and must not be
++     misrepresented as being the original software.
++  3. This notice may not be removed or altered from any source distribution.
++
++  Jean-loup Gailly        Mark Adler
++  jloup@gzip.org          madler@alumni.caltech.edu
++
++
++  The data format used by the zlib library is described by RFCs (Request for
++  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
++  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
++*/
++
++#ifndef _ZLIB_H
++#define _ZLIB_H
++
++#include "zconf.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define ZLIB_VERSION "1.1.4"
++
++/* 
++     The 'zlib' compression library provides in-memory compression and
++  decompression functions, including integrity checks of the uncompressed
++  data.  This version of the library supports only one compression method
++  (deflation) but other algorithms will be added later and will have the same
++  stream interface.
++
++     Compression can be done in a single step if the buffers are large
++  enough (for example if an input file is mmap'ed), or can be done by
++  repeated calls of the compression function.  In the latter case, the
++  application must provide more input and/or consume the output
++  (providing more output space) before each call.
++
++     The library also supports reading and writing files in gzip (.gz) format
++  with an interface similar to that of stdio.
++
++     The library does not install any signal handler. The decoder checks
++  the consistency of the compressed data, so the library should never
++  crash even in case of corrupted input.
++*/
++
++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
++typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
++
++struct internal_state;
++
++typedef struct z_stream_s {
++    Bytef    *next_in;  /* next input byte */
++    uInt     avail_in;  /* number of bytes available at next_in */
++    uLong    total_in;  /* total nb of input bytes read so far */
++
++    Bytef    *next_out; /* next output byte should be put there */
++    uInt     avail_out; /* remaining free space at next_out */
++    uLong    total_out; /* total nb of bytes output so far */
++
++    const char     *msg;      /* last error message, NULL if no error */
++    struct internal_state FAR *state; /* not visible by applications */
++
++    alloc_func zalloc;  /* used to allocate the internal state */
++    free_func  zfree;   /* used to free the internal state */
++    voidpf     opaque;  /* private data object passed to zalloc and zfree */
++
++    int     data_type;  /* best guess about the data type: ascii or binary */
++    uLong   adler;      /* adler32 value of the uncompressed data */
++    uLong   reserved;   /* reserved for future use */
++} z_stream;
++
++typedef z_stream FAR *z_streamp;
++
++/*
++   The application must update next_in and avail_in when avail_in has
++   dropped to zero. It must update next_out and avail_out when avail_out
++   has dropped to zero. The application must initialize zalloc, zfree and
++   opaque before calling the init function. All other fields are set by the
++   compression library and must not be updated by the application.
++
++   The opaque value provided by the application will be passed as the first
++   parameter for calls of zalloc and zfree. This can be useful for custom
++   memory management. The compression library attaches no meaning to the
++   opaque value.
++
++   zalloc must return Z_NULL if there is not enough memory for the object.
++   If zlib is used in a multi-threaded application, zalloc and zfree must be
++   thread safe.
++
++   On 16-bit systems, the functions zalloc and zfree must be able to allocate
++   exactly 65536 bytes, but will not be required to allocate more than this
++   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
++   pointers returned by zalloc for objects of exactly 65536 bytes *must*
++   have their offset normalized to zero. The default allocation function
++   provided by this library ensures this (see zutil.c). To reduce memory
++   requirements and avoid any allocation of 64K objects, at the expense of
++   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
++
++   The fields total_in and total_out can be used for statistics or
++   progress reports. After compression, total_in holds the total size of
++   the uncompressed data and may be saved for use in the decompressor
++   (particularly if the decompressor wants to decompress everything in
++   a single step).
++*/
++
++                        /* constants */
++
++#define Z_NO_FLUSH      0
++#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
++#define Z_SYNC_FLUSH    2
++#define Z_FULL_FLUSH    3
++#define Z_FINISH        4
++/* Allowed flush values; see deflate() below for details */
++
++#define Z_OK            0
++#define Z_STREAM_END    1
++#define Z_NEED_DICT     2
++#define Z_ERRNO        (-1)
++#define Z_STREAM_ERROR (-2)
++#define Z_DATA_ERROR   (-3)
++#define Z_MEM_ERROR    (-4)
++#define Z_BUF_ERROR    (-5)
++#define Z_VERSION_ERROR (-6)
++/* Return codes for the compression/decompression functions. Negative
++ * values are errors, positive values are used for special but normal events.
++ */
++
++#define Z_NO_COMPRESSION         0
++#define Z_BEST_SPEED             1
++#define Z_BEST_COMPRESSION       9
++#define Z_DEFAULT_COMPRESSION  (-1)
++/* compression levels */
++
++#define Z_FILTERED            1
++#define Z_HUFFMAN_ONLY        2
++#define Z_DEFAULT_STRATEGY    0
++/* compression strategy; see deflateInit2() below for details */
++
++#define Z_BINARY   0
++#define Z_ASCII    1
++#define Z_UNKNOWN  2
++/* Possible values of the data_type field */
++
++#define Z_DEFLATED   8
++/* The deflate compression method (the only one supported in this version) */
++
++#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
++
++#define zlib_version zlibVersion()
++/* for compatibility with versions < 1.0.2 */
++
++                        /* basic functions */
++
++ZEXTERN const char * ZEXPORT zlibVersion OF((void));
++/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
++   If the first character differs, the library code actually used is
++   not compatible with the zlib.h header file used by the application.
++   This check is automatically made by deflateInit and inflateInit.
++ */
++
++/* 
++ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
++
++     Initializes the internal stream state for compression. The fields
++   zalloc, zfree and opaque must be initialized before by the caller.
++   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
++   use default allocation functions.
++
++     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
++   1 gives best speed, 9 gives best compression, 0 gives no compression at
++   all (the input data is simply copied a block at a time).
++   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
++   compression (currently equivalent to level 6).
++
++     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
++   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
++   with the version assumed by the caller (ZLIB_VERSION).
++   msg is set to null if there is no error message.  deflateInit does not
++   perform any compression: this will be done by deflate().
++*/
++
++
++ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
++/*
++    deflate compresses as much data as possible, and stops when the input
++  buffer becomes empty or the output buffer becomes full. It may introduce some
++  output latency (reading input without producing any output) except when
++  forced to flush.
++
++    The detailed semantics are as follows. deflate performs one or both of the
++  following actions:
++
++  - Compress more input starting at next_in and update next_in and avail_in
++    accordingly. If not all input can be processed (because there is not
++    enough room in the output buffer), next_in and avail_in are updated and
++    processing will resume at this point for the next call of deflate().
++
++  - Provide more output starting at next_out and update next_out and avail_out
++    accordingly. This action is forced if the parameter flush is non zero.
++    Forcing flush frequently degrades the compression ratio, so this parameter
++    should be set only when necessary (in interactive applications).
++    Some output may be provided even if flush is not set.
++
++  Before the call of deflate(), the application should ensure that at least
++  one of the actions is possible, by providing more input and/or consuming
++  more output, and updating avail_in or avail_out accordingly; avail_out
++  should never be zero before the call. The application can consume the
++  compressed output when it wants, for example when the output buffer is full
++  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
++  and with zero avail_out, it must be called again after making room in the
++  output buffer because there might be more output pending.
++
++    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
++  flushed to the output buffer and the output is aligned on a byte boundary, so
++  that the decompressor can get all input data available so far. (In particular
++  avail_in is zero after the call if enough output space has been provided
++  before the call.)  Flushing may degrade compression for some compression
++  algorithms and so it should be used only when necessary.
++
++    If flush is set to Z_FULL_FLUSH, all output is flushed as with
++  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
++  restart from this point if previous compressed data has been damaged or if
++  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
++  the compression.
++
++    If deflate returns with avail_out == 0, this function must be called again
++  with the same value of the flush parameter and more output space (updated
++  avail_out), until the flush is complete (deflate returns with non-zero
++  avail_out).
++
++    If the parameter flush is set to Z_FINISH, pending input is processed,
++  pending output is flushed and deflate returns with Z_STREAM_END if there
++  was enough output space; if deflate returns with Z_OK, this function must be
++  called again with Z_FINISH and more output space (updated avail_out) but no
++  more input data, until it returns with Z_STREAM_END or an error. After
++  deflate has returned Z_STREAM_END, the only possible operations on the
++  stream are deflateReset or deflateEnd.
++  
++    Z_FINISH can be used immediately after deflateInit if all the compression
++  is to be done in a single step. In this case, avail_out must be at least
++  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
++  Z_STREAM_END, then it must be called again as described above.
++
++    deflate() sets strm->adler to the adler32 checksum of all input read
++  so far (that is, total_in bytes).
++
++    deflate() may update data_type if it can make a good guess about
++  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
++  binary. This field is only for information purposes and does not affect
++  the compression algorithm in any manner.
++
++    deflate() returns Z_OK if some progress has been made (more input
++  processed or more output produced), Z_STREAM_END if all input has been
++  consumed and all output has been produced (only when flush is set to
++  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
++  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
++  (for example avail_in or avail_out was zero).
++*/
++
++
++ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
++/*
++     All dynamically allocated data structures for this stream are freed.
++   This function discards any unprocessed input and does not flush any
++   pending output.
++
++     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
++   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
++   prematurely (some input or output was discarded). In the error case,
++   msg may be set but then points to a static string (which must not be
++   deallocated).
++*/
++
++
++/* 
++ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
++
++     Initializes the internal stream state for decompression. The fields
++   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
++   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
++   value depends on the compression method), inflateInit determines the
++   compression method from the zlib header and allocates all data structures
++   accordingly; otherwise the allocation will be deferred to the first call of
++   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
++   use default allocation functions.
++
++     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
++   version assumed by the caller.  msg is set to null if there is no error
++   message. inflateInit does not perform any decompression apart from reading
++   the zlib header if present: this will be done by inflate().  (So next_in and
++   avail_in may be modified, but next_out and avail_out are unchanged.)
++*/
++
++
++ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
++/*
++    inflate decompresses as much data as possible, and stops when the input
++  buffer becomes empty or the output buffer becomes full. It may some
++  introduce some output latency (reading input without producing any output)
++  except when forced to flush.
++
++  The detailed semantics are as follows. inflate performs one or both of the
++  following actions:
++
++  - Decompress more input starting at next_in and update next_in and avail_in
++    accordingly. If not all input can be processed (because there is not
++    enough room in the output buffer), next_in is updated and processing
++    will resume at this point for the next call of inflate().
++
++  - Provide more output starting at next_out and update next_out and avail_out
++    accordingly.  inflate() provides as much output as possible, until there
++    is no more input data or no more space in the output buffer (see below
++    about the flush parameter).
++
++  Before the call of inflate(), the application should ensure that at least
++  one of the actions is possible, by providing more input and/or consuming
++  more output, and updating the next_* and avail_* values accordingly.
++  The application can consume the uncompressed output when it wants, for
++  example when the output buffer is full (avail_out == 0), or after each
++  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
++  must be called again after making room in the output buffer because there
++  might be more output pending.
++
++    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
++  output as possible to the output buffer. The flushing behavior of inflate is
++  not specified for values of the flush parameter other than Z_SYNC_FLUSH
++  and Z_FINISH, but the current implementation actually flushes as much output
++  as possible anyway.
++
++    inflate() should normally be called until it returns Z_STREAM_END or an
++  error. However if all decompression is to be performed in a single step
++  (a single call of inflate), the parameter flush should be set to
++  Z_FINISH. In this case all pending input is processed and all pending
++  output is flushed; avail_out must be large enough to hold all the
++  uncompressed data. (The size of the uncompressed data may have been saved
++  by the compressor for this purpose.) The next operation on this stream must
++  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
++  is never required, but can be used to inform inflate that a faster routine
++  may be used for the single inflate() call.
++
++     If a preset dictionary is needed at this point (see inflateSetDictionary
++  below), inflate sets strm-adler to the adler32 checksum of the
++  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
++  it sets strm->adler to the adler32 checksum of all output produced
++  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
++  an error code as described below. At the end of the stream, inflate()
++  checks that its computed adler32 checksum is equal to that saved by the
++  compressor and returns Z_STREAM_END only if the checksum is correct.
++
++    inflate() returns Z_OK if some progress has been made (more input processed
++  or more output produced), Z_STREAM_END if the end of the compressed data has
++  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
++  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
++  corrupted (input stream not conforming to the zlib format or incorrect
++  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
++  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
++  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
++  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
++  case, the application may then call inflateSync to look for a good
++  compression block.
++*/
++
++
++ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
++/*
++     All dynamically allocated data structures for this stream are freed.
++   This function discards any unprocessed input and does not flush any
++   pending output.
++
++     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
++   was inconsistent. In the error case, msg may be set but then points to a
++   static string (which must not be deallocated).
++*/
++
++                        /* Advanced functions */
++
++/*
++    The following functions are needed only in some special applications.
++*/
++
++/*   
++ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
++                                     int  level,
++                                     int  method,
++                                     int  windowBits,
++                                     int  memLevel,
++                                     int  strategy));
++
++     This is another version of deflateInit with more compression options. The
++   fields next_in, zalloc, zfree and opaque must be initialized before by
++   the caller.
++
++     The method parameter is the compression method. It must be Z_DEFLATED in
++   this version of the library.
++
++     The windowBits parameter is the base two logarithm of the window size
++   (the size of the history buffer).  It should be in the range 8..15 for this
++   version of the library. Larger values of this parameter result in better
++   compression at the expense of memory usage. The default value is 15 if
++   deflateInit is used instead.
++
++     The memLevel parameter specifies how much memory should be allocated
++   for the internal compression state. memLevel=1 uses minimum memory but
++   is slow and reduces compression ratio; memLevel=9 uses maximum memory
++   for optimal speed. The default value is 8. See zconf.h for total memory
++   usage as a function of windowBits and memLevel.
++
++     The strategy parameter is used to tune the compression algorithm. Use the
++   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
++   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
++   string match).  Filtered data consists mostly of small values with a
++   somewhat random distribution. In this case, the compression algorithm is
++   tuned to compress them better. The effect of Z_FILTERED is to force more
++   Huffman coding and less string matching; it is somewhat intermediate
++   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
++   the compression ratio but not the correctness of the compressed output even
++   if it is not set appropriately.
++
++      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
++   method). msg is set to null if there is no error message.  deflateInit2 does
++   not perform any compression: this will be done by deflate().
++*/
++                            
++ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
++                                             const Bytef *dictionary,
++                                             uInt  dictLength));
++/*
++     Initializes the compression dictionary from the given byte sequence
++   without producing any compressed output. This function must be called
++   immediately after deflateInit, deflateInit2 or deflateReset, before any
++   call of deflate. The compressor and decompressor must use exactly the same
++   dictionary (see inflateSetDictionary).
++
++     The dictionary should consist of strings (byte sequences) that are likely
++   to be encountered later in the data to be compressed, with the most commonly
++   used strings preferably put towards the end of the dictionary. Using a
++   dictionary is most useful when the data to be compressed is short and can be
++   predicted with good accuracy; the data can then be compressed better than
++   with the default empty dictionary.
++
++     Depending on the size of the compression data structures selected by
++   deflateInit or deflateInit2, a part of the dictionary may in effect be
++   discarded, for example if the dictionary is larger than the window size in
++   deflate or deflate2. Thus the strings most likely to be useful should be
++   put at the end of the dictionary, not at the front.
++
++     Upon return of this function, strm->adler is set to the Adler32 value
++   of the dictionary; the decompressor may later use this value to determine
++   which dictionary has been used by the compressor. (The Adler32 value
++   applies to the whole dictionary even if only a subset of the dictionary is
++   actually used by the compressor.)
++
++     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
++   parameter is invalid (such as NULL dictionary) or the stream state is
++   inconsistent (for example if deflate has already been called for this stream
++   or if the compression method is bsort). deflateSetDictionary does not
++   perform any compression: this will be done by deflate().
++*/
++
++ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
++                                    z_streamp source));
++/*
++     Sets the destination stream as a complete copy of the source stream.
++
++     This function can be useful when several compression strategies will be
++   tried, for example when there are several ways of pre-processing the input
++   data with a filter. The streams that will be discarded should then be freed
++   by calling deflateEnd.  Note that deflateCopy duplicates the internal
++   compression state which can be quite large, so this strategy is slow and
++   can consume lots of memory.
++
++     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
++   (such as zalloc being NULL). msg is left unchanged in both source and
++   destination.
++*/
++
++ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
++/*
++     This function is equivalent to deflateEnd followed by deflateInit,
++   but does not free and reallocate all the internal compression state.
++   The stream will keep the same compression level and any other attributes
++   that may have been set by deflateInit2.
++
++      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++   stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
++                                    int level,
++                                    int strategy));
++/*
++     Dynamically update the compression level and compression strategy.  The
++   interpretation of level and strategy is as in deflateInit2.  This can be
++   used to switch between compression and straight copy of the input data, or
++   to switch to a different kind of input data requiring a different
++   strategy. If the compression level is changed, the input available so far
++   is compressed with the old level (and may be flushed); the new level will
++   take effect only at the next call of deflate().
++
++     Before the call of deflateParams, the stream state must be set as for
++   a call of deflate(), since the currently available input may have to
++   be compressed and flushed. In particular, strm->avail_out must be non-zero.
++
++     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
++   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
++   if strm->avail_out was zero.
++*/
++
++/*   
++ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
++                                     int  windowBits));
++
++     This is another version of inflateInit with an extra parameter. The
++   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
++   before by the caller.
++
++     The windowBits parameter is the base two logarithm of the maximum window
++   size (the size of the history buffer).  It should be in the range 8..15 for
++   this version of the library. The default value is 15 if inflateInit is used
++   instead. If a compressed stream with a larger window size is given as
++   input, inflate() will return with the error code Z_DATA_ERROR instead of
++   trying to allocate a larger window.
++
++      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
++   memLevel). msg is set to null if there is no error message.  inflateInit2
++   does not perform any decompression apart from reading the zlib header if
++   present: this will be done by inflate(). (So next_in and avail_in may be
++   modified, but next_out and avail_out are unchanged.)
++*/
++
++ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
++                                             const Bytef *dictionary,
++                                             uInt  dictLength));
++/*
++     Initializes the decompression dictionary from the given uncompressed byte
++   sequence. This function must be called immediately after a call of inflate
++   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
++   can be determined from the Adler32 value returned by this call of
++   inflate. The compressor and decompressor must use exactly the same
++   dictionary (see deflateSetDictionary).
++
++     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
++   parameter is invalid (such as NULL dictionary) or the stream state is
++   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
++   expected one (incorrect Adler32 value). inflateSetDictionary does not
++   perform any decompression: this will be done by subsequent calls of
++   inflate().
++*/
++
++ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
++/* 
++    Skips invalid compressed data until a full flush point (see above the
++  description of deflate with Z_FULL_FLUSH) can be found, or until all
++  available input is skipped. No output is provided.
++
++    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
++  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
++  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
++  case, the application may save the current current value of total_in which
++  indicates where valid compressed data was found. In the error case, the
++  application may repeatedly call inflateSync, providing more input each time,
++  until success or end of the input data.
++*/
++
++ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
++/*
++     This function is equivalent to inflateEnd followed by inflateInit,
++   but does not free and reallocate all the internal decompression state.
++   The stream will keep attributes that may have been set by inflateInit2.
++
++      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++   stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++
++                        /* utility functions */
++
++/*
++     The following utility functions are implemented on top of the
++   basic stream-oriented functions. To simplify the interface, some
++   default options are assumed (compression level and memory usage,
++   standard memory allocation functions). The source code of these
++   utility functions can easily be modified if you need special options.
++*/
++
++ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
++                                 const Bytef *source, uLong sourceLen));
++/*
++     Compresses the source buffer into the destination buffer.  sourceLen is
++   the byte length of the source buffer. Upon entry, destLen is the total
++   size of the destination buffer, which must be at least 0.1% larger than
++   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
++   compressed buffer.
++     This function can be used to compress a whole file at once if the
++   input file is mmap'ed.
++     compress returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_BUF_ERROR if there was not enough room in the output
++   buffer.
++*/
++
++ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
++                                  const Bytef *source, uLong sourceLen,
++                                  int level));
++/*
++     Compresses the source buffer into the destination buffer. The level
++   parameter has the same meaning as in deflateInit.  sourceLen is the byte
++   length of the source buffer. Upon entry, destLen is the total size of the
++   destination buffer, which must be at least 0.1% larger than sourceLen plus
++   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
++
++     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
++   Z_STREAM_ERROR if the level parameter is invalid.
++*/
++
++ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
++                                   const Bytef *source, uLong sourceLen));
++/*
++     Decompresses the source buffer into the destination buffer.  sourceLen is
++   the byte length of the source buffer. Upon entry, destLen is the total
++   size of the destination buffer, which must be large enough to hold the
++   entire uncompressed data. (The size of the uncompressed data must have
++   been saved previously by the compressor and transmitted to the decompressor
++   by some mechanism outside the scope of this compression library.)
++   Upon exit, destLen is the actual size of the compressed buffer.
++     This function can be used to decompress a whole file at once if the
++   input file is mmap'ed.
++
++     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_BUF_ERROR if there was not enough room in the output
++   buffer, or Z_DATA_ERROR if the input data was corrupted.
++*/
++
++
++typedef voidp gzFile;
++
++ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
++/*
++     Opens a gzip (.gz) file for reading or writing. The mode parameter
++   is as in fopen ("rb" or "wb") but can also include a compression level
++   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
++   Huffman only compression as in "wb1h". (See the description
++   of deflateInit2 for more information about the strategy parameter.)
++
++     gzopen can be used to read a file which is not in gzip format; in this
++   case gzread will directly read from the file without decompression.
++
++     gzopen returns NULL if the file could not be opened or if there was
++   insufficient memory to allocate the (de)compression state; errno
++   can be checked to distinguish the two cases (if errno is zero, the
++   zlib error is Z_MEM_ERROR).  */
++
++ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
++/*
++     gzdopen() associates a gzFile with the file descriptor fd.  File
++   descriptors are obtained from calls like open, dup, creat, pipe or
++   fileno (in the file has been previously opened with fopen).
++   The mode parameter is as in gzopen.
++     The next call of gzclose on the returned gzFile will also close the
++   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
++   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
++     gzdopen returns NULL if there was insufficient memory to allocate
++   the (de)compression state.
++*/
++
++ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
++/*
++     Dynamically update the compression level or strategy. See the description
++   of deflateInit2 for the meaning of these parameters.
++     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
++   opened for writing.
++*/
++
++ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
++/*
++     Reads the given number of uncompressed bytes from the compressed file.
++   If the input file was not in gzip format, gzread copies the given number
++   of bytes into the buffer.
++     gzread returns the number of uncompressed bytes actually read (0 for
++   end of file, -1 for error). */
++
++ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
++                                 const voidp buf, unsigned len));
++/*
++     Writes the given number of uncompressed bytes into the compressed file.
++   gzwrite returns the number of uncompressed bytes actually written
++   (0 in case of error).
++*/
++
++ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
++/*
++     Converts, formats, and writes the args to the compressed file under
++   control of the format string, as in fprintf. gzprintf returns the number of
++   uncompressed bytes actually written (0 in case of error).
++*/
++
++ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
++/*
++      Writes the given null-terminated string to the compressed file, excluding
++   the terminating null character.
++      gzputs returns the number of characters written, or -1 in case of error.
++*/
++
++ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
++/*
++      Reads bytes from the compressed file until len-1 characters are read, or
++   a newline character is read and transferred to buf, or an end-of-file
++   condition is encountered.  The string is then terminated with a null
++   character.
++      gzgets returns buf, or Z_NULL in case of error.
++*/
++
++ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
++/*
++      Writes c, converted to an unsigned char, into the compressed file.
++   gzputc returns the value that was written, or -1 in case of error.
++*/
++
++ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
++/*
++      Reads one byte from the compressed file. gzgetc returns this byte
++   or -1 in case of end of file or error.
++*/
++
++ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
++/*
++     Flushes all pending output into the compressed file. The parameter
++   flush is as in the deflate() function. The return value is the zlib
++   error number (see function gzerror below). gzflush returns Z_OK if
++   the flush parameter is Z_FINISH and all output could be flushed.
++     gzflush should be called only when strictly necessary because it can
++   degrade compression.
++*/
++
++ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
++                                    z_off_t offset, int whence));
++/* 
++      Sets the starting position for the next gzread or gzwrite on the
++   given compressed file. The offset represents a number of bytes in the
++   uncompressed data stream. The whence parameter is defined as in lseek(2);
++   the value SEEK_END is not supported.
++     If the file is opened for reading, this function is emulated but can be
++   extremely slow. If the file is opened for writing, only forward seeks are
++   supported; gzseek then compresses a sequence of zeroes up to the new
++   starting position.
++
++      gzseek returns the resulting offset location as measured in bytes from
++   the beginning of the uncompressed stream, or -1 in case of error, in
++   particular if the file is opened for writing and the new starting position
++   would be before the current position.
++*/
++
++ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
++/*
++     Rewinds the given file. This function is supported only for reading.
++
++   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
++*/
++
++ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
++/*
++     Returns the starting position for the next gzread or gzwrite on the
++   given compressed file. This position represents a number of bytes in the
++   uncompressed data stream.
++
++   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
++*/
++
++ZEXTERN int ZEXPORT gzeof OF((gzFile file));
++/*
++     Returns 1 when EOF has previously been detected reading the given
++   input stream, otherwise zero.
++*/
++
++ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
++/*
++     Flushes all pending output if necessary, closes the compressed file
++   and deallocates all the (de)compression state. The return value is the zlib
++   error number (see function gzerror below).
++*/
++
++ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
++/*
++     Returns the error message for the last error which occurred on the
++   given compressed file. errnum is set to zlib error number. If an
++   error occurred in the file system and not in the compression library,
++   errnum is set to Z_ERRNO and the application may consult errno
++   to get the exact error code.
++*/
++
++                        /* checksum functions */
++
++/*
++     These functions are not related to compression but are exported
++   anyway because they might be useful in applications using the
++   compression library.
++*/
++
++ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
++
++/*
++     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
++   return the updated checksum. If buf is NULL, this function returns
++   the required initial value for the checksum.
++   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
++   much faster. Usage example:
++
++     uLong adler = adler32(0L, Z_NULL, 0);
++
++     while (read_buffer(buffer, length) != EOF) {
++       adler = adler32(adler, buffer, length);
++     }
++     if (adler != original_adler) error();
++*/
++
++ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
++/*
++     Update a running crc with the bytes buf[0..len-1] and return the updated
++   crc. If buf is NULL, this function returns the required initial value
++   for the crc. Pre- and post-conditioning (one's complement) is performed
++   within this function so it shouldn't be done by the application.
++   Usage example:
++
++     uLong crc = crc32(0L, Z_NULL, 0);
++
++     while (read_buffer(buffer, length) != EOF) {
++       crc = crc32(crc, buffer, length);
++     }
++     if (crc != original_crc) error();
++*/
++
++
++                        /* various hacks, don't look :) */
++
++/* deflateInit and inflateInit are macros to allow checking the zlib version
++ * and the compiler's view of z_stream:
++ */
++ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
++                                     const char *version, int stream_size));
++ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
++                                     const char *version, int stream_size));
++ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
++                                      int windowBits, int memLevel,
++                                      int strategy, const char *version,
++                                      int stream_size));
++ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
++                                      const char *version, int stream_size));
++#define deflateInit(strm, level) \
++        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit(strm) \
++        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
++#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
++        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
++                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit2(strm, windowBits) \
++        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
++
++
++#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
++    struct internal_state {int dummy;}; /* hack for buggy compilers */
++#endif
++
++ZEXTERN const char   * ZEXPORT zError           OF((int err));
++ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
++ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _ZLIB_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/include/zlib/zutil.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,225 @@
++/* zutil.h -- internal interface and configuration of the compression library
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++/* @(#) $Id: zutil.h,v 1.4 2002/04/24 07:36:48 mcr Exp $ */
++
++#ifndef _Z_UTIL_H
++#define _Z_UTIL_H
++
++#include "zlib.h"
++
++#include <linux/string.h>
++#define HAVE_MEMCPY
++
++#if 0 // #ifdef STDC
++#  include <stddef.h>
++#  include <string.h>
++#  include <stdlib.h>
++#endif
++#ifndef __KERNEL__
++#ifdef NO_ERRNO_H
++    extern int errno;
++#else
++#   include <errno.h>
++#endif
++#endif
++
++#ifndef local
++#  define local static
++#endif
++/* compile with -Dlocal if your debugger can't find static symbols */
++
++typedef unsigned char  uch;
++typedef uch FAR uchf;
++typedef unsigned short ush;
++typedef ush FAR ushf;
++typedef unsigned long  ulg;
++
++extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
++/* (size given to avoid silly warnings with Visual C++) */
++
++#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
++
++#define ERR_RETURN(strm,err) \
++  return (strm->msg = ERR_MSG(err), (err))
++/* To be used only when the state is known to be valid */
++
++        /* common constants */
++
++#ifndef DEF_WBITS
++#  define DEF_WBITS MAX_WBITS
++#endif
++/* default windowBits for decompression. MAX_WBITS is for compression only */
++
++#if MAX_MEM_LEVEL >= 8
++#  define DEF_MEM_LEVEL 8
++#else
++#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
++#endif
++/* default memLevel */
++
++#define STORED_BLOCK 0
++#define STATIC_TREES 1
++#define DYN_TREES    2
++/* The three kinds of block type */
++
++#define MIN_MATCH  3
++#define MAX_MATCH  258
++/* The minimum and maximum match lengths */
++
++#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
++
++        /* target dependencies */
++
++#ifdef MSDOS
++#  define OS_CODE  0x00
++#  if defined(__TURBOC__) || defined(__BORLANDC__)
++#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
++       /* Allow compilation with ANSI keywords only enabled */
++       void _Cdecl farfree( void *block );
++       void *_Cdecl farmalloc( unsigned long nbytes );
++#    else
++#     include <alloc.h>
++#    endif
++#  else /* MSC or DJGPP */
++#    include <malloc.h>
++#  endif
++#endif
++
++#ifdef OS2
++#  define OS_CODE  0x06
++#endif
++
++#ifdef WIN32 /* Window 95 & Windows NT */
++#  define OS_CODE  0x0b
++#endif
++
++#if defined(VAXC) || defined(VMS)
++#  define OS_CODE  0x02
++#  define F_OPEN(name, mode) \
++     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
++#endif
++
++#ifdef AMIGA
++#  define OS_CODE  0x01
++#endif
++
++#if defined(ATARI) || defined(atarist)
++#  define OS_CODE  0x05
++#endif
++
++#if defined(MACOS) || defined(TARGET_OS_MAC)
++#  define OS_CODE  0x07
++#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
++#    include <unix.h> /* for fdopen */
++#  else
++#    ifndef fdopen
++#      define fdopen(fd,mode) NULL /* No fdopen() */
++#    endif
++#  endif
++#endif
++
++#ifdef __50SERIES /* Prime/PRIMOS */
++#  define OS_CODE  0x0F
++#endif
++
++#ifdef TOPS20
++#  define OS_CODE  0x0a
++#endif
++
++#if defined(_BEOS_) || defined(RISCOS)
++#  define fdopen(fd,mode) NULL /* No fdopen() */
++#endif
++
++#if (defined(_MSC_VER) && (_MSC_VER > 600))
++#  define fdopen(fd,type)  _fdopen(fd,type)
++#endif
++
++
++        /* Common defaults */
++
++#ifndef OS_CODE
++#  define OS_CODE  0x03  /* assume Unix */
++#endif
++
++#ifndef F_OPEN
++#  define F_OPEN(name, mode) fopen((name), (mode))
++#endif
++
++         /* functions */
++
++#ifdef HAVE_STRERROR
++   extern char *strerror OF((int));
++#  define zstrerror(errnum) strerror(errnum)
++#else
++#  define zstrerror(errnum) ""
++#endif
++
++#if defined(pyr)
++#  define NO_MEMCPY
++#endif
++#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
++ /* Use our own functions for small and medium model with MSC <= 5.0.
++  * You may have to use the same strategy for Borland C (untested).
++  * The __SC__ check is for Symantec.
++  */
++#  define NO_MEMCPY
++#endif
++#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
++#  define HAVE_MEMCPY
++#endif
++#ifdef HAVE_MEMCPY
++#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
++#    define zmemcpy _fmemcpy
++#    define zmemcmp _fmemcmp
++#    define zmemzero(dest, len) _fmemset(dest, 0, len)
++#  else
++#    define zmemcpy memcpy
++#    define zmemcmp memcmp
++#    define zmemzero(dest, len) memset(dest, 0, len)
++#  endif
++#else
++   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
++   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
++   extern void zmemzero OF((Bytef* dest, uInt len));
++#endif
++
++/* Diagnostic functions */
++#ifdef DEBUG
++#  include <stdio.h>
++   extern int z_verbose;
++   extern void z_error    OF((char *m));
++#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
++#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
++#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
++#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
++#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
++#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
++#else
++#  define Assert(cond,msg)
++#  define Trace(x)
++#  define Tracev(x)
++#  define Tracevv(x)
++#  define Tracec(c,x)
++#  define Tracecv(c,x)
++#endif
++
++
++typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
++                                     uInt len));
++voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
++void   zcfree  OF((voidpf opaque, voidpf ptr));
++
++#define ZALLOC(strm, items, size) \
++           (*((strm)->zalloc))((strm)->opaque, (items), (size))
++#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
++#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
++
++#endif /* _Z_UTIL_H */
+--- swan26/net/Kconfig.preipsec        2005-09-01 18:15:19.000000000 -0400
++++ swan26/net/Kconfig 2005-09-03 16:51:17.000000000 -0400
+@@ -215,2 +215,6 @@
++if INET
++source "net/ipsec/Kconfig"
++endif # if INET
++
+ endif   # if NET
+--- /distros/kernel/linux-2.6.3-rc4/net/Makefile       Mon Feb 16 21:22:12 2004
++++ ref26/net/Makefile Thu Feb 19 21:02:25 2004
+@@ -42,3 +42,6 @@
+ ifeq ($(CONFIG_NET),y)
+ obj-$(CONFIG_SYSCTL)          += sysctl_net.o
+ endif
++
++obj-$(CONFIG_KLIPS)             += ipsec/
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/Kconfig     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,143 @@
++#
++# IPSEC configuration
++# Copyright (C) 2004 Michael Richardson <mcr@freeswan.org>
++# 
++# This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++# 
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++# for more details.
++#
++
++config KLIPS
++      tristate "Openswan IPsec (KLIPS)"
++      default n
++#     depends on NF_CONNTRACK && NETFILTER
++      help
++        KLIPS is the Openswan (www.openswan.org) Kernel Level IP Security
++        system. It is extensively tested, and has interoperated with
++        many other systems. 
++        It provides "ipsecX" devices on which one can do firewalling.
++        The Openswan userland, is compatible with both KLIPS and NETKEY
++        You cannot build KLIPS and NETKEY inline into the kernel.
++
++menu "KLIPS options"
++      depends on KLIPS
++
++config KLIPS_ESP
++      bool 'Encapsulating Security Payload - ESP ("VPN")'
++      default y
++      help
++         This option provides support for the IPSEC Encapsulation Security
++         Payload (IP protocol 50) which provides packet layer content
++           hiding, and content authentication.
++         It is recommended to enable this.  RFC2406
++
++config KLIPS_AH
++      bool 'Authentication Header - AH'
++      default n
++      help
++           This option provides support for the IPSEC Authentication Header
++           (IP protocol 51) which provides packet layer sender and content
++           authentication. It does not provide for confidentiality.
++         It is not recommended to enable this.  RFC2402
++
++config KLIPS_AUTH_HMAC_MD5
++      bool 'HMAC-MD5 authentication algorithm' 
++      default y
++      help
++           The HMAC-MD5 algorithm is used by ESP (and AH) to guarantee packet
++         integrity. There is little reason not to include it.
++
++config KLIPS_AUTH_HMAC_SHA1
++      bool 'HMAC-SHA1 authentication algorithm' 
++      default y
++      help
++           The HMAC-SHA1 algorithm is used by ESP (and AH) to guarantee packet
++         integrity. SHA1 is a little slower than MD5, but is said to be 
++         a bit more secure. There is little reason not to include it.
++
++config KLIPS_ALG
++      bool 'KLIPS_ALG software encryption'
++      default y
++      help
++         This option provides support for loading new algorithms into the 
++         kernel for crypto use. You may disable this if using the
++         CONFIG_KLIPS_OCF option for hardware offload.
++
++config KLIPS_ENC_CRYPTOAPI
++      bool 'CryptoAPI algorithm interface'
++      default n
++      depends on KLIPS_ALG
++      help
++         Enable the algorithm interface to make all CryptoAPI 1.0 algorithms
++         available to KLIPS.
++
++config KLIPS_ENC_1DES
++      bool 'Include 1DES with CryptoAPI'
++      default n
++      depends on KLIPS_ENC_CRYPTOAPI
++      help
++         The CryptoAPI interface does not include support for every algorithm
++         yet, and one that it doesn't support by default is the VERY WEAK
++         1DES. Select this if you are terminally stupid.
++      
++config KLIPS_ENC_3DES
++      bool '3DES encryption algorithm'
++      default y
++      help
++           The 3DES algorithm is used by ESP to provide for packet privacy.
++         3DES is 3-repeats of the DES algorithm. 3DES is widely supported,
++         and analyzed and is considered very secure. 1DES is not supported.
++
++config KLIPS_ENC_AES
++      bool 'AES encryption algorithm'
++      default y
++      depends on KLIPS_ALG
++      help
++           The AES algorithm is used by ESP to provide for packet privacy.
++         AES the NIST replacement for DES. AES is being widely analyzed,
++           and is very fast.
++
++config KLIPS_IPCOMP
++      bool 'IP compression'
++      default y
++      help
++           The IPcomp protocol is used prior to ESP to make the packet
++         smaller. Once encrypted, compression will fail, so any link
++         layer efforts (e.g. PPP) will not work. 
++
++config KLIPS_OCF
++      bool 'IPsec OCF Acceleration Support'
++      default n
++      help
++         OCF provides Asynchronous crypto acceleration for kernel and
++         user applications.   It supports various HW accelerators.
++         If you have OCF support enabled and wish IPsec to utilise
++         the hardware managed by OCF,  then enable this option.
++         OCF is a kernel patch, see http://ocf-linux.sourceforge.net/
++
++config KLIPS_DEBUG
++      bool 'IPsec debugging'
++      default y 
++      help
++           KLIPS includes a lot of debugging code. Unless there is a real
++         tangible benefit to removing this code, it should be left in place.
++         Debugging connections without access to kernel level debugging is
++         essentially impossible. Leave this on.
++
++config KLIPS_IF_MAX
++      int 'Maximum number of virtual interfaces'
++      default 64
++      range 4 256
++      help
++         KLIPS creates virtual interfaces for tunnel purposes. At present
++         it keeps track of certain items in an array (FIX ME), and needs
++         to preallocate this array. Only a pointer is used per item.
++
++endmenu
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/Makefile     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,192 @@
++# Makefile for KLIPS kernel code as a module    for 2.6 kernels
++#
++# Makefile for KLIPS kernel code as a module
++# Copyright (C) 1998, 1999, 2000,2001  Richard Guy Briggs.
++# Copyright (C) 2002-2004     Michael Richardson <mcr@freeswan.org>
++# 
++# This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++# 
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++# for more details.
++#
++# RCSID $Id: Makefile.fs2_6,v 1.8.2.1 2006/04/20 16:33:06 mcr Exp $
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++OPENSWANSRCDIR?=.
++KLIPS_TOP?=.
++
++-include ${OPENSWANSRCDIR}/Makefile.ver
++
++base-klips-objs := 
++
++base-klips-objs+= ipsec_init.o ipsec_sa.o ipsec_radij.o radij.o
++base-klips-objs+= ipsec_life.o ipsec_proc.o
++base-klips-objs+= ipsec_tunnel.o ipsec_xmit.o ipsec_rcv.o ipsec_ipip.o
++base-klips-objs+= ipsec_snprintf.o
++base-klips-objs+= ipsec_mast.o
++base-klips-objs+= sysctl_net_ipsec.o 
++base-klips-objs+= pfkey_v2.o pfkey_v2_parser.o pfkey_v2_ext_process.o 
++base-klips-objs+= version.o
++
++base-klips-objs+= satot.o
++base-klips-objs+= addrtot.o
++base-klips-objs+= ultot.o 
++base-klips-objs+= addrtypeof.o
++base-klips-objs+= anyaddr.o
++base-klips-objs+= initaddr.o
++base-klips-objs+= ultoa.o 
++base-klips-objs+= addrtoa.o 
++base-klips-objs+= subnettoa.o 
++base-klips-objs+= subnetof.o 
++base-klips-objs+= goodmask.o 
++base-klips-objs+= datatot.o 
++base-klips-objs+= rangetoa.o 
++base-klips-objs+= prng.o 
++base-klips-objs+= pfkey_v2_parse.o 
++base-klips-objs+= pfkey_v2_build.o 
++base-klips-objs+= pfkey_v2_debug.o 
++base-klips-objs+= pfkey_v2_ext_bits.o 
++base-klips-objs+= version.o
++
++obj-${CONFIG_KLIPS} += ipsec.o
++
++ipsec-objs += ${base-klips-objs}
++
++ipsec-$(CONFIG_KLIPS_ESP)     += ipsec_esp.o
++ipsec-$(CONFIG_KLIPS_OCF)     += ipsec_ocf.o
++ipsec-$(CONFIG_KLIPS_IPCOMP)  += ipsec_ipcomp.o
++ipsec-$(CONFIG_KLIPS_AUTH_HMAC_MD5)  += ipsec_md5c.o
++ipsec-$(CONFIG_KLIPS_AUTH_HMAC_SHA1) += ipsec_sha1.o
++
++# AH, if you really think you need it.
++ipsec-$(CONFIG_KLIPS_AH)   += ipsec_ah.o
++
++ipsec-$(CONFIG_KLIPS_ALG) += ipsec_alg.o 
++
++# include code from DES subdir
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/ipsec_alg_3des.o
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/cbc_enc.o
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/ecb_enc.o
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/set_key.o
++
++ifeq ($(strip ${SUBARCH}),)
++SUBARCH:=${ARCH}
++endif
++
++# the assembly version expects frame pointers, which are
++# optional in many kernel builds. If you want speed, you should
++# probably use cryptoapi code instead.
++USEASSEMBLY=${SUBARCH}${CONFIG_FRAME_POINTER}
++ifeq (${USEASSEMBLY},i386y)
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/dx86unix.o
++else
++crypto-$(CONFIG_KLIPS_ENC_3DES) += des/des_enc.o
++endif
++
++# include code from AES subdir
++crypto-$(CONFIG_KLIPS_ENC_AES) += aes/ipsec_alg_aes.o
++crypto-$(CONFIG_KLIPS_ENC_AES) += aes/aes_xcbc_mac.o
++crypto-$(CONFIG_KLIPS_ENC_AES) += aes/aes_cbc.o
++
++ifeq ($(strip ${SUBARCH}),)
++SUBARCH:=${ARCH}
++endif
++
++USEASSEMBLY=${SUBARCH}${CONFIG_FRAME_POINTER}
++ifeq (${USEASSEMBLY},i386y)
++crypto-$(CONFIG_KLIPS_ENC_AES) += aes/aes-i586.o
++else
++crypto-$(CONFIG_KLIPS_ENC_AES) += aes/aes.o
++endif
++
++ipsec-y += ${crypto-y}
++
++ipsec-$(CONFIG_KLIPS_ENC_CRYPTOAPI) += ipsec_alg_cryptoapi.o
++
++# IPcomp stuff
++base-ipcomp-objs := ipcomp.o 
++base-ipcomp-objs += adler32.o
++base-ipcomp-objs += deflate.o
++base-ipcomp-objs += infblock.o
++base-ipcomp-objs += infcodes.o
++base-ipcomp-objs += inffast.o
++base-ipcomp-objs += inflate.o
++base-ipcomp-objs += inftrees.o
++base-ipcomp-objs += infutil.o
++base-ipcomp-objs += trees.o
++base-ipcomp-objs += zutil.o
++asm-ipcomp-obj-$(CONFIG_M586)          += match586.o
++asm-ipcomp-obj-$(CONFIG_M586TSC)       += match586.o
++asm-ipcomp-obj-$(CONFIG_M586MMX)       += match586.o
++asm-ipcomp-obj-$(CONFIG_M686)          += match686.o
++asm-ipcomp-obj-$(CONFIG_MPENTIUMIII)   += match686.o
++asm-ipcomp-obj-$(CONFIG_MPENTIUM4)     += match686.o
++asm-ipcomp-obj-$(CONFIG_MK6)           += match586.o
++asm-ipcomp-obj-$(CONFIG_MK7)           += match686.o
++asm-ipcomp-obj-$(CONFIG_MCRUSOE)       += match586.o
++asm-ipcomp-obj-$(CONFIG_MWINCHIPC6)    += match586.o
++asm-ipcomp-obj-$(CONFIG_MWINCHIP2)     += match686.o
++asm-ipcomp-obj-$(CONFIG_MWINCHIP3D)    += match686.o
++base-ipcomp-objs += ${asm-ipcomp-obj-y}
++
++ipsec-$(CONFIG_KLIPS_IPCOMP) += ${base-ipcomp-objs}
++
++EXTRA_CFLAGS += -DIPCOMP_PREFIX -DKLIPS
++EXTRA_CFLAGS += -Icrypto/ocf
++
++#
++# $Log: Makefile.fs2_6,v $
++# Revision 1.8.2.1  2006/04/20 16:33:06  mcr
++# remove all of CONFIG_KLIPS_ALG --- one can no longer build without it.
++# Fix in-kernel module compilation. Sub-makefiles do not work.
++#
++# Revision 1.8  2005/05/11 03:15:42  mcr
++#     adjusted makefiles to sanely build modules properly.
++#
++# Revision 1.7  2005/04/13 22:52:12  mcr
++#     moved KLIPS specific snprintf() wrapper to seperate file.
++#
++# Revision 1.6  2004/08/22 05:02:03  mcr
++#     organized symbols such that it is easier to build modules.
++#
++# Revision 1.5  2004/08/18 01:43:56  mcr
++#     adjusted makefile enumation so that it can be used by module
++#     wrapper.
++#
++# Revision 1.4  2004/08/17 03:27:23  mcr
++#     klips 2.6 edits.
++#
++# Revision 1.3  2004/08/04 16:50:13  mcr
++#     removed duplicate definition of dx86unix.o
++#
++# Revision 1.2  2004/08/03 18:21:09  mcr
++#     only set KLIPS_TOP and OPENSWANSRCDIR if not already set.
++#
++# Revision 1.1  2004/07/26 15:02:22  mcr
++#     makefile for KLIPS module for 2.6.
++#
++# Revision 1.3  2004/02/24 17:17:04  mcr
++#     s/CONFIG_IPSEC/CONFIG_KLIPS/ as 26sec uses "CONFIG_IPSEC" to
++#     turn it on/off as well.
++#
++# Revision 1.2  2004/02/22 06:50:42  mcr
++#     kernel 2.6 port - merged with 2.4 code.
++#
++# Revision 1.1.2.1  2004/02/20 02:07:53  mcr
++#     module configuration for KLIPS 2.6
++#
++#
++# Local Variables:
++# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
++# End Variables:
++#
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/README-zlib     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,147 @@
++zlib 1.1.4 is a general purpose data compression library.  All the code
++is thread safe.  The data format used by the zlib library
++is described by RFCs (Request for Comments) 1950 to 1952 in the files 
++http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
++format) and rfc1952.txt (gzip format). These documents are also available in
++other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
++
++All functions of the compression library are documented in the file zlib.h
++(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
++example of the library is given in the file example.c which also tests that
++the library is working correctly. Another example is given in the file
++minigzip.c. The compression library itself is composed of all source files
++except example.c and minigzip.c.
++
++To compile all files and run the test program, follow the instructions
++given at the top of Makefile. In short "make test; make install"
++should work for most machines. For Unix: "./configure; make test; make install"
++For MSDOS, use one of the special makefiles such as Makefile.msc.
++For VMS, use Make_vms.com or descrip.mms.
++
++Questions about zlib should be sent to <zlib@gzip.org>, or to
++Gilles Vollant <info@winimage.com> for the Windows DLL version.
++The zlib home page is http://www.zlib.org or http://www.gzip.org/zlib/
++Before reporting a problem, please check this site to verify that
++you have the latest version of zlib; otherwise get the latest version and
++check whether the problem still exists or not.
++
++PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html
++before asking for help.
++
++Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
++issue of  Dr. Dobb's Journal; a copy of the article is available in
++http://dogma.net/markn/articles/zlibtool/zlibtool.htm
++
++The changes made in version 1.1.4 are documented in the file ChangeLog.
++The only changes made since 1.1.3 are bug corrections:
++
++- ZFREE was repeated on same allocation on some error conditions.
++  This creates a security problem described in
++  http://www.zlib.org/advisory-2002-03-11.txt
++- Returned incorrect error (Z_MEM_ERROR) on some invalid data
++- Avoid accesses before window for invalid distances with inflate window
++  less than 32K.
++- force windowBits > 8 to avoid a bug in the encoder for a window size
++  of 256 bytes. (A complete fix will be available in 1.1.5).
++
++The beta version 1.1.5beta includes many more changes. A new official
++version 1.1.5 will be released as soon as extensive testing has been
++completed on it.
++
++
++Unsupported third party contributions are provided in directory "contrib".
++
++A Java implementation of zlib is available in the Java Development Kit
++http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
++See the zlib home page http://www.zlib.org for details.
++
++A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
++is in the CPAN (Comprehensive Perl Archive Network) sites
++http://www.cpan.org/modules/by-module/Compress/
++
++A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
++is available in Python 1.5 and later versions, see
++http://www.python.org/doc/lib/module-zlib.html
++
++A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
++is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
++
++An experimental package to read and write files in .zip format,
++written on top of zlib by Gilles Vollant <info@winimage.com>, is
++available at http://www.winimage.com/zLibDll/unzip.html
++and also in the contrib/minizip directory of zlib.
++
++
++Notes for some targets:
++
++- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
++  and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
++  The zlib DLL support was initially done by Alessandro Iacopetti and is
++  now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
++  home page at http://www.winimage.com/zLibDll
++
++  From Visual Basic, you can call the DLL functions which do not take
++  a structure as argument: compress, uncompress and all gz* functions.
++  See contrib/visual-basic.txt for more information, or get
++  http://www.tcfb.com/dowseware/cmp-z-it.zip
++
++- For 64-bit Irix, deflate.c must be compiled without any optimization.
++  With -O, one libpng test fails. The test works in 32 bit mode (with
++  the -n32 compiler flag). The compiler bug has been reported to SGI.
++
++- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1   
++  it works when compiled with cc.
++
++- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1
++  is necessary to get gzprintf working correctly. This is done by configure.
++
++- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works
++  with other compilers. Use "make test" to check your compiler.
++
++- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
++
++- For Turbo C the small model is supported only with reduced performance to
++  avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
++
++- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
++  Per Harald Myrvang <perm@stud.cs.uit.no>
++
++
++Acknowledgments:
++
++  The deflate format used by zlib was defined by Phil Katz. The deflate
++  and zlib specifications were written by L. Peter Deutsch. Thanks to all the
++  people who reported problems and suggested various improvements in zlib;
++  they are too numerous to cite here.
++
++Copyright notice:
++
++ (C) 1995-2002 Jean-loup Gailly and Mark Adler
++
++  This software is provided 'as-is', without any express or implied
++  warranty.  In no event will the authors be held liable for any damages
++  arising from the use of this software.
++
++  Permission is granted to anyone to use this software for any purpose,
++  including commercial applications, and to alter it and redistribute it
++  freely, subject to the following restrictions:
++
++  1. The origin of this software must not be misrepresented; you must not
++     claim that you wrote the original software. If you use this software
++     in a product, an acknowledgment in the product documentation would be
++     appreciated but is not required.
++  2. Altered source versions must be plainly marked as such, and must not be
++     misrepresented as being the original software.
++  3. This notice may not be removed or altered from any source distribution.
++
++  Jean-loup Gailly        Mark Adler
++  jloup@gzip.org          madler@alumni.caltech.edu
++
++If you use the zlib library in a product, we would appreciate *not*
++receiving lengthy legal documents to sign. The sources are provided
++for free but without warranty of any kind.  The library has been
++entirely written by Jean-loup Gailly and Mark Adler; it does not
++include third-party code.
++
++If you redistribute modified sources, we would appreciate that you include
++in the file ChangeLog history information documenting your changes.
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/README-zlib.freeswan     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,13 @@
++The only changes made to these files for use in FreeS/WAN are:
++
++ - In zconf.h, macros are defined to prefix global symbols with "ipcomp_"
++   (or "_ipcomp"), when compiled with -DIPCOMP_PREFIX.
++ - The copyright strings are defined local (static)
++
++ The above changes are made to avoid name collisions with ppp_deflate
++ and ext2compr.
++
++ - Files not needed for FreeS/WAN have been removed
++
++ See the "README" file for information about where to obtain the complete
++ zlib package.
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/addrtoa.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,67 @@
++/*
++ * addresses to ASCII
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: addrtoa.c,v 1.10 2004/07/10 07:43:47 mcr Exp $
++ */
++#include "openswan.h"
++
++#define       NBYTES  4               /* bytes in an address */
++#define       PERBYTE 4               /* three digits plus a dot or NUL */
++#define       BUFLEN  (NBYTES*PERBYTE)
++
++#if BUFLEN != ADDRTOA_BUF
++#error        "ADDRTOA_BUF in openswan.h inconsistent with addrtoa() code"
++#endif
++
++/*
++ - addrtoa - convert binary address to ASCII dotted decimal
++ */
++size_t                                /* space needed for full conversion */
++addrtoa(addr, format, dst, dstlen)
++struct in_addr addr;
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      unsigned long a = ntohl(addr.s_addr);
++      int i;
++      size_t n;
++      unsigned long byte;
++      char buf[BUFLEN];
++      char *p;
++
++      switch (format) {
++      case 0:
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      p = buf;
++      for (i = NBYTES-1; i >= 0; i--) {
++              byte = (a >> (i*8)) & 0xff;
++              p += ultoa(byte, 10, p, PERBYTE);
++              if (i != 0)
++                      *(p-1) = '.';
++      }
++      n = p - buf;
++
++      if (dstlen > 0) {
++              if (n > dstlen)
++                      buf[dstlen - 1] = '\0';
++              strcpy(dst, buf);
++      }
++      return n;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/addrtot.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,344 @@
++/*
++ * addresses to text
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ */
++
++#if defined(__KERNEL__) && defined(__HAVE_ARCH_STRSTR)
++#include <linux/string.h>
++#endif
++
++#include "openswan.h"
++
++#define       IP4BYTES        4       /* bytes in an IPv4 address */
++#define       PERBYTE         4       /* three digits plus a dot or NUL */
++#define       IP6BYTES        16      /* bytes in an IPv6 address */
++
++/* forwards */
++static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp);
++static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish);
++static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp);
++static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp);
++
++#if defined(__KERNEL__) && !defined(__HAVE_ARCH_STRSTR) 
++#define strstr ipsec_strstr
++/*
++ * Find the first occurrence of find in s.
++ * (from NetBSD 1.6's /src/lib/libc/string/strstr.c)
++ */
++
++static char *
++ipsec_strstr(s, find)
++      const char *s, *find;
++{
++      char c, sc;
++      size_t len;
++
++      if ((c = *find++) != 0) {
++              len = strlen(find);
++              do {
++                      do {
++                              if ((sc = *s++) == 0)
++                                      return (NULL);
++                      } while (sc != c);
++              } while (strncmp(s, find, len) != 0);
++              s--;
++      }
++      /* LINTED interface specification */
++      return ((char *)s);
++}
++#endif
++
++/*
++ - addrtot - convert binary address to text (dotted decimal or IPv6 string)
++ */
++size_t                                /* space needed for full conversion */
++addrtot(src, format, dst, dstlen)
++const ip_address *src;
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      const unsigned char *b;
++      size_t n;
++      char buf[1+ADDRTOT_BUF+1];      /* :address: */
++      char *p;
++      int t = addrtypeof(src);
++#     define  TF(t, f)        (((t)<<8) | (f))
++
++      n = addrbytesptr(src, &b);
++      if (n == 0) {
++      bad:
++        dst[0]='\0';
++        strncat(dst, "<invalid>", dstlen);
++        return sizeof("<invalid>");
++      }
++
++      switch (TF(t, format)) {
++      case TF(AF_INET, 0):
++              n = normal4(b, n, buf, &p);
++              break;
++      case TF(AF_INET6, 0):
++              n = normal6(b, n, buf, &p, 1);
++              break;
++      case TF(AF_INET, 'Q'):
++              n = normal4(b, n, buf, &p);
++              break;
++      case TF(AF_INET6, 'Q'):
++              n = normal6(b, n, buf, &p, 0);
++              break;
++      case TF(AF_INET, 'r'):
++              n = reverse4(b, n, buf, &p);
++              break;
++      case TF(AF_INET6, 'r'):
++              n = reverse6(b, n, buf, &p);
++              break;
++      default:                /* including (AF_INET, 'R') */
++              goto bad;
++              break;
++      }
++
++      if (dstlen > 0) {
++              if (dstlen < n)
++                      p[dstlen - 1] = '\0';
++              strcpy(dst, p);
++      }
++      return n;
++}
++
++/*
++ - normal4 - normal IPv4 address-text conversion
++ */
++static size_t                 /* size of text, including NUL */
++normal4(srcp, srclen, buf, dstp)
++const unsigned char *srcp;
++size_t srclen;
++char *buf;                    /* guaranteed large enough */
++char **dstp;                  /* where to put result pointer */
++{
++      int i;
++      char *p;
++
++      if (srclen != IP4BYTES) /* "can't happen" */
++              return 0;
++      p = buf;
++      for (i = 0; i < IP4BYTES; i++) {
++              p += ultot(srcp[i], 10, p, PERBYTE);
++              if (i != IP4BYTES - 1)
++                      *(p-1) = '.';   /* overwrites the NUL */
++      }
++      *dstp = buf;
++      return p - buf;
++}
++
++/*
++ - normal6 - normal IPv6 address-text conversion
++ */
++static size_t                 /* size of text, including NUL */
++normal6(srcp, srclen, buf, dstp, squish)
++const unsigned char *srcp;
++size_t srclen;
++char *buf;                    /* guaranteed large enough, plus 2 */
++char **dstp;                  /* where to put result pointer */
++int    squish;                  /* whether to squish out 0:0 */
++{
++      int i;
++      unsigned long piece;
++      char *p;
++      char *q;
++
++      if (srclen != IP6BYTES) /* "can't happen" */
++              return 0;
++      p = buf;
++      *p++ = ':';
++      for (i = 0; i < IP6BYTES/2; i++) {
++              piece = (srcp[2*i] << 8) + srcp[2*i + 1];
++              p += ultot(piece, 16, p, 5);    /* 5 = abcd + NUL */
++              *(p-1) = ':';   /* overwrites the NUL */
++      }
++      *p = '\0';
++      q = strstr(buf, ":0:0:");
++      if (squish && q != NULL) {      /* zero squishing is possible */
++              p = q + 1;
++              while (*p == '0' && *(p+1) == ':')
++                      p += 2;
++              q++;
++              *q++ = ':';     /* overwrite first 0 */
++              while (*p != '\0')
++                      *q++ = *p++;
++              *q = '\0';
++              if (!(*(q-1) == ':' && *(q-2) == ':'))
++                      *--q = '\0';    /* strip final : unless :: */
++              p = buf;
++              if (!(*p == ':' && *(p+1) == ':'))
++                      p++;    /* skip initial : unless :: */
++      } else {
++              q = p;
++              *--q = '\0';    /* strip final : */
++              p = buf + 1;    /* skip initial : */
++      }
++      *dstp = p;
++      return q - p + 1;
++}
++
++/*
++ - reverse4 - IPv4 reverse-lookup conversion
++ */
++static size_t                 /* size of text, including NUL */
++reverse4(srcp, srclen, buf, dstp)
++const unsigned char *srcp;
++size_t srclen;
++char *buf;                    /* guaranteed large enough */
++char **dstp;                  /* where to put result pointer */
++{
++      int i;
++      char *p;
++
++      if (srclen != IP4BYTES) /* "can't happen" */
++              return 0;
++      p = buf;
++      for (i = IP4BYTES-1; i >= 0; i--) {
++              p += ultot(srcp[i], 10, p, PERBYTE);
++              *(p-1) = '.';   /* overwrites the NUL */
++      }
++      strcpy(p, "IN-ADDR.ARPA.");
++      *dstp = buf;
++      return strlen(buf) + 1;
++}
++
++/*
++ - reverse6 - IPv6 reverse-lookup conversion (RFC 1886)
++ * A trifle inefficient, really shouldn't use ultot...
++ */
++static size_t                 /* size of text, including NUL */
++reverse6(srcp, srclen, buf, dstp)
++const unsigned char *srcp;
++size_t srclen;
++char *buf;                    /* guaranteed large enough */
++char **dstp;                  /* where to put result pointer */
++{
++      int i;
++      unsigned long piece;
++      char *p;
++
++      if (srclen != IP6BYTES) /* "can't happen" */
++              return 0;
++      p = buf;
++      for (i = IP6BYTES-1; i >= 0; i--) {
++              piece = srcp[i];
++              p += ultot(piece&0xf, 16, p, 2);
++              *(p-1) = '.';
++              p += ultot(piece>>4, 16, p, 2);
++              *(p-1) = '.';
++      }
++      strcpy(p, "IP6.ARPA.");
++      *dstp = buf;
++      return strlen(buf) + 1;
++}
++
++/*
++ - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874)
++ * this version removed as it was obsoleted in the end.
++ */
++
++#ifdef ADDRTOT_MAIN
++
++#include <stdio.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++
++void regress(void);
++
++int
++main(int argc, char *argv[])
++{
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
++                                                              argv[0]);
++              exit(2);
++      }
++
++      if (strcmp(argv[1], "-r") == 0) {
++              regress();
++              fprintf(stderr, "regress() returned?!?\n");
++              exit(1);
++      }
++      exit(0);
++}
++
++struct rtab {
++      char *input;
++        char  format;
++      char *output;                   /* NULL means error expected */
++} rtab[] = {
++      {"1.2.3.0",                     0, "1.2.3.0"},
++      {"1:2::3:4",                    0, "1:2::3:4"},
++      {"1:2::3:4",                   'Q', "1:2:0:0:0:0:3:4"},
++      {"1:2:0:0:3:4:0:0",             0, "1:2::3:4:0:0"},
++      {"1.2.3.4",                    'r' , "4.3.2.1.IN-ADDR.ARPA."},
++      /*                                    0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */
++      {"1:2::3:4",                   'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."},
++       {NULL,                         0, NULL}
++};
++
++void
++regress()
++{
++      struct rtab *r;
++      int status = 0;
++      ip_address a;
++      char in[100];
++      char buf[100];
++      const char *oops;
++      size_t n;
++
++      for (r = rtab; r->input != NULL; r++) {
++              strcpy(in, r->input);
++
++              /* convert it *to* internal format */
++              oops = ttoaddr(in, strlen(in), 0, &a);
++
++              /* now convert it back */
++
++              n = addrtot(&a, r->format, buf, sizeof(buf));
++
++              if (n == 0 && r->output == NULL)
++                      {}              /* okay, error expected */
++              
++              else if (n == 0) {
++                      printf("`%s' atoasr failed\n", r->input);
++                      status = 1;
++                      
++              } else if (r->output == NULL) {
++                      printf("`%s' atoasr succeeded unexpectedly '%c'\n",
++                                                      r->input, r->format);
++                      status = 1;
++              } else {
++                if (strcasecmp(r->output, buf) != 0) {
++                  printf("`%s' '%c' gave `%s', expected `%s'\n",
++                         r->input, r->format, buf, r->output);
++                  status = 1;
++                }
++              }
++      }
++      exit(status);
++}
++
++#endif /* ADDRTOT_MAIN */
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/addrtypeof.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,123 @@
++/*
++ * extract parts of an ip_address
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: addrtypeof.c,v 1.10 2004/07/10 07:43:47 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - addrtypeof - get the type of an ip_address
++ */
++int
++addrtypeof(src)
++const ip_address *src;
++{
++      return src->u.v4.sin_family;
++}
++
++/*
++ - addrbytesptr - get pointer to the address bytes of an ip_address
++ */
++size_t                                /* 0 for error */
++addrbytesptr(src, dstp)
++const ip_address *src;
++const unsigned char **dstp;   /* NULL means just a size query */
++{
++      const unsigned char *p;
++      size_t n;
++
++      switch (src->u.v4.sin_family) {
++      case AF_INET:
++              p = (const unsigned char *)&src->u.v4.sin_addr.s_addr;
++              n = 4;
++              break;
++      case AF_INET6:
++              p = (const unsigned char *)&src->u.v6.sin6_addr;
++              n = 16;
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      if (dstp != NULL)
++              *dstp = p;
++      return n;
++
++}
++/*
++ - addrbytesptr - get pointer to the address bytes of an ip_address
++ */
++size_t                                /* 0 for error */
++addrbytesptr_write(src, dstp)
++ip_address *src;
++unsigned char **dstp; /* NULL means just a size query */
++{
++      unsigned char *p;
++      size_t n;
++
++      switch (src->u.v4.sin_family) {
++      case AF_INET:
++              p = (unsigned char *)&src->u.v4.sin_addr.s_addr;
++              n = 4;
++              break;
++      case AF_INET6:
++              p = (unsigned char *)&src->u.v6.sin6_addr;
++              n = 16;
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      if (dstp != NULL)
++              *dstp = p;
++      return n;
++}
++
++/*
++ - addrlenof - get length of the address bytes of an ip_address
++ */
++size_t                                /* 0 for error */
++addrlenof(src)
++const ip_address *src;
++{
++      return addrbytesptr(src, NULL);
++}
++
++/*
++ - addrbytesof - get the address bytes of an ip_address
++ */
++size_t                                /* 0 for error */
++addrbytesof(src, dst, dstlen)
++const ip_address *src;
++unsigned char *dst;
++size_t dstlen;
++{
++      const unsigned char *p;
++      size_t n;
++      size_t ncopy;
++
++      n = addrbytesptr(src, &p);
++      if (n == 0)
++              return 0;
++
++      if (dstlen > 0) {
++              ncopy = n;
++              if (ncopy > dstlen)
++                      ncopy = dstlen;
++              memcpy(dst, p, ncopy);
++      }
++      return n;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/adler32.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,49 @@
++/* adler32.c -- compute the Adler-32 checksum of a data stream
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* @(#) $Id: adler32.c,v 1.6 2004/07/10 19:11:18 mcr Exp $ */
++
++#include <zlib/zlib.h>
++#include <zlib/zconf.h>
++
++#define BASE 65521L /* largest prime smaller than 65536 */
++#define NMAX 5552
++/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
++
++#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
++#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
++#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
++#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
++#define DO16(buf)   DO8(buf,0); DO8(buf,8);
++
++/* ========================================================================= */
++uLong ZEXPORT adler32(adler, buf, len)
++    uLong adler;
++    const Bytef *buf;
++    uInt len;
++{
++    unsigned long s1 = adler & 0xffff;
++    unsigned long s2 = (adler >> 16) & 0xffff;
++    int k;
++
++    if (buf == Z_NULL) return 1L;
++
++    while (len > 0) {
++        k = len < NMAX ? len : NMAX;
++        len -= k;
++        while (k >= 16) {
++            DO16(buf);
++          buf += 16;
++            k -= 16;
++        }
++        if (k != 0) do {
++            s1 += *buf++;
++          s2 += s1;
++        } while (--k);
++        s1 %= BASE;
++        s2 %= BASE;
++    }
++    return (s2 << 16) | s1;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/Makefile     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,56 @@
++# Makefile for KLIPS 3DES kernel code as a module    for 2.6 kernels
++#
++# Makefile for KLIPS kernel code as a module
++# Copyright (C) 2002-2004     Michael Richardson <mcr@xelerance.com>
++# 
++# This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++# 
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++# for more details.
++#
++# RCSID $Id: Makefile.fs2_6,v 1.2 2005/08/12 14:13:58 mcr Exp $
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++obj-$(CONFIG_KLIPS_ENC_AES) += ipsec_alg_aes.o
++obj-$(CONFIG_KLIPS_ENC_AES) += aes_xcbc_mac.o
++obj-$(CONFIG_KLIPS_ENC_AES) += aes_cbc.o
++
++ifeq ($(strip ${SUBARCH}),)
++SUBARCH:=${ARCH}
++endif
++
++# the assembly version expects frame pointers, which are
++# optional in many kernel builds. If you want speed, you should
++# probably use cryptoapi code instead.
++USEASSEMBLY=${SUBARCH}${CONFIG_FRAME_POINTER}
++ifeq (${USEASSEMBLY},i386y)
++obj-$(CONFIG_KLIPS_ENC_AES) += aes-i586.o
++else
++obj-$(CONFIG_KLIPS_ENC_AES) += aes.o
++endif
++
++
++#
++# $Log: Makefile.fs2_6,v $
++# Revision 1.2  2005/08/12 14:13:58  mcr
++#     do not use assembly code with there are no frame pointers,
++#     as it does not have the right linkages.
++#
++# Revision 1.1  2004/08/17 03:31:34  mcr
++#     klips 2.6 edits.
++#
++#
++# Local Variables:
++# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
++# End Variables:
++#
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/aes-i586.S     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,892 @@
++//
++// Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
++// All rights reserved.
++//
++// TERMS
++//
++//  Redistribution and use in source and binary forms, with or without
++//  modification, are permitted subject to the following conditions:
++//
++//  1. Redistributions of source code must retain the above copyright
++//     notice, this list of conditions and the following disclaimer.
++//
++//  2. Redistributions in binary form must reproduce the above copyright
++//     notice, this list of conditions and the following disclaimer in the
++//     documentation and/or other materials provided with the distribution.
++//
++//  3. The copyright holder's name must not be used to endorse or promote
++//     any products derived from this software without his specific prior
++//     written permission.
++//
++//  This software is provided 'as is' with no express or implied warranties
++//  of correctness or fitness for purpose.
++
++// Modified by Jari Ruusu,  December 24 2001
++//  - Converted syntax to GNU CPP/assembler syntax
++//  - C programming interface converted back to "old" API
++//  - Minor portability cleanups and speed optimizations
++
++// An AES (Rijndael) implementation for the Pentium. This version only
++// implements the standard AES block length (128 bits, 16 bytes). This code
++// does not preserve the eax, ecx or edx registers or the artihmetic status
++// flags. However, the ebx, esi, edi, and ebp registers are preserved across
++// calls.
++
++// void aes_set_key(aes_context *cx, const unsigned char key[], const int key_len, const int f)
++// void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
++// void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
++
++#if defined(USE_UNDERLINE)
++# define aes_set_key _aes_set_key
++# define aes_encrypt _aes_encrypt
++# define aes_decrypt _aes_decrypt
++#endif
++#if !defined(ALIGN32BYTES)
++# define ALIGN32BYTES 32
++#endif
++
++      .file   "aes-i586.S"
++      .globl  aes_set_key
++      .globl  aes_encrypt
++      .globl  aes_decrypt
++
++#define tlen  1024    // length of each of 4 'xor' arrays (256 32-bit words)
++
++// offsets to parameters with one register pushed onto stack
++
++#define ctx   8       // AES context structure
++#define in_blk        12      // input byte array address parameter
++#define out_blk       16      // output byte array address parameter
++
++// offsets in context structure
++
++#define nkey  0       // key length, size 4
++#define nrnd  4       // number of rounds, size 4
++#define ekey  8       // encryption key schedule base address, size 256
++#define dkey  264     // decryption key schedule base address, size 256
++
++// This macro performs a forward encryption cycle. It is entered with
++// the first previous round column values in %eax, %ebx, %esi and %edi and
++// exits with the final values in the same registers.
++
++#define fwd_rnd(p1,p2)                         \
++      mov     %ebx,(%esp)             ;\
++      movzbl  %al,%edx                ;\
++      mov     %eax,%ecx               ;\
++      mov     p2(%ebp),%eax           ;\
++      mov     %edi,4(%esp)            ;\
++      mov     p2+12(%ebp),%edi        ;\
++      xor     p1(,%edx,4),%eax        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      mov     p2+4(%ebp),%ebx         ;\
++      xor     p1+tlen(,%edx,4),%edi   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+3*tlen(,%ecx,4),%ebx ;\
++      mov     %esi,%ecx               ;\
++      mov     p1+2*tlen(,%edx,4),%esi ;\
++      movzbl  %cl,%edx                ;\
++      xor     p1(,%edx,4),%esi        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      xor     p1+tlen(,%edx,4),%ebx   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+2*tlen(,%edx,4),%eax ;\
++      mov     (%esp),%edx             ;\
++      xor     p1+3*tlen(,%ecx,4),%edi ;\
++      movzbl  %dl,%ecx                ;\
++      xor     p2+8(%ebp),%esi         ;\
++      xor     p1(,%ecx,4),%ebx        ;\
++      movzbl  %dh,%ecx                ;\
++      shr     $16,%edx                ;\
++      xor     p1+tlen(,%ecx,4),%eax   ;\
++      movzbl  %dl,%ecx                ;\
++      movzbl  %dh,%edx                ;\
++      xor     p1+2*tlen(,%ecx,4),%edi ;\
++      mov     4(%esp),%ecx            ;\
++      xor     p1+3*tlen(,%edx,4),%esi ;\
++      movzbl  %cl,%edx                ;\
++      xor     p1(,%edx,4),%edi        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      xor     p1+tlen(,%edx,4),%esi   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+2*tlen(,%edx,4),%ebx ;\
++      xor     p1+3*tlen(,%ecx,4),%eax
++
++// This macro performs an inverse encryption cycle. It is entered with
++// the first previous round column values in %eax, %ebx, %esi and %edi and
++// exits with the final values in the same registers.
++
++#define inv_rnd(p1,p2)                         \
++      movzbl  %al,%edx                ;\
++      mov     %ebx,(%esp)             ;\
++      mov     %eax,%ecx               ;\
++      mov     p2(%ebp),%eax           ;\
++      mov     %edi,4(%esp)            ;\
++      mov     p2+4(%ebp),%ebx         ;\
++      xor     p1(,%edx,4),%eax        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      mov     p2+12(%ebp),%edi        ;\
++      xor     p1+tlen(,%edx,4),%ebx   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+3*tlen(,%ecx,4),%edi ;\
++      mov     %esi,%ecx               ;\
++      mov     p1+2*tlen(,%edx,4),%esi ;\
++      movzbl  %cl,%edx                ;\
++      xor     p1(,%edx,4),%esi        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      xor     p1+tlen(,%edx,4),%edi   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+2*tlen(,%edx,4),%eax ;\
++      mov     (%esp),%edx             ;\
++      xor     p1+3*tlen(,%ecx,4),%ebx ;\
++      movzbl  %dl,%ecx                ;\
++      xor     p2+8(%ebp),%esi         ;\
++      xor     p1(,%ecx,4),%ebx        ;\
++      movzbl  %dh,%ecx                ;\
++      shr     $16,%edx                ;\
++      xor     p1+tlen(,%ecx,4),%esi   ;\
++      movzbl  %dl,%ecx                ;\
++      movzbl  %dh,%edx                ;\
++      xor     p1+2*tlen(,%ecx,4),%edi ;\
++      mov     4(%esp),%ecx            ;\
++      xor     p1+3*tlen(,%edx,4),%eax ;\
++      movzbl  %cl,%edx                ;\
++      xor     p1(,%edx,4),%edi        ;\
++      movzbl  %ch,%edx                ;\
++      shr     $16,%ecx                ;\
++      xor     p1+tlen(,%edx,4),%eax   ;\
++      movzbl  %cl,%edx                ;\
++      movzbl  %ch,%ecx                ;\
++      xor     p1+2*tlen(,%edx,4),%ebx ;\
++      xor     p1+3*tlen(,%ecx,4),%esi
++
++// AES (Rijndael) Encryption Subroutine
++
++      .text
++      .align  ALIGN32BYTES
++aes_encrypt:
++      push    %ebp
++      mov     ctx(%esp),%ebp          // pointer to context
++      mov     in_blk(%esp),%ecx
++      push    %ebx
++      push    %esi
++      push    %edi
++      mov     nrnd(%ebp),%edx         // number of rounds
++      lea     ekey+16(%ebp),%ebp      // key pointer
++
++// input four columns and xor in first round key
++
++      mov     (%ecx),%eax
++      mov     4(%ecx),%ebx
++      mov     8(%ecx),%esi
++      mov     12(%ecx),%edi
++      xor     -16(%ebp),%eax
++      xor     -12(%ebp),%ebx
++      xor     -8(%ebp),%esi
++      xor     -4(%ebp),%edi
++
++      sub     $8,%esp                 // space for register saves on stack
++
++      sub     $10,%edx
++      je      aes_15
++      add     $32,%ebp
++      sub     $2,%edx
++      je      aes_13
++      add     $32,%ebp
++
++      fwd_rnd(aes_ft_tab,-64)         // 14 rounds for 256-bit key
++      fwd_rnd(aes_ft_tab,-48)
++aes_13:       fwd_rnd(aes_ft_tab,-32)         // 12 rounds for 192-bit key
++      fwd_rnd(aes_ft_tab,-16)
++aes_15:       fwd_rnd(aes_ft_tab,0)           // 10 rounds for 128-bit key
++      fwd_rnd(aes_ft_tab,16)
++      fwd_rnd(aes_ft_tab,32)
++      fwd_rnd(aes_ft_tab,48)
++      fwd_rnd(aes_ft_tab,64)
++      fwd_rnd(aes_ft_tab,80)
++      fwd_rnd(aes_ft_tab,96)
++      fwd_rnd(aes_ft_tab,112)
++      fwd_rnd(aes_ft_tab,128)
++      fwd_rnd(aes_fl_tab,144)         // last round uses a different table
++
++// move final values to the output array.
++
++      mov     out_blk+20(%esp),%ebp
++      add     $8,%esp
++      mov     %eax,(%ebp)
++      mov     %ebx,4(%ebp)
++      mov     %esi,8(%ebp)
++      mov     %edi,12(%ebp)
++      pop     %edi
++      pop     %esi
++      pop     %ebx
++      pop     %ebp
++      ret
++
++
++// AES (Rijndael) Decryption Subroutine
++
++      .align  ALIGN32BYTES
++aes_decrypt:
++      push    %ebp
++      mov     ctx(%esp),%ebp          // pointer to context
++      mov     in_blk(%esp),%ecx
++      push    %ebx
++      push    %esi
++      push    %edi
++      mov     nrnd(%ebp),%edx         // number of rounds
++      lea     dkey+16(%ebp),%ebp      // key pointer
++
++// input four columns and xor in first round key
++
++      mov     (%ecx),%eax
++      mov     4(%ecx),%ebx
++      mov     8(%ecx),%esi
++      mov     12(%ecx),%edi
++      xor     -16(%ebp),%eax
++      xor     -12(%ebp),%ebx
++      xor     -8(%ebp),%esi
++      xor     -4(%ebp),%edi
++
++      sub     $8,%esp                 // space for register saves on stack
++
++      sub     $10,%edx
++      je      aes_25
++      add     $32,%ebp
++      sub     $2,%edx
++      je      aes_23
++      add     $32,%ebp
++
++      inv_rnd(aes_it_tab,-64)         // 14 rounds for 256-bit key
++      inv_rnd(aes_it_tab,-48)
++aes_23:       inv_rnd(aes_it_tab,-32)         // 12 rounds for 192-bit key
++      inv_rnd(aes_it_tab,-16)
++aes_25:       inv_rnd(aes_it_tab,0)           // 10 rounds for 128-bit key
++      inv_rnd(aes_it_tab,16)
++      inv_rnd(aes_it_tab,32)
++      inv_rnd(aes_it_tab,48)
++      inv_rnd(aes_it_tab,64)
++      inv_rnd(aes_it_tab,80)
++      inv_rnd(aes_it_tab,96)
++      inv_rnd(aes_it_tab,112)
++      inv_rnd(aes_it_tab,128)
++      inv_rnd(aes_il_tab,144)         // last round uses a different table
++
++// move final values to the output array.
++
++      mov     out_blk+20(%esp),%ebp
++      add     $8,%esp
++      mov     %eax,(%ebp)
++      mov     %ebx,4(%ebp)
++      mov     %esi,8(%ebp)
++      mov     %edi,12(%ebp)
++      pop     %edi
++      pop     %esi
++      pop     %ebx
++      pop     %ebp
++      ret
++
++// AES (Rijndael) Key Schedule Subroutine
++
++// input/output parameters
++
++#define aes_cx        12      // AES context
++#define in_key        16      // key input array address
++#define key_ln        20      // key length, bytes (16,24,32) or bits (128,192,256)
++#define ed_flg        24      // 0=create both encr/decr keys, 1=create encr key only
++
++// offsets for locals
++
++#define cnt   -4
++#define kpf   -8
++#define slen  8
++
++// This macro performs a column mixing operation on an input 32-bit
++// word to give a 32-bit result. It uses each of the 4 bytes in the
++// the input column to index 4 different tables of 256 32-bit words
++// that are xored together to form the output value.
++
++#define mix_col(p1)                    \
++      movzbl  %bl,%ecx                ;\
++      mov     p1(,%ecx,4),%eax        ;\
++      movzbl  %bh,%ecx                ;\
++      ror     $16,%ebx                ;\
++      xor     p1+tlen(,%ecx,4),%eax   ;\
++      movzbl  %bl,%ecx                ;\
++      xor     p1+2*tlen(,%ecx,4),%eax ;\
++      movzbl  %bh,%ecx                ;\
++      xor     p1+3*tlen(,%ecx,4),%eax
++
++// Key Schedule Macros
++
++#define ksc4(p1)                       \
++      rol     $24,%ebx                ;\
++      mix_col(aes_fl_tab)             ;\
++      ror     $8,%ebx                 ;\
++      xor     4*p1+aes_rcon_tab,%eax  ;\
++      xor     %eax,%esi               ;\
++      xor     %esi,%ebp               ;\
++      mov     %esi,16*p1(%edi)        ;\
++      mov     %ebp,16*p1+4(%edi)      ;\
++      xor     %ebp,%edx               ;\
++      xor     %edx,%ebx               ;\
++      mov     %edx,16*p1+8(%edi)      ;\
++      mov     %ebx,16*p1+12(%edi)
++
++#define ksc6(p1)                       \
++      rol     $24,%ebx                ;\
++      mix_col(aes_fl_tab)             ;\
++      ror     $8,%ebx                 ;\
++      xor     4*p1+aes_rcon_tab,%eax  ;\
++      xor     24*p1-24(%edi),%eax     ;\
++      mov     %eax,24*p1(%edi)        ;\
++      xor     24*p1-20(%edi),%eax     ;\
++      mov     %eax,24*p1+4(%edi)      ;\
++      xor     %eax,%esi               ;\
++      xor     %esi,%ebp               ;\
++      mov     %esi,24*p1+8(%edi)      ;\
++      mov     %ebp,24*p1+12(%edi)     ;\
++      xor     %ebp,%edx               ;\
++      xor     %edx,%ebx               ;\
++      mov     %edx,24*p1+16(%edi)     ;\
++      mov     %ebx,24*p1+20(%edi)
++
++#define ksc8(p1)                       \
++      rol     $24,%ebx                ;\
++      mix_col(aes_fl_tab)             ;\
++      ror     $8,%ebx                 ;\
++      xor     4*p1+aes_rcon_tab,%eax  ;\
++      xor     32*p1-32(%edi),%eax     ;\
++      mov     %eax,32*p1(%edi)        ;\
++      xor     32*p1-28(%edi),%eax     ;\
++      mov     %eax,32*p1+4(%edi)      ;\
++      xor     32*p1-24(%edi),%eax     ;\
++      mov     %eax,32*p1+8(%edi)      ;\
++      xor     32*p1-20(%edi),%eax     ;\
++      mov     %eax,32*p1+12(%edi)     ;\
++      push    %ebx                    ;\
++      mov     %eax,%ebx               ;\
++      mix_col(aes_fl_tab)             ;\
++      pop     %ebx                    ;\
++      xor     %eax,%esi               ;\
++      xor     %esi,%ebp               ;\
++      mov     %esi,32*p1+16(%edi)     ;\
++      mov     %ebp,32*p1+20(%edi)     ;\
++      xor     %ebp,%edx               ;\
++      xor     %edx,%ebx               ;\
++      mov     %edx,32*p1+24(%edi)     ;\
++      mov     %ebx,32*p1+28(%edi)
++
++      .align  ALIGN32BYTES
++aes_set_key:
++      pushfl
++      push    %ebp
++      mov     %esp,%ebp
++      sub     $slen,%esp
++      push    %ebx
++      push    %esi
++      push    %edi
++
++      mov     aes_cx(%ebp),%edx       // edx -> AES context
++
++      mov     key_ln(%ebp),%ecx       // key length
++      cmpl    $128,%ecx
++      jb      aes_30
++      shr     $3,%ecx
++aes_30:       cmpl    $32,%ecx
++      je      aes_32
++      cmpl    $24,%ecx
++      je      aes_32
++      mov     $16,%ecx
++aes_32:       shr     $2,%ecx
++      mov     %ecx,nkey(%edx)
++
++      lea     6(%ecx),%eax            // 10/12/14 for 4/6/8 32-bit key length
++      mov     %eax,nrnd(%edx)
++
++      mov     in_key(%ebp),%esi       // key input array
++      lea     ekey(%edx),%edi         // key position in AES context
++      cld
++      push    %ebp
++      mov     %ecx,%eax               // save key length in eax
++      rep ;   movsl                   // words in the key schedule
++      mov     -4(%esi),%ebx           // put some values in registers
++      mov     -8(%esi),%edx           // to allow faster code
++      mov     -12(%esi),%ebp
++      mov     -16(%esi),%esi
++
++      cmpl    $4,%eax                 // jump on key size
++      je      aes_36
++      cmpl    $6,%eax
++      je      aes_35
++
++      ksc8(0)
++      ksc8(1)
++      ksc8(2)
++      ksc8(3)
++      ksc8(4)
++      ksc8(5)
++      ksc8(6)
++      jmp     aes_37
++aes_35:       ksc6(0)
++      ksc6(1)
++      ksc6(2)
++      ksc6(3)
++      ksc6(4)
++      ksc6(5)
++      ksc6(6)
++      ksc6(7)
++      jmp     aes_37
++aes_36:       ksc4(0)
++      ksc4(1)
++      ksc4(2)
++      ksc4(3)
++      ksc4(4)
++      ksc4(5)
++      ksc4(6)
++      ksc4(7)
++      ksc4(8)
++      ksc4(9)
++aes_37:       pop     %ebp
++      mov     aes_cx(%ebp),%edx       // edx -> AES context
++      cmpl    $0,ed_flg(%ebp)
++      jne     aes_39
++
++// compile decryption key schedule from encryption schedule - reverse
++// order and do mix_column operation on round keys except first and last
++
++      mov     nrnd(%edx),%eax         // kt = cx->d_key + nc * cx->Nrnd
++      shl     $2,%eax
++      lea     dkey(%edx,%eax,4),%edi
++      lea     ekey(%edx),%esi         // kf = cx->e_key
++
++      movsl                           // copy first round key (unmodified)
++      movsl
++      movsl
++      movsl
++      sub     $32,%edi
++      movl    $1,cnt(%ebp)
++aes_38:                                       // do mix column on each column of
++      lodsl                           // each round key
++      mov     %eax,%ebx
++      mix_col(aes_im_tab)
++      stosl
++      lodsl
++      mov     %eax,%ebx
++      mix_col(aes_im_tab)
++      stosl
++      lodsl
++      mov     %eax,%ebx
++      mix_col(aes_im_tab)
++      stosl
++      lodsl
++      mov     %eax,%ebx
++      mix_col(aes_im_tab)
++      stosl
++      sub     $32,%edi
++
++      incl    cnt(%ebp)
++      mov     cnt(%ebp),%eax
++      cmp     nrnd(%edx),%eax
++      jb      aes_38
++
++      movsl                           // copy last round key (unmodified)
++      movsl
++      movsl
++      movsl
++aes_39:       pop     %edi
++      pop     %esi
++      pop     %ebx
++      mov     %ebp,%esp
++      pop     %ebp
++      popfl
++      ret
++
++
++// finite field multiplies by {02}, {04} and {08}
++
++#define f2(x) ((x<<1)^(((x>>7)&1)*0x11b))
++#define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b))
++#define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b))
++
++// finite field multiplies required in table generation
++
++#define f3(x) (f2(x) ^ x)
++#define f9(x) (f8(x) ^ x)
++#define fb(x) (f8(x) ^ f2(x) ^ x)
++#define fd(x) (f8(x) ^ f4(x) ^ x)
++#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
++
++// These defines generate the forward table entries
++
++#define u0(x) ((f3(x) << 24) | (x << 16) | (x << 8) | f2(x))
++#define u1(x) ((x << 24) | (x << 16) | (f2(x) << 8) | f3(x))
++#define u2(x) ((x << 24) | (f2(x) << 16) | (f3(x) << 8) | x)
++#define u3(x) ((f2(x) << 24) | (f3(x) << 16) | (x << 8) | x)
++
++// These defines generate the inverse table entries
++
++#define v0(x) ((fb(x) << 24) | (fd(x) << 16) | (f9(x) << 8) | fe(x))
++#define v1(x) ((fd(x) << 24) | (f9(x) << 16) | (fe(x) << 8) | fb(x))
++#define v2(x) ((f9(x) << 24) | (fe(x) << 16) | (fb(x) << 8) | fd(x))
++#define v3(x) ((fe(x) << 24) | (fb(x) << 16) | (fd(x) << 8) | f9(x))
++
++// These defines generate entries for the last round tables
++
++#define w0(x) (x)
++#define w1(x) (x <<  8)
++#define w2(x) (x << 16)
++#define w3(x) (x << 24)
++
++// macro to generate inverse mix column tables (needed for the key schedule)
++
++#define im_data0(p1) \
++      .long   p1(0x00),p1(0x01),p1(0x02),p1(0x03),p1(0x04),p1(0x05),p1(0x06),p1(0x07) ;\
++      .long   p1(0x08),p1(0x09),p1(0x0a),p1(0x0b),p1(0x0c),p1(0x0d),p1(0x0e),p1(0x0f) ;\
++      .long   p1(0x10),p1(0x11),p1(0x12),p1(0x13),p1(0x14),p1(0x15),p1(0x16),p1(0x17) ;\
++      .long   p1(0x18),p1(0x19),p1(0x1a),p1(0x1b),p1(0x1c),p1(0x1d),p1(0x1e),p1(0x1f)
++#define im_data1(p1) \
++      .long   p1(0x20),p1(0x21),p1(0x22),p1(0x23),p1(0x24),p1(0x25),p1(0x26),p1(0x27) ;\
++      .long   p1(0x28),p1(0x29),p1(0x2a),p1(0x2b),p1(0x2c),p1(0x2d),p1(0x2e),p1(0x2f) ;\
++      .long   p1(0x30),p1(0x31),p1(0x32),p1(0x33),p1(0x34),p1(0x35),p1(0x36),p1(0x37) ;\
++      .long   p1(0x38),p1(0x39),p1(0x3a),p1(0x3b),p1(0x3c),p1(0x3d),p1(0x3e),p1(0x3f)
++#define im_data2(p1) \
++      .long   p1(0x40),p1(0x41),p1(0x42),p1(0x43),p1(0x44),p1(0x45),p1(0x46),p1(0x47) ;\
++      .long   p1(0x48),p1(0x49),p1(0x4a),p1(0x4b),p1(0x4c),p1(0x4d),p1(0x4e),p1(0x4f) ;\
++      .long   p1(0x50),p1(0x51),p1(0x52),p1(0x53),p1(0x54),p1(0x55),p1(0x56),p1(0x57) ;\
++      .long   p1(0x58),p1(0x59),p1(0x5a),p1(0x5b),p1(0x5c),p1(0x5d),p1(0x5e),p1(0x5f)
++#define im_data3(p1) \
++      .long   p1(0x60),p1(0x61),p1(0x62),p1(0x63),p1(0x64),p1(0x65),p1(0x66),p1(0x67) ;\
++      .long   p1(0x68),p1(0x69),p1(0x6a),p1(0x6b),p1(0x6c),p1(0x6d),p1(0x6e),p1(0x6f) ;\
++      .long   p1(0x70),p1(0x71),p1(0x72),p1(0x73),p1(0x74),p1(0x75),p1(0x76),p1(0x77) ;\
++      .long   p1(0x78),p1(0x79),p1(0x7a),p1(0x7b),p1(0x7c),p1(0x7d),p1(0x7e),p1(0x7f)
++#define im_data4(p1) \
++      .long   p1(0x80),p1(0x81),p1(0x82),p1(0x83),p1(0x84),p1(0x85),p1(0x86),p1(0x87) ;\
++      .long   p1(0x88),p1(0x89),p1(0x8a),p1(0x8b),p1(0x8c),p1(0x8d),p1(0x8e),p1(0x8f) ;\
++      .long   p1(0x90),p1(0x91),p1(0x92),p1(0x93),p1(0x94),p1(0x95),p1(0x96),p1(0x97) ;\
++      .long   p1(0x98),p1(0x99),p1(0x9a),p1(0x9b),p1(0x9c),p1(0x9d),p1(0x9e),p1(0x9f)
++#define im_data5(p1) \
++      .long   p1(0xa0),p1(0xa1),p1(0xa2),p1(0xa3),p1(0xa4),p1(0xa5),p1(0xa6),p1(0xa7) ;\
++      .long   p1(0xa8),p1(0xa9),p1(0xaa),p1(0xab),p1(0xac),p1(0xad),p1(0xae),p1(0xaf) ;\
++      .long   p1(0xb0),p1(0xb1),p1(0xb2),p1(0xb3),p1(0xb4),p1(0xb5),p1(0xb6),p1(0xb7) ;\
++      .long   p1(0xb8),p1(0xb9),p1(0xba),p1(0xbb),p1(0xbc),p1(0xbd),p1(0xbe),p1(0xbf)
++#define im_data6(p1) \
++      .long   p1(0xc0),p1(0xc1),p1(0xc2),p1(0xc3),p1(0xc4),p1(0xc5),p1(0xc6),p1(0xc7) ;\
++      .long   p1(0xc8),p1(0xc9),p1(0xca),p1(0xcb),p1(0xcc),p1(0xcd),p1(0xce),p1(0xcf) ;\
++      .long   p1(0xd0),p1(0xd1),p1(0xd2),p1(0xd3),p1(0xd4),p1(0xd5),p1(0xd6),p1(0xd7) ;\
++      .long   p1(0xd8),p1(0xd9),p1(0xda),p1(0xdb),p1(0xdc),p1(0xdd),p1(0xde),p1(0xdf)
++#define im_data7(p1) \
++      .long   p1(0xe0),p1(0xe1),p1(0xe2),p1(0xe3),p1(0xe4),p1(0xe5),p1(0xe6),p1(0xe7) ;\
++      .long   p1(0xe8),p1(0xe9),p1(0xea),p1(0xeb),p1(0xec),p1(0xed),p1(0xee),p1(0xef) ;\
++      .long   p1(0xf0),p1(0xf1),p1(0xf2),p1(0xf3),p1(0xf4),p1(0xf5),p1(0xf6),p1(0xf7) ;\
++      .long   p1(0xf8),p1(0xf9),p1(0xfa),p1(0xfb),p1(0xfc),p1(0xfd),p1(0xfe),p1(0xff)
++
++// S-box data - 256 entries
++
++#define sb_data0(p1) \
++      .long   p1(0x63),p1(0x7c),p1(0x77),p1(0x7b),p1(0xf2),p1(0x6b),p1(0x6f),p1(0xc5) ;\
++      .long   p1(0x30),p1(0x01),p1(0x67),p1(0x2b),p1(0xfe),p1(0xd7),p1(0xab),p1(0x76) ;\
++      .long   p1(0xca),p1(0x82),p1(0xc9),p1(0x7d),p1(0xfa),p1(0x59),p1(0x47),p1(0xf0) ;\
++      .long   p1(0xad),p1(0xd4),p1(0xa2),p1(0xaf),p1(0x9c),p1(0xa4),p1(0x72),p1(0xc0)
++#define sb_data1(p1) \
++      .long   p1(0xb7),p1(0xfd),p1(0x93),p1(0x26),p1(0x36),p1(0x3f),p1(0xf7),p1(0xcc) ;\
++      .long   p1(0x34),p1(0xa5),p1(0xe5),p1(0xf1),p1(0x71),p1(0xd8),p1(0x31),p1(0x15) ;\
++      .long   p1(0x04),p1(0xc7),p1(0x23),p1(0xc3),p1(0x18),p1(0x96),p1(0x05),p1(0x9a) ;\
++      .long   p1(0x07),p1(0x12),p1(0x80),p1(0xe2),p1(0xeb),p1(0x27),p1(0xb2),p1(0x75)
++#define sb_data2(p1) \
++      .long   p1(0x09),p1(0x83),p1(0x2c),p1(0x1a),p1(0x1b),p1(0x6e),p1(0x5a),p1(0xa0) ;\
++      .long   p1(0x52),p1(0x3b),p1(0xd6),p1(0xb3),p1(0x29),p1(0xe3),p1(0x2f),p1(0x84) ;\
++      .long   p1(0x53),p1(0xd1),p1(0x00),p1(0xed),p1(0x20),p1(0xfc),p1(0xb1),p1(0x5b) ;\
++      .long   p1(0x6a),p1(0xcb),p1(0xbe),p1(0x39),p1(0x4a),p1(0x4c),p1(0x58),p1(0xcf)
++#define sb_data3(p1) \
++      .long   p1(0xd0),p1(0xef),p1(0xaa),p1(0xfb),p1(0x43),p1(0x4d),p1(0x33),p1(0x85) ;\
++      .long   p1(0x45),p1(0xf9),p1(0x02),p1(0x7f),p1(0x50),p1(0x3c),p1(0x9f),p1(0xa8) ;\
++      .long   p1(0x51),p1(0xa3),p1(0x40),p1(0x8f),p1(0x92),p1(0x9d),p1(0x38),p1(0xf5) ;\
++      .long   p1(0xbc),p1(0xb6),p1(0xda),p1(0x21),p1(0x10),p1(0xff),p1(0xf3),p1(0xd2)
++#define sb_data4(p1) \
++      .long   p1(0xcd),p1(0x0c),p1(0x13),p1(0xec),p1(0x5f),p1(0x97),p1(0x44),p1(0x17) ;\
++      .long   p1(0xc4),p1(0xa7),p1(0x7e),p1(0x3d),p1(0x64),p1(0x5d),p1(0x19),p1(0x73) ;\
++      .long   p1(0x60),p1(0x81),p1(0x4f),p1(0xdc),p1(0x22),p1(0x2a),p1(0x90),p1(0x88) ;\
++      .long   p1(0x46),p1(0xee),p1(0xb8),p1(0x14),p1(0xde),p1(0x5e),p1(0x0b),p1(0xdb)
++#define sb_data5(p1) \
++      .long   p1(0xe0),p1(0x32),p1(0x3a),p1(0x0a),p1(0x49),p1(0x06),p1(0x24),p1(0x5c) ;\
++      .long   p1(0xc2),p1(0xd3),p1(0xac),p1(0x62),p1(0x91),p1(0x95),p1(0xe4),p1(0x79) ;\
++      .long   p1(0xe7),p1(0xc8),p1(0x37),p1(0x6d),p1(0x8d),p1(0xd5),p1(0x4e),p1(0xa9) ;\
++      .long   p1(0x6c),p1(0x56),p1(0xf4),p1(0xea),p1(0x65),p1(0x7a),p1(0xae),p1(0x08)
++#define sb_data6(p1) \
++      .long   p1(0xba),p1(0x78),p1(0x25),p1(0x2e),p1(0x1c),p1(0xa6),p1(0xb4),p1(0xc6) ;\
++      .long   p1(0xe8),p1(0xdd),p1(0x74),p1(0x1f),p1(0x4b),p1(0xbd),p1(0x8b),p1(0x8a) ;\
++      .long   p1(0x70),p1(0x3e),p1(0xb5),p1(0x66),p1(0x48),p1(0x03),p1(0xf6),p1(0x0e) ;\
++      .long   p1(0x61),p1(0x35),p1(0x57),p1(0xb9),p1(0x86),p1(0xc1),p1(0x1d),p1(0x9e)
++#define sb_data7(p1) \
++      .long   p1(0xe1),p1(0xf8),p1(0x98),p1(0x11),p1(0x69),p1(0xd9),p1(0x8e),p1(0x94) ;\
++      .long   p1(0x9b),p1(0x1e),p1(0x87),p1(0xe9),p1(0xce),p1(0x55),p1(0x28),p1(0xdf) ;\
++      .long   p1(0x8c),p1(0xa1),p1(0x89),p1(0x0d),p1(0xbf),p1(0xe6),p1(0x42),p1(0x68) ;\
++      .long   p1(0x41),p1(0x99),p1(0x2d),p1(0x0f),p1(0xb0),p1(0x54),p1(0xbb),p1(0x16)
++
++// Inverse S-box data - 256 entries
++
++#define ib_data0(p1) \
++      .long   p1(0x52),p1(0x09),p1(0x6a),p1(0xd5),p1(0x30),p1(0x36),p1(0xa5),p1(0x38) ;\
++      .long   p1(0xbf),p1(0x40),p1(0xa3),p1(0x9e),p1(0x81),p1(0xf3),p1(0xd7),p1(0xfb) ;\
++      .long   p1(0x7c),p1(0xe3),p1(0x39),p1(0x82),p1(0x9b),p1(0x2f),p1(0xff),p1(0x87) ;\
++      .long   p1(0x34),p1(0x8e),p1(0x43),p1(0x44),p1(0xc4),p1(0xde),p1(0xe9),p1(0xcb)
++#define ib_data1(p1) \
++      .long   p1(0x54),p1(0x7b),p1(0x94),p1(0x32),p1(0xa6),p1(0xc2),p1(0x23),p1(0x3d) ;\
++      .long   p1(0xee),p1(0x4c),p1(0x95),p1(0x0b),p1(0x42),p1(0xfa),p1(0xc3),p1(0x4e) ;\
++      .long   p1(0x08),p1(0x2e),p1(0xa1),p1(0x66),p1(0x28),p1(0xd9),p1(0x24),p1(0xb2) ;\
++      .long   p1(0x76),p1(0x5b),p1(0xa2),p1(0x49),p1(0x6d),p1(0x8b),p1(0xd1),p1(0x25)
++#define ib_data2(p1) \
++      .long   p1(0x72),p1(0xf8),p1(0xf6),p1(0x64),p1(0x86),p1(0x68),p1(0x98),p1(0x16) ;\
++      .long   p1(0xd4),p1(0xa4),p1(0x5c),p1(0xcc),p1(0x5d),p1(0x65),p1(0xb6),p1(0x92) ;\
++      .long   p1(0x6c),p1(0x70),p1(0x48),p1(0x50),p1(0xfd),p1(0xed),p1(0xb9),p1(0xda) ;\
++      .long   p1(0x5e),p1(0x15),p1(0x46),p1(0x57),p1(0xa7),p1(0x8d),p1(0x9d),p1(0x84)
++#define ib_data3(p1) \
++      .long   p1(0x90),p1(0xd8),p1(0xab),p1(0x00),p1(0x8c),p1(0xbc),p1(0xd3),p1(0x0a) ;\
++      .long   p1(0xf7),p1(0xe4),p1(0x58),p1(0x05),p1(0xb8),p1(0xb3),p1(0x45),p1(0x06) ;\
++      .long   p1(0xd0),p1(0x2c),p1(0x1e),p1(0x8f),p1(0xca),p1(0x3f),p1(0x0f),p1(0x02) ;\
++      .long   p1(0xc1),p1(0xaf),p1(0xbd),p1(0x03),p1(0x01),p1(0x13),p1(0x8a),p1(0x6b)
++#define ib_data4(p1) \
++      .long   p1(0x3a),p1(0x91),p1(0x11),p1(0x41),p1(0x4f),p1(0x67),p1(0xdc),p1(0xea) ;\
++      .long   p1(0x97),p1(0xf2),p1(0xcf),p1(0xce),p1(0xf0),p1(0xb4),p1(0xe6),p1(0x73) ;\
++      .long   p1(0x96),p1(0xac),p1(0x74),p1(0x22),p1(0xe7),p1(0xad),p1(0x35),p1(0x85) ;\
++      .long   p1(0xe2),p1(0xf9),p1(0x37),p1(0xe8),p1(0x1c),p1(0x75),p1(0xdf),p1(0x6e)
++#define ib_data5(p1) \
++      .long   p1(0x47),p1(0xf1),p1(0x1a),p1(0x71),p1(0x1d),p1(0x29),p1(0xc5),p1(0x89) ;\
++      .long   p1(0x6f),p1(0xb7),p1(0x62),p1(0x0e),p1(0xaa),p1(0x18),p1(0xbe),p1(0x1b) ;\
++      .long   p1(0xfc),p1(0x56),p1(0x3e),p1(0x4b),p1(0xc6),p1(0xd2),p1(0x79),p1(0x20) ;\
++      .long   p1(0x9a),p1(0xdb),p1(0xc0),p1(0xfe),p1(0x78),p1(0xcd),p1(0x5a),p1(0xf4)
++#define ib_data6(p1) \
++      .long   p1(0x1f),p1(0xdd),p1(0xa8),p1(0x33),p1(0x88),p1(0x07),p1(0xc7),p1(0x31) ;\
++      .long   p1(0xb1),p1(0x12),p1(0x10),p1(0x59),p1(0x27),p1(0x80),p1(0xec),p1(0x5f) ;\
++      .long   p1(0x60),p1(0x51),p1(0x7f),p1(0xa9),p1(0x19),p1(0xb5),p1(0x4a),p1(0x0d) ;\
++      .long   p1(0x2d),p1(0xe5),p1(0x7a),p1(0x9f),p1(0x93),p1(0xc9),p1(0x9c),p1(0xef)
++#define ib_data7(p1) \
++      .long   p1(0xa0),p1(0xe0),p1(0x3b),p1(0x4d),p1(0xae),p1(0x2a),p1(0xf5),p1(0xb0) ;\
++      .long   p1(0xc8),p1(0xeb),p1(0xbb),p1(0x3c),p1(0x83),p1(0x53),p1(0x99),p1(0x61) ;\
++      .long   p1(0x17),p1(0x2b),p1(0x04),p1(0x7e),p1(0xba),p1(0x77),p1(0xd6),p1(0x26) ;\
++      .long   p1(0xe1),p1(0x69),p1(0x14),p1(0x63),p1(0x55),p1(0x21),p1(0x0c),p1(0x7d)
++
++// The rcon_table (needed for the key schedule)
++//
++// Here is original Dr Brian Gladman's source code:
++//    _rcon_tab:
++//    %assign x   1
++//    %rep 29
++//        dd  x
++//    %assign x f2(x)
++//    %endrep
++//
++// Here is precomputed output (it's more portable this way):
++
++      .align  ALIGN32BYTES
++aes_rcon_tab:
++      .long   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
++      .long   0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f
++      .long   0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4
++      .long   0xb3,0x7d,0xfa,0xef,0xc5
++
++// The forward xor tables
++
++      .align  ALIGN32BYTES
++aes_ft_tab:
++      sb_data0(u0)
++      sb_data1(u0)
++      sb_data2(u0)
++      sb_data3(u0)
++      sb_data4(u0)
++      sb_data5(u0)
++      sb_data6(u0)
++      sb_data7(u0)
++
++      sb_data0(u1)
++      sb_data1(u1)
++      sb_data2(u1)
++      sb_data3(u1)
++      sb_data4(u1)
++      sb_data5(u1)
++      sb_data6(u1)
++      sb_data7(u1)
++
++      sb_data0(u2)
++      sb_data1(u2)
++      sb_data2(u2)
++      sb_data3(u2)
++      sb_data4(u2)
++      sb_data5(u2)
++      sb_data6(u2)
++      sb_data7(u2)
++
++      sb_data0(u3)
++      sb_data1(u3)
++      sb_data2(u3)
++      sb_data3(u3)
++      sb_data4(u3)
++      sb_data5(u3)
++      sb_data6(u3)
++      sb_data7(u3)
++
++      .align  ALIGN32BYTES
++aes_fl_tab:
++      sb_data0(w0)
++      sb_data1(w0)
++      sb_data2(w0)
++      sb_data3(w0)
++      sb_data4(w0)
++      sb_data5(w0)
++      sb_data6(w0)
++      sb_data7(w0)
++
++      sb_data0(w1)
++      sb_data1(w1)
++      sb_data2(w1)
++      sb_data3(w1)
++      sb_data4(w1)
++      sb_data5(w1)
++      sb_data6(w1)
++      sb_data7(w1)
++
++      sb_data0(w2)
++      sb_data1(w2)
++      sb_data2(w2)
++      sb_data3(w2)
++      sb_data4(w2)
++      sb_data5(w2)
++      sb_data6(w2)
++      sb_data7(w2)
++
++      sb_data0(w3)
++      sb_data1(w3)
++      sb_data2(w3)
++      sb_data3(w3)
++      sb_data4(w3)
++      sb_data5(w3)
++      sb_data6(w3)
++      sb_data7(w3)
++
++// The inverse xor tables
++
++      .align  ALIGN32BYTES
++aes_it_tab:
++      ib_data0(v0)
++      ib_data1(v0)
++      ib_data2(v0)
++      ib_data3(v0)
++      ib_data4(v0)
++      ib_data5(v0)
++      ib_data6(v0)
++      ib_data7(v0)
++
++      ib_data0(v1)
++      ib_data1(v1)
++      ib_data2(v1)
++      ib_data3(v1)
++      ib_data4(v1)
++      ib_data5(v1)
++      ib_data6(v1)
++      ib_data7(v1)
++
++      ib_data0(v2)
++      ib_data1(v2)
++      ib_data2(v2)
++      ib_data3(v2)
++      ib_data4(v2)
++      ib_data5(v2)
++      ib_data6(v2)
++      ib_data7(v2)
++
++      ib_data0(v3)
++      ib_data1(v3)
++      ib_data2(v3)
++      ib_data3(v3)
++      ib_data4(v3)
++      ib_data5(v3)
++      ib_data6(v3)
++      ib_data7(v3)
++
++      .align  ALIGN32BYTES
++aes_il_tab:
++      ib_data0(w0)
++      ib_data1(w0)
++      ib_data2(w0)
++      ib_data3(w0)
++      ib_data4(w0)
++      ib_data5(w0)
++      ib_data6(w0)
++      ib_data7(w0)
++
++      ib_data0(w1)
++      ib_data1(w1)
++      ib_data2(w1)
++      ib_data3(w1)
++      ib_data4(w1)
++      ib_data5(w1)
++      ib_data6(w1)
++      ib_data7(w1)
++
++      ib_data0(w2)
++      ib_data1(w2)
++      ib_data2(w2)
++      ib_data3(w2)
++      ib_data4(w2)
++      ib_data5(w2)
++      ib_data6(w2)
++      ib_data7(w2)
++
++      ib_data0(w3)
++      ib_data1(w3)
++      ib_data2(w3)
++      ib_data3(w3)
++      ib_data4(w3)
++      ib_data5(w3)
++      ib_data6(w3)
++      ib_data7(w3)
++
++// The inverse mix column tables
++
++      .align  ALIGN32BYTES
++aes_im_tab:
++      im_data0(v0)
++      im_data1(v0)
++      im_data2(v0)
++      im_data3(v0)
++      im_data4(v0)
++      im_data5(v0)
++      im_data6(v0)
++      im_data7(v0)
++
++      im_data0(v1)
++      im_data1(v1)
++      im_data2(v1)
++      im_data3(v1)
++      im_data4(v1)
++      im_data5(v1)
++      im_data6(v1)
++      im_data7(v1)
++
++      im_data0(v2)
++      im_data1(v2)
++      im_data2(v2)
++      im_data3(v2)
++      im_data4(v2)
++      im_data5(v2)
++      im_data6(v2)
++      im_data7(v2)
++
++      im_data0(v3)
++      im_data1(v3)
++      im_data2(v3)
++      im_data3(v3)
++      im_data4(v3)
++      im_data5(v3)
++      im_data6(v3)
++      im_data7(v3)
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/aes.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1427 @@
++// I retain copyright in this code but I encourage its free use provided
++// that I don't carry any responsibility for the results. I am especially 
++// happy to see it used in free and open source software. If you do use 
++// it I would appreciate an acknowledgement of its origin in the code or
++// the product that results and I would also appreciate knowing a little
++// about the use to which it is being put. I am grateful to Frank Yellin
++// for some ideas that are used in this implementation.
++//
++// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
++//
++// This is an implementation of the AES encryption algorithm (Rijndael)
++// designed by Joan Daemen and Vincent Rijmen. This version is designed
++// to provide both fixed and dynamic block and key lengths and can also 
++// run with either big or little endian internal byte order (see aes.h). 
++// It inputs block and key lengths in bytes with the legal values being 
++// 16, 24 and 32.
++
++/*
++ * Modified by Jari Ruusu,  May 1 2001
++ *  - Fixed some compile warnings, code was ok but gcc warned anyway.
++ *  - Changed basic types: byte -> unsigned char, word -> u_int32_t
++ *  - Major name space cleanup: Names visible to outside now begin
++ *    with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
++ *  - Removed C++ and DLL support as part of name space cleanup.
++ *  - Eliminated unnecessary recomputation of tables. (actual bug fix)
++ *  - Merged precomputed constant tables to aes.c file.
++ *  - Removed data alignment restrictions for portability reasons.
++ *  - Made block and key lengths accept bit count (128/192/256)
++ *    as well byte count (16/24/32).
++ *  - Removed all error checks. This change also eliminated the need
++ *    to preinitialize the context struct to zero.
++ *  - Removed some totally unused constants.
++ */
++
++#include "klips-crypto/aes.h"
++
++#ifdef OCF_ASSIST
++#include "klips-crypto/ocf_assist.h"
++#endif
++
++// CONFIGURATION OPTIONS (see also aes.h)
++//
++// 1.  Define UNROLL for full loop unrolling in encryption and decryption.
++// 2.  Define PARTIAL_UNROLL to unroll two loops in encryption and decryption.
++// 3.  Define FIXED_TABLES for compiled rather than dynamic tables.
++// 4.  Define FF_TABLES to use tables for field multiplies and inverses.
++//     Do not enable this without understanding stack space requirements.
++// 5.  Define ARRAYS to use arrays to hold the local state block. If this
++//     is not defined, individually declared 32-bit words are used.
++// 6.  Define FAST_VARIABLE if a high speed variable block implementation
++//     is needed (essentially three separate fixed block size code sequences)
++// 7.  Define either ONE_TABLE or FOUR_TABLES for a fast table driven 
++//     version using 1 table (2 kbytes of table space) or 4 tables (8
++//     kbytes of table space) for higher speed.
++// 8.  Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed 
++//     increase by using tables for the last rounds but with more table
++//     space (2 or 8 kbytes extra).
++// 9.  If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but 
++//     slower version is provided.
++// 10. If fast decryption key scheduling is needed define ONE_IM_TABLE
++//     or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra).
++
++#define UNROLL
++//#define PARTIAL_UNROLL
++
++#define FIXED_TABLES
++//#define FF_TABLES
++//#define ARRAYS
++#define FAST_VARIABLE
++
++//#define ONE_TABLE
++#define FOUR_TABLES
++
++//#define ONE_LR_TABLE
++#define FOUR_LR_TABLES
++
++//#define ONE_IM_TABLE
++#define FOUR_IM_TABLES
++
++#if defined(UNROLL) && defined (PARTIAL_UNROLL)
++#error both UNROLL and PARTIAL_UNROLL are defined
++#endif
++
++#if defined(ONE_TABLE) && defined (FOUR_TABLES)
++#error both ONE_TABLE and FOUR_TABLES are defined
++#endif
++
++#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES)
++#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined
++#endif
++
++#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES)
++#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined
++#endif
++
++#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32
++#error an illegal block size has been specified
++#endif  
++
++// upr(x,n): rotates bytes within words by n positions, moving bytes 
++// to higher index positions with wrap around into low positions
++// ups(x,n): moves bytes by n positions to higher index positions in 
++// words but without wrap around
++// bval(x,n): extracts a byte from a word
++
++#define upr(x,n)        (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
++#define ups(x,n)        ((x) << 8 * (n))
++#define bval(x,n)       ((unsigned char)((x) >> 8 * (n)))
++#define bytes2word(b0, b1, b2, b3)  \
++        ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0))
++
++
++/* little endian processor without data alignment restrictions: AES_LE_OK */
++/* original code: i386 */
++#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386) 
++#define       AES_LE_OK 1
++/* added (tested): alpha  --jjo */
++#elif defined(__alpha__)|| defined (__alpha)
++#define AES_LE_OK 1
++/* added (tested): ia64  --jjo */
++#elif defined(__ia64__)|| defined (__ia64)
++#define AES_LE_OK 1
++#endif
++
++#ifdef AES_LE_OK
++/* little endian processor without data alignment restrictions */
++#define word_in(x)      *(u_int32_t*)(x)
++#define const_word_in(x)      *(const u_int32_t*)(x)
++#define word_out(x,v)   *(u_int32_t*)(x) = (v)
++#define const_word_out(x,v)   *(const u_int32_t*)(x) = (v)
++#else
++/* slower but generic big endian or with data alignment restrictions */
++/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */
++#define word_in(x)      ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24))
++#define const_word_in(x)      ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24))
++#define word_out(x,v)   ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24)
++#define const_word_out(x,v)   ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24)
++#endif
++
++// Disable at least some poor combinations of options
++
++#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
++#define FIXED_TABLES
++#undef  UNROLL
++#undef  ONE_LR_TABLE
++#undef  FOUR_LR_TABLES
++#undef  ONE_IM_TABLE
++#undef  FOUR_IM_TABLES
++#elif !defined(FOUR_TABLES)
++#ifdef  FOUR_LR_TABLES
++#undef  FOUR_LR_TABLES
++#define ONE_LR_TABLE
++#endif
++#ifdef  FOUR_IM_TABLES
++#undef  FOUR_IM_TABLES
++#define ONE_IM_TABLE
++#endif
++#elif !defined(AES_BLOCK_SIZE)
++#if defined(UNROLL)
++#define PARTIAL_UNROLL
++#undef UNROLL
++#endif
++#endif
++
++// the finite field modular polynomial and elements
++
++#define ff_poly 0x011b
++#define ff_hi   0x80
++
++// multiply four bytes in GF(2^8) by 'x' {02} in parallel
++
++#define m1  0x80808080
++#define m2  0x7f7f7f7f
++#define m3  0x0000001b
++#define FFmulX(x)  ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3))
++
++// The following defines provide alternative definitions of FFmulX that might
++// give improved performance if a fast 32-bit multiply is not available. Note
++// that a temporary variable u needs to be defined where FFmulX is used.
++
++// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) 
++// #define m4  0x1b1b1b1b
++// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) 
++
++// perform column mix operation on four bytes in parallel
++
++#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1))
++
++#if defined(FIXED_TABLES)
++
++// the S-Box table
++
++static const unsigned char s_box[256] =
++{
++    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
++    0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
++    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
++    0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
++    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
++    0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
++    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
++    0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
++    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
++    0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
++    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
++    0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
++    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
++    0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
++    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
++    0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
++    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
++    0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
++    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
++    0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
++    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
++    0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
++    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
++    0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
++    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
++    0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
++    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
++    0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
++    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
++    0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
++    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
++    0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
++};
++
++// the inverse S-Box table
++
++static const unsigned char inv_s_box[256] =
++{
++    0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
++    0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
++    0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
++    0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
++    0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
++    0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
++    0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
++    0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
++    0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
++    0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
++    0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
++    0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
++    0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
++    0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
++    0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
++    0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
++    0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
++    0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
++    0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
++    0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
++    0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
++    0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
++    0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
++    0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
++    0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
++    0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
++    0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
++    0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
++    0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
++    0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
++    0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
++    0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
++};
++
++#define w0(p)          0x000000##p
++
++// Number of elements required in this table for different
++// block and key lengths is:
++//
++// Nk =      4  6  8
++//        ----------
++// Nb = 4 | 10  8  7
++//      6 | 19 12 11
++//      8 | 29 19 14
++//
++// this table can be a table of bytes if the key schedule
++// code is adjusted accordingly
++
++static const u_int32_t rcon_tab[29] =
++{
++    w0(01), w0(02), w0(04), w0(08),
++    w0(10), w0(20), w0(40), w0(80),
++    w0(1b), w0(36), w0(6c), w0(d8),
++    w0(ab), w0(4d), w0(9a), w0(2f),
++    w0(5e), w0(bc), w0(63), w0(c6),
++    w0(97), w0(35), w0(6a), w0(d4),
++    w0(b3), w0(7d), w0(fa), w0(ef),
++    w0(c5)
++};
++
++#undef  w0
++
++#define r0(p,q,r,s) 0x##p##q##r##s
++#define r1(p,q,r,s) 0x##q##r##s##p
++#define r2(p,q,r,s) 0x##r##s##p##q
++#define r3(p,q,r,s) 0x##s##p##q##r
++#define w0(p)          0x000000##p
++#define w1(p)        0x0000##p##00
++#define w2(p)        0x00##p##0000
++#define w3(p)        0x##p##000000
++
++#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) 
++
++//  data for forward tables (other than last round)
++
++#define f_table \
++    r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\
++    r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\
++    r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\
++    r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\
++    r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\
++    r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\
++    r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\
++    r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\
++    r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\
++    r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\
++    r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\
++    r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\
++    r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\
++    r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\
++    r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\
++    r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\
++    r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\
++    r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\
++    r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\
++    r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\
++    r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\
++    r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\
++    r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\
++    r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\
++    r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\
++    r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\
++    r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\
++    r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\
++    r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\
++    r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\
++    r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\
++    r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\
++    r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\
++    r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\
++    r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\
++    r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\
++    r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\
++    r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\
++    r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\
++    r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\
++    r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\
++    r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\
++    r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\
++    r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\
++    r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\
++    r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\
++    r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\
++    r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\
++    r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\
++    r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\
++    r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\
++    r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\
++    r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\
++    r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\
++    r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\
++    r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\
++    r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\
++    r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\
++    r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\
++    r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\
++    r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\
++    r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\
++    r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\
++    r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c)
++
++//  data for inverse tables (other than last round)
++
++#define i_table \
++    r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\
++    r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\
++    r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\
++    r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\
++    r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\
++    r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\
++    r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\
++    r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\
++    r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\
++    r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\
++    r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\
++    r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\
++    r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\
++    r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\
++    r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\
++    r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\
++    r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\
++    r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\
++    r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\
++    r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\
++    r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\
++    r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\
++    r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\
++    r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\
++    r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\
++    r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\
++    r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\
++    r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\
++    r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\
++    r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\
++    r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\
++    r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\
++    r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\
++    r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\
++    r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\
++    r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\
++    r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\
++    r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\
++    r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\
++    r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\
++    r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\
++    r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\
++    r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\
++    r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\
++    r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\
++    r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\
++    r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\
++    r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\
++    r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\
++    r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\
++    r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\
++    r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\
++    r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\
++    r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\
++    r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\
++    r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\
++    r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\
++    r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\
++    r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\
++    r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\
++    r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\
++    r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\
++    r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\
++    r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0)
++
++// generate the required tables in the desired endian format
++
++#undef  r
++#define r   r0
++
++#if defined(ONE_TABLE)
++static const u_int32_t ft_tab[256] =
++    {   f_table };
++#elif defined(FOUR_TABLES)
++static const u_int32_t ft_tab[4][256] =
++{   {   f_table },
++#undef  r
++#define r   r1
++    {   f_table },
++#undef  r
++#define r   r2
++    {   f_table },
++#undef  r
++#define r   r3
++    {   f_table }
++};
++#endif
++
++#undef  r
++#define r   r0
++#if defined(ONE_TABLE)
++static const u_int32_t it_tab[256] =
++    {   i_table };
++#elif defined(FOUR_TABLES)
++static const u_int32_t it_tab[4][256] =
++{   {   i_table },
++#undef  r
++#define r   r1
++    {   i_table },
++#undef  r
++#define r   r2
++    {   i_table },
++#undef  r
++#define r   r3
++    {   i_table }
++};
++#endif
++
++#endif
++
++#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) 
++
++//  data for inverse tables (last round)
++
++#define li_table    \
++    w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\
++    w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\
++    w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\
++    w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\
++    w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\
++    w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\
++    w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\
++    w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\
++    w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\
++    w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\
++    w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\
++    w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\
++    w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\
++    w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\
++    w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\
++    w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\
++    w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\
++    w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\
++    w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\
++    w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\
++    w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\
++    w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\
++    w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\
++    w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\
++    w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\
++    w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\
++    w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\
++    w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\
++    w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\
++    w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\
++    w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\
++    w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d),
++
++// generate the required tables in the desired endian format
++
++#undef  r
++#define r(p,q,r,s)  w0(q)
++#if defined(ONE_LR_TABLE)
++static const u_int32_t fl_tab[256] =
++    {   f_table     };
++#elif defined(FOUR_LR_TABLES)
++static const u_int32_t fl_tab[4][256] =
++{   {   f_table    },
++#undef  r
++#define r(p,q,r,s)   w1(q)
++    {   f_table    },
++#undef  r
++#define r(p,q,r,s)   w2(q)
++    {   f_table    },
++#undef  r
++#define r(p,q,r,s)   w3(q)
++    {   f_table    }
++};
++#endif
++
++#undef  w
++#define w   w0
++#if defined(ONE_LR_TABLE)
++static const u_int32_t il_tab[256] =
++    {   li_table    };
++#elif defined(FOUR_LR_TABLES)
++static const u_int32_t il_tab[4][256] =
++{   {   li_table    },
++#undef  w
++#define w   w1
++    {   li_table    },
++#undef  w
++#define w   w2
++    {   li_table    },
++#undef  w
++#define w   w3
++    {   li_table    }
++};
++#endif
++
++#endif
++
++#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) 
++
++#define m_table \
++    r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\
++    r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\
++    r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\
++    r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\
++    r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\
++    r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\
++    r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\
++    r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\
++    r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\
++    r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\
++    r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\
++    r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\
++    r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\
++    r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\
++    r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\
++    r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\
++    r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\
++    r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\
++    r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\
++    r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\
++    r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\
++    r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\
++    r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\
++    r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\
++    r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\
++    r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\
++    r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\
++    r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\
++    r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\
++    r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\
++    r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\
++    r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\
++    r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\
++    r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\
++    r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\
++    r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\
++    r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\
++    r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\
++    r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\
++    r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\
++    r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\
++    r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\
++    r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\
++    r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\
++    r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\
++    r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\
++    r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\
++    r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\
++    r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\
++    r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\
++    r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\
++    r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\
++    r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\
++    r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\
++    r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\
++    r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\
++    r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\
++    r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\
++    r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\
++    r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\
++    r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\
++    r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\
++    r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\
++    r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d)
++
++#undef r
++#define r   r0
++
++#if defined(ONE_IM_TABLE)
++static const u_int32_t im_tab[256] =
++    {   m_table };
++#elif defined(FOUR_IM_TABLES)
++static const u_int32_t im_tab[4][256] =
++{   {   m_table },
++#undef  r
++#define r   r1
++    {   m_table },
++#undef  r
++#define r   r2
++    {   m_table },
++#undef  r
++#define r   r3
++    {   m_table }
++};
++#endif
++
++#endif
++
++#else
++
++static int tab_gen = 0;
++
++static unsigned char  s_box[256];            // the S box
++static unsigned char  inv_s_box[256];        // the inverse S box
++static u_int32_t  rcon_tab[AES_RC_LENGTH];   // table of round constants
++
++#if defined(ONE_TABLE)
++static u_int32_t  ft_tab[256];
++static u_int32_t  it_tab[256];
++#elif defined(FOUR_TABLES)
++static u_int32_t  ft_tab[4][256];
++static u_int32_t  it_tab[4][256];
++#endif
++
++#if defined(ONE_LR_TABLE)
++static u_int32_t  fl_tab[256];
++static u_int32_t  il_tab[256];
++#elif defined(FOUR_LR_TABLES)
++static u_int32_t  fl_tab[4][256];
++static u_int32_t  il_tab[4][256];
++#endif
++
++#if defined(ONE_IM_TABLE)
++static u_int32_t  im_tab[256];
++#elif defined(FOUR_IM_TABLES)
++static u_int32_t  im_tab[4][256];
++#endif
++
++// Generate the tables for the dynamic table option
++
++#if !defined(FF_TABLES)
++
++// It will generally be sensible to use tables to compute finite 
++// field multiplies and inverses but where memory is scarse this 
++// code might sometimes be better.
++
++// return 2 ^ (n - 1) where n is the bit number of the highest bit
++// set in x with x in the range 1 < x < 0x00000200.   This form is
++// used so that locals within FFinv can be bytes rather than words
++
++static unsigned char hibit(const u_int32_t x)
++{   unsigned char r = (unsigned char)((x >> 1) | (x >> 2));
++    
++    r |= (r >> 2);
++    r |= (r >> 4);
++    return (r + 1) >> 1;
++}
++
++// return the inverse of the finite field element x
++
++static unsigned char FFinv(const unsigned char x)
++{   unsigned char    p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
++
++    if(x < 2) return x;
++
++    for(;;)
++    {
++        if(!n1) return v1;
++
++        while(n2 >= n1)
++        {   
++            n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
++        }
++        
++        if(!n2) return v2;
++
++        while(n1 >= n2)
++        {   
++            n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
++        }
++    }
++}
++
++// define the finite field multiplies required for Rijndael
++
++#define FFmul02(x)  ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0))
++#define FFmul03(x)  ((x) ^ FFmul02(x))
++#define FFmul09(x)  ((x) ^ FFmul02(FFmul02(FFmul02(x))))
++#define FFmul0b(x)  ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x))))
++#define FFmul0d(x)  ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x))))
++#define FFmul0e(x)  FFmul02((x) ^ FFmul02((x) ^ FFmul02(x)))
++
++#else
++
++#define FFinv(x)    ((x) ? pow[255 - log[x]]: 0)
++
++#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
++#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
++#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
++#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
++#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
++#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
++
++#endif
++
++// The forward and inverse affine transformations used in the S-box
++
++#define fwd_affine(x) \
++    (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8)))
++
++#define inv_affine(x) \
++    (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8)))
++
++static void gen_tabs(void)
++{   u_int32_t  i, w;
++
++#if defined(FF_TABLES)
++
++    unsigned char  pow[512], log[256];
++
++    // log and power tables for GF(2^8) finite field with
++    // 0x011b as modular polynomial - the simplest primitive
++    // root is 0x03, used here to generate the tables
++
++    i = 0; w = 1; 
++    do
++    {   
++        pow[i] = (unsigned char)w;
++        pow[i + 255] = (unsigned char)w;
++        log[w] = (unsigned char)i++;
++        w ^=  (w << 1) ^ (w & ff_hi ? ff_poly : 0);
++    }
++    while (w != 1);
++
++#endif
++
++    for(i = 0, w = 1; i < AES_RC_LENGTH; ++i)
++    {
++        rcon_tab[i] = bytes2word(w, 0, 0, 0);
++        w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
++    }
++
++    for(i = 0; i < 256; ++i)
++    {   unsigned char    b;
++
++        s_box[i] = b = fwd_affine(FFinv((unsigned char)i));
++
++        w = bytes2word(b, 0, 0, 0);
++#if defined(ONE_LR_TABLE)
++        fl_tab[i] = w;
++#elif defined(FOUR_LR_TABLES)
++        fl_tab[0][i] = w;
++        fl_tab[1][i] = upr(w,1);
++        fl_tab[2][i] = upr(w,2);
++        fl_tab[3][i] = upr(w,3);
++#endif
++        w = bytes2word(FFmul02(b), b, b, FFmul03(b));
++#if defined(ONE_TABLE)
++        ft_tab[i] = w;
++#elif defined(FOUR_TABLES)
++        ft_tab[0][i] = w;
++        ft_tab[1][i] = upr(w,1);
++        ft_tab[2][i] = upr(w,2);
++        ft_tab[3][i] = upr(w,3);
++#endif
++        inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i));
++
++        w = bytes2word(b, 0, 0, 0);
++#if defined(ONE_LR_TABLE)
++        il_tab[i] = w;
++#elif defined(FOUR_LR_TABLES)
++        il_tab[0][i] = w;
++        il_tab[1][i] = upr(w,1);
++        il_tab[2][i] = upr(w,2);
++        il_tab[3][i] = upr(w,3);
++#endif
++        w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b));
++#if defined(ONE_TABLE)
++        it_tab[i] = w;
++#elif defined(FOUR_TABLES)
++        it_tab[0][i] = w;
++        it_tab[1][i] = upr(w,1);
++        it_tab[2][i] = upr(w,2);
++        it_tab[3][i] = upr(w,3);
++#endif
++#if defined(ONE_IM_TABLE)
++        im_tab[b] = w;
++#elif defined(FOUR_IM_TABLES)
++        im_tab[0][b] = w;
++        im_tab[1][b] = upr(w,1);
++        im_tab[2][b] = upr(w,2);
++        im_tab[3][b] = upr(w,3);
++#endif
++
++    }
++}
++
++#endif
++
++#define no_table(x,box,vf,rf,c) bytes2word( \
++    box[bval(vf(x,0,c),rf(0,c))], \
++    box[bval(vf(x,1,c),rf(1,c))], \
++    box[bval(vf(x,2,c),rf(2,c))], \
++    box[bval(vf(x,3,c),rf(3,c))])
++
++#define one_table(x,op,tab,vf,rf,c) \
++ (     tab[bval(vf(x,0,c),rf(0,c))] \
++  ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
++  ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
++  ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
++
++#define four_tables(x,tab,vf,rf,c) \
++ (  tab[0][bval(vf(x,0,c),rf(0,c))] \
++  ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
++  ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
++  ^ tab[3][bval(vf(x,3,c),rf(3,c))])
++
++#define vf1(x,r,c)  (x)
++#define rf1(r,c)    (r)
++#define rf2(r,c)    ((r-c)&3)
++
++#if defined(FOUR_LR_TABLES)
++#define ls_box(x,c)     four_tables(x,fl_tab,vf1,rf2,c)
++#elif defined(ONE_LR_TABLE)
++#define ls_box(x,c)     one_table(x,upr,fl_tab,vf1,rf2,c)
++#else
++#define ls_box(x,c)     no_table(x,s_box,vf1,rf2,c)
++#endif
++
++#if defined(FOUR_IM_TABLES)
++#define inv_mcol(x)     four_tables(x,im_tab,vf1,rf1,0)
++#elif defined(ONE_IM_TABLE)
++#define inv_mcol(x)     one_table(x,upr,im_tab,vf1,rf1,0)
++#else
++#define inv_mcol(x) \
++    (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
++    f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
++#endif
++
++// Subroutine to set the block size (if variable) in bytes, legal
++// values being 16, 24 and 32.
++
++#if defined(AES_BLOCK_SIZE)
++#define nc   (AES_BLOCK_SIZE / 4)
++#else
++#define nc   (cx->aes_Ncol)
++
++void aes_set_blk(aes_context *cx, int n_bytes)
++{
++#if !defined(FIXED_TABLES)
++    if(!tab_gen) { gen_tabs(); tab_gen = 1; }
++#endif
++
++    switch(n_bytes) {
++    case 32:        /* bytes */
++    case 256:       /* bits */
++        nc = 8;
++        break;
++    case 24:        /* bytes */
++    case 192:       /* bits */
++        nc = 6;
++        break;
++    case 16:        /* bytes */
++    case 128:       /* bits */
++    default:
++        nc = 4;
++        break;
++    }
++}
++
++#endif
++
++// Initialise the key schedule from the user supplied key. The key
++// length is now specified in bytes - 16, 24 or 32 as appropriate.
++// This corresponds to bit lengths of 128, 192 and 256 bits, and
++// to Nk values of 4, 6 and 8 respectively.
++
++#define mx(t,f) (*t++ = inv_mcol(*f),f++)
++#define cp(t,f) *t++ = *f++
++
++#if   AES_BLOCK_SIZE == 16
++#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
++#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
++#elif AES_BLOCK_SIZE == 24
++#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
++                    cp(d,s); cp(d,s)
++#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
++                    mx(d,s); mx(d,s)
++#elif AES_BLOCK_SIZE == 32
++#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
++                    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
++#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
++                    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
++#else
++
++#define cpy(d,s) \
++switch(nc) \
++{   case 8: cp(d,s); cp(d,s); \
++    case 6: cp(d,s); cp(d,s); \
++    case 4: cp(d,s); cp(d,s); \
++            cp(d,s); cp(d,s); \
++}
++
++#define mix(d,s) \
++switch(nc) \
++{   case 8: mx(d,s); mx(d,s); \
++    case 6: mx(d,s); mx(d,s); \
++    case 4: mx(d,s); mx(d,s); \
++            mx(d,s); mx(d,s); \
++}
++
++#endif
++
++void aes_set_key(aes_context *cx, const unsigned char in_key[], int n_bytes, const int f)
++{   u_int32_t    *kf, *kt, rci;
++
++#if !defined(FIXED_TABLES)
++    if(!tab_gen) { gen_tabs(); tab_gen = 1; }
++#endif
++
++/* only need to do a special set_key for the cryptodev hw acceleration */
++#ifdef OCF_ASSIST
++      if (ocf_aes_assist() & OCF_PROVIDES_AES) {
++              ocf_aes_set_key(cx, in_key, n_bytes, f);
++              return;
++      }
++#endif
++
++    switch(n_bytes) {
++    case 32:                    /* bytes */
++    case 256:                   /* bits */
++        cx->aes_Nkey = 8;
++        break;
++    case 24:                    /* bytes */
++    case 192:                   /* bits */
++        cx->aes_Nkey = 6;
++        break;
++    case 16:                    /* bytes */
++    case 128:                   /* bits */
++    default:
++        cx->aes_Nkey = 4;
++        break;
++    }
++
++    cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6; 
++
++    cx->aes_e_key[0] = const_word_in(in_key     );
++    cx->aes_e_key[1] = const_word_in(in_key +  4);
++    cx->aes_e_key[2] = const_word_in(in_key +  8);
++    cx->aes_e_key[3] = const_word_in(in_key + 12);
++
++    kf = cx->aes_e_key; 
++    kt = kf + nc * (cx->aes_Nrnd + 1) - cx->aes_Nkey; 
++    rci = 0;
++
++    switch(cx->aes_Nkey)
++    {
++    case 4: do
++            {   kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++];
++                kf[5] = kf[1] ^ kf[4];
++                kf[6] = kf[2] ^ kf[5];
++                kf[7] = kf[3] ^ kf[6];
++                kf += 4;
++            }
++            while(kf < kt);
++            break;
++
++    case 6: cx->aes_e_key[4] = const_word_in(in_key + 16);
++            cx->aes_e_key[5] = const_word_in(in_key + 20);
++            do
++            {   kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++];
++                kf[ 7] = kf[1] ^ kf[ 6];
++                kf[ 8] = kf[2] ^ kf[ 7];
++                kf[ 9] = kf[3] ^ kf[ 8];
++                kf[10] = kf[4] ^ kf[ 9];
++                kf[11] = kf[5] ^ kf[10];
++                kf += 6;
++            }
++            while(kf < kt);
++            break;
++
++    case 8: cx->aes_e_key[4] = const_word_in(in_key + 16);
++            cx->aes_e_key[5] = const_word_in(in_key + 20);
++            cx->aes_e_key[6] = const_word_in(in_key + 24);
++            cx->aes_e_key[7] = const_word_in(in_key + 28);
++            do
++            {   kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++];
++                kf[ 9] = kf[1] ^ kf[ 8];
++                kf[10] = kf[2] ^ kf[ 9];
++                kf[11] = kf[3] ^ kf[10];
++                kf[12] = kf[4] ^ ls_box(kf[11],0);
++                kf[13] = kf[5] ^ kf[12];
++                kf[14] = kf[6] ^ kf[13];
++                kf[15] = kf[7] ^ kf[14];
++                kf += 8;
++            }
++            while (kf < kt);
++            break;
++    }
++
++    if(!f)
++    {   u_int32_t    i;
++        
++        kt = cx->aes_d_key + nc * cx->aes_Nrnd;
++        kf = cx->aes_e_key;
++        
++        cpy(kt, kf); kt -= 2 * nc;
++
++        for(i = 1; i < cx->aes_Nrnd; ++i)
++        { 
++#if defined(ONE_TABLE) || defined(FOUR_TABLES)
++#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES)
++            u_int32_t    f2, f4, f8, f9;
++#endif
++            mix(kt, kf);
++#else
++            cpy(kt, kf);
++#endif
++            kt -= 2 * nc;
++        }
++        
++        cpy(kt, kf);
++    }
++}
++
++// y = output word, x = input word, r = row, c = column
++// for r = 0, 1, 2 and 3 = column accessed for row r
++
++#if defined(ARRAYS)
++#define s(x,c) x[c]
++#else
++#define s(x,c) x##c
++#endif
++
++// I am grateful to Frank Yellin for the following constructions
++// which, given the column (c) of the output state variable that
++// is being computed, return the input state variables which are
++// needed for each row (r) of the state
++
++// For the fixed block size options, compilers reduce these two 
++// expressions to fixed variable references. For variable block 
++// size code conditional clauses will sometimes be returned
++
++#define unused  77  // Sunset Strip
++
++#define fwd_var(x,r,c) \
++ ( r==0 ?                     \
++    ( c==0 ? s(x,0) \
++    : c==1 ? s(x,1) \
++    : c==2 ? s(x,2) \
++    : c==3 ? s(x,3) \
++    : c==4 ? s(x,4) \
++    : c==5 ? s(x,5) \
++    : c==6 ? s(x,6) \
++    : s(x,7))         \
++ : r==1 ?                     \
++    ( c==0 ? s(x,1) \
++    : c==1 ? s(x,2) \
++    : c==2 ? s(x,3) \
++    : c==3 ? nc==4 ? s(x,0) : s(x,4) \
++    : c==4 ? s(x,5) \
++    : c==5 ? nc==8 ? s(x,6) : s(x,0) \
++    : c==6 ? s(x,7) \
++    : s(x,0))         \
++ : r==2 ?                     \
++    ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
++    : c==1 ? nc==8 ? s(x,4) : s(x,3) \
++    : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
++    : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
++    : c==4 ? nc==8 ? s(x,7) : s(x,0) \
++    : c==5 ? nc==8 ? s(x,0) : s(x,1) \
++    : c==6 ? s(x,1) \
++    : s(x,2))         \
++ :                                    \
++    ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
++    : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
++    : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
++    : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
++    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
++    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
++    : c==6 ? s(x,2) \
++    : s(x,3)))
++
++#define inv_var(x,r,c) \
++ ( r==0 ?                     \
++    ( c==0 ? s(x,0) \
++    : c==1 ? s(x,1) \
++    : c==2 ? s(x,2) \
++    : c==3 ? s(x,3) \
++    : c==4 ? s(x,4) \
++    : c==5 ? s(x,5) \
++    : c==6 ? s(x,6) \
++    : s(x,7))         \
++ : r==1 ?                     \
++    ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
++    : c==1 ? s(x,0) \
++    : c==2 ? s(x,1) \
++    : c==3 ? s(x,2) \
++    : c==4 ? s(x,3) \
++    : c==5 ? s(x,4) \
++    : c==6 ? s(x,5) \
++    : s(x,6))         \
++ : r==2 ?                     \
++    ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
++    : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
++    : c==2 ? nc==8 ? s(x,7) : s(x,0) \
++    : c==3 ? nc==8 ? s(x,0) : s(x,1) \
++    : c==4 ? nc==8 ? s(x,1) : s(x,2) \
++    : c==5 ? nc==8 ? s(x,2) : s(x,3) \
++    : c==6 ? s(x,3) \
++    : s(x,4))         \
++ :                                    \
++    ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
++    : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
++    : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
++    : c==3 ? nc==8 ? s(x,7) : s(x,0) \
++    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
++    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
++    : c==6 ? s(x,2) \
++    : s(x,3)))
++
++#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c]
++#define so(y,x,c)   word_out(y + 4 * c, s(x,c))
++
++#if defined(FOUR_TABLES)
++#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
++#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
++#elif defined(ONE_TABLE)
++#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
++#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
++#else
++#define fwd_rnd(y,x,k,c)    s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
++#define inv_rnd(y,x,k,c)    s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
++#endif
++
++#if defined(FOUR_LR_TABLES)
++#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
++#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
++#elif defined(ONE_LR_TABLE)
++#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
++#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
++#else
++#define fwd_lrnd(y,x,k,c)   s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
++#define inv_lrnd(y,x,k,c)   s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
++#endif
++
++#if AES_BLOCK_SIZE == 16
++
++#if defined(ARRAYS)
++#define locals(y,x)     x[4],y[4]
++#else
++#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
++// the following defines prevent the compiler requiring the declaration
++// of generated but unused variables in the fwd_var and inv_var macros
++#define b04 unused
++#define b05 unused
++#define b06 unused
++#define b07 unused
++#define b14 unused
++#define b15 unused
++#define b16 unused
++#define b17 unused
++#endif
++#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
++                        s(y,2) = s(x,2); s(y,3) = s(x,3);
++#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
++#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
++#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
++
++#elif AES_BLOCK_SIZE == 24
++
++#if defined(ARRAYS)
++#define locals(y,x)     x[6],y[6]
++#else
++#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5, \
++                        y##0,y##1,y##2,y##3,y##4,y##5
++#define b06 unused
++#define b07 unused
++#define b16 unused
++#define b17 unused
++#endif
++#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
++                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
++                        s(y,4) = s(x,4); s(y,5) = s(x,5);
++#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
++                        si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
++#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); \
++                        so(y,x,3); so(y,x,4); so(y,x,5)
++#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
++                        rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
++#else
++
++#if defined(ARRAYS)
++#define locals(y,x)     x[8],y[8]
++#else
++#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
++                        y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
++#endif
++#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
++                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
++                        s(y,4) = s(x,4); s(y,5) = s(x,5); \
++                        s(y,6) = s(x,6); s(y,7) = s(x,7);
++
++#if AES_BLOCK_SIZE == 32
++
++#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
++                        si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
++#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
++                        so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
++#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
++                        rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
++#else
++
++#define state_in(y,x,k) \
++switch(nc) \
++{   case 8: si(y,x,k,7); si(y,x,k,6); \
++    case 6: si(y,x,k,5); si(y,x,k,4); \
++    case 4: si(y,x,k,3); si(y,x,k,2); \
++            si(y,x,k,1); si(y,x,k,0); \
++}
++
++#define state_out(y,x) \
++switch(nc) \
++{   case 8: so(y,x,7); so(y,x,6); \
++    case 6: so(y,x,5); so(y,x,4); \
++    case 4: so(y,x,3); so(y,x,2); \
++            so(y,x,1); so(y,x,0); \
++}
++
++#if defined(FAST_VARIABLE)
++
++#define round(rm,y,x,k) \
++switch(nc) \
++{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
++            rm(y,x,k,5); rm(y,x,k,4); \
++            rm(y,x,k,3); rm(y,x,k,2); \
++            rm(y,x,k,1); rm(y,x,k,0); \
++            break; \
++    case 6: rm(y,x,k,5); rm(y,x,k,4); \
++            rm(y,x,k,3); rm(y,x,k,2); \
++            rm(y,x,k,1); rm(y,x,k,0); \
++            break; \
++    case 4: rm(y,x,k,3); rm(y,x,k,2); \
++            rm(y,x,k,1); rm(y,x,k,0); \
++            break; \
++}
++#else
++
++#define round(rm,y,x,k) \
++switch(nc) \
++{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
++    case 6: rm(y,x,k,5); rm(y,x,k,4); \
++    case 4: rm(y,x,k,3); rm(y,x,k,2); \
++            rm(y,x,k,1); rm(y,x,k,0); \
++}
++
++#endif
++
++#endif
++#endif
++
++void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
++{   u_int32_t        locals(b0, b1);
++    const u_int32_t  *kp = cx->aes_e_key;
++
++#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
++    u_int32_t        f2;
++#endif
++
++    state_in(b0, in_blk, kp); kp += nc;
++
++#if defined(UNROLL)
++
++    switch(cx->aes_Nrnd)
++    {
++    case 14:    round(fwd_rnd,  b1, b0, kp         ); 
++                round(fwd_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
++    case 12:    round(fwd_rnd,  b1, b0, kp         ); 
++                round(fwd_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
++    case 10:    round(fwd_rnd,  b1, b0, kp         );             
++                round(fwd_rnd,  b0, b1, kp +     nc);
++                round(fwd_rnd,  b1, b0, kp + 2 * nc); 
++                round(fwd_rnd,  b0, b1, kp + 3 * nc);
++                round(fwd_rnd,  b1, b0, kp + 4 * nc); 
++                round(fwd_rnd,  b0, b1, kp + 5 * nc);
++                round(fwd_rnd,  b1, b0, kp + 6 * nc); 
++                round(fwd_rnd,  b0, b1, kp + 7 * nc);
++                round(fwd_rnd,  b1, b0, kp + 8 * nc);
++                round(fwd_lrnd, b0, b1, kp + 9 * nc);
++    }
++
++#elif defined(PARTIAL_UNROLL)
++    {   u_int32_t    rnd;
++
++        for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
++        {
++            round(fwd_rnd, b1, b0, kp); 
++            round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc;
++        }
++
++        round(fwd_rnd,  b1, b0, kp);
++        round(fwd_lrnd, b0, b1, kp + nc);
++    }
++#else
++    {   u_int32_t    rnd;
++
++        for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
++        {
++            round(fwd_rnd, b1, b0, kp); 
++            l_copy(b0, b1); kp += nc;
++        }
++
++        round(fwd_lrnd, b0, b1, kp);
++    }
++#endif
++
++    state_out(out_blk, b0);
++}
++
++void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
++{   u_int32_t        locals(b0, b1);
++    const u_int32_t  *kp = cx->aes_d_key;
++
++#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
++    u_int32_t        f2, f4, f8, f9; 
++#endif
++
++    state_in(b0, in_blk, kp); kp += nc;
++
++#if defined(UNROLL)
++
++    switch(cx->aes_Nrnd)
++    {
++    case 14:    round(inv_rnd,  b1, b0, kp         );
++                round(inv_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
++    case 12:    round(inv_rnd,  b1, b0, kp         );
++                round(inv_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
++    case 10:    round(inv_rnd,  b1, b0, kp         );             
++                round(inv_rnd,  b0, b1, kp +     nc);
++                round(inv_rnd,  b1, b0, kp + 2 * nc); 
++                round(inv_rnd,  b0, b1, kp + 3 * nc);
++                round(inv_rnd,  b1, b0, kp + 4 * nc); 
++                round(inv_rnd,  b0, b1, kp + 5 * nc);
++                round(inv_rnd,  b1, b0, kp + 6 * nc); 
++                round(inv_rnd,  b0, b1, kp + 7 * nc);
++                round(inv_rnd,  b1, b0, kp + 8 * nc);
++                round(inv_lrnd, b0, b1, kp + 9 * nc);
++    }
++
++#elif defined(PARTIAL_UNROLL)
++    {   u_int32_t    rnd;
++
++        for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
++        {
++            round(inv_rnd, b1, b0, kp); 
++            round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc;
++        }
++
++        round(inv_rnd,  b1, b0, kp);
++        round(inv_lrnd, b0, b1, kp + nc);
++    }
++#else
++    {   u_int32_t    rnd;
++
++        for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
++        {
++            round(inv_rnd, b1, b0, kp); 
++            l_copy(b0, b1); kp += nc;
++        }
++
++        round(inv_lrnd, b0, b1, kp);
++    }
++#endif
++
++    state_out(out_blk, b0);
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/aes_cbc.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,67 @@
++/*
++// I retain copyright in this code but I encourage its free use provided
++// that I don't carry any responsibility for the results. I am especially 
++// happy to see it used in free and open source software. If you do use 
++// it I would appreciate an acknowledgement of its origin in the code or
++// the product that results and I would also appreciate knowing a little
++// about the use to which it is being put. I am grateful to Frank Yellin
++// for some ideas that are used in this implementation.
++//
++// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
++//
++// This is an implementation of the AES encryption algorithm (Rijndael)
++// designed by Joan Daemen and Vincent Rijmen. This version is designed
++// to provide both fixed and dynamic block and key lengths and can also 
++// run with either big or little endian internal byte order (see aes.h). 
++// It inputs block and key lengths in bytes with the legal values being 
++// 16, 24 and 32.
++*
++*/
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#else
++#include <sys/types.h>
++#endif
++#include "klips-crypto/aes_cbc.h"
++#include "klips-crypto/cbc_generic.h"
++#ifdef OCF_ASSIST
++#include "klips-crypto/ocf_assist.h"
++#endif
++
++/* returns bool success */
++int AES_set_key(aes_context *aes_ctx, const u_int8_t *key, int keysize) {
++      aes_set_key(aes_ctx, key, keysize, 0);
++      return 1;       
++}
++
++#ifdef OCF_ASSIST
++
++CBC_IMPL_BLK16(_AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
++
++int
++AES_cbc_encrypt(aes_context *ctx, const u_int8_t *in, u_int8_t *out, int ilen,
++              const u_int8_t *iv, int encrypt)
++{
++      if (ocf_aes_assist() & OCF_PROVIDES_AES) {
++              return ocf_aes_cbc_encrypt(ctx, in, out, ilen, iv, encrypt);
++      } else {
++              return _AES_cbc_encrypt(ctx, in, out, ilen, iv, encrypt);
++      }
++}
++
++#else
++CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
++#endif
++
++
++/*
++ * $Log: aes_cbc.c,v $
++ * Revision 1.2  2004/07/10 07:48:40  mcr
++ * Moved from linux/crypto/ciphers/aes/aes_cbc.c,v
++ *
++ * Revision 1.1  2004/04/06 02:48:12  mcr
++ *    pullup of AES cipher from alg-branch.
++ *
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/aes_xcbc_mac.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,67 @@
++#ifdef __KERNEL__
++#include <linux/types.h>
++#include <linux/kernel.h>
++#define AES_DEBUG(x) 
++#else
++#include <stdio.h>
++#include <sys/types.h>
++#define AES_DEBUG(x) x
++#endif
++
++#include "klips-crypto/aes.h"
++#include "klips-crypto/aes_xcbc_mac.h"
++
++int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen)
++{
++      int ret=1;
++      aes_block kn[3] = { 
++              { 0x01010101, 0x01010101, 0x01010101, 0x01010101 },
++              { 0x02020202, 0x02020202, 0x02020202, 0x02020202 },
++              { 0x03030303, 0x03030303, 0x03030303, 0x03030303 },
++      };
++      aes_set_key(&ctxm->ctx_k1, key, keylen, 0);
++      aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[0], (u_int8_t *) kn[0]);
++      aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[1], (u_int8_t *) ctxm->k2);
++      aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[2], (u_int8_t *) ctxm->k3);
++      aes_set_key(&ctxm->ctx_k1, (u_int8_t *) kn[0], 16, 0);
++      return ret;
++}
++static void do_pad_xor(u_int8_t *out, const u_int8_t *in, int len) {
++      int pos=0;
++      for (pos=1; pos <= 16; pos++, in++, out++) {
++              if (pos <= len)
++                      *out ^= *in;
++              if (pos > len) {
++                      AES_DEBUG(printf("put 0x80 at pos=%d\n", pos));
++                      *out ^= 0x80;
++                      break;
++              }
++      }
++}
++static void xor_block(aes_block res, const aes_block op) {
++      res[0] ^= op[0];
++      res[1] ^= op[1];
++      res[2] ^= op[2];
++      res[3] ^= op[3];
++}
++int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]) {
++      int ret=ilen;
++      u_int32_t out[4] = { 0, 0, 0, 0 }; 
++      for (; ilen > 16 ; ilen-=16) {
++              xor_block(out, (const u_int32_t*) &in[0]);
++              aes_encrypt(&ctxm->ctx_k1, in, (u_int8_t *)&out[0]);
++              in+=16; 
++      }
++      do_pad_xor((u_int8_t *)&out, in, ilen);
++      if (ilen==16) {
++              AES_DEBUG(printf("using k3\n"));
++              xor_block(out, ctxm->k3);
++      }
++      else 
++      {
++              AES_DEBUG(printf("using k2\n"));
++              xor_block(out, ctxm->k2);
++      }
++      aes_encrypt(&ctxm->ctx_k1, (u_int8_t *)out, hash);
++      return ret;
++} 
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/aes/ipsec_alg_aes.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,300 @@
++/*
++ * ipsec_alg AES cipher stubs
++ *
++ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ * 
++ * ipsec_alg_aes.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * Fixes by:
++ *    PK:     Pawel Krawczyk <kravietz@aba.krakow.pl>
++ * Fixes list:
++ *    PK:     make XCBC comply with latest draft (keylength)
++ *
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++/*    
++ *    special case: ipsec core modular with this static algo inside:
++ *    must avoid MODULE magic for this file
++ */
++#if defined(CONFIG_KLIPS_MODULE) && defined(CONFIG_KLIPS_ENC_AES)
++#undef MODULE
++#endif
++
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/string.h>
++
++/* Check if __exit is defined, if not null it */
++#ifndef __exit
++#define __exit
++#endif
++
++/*    Low freeswan header coupling    */
++#include <openswan.h>
++#include "openswan/ipsec_alg.h"
++#include "klips-crypto/aes_cbc.h"
++
++#define CONFIG_KLIPS_ENC_AES_MAC 1
++
++#define AES_CONTEXT_T aes_context
++static int debug_aes=0;
++static int test_aes=0;
++static int excl_aes=0;
++static int keyminbits=0;
++static int keymaxbits=0;
++#if defined(CONFIG_KLIPS_ENC_AES_MODULE)
++MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
++#ifdef module_param
++module_param(debug_aes,int,0664);
++module_param(test_aes,int,0664);
++module_param(excl_aes,int,0664);
++module_param(keyminbits,int,0664);
++module_param(keymaxbits,int,0664);
++#else
++MODULE_PARM(debug_aes, "i");
++MODULE_PARM(test_aes, "i");
++MODULE_PARM(excl_aes, "i");
++MODULE_PARM(keyminbits, "i");
++MODULE_PARM(keymaxbits, "i");
++#endif
++#endif
++
++#if CONFIG_KLIPS_ENC_AES_MAC
++#include "klips-crypto/aes_xcbc_mac.h"
++
++/*    
++ *    Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
++ *    We use 9 for non-modular algorithm and none for modular, thus
++ *    forcing user to specify one on module load. -kravietz
++ */
++#ifdef MODULE
++static int auth_id=0;
++#else
++static int auth_id=9;
++#endif
++#if 0
++#ifdef MODULE_PARM
++MODULE_PARM(auth_id, "i");
++#else
++module_param(auth_id,int,0664);
++#endif
++#endif
++#endif
++
++#define ESP_AES                       12      /* truely _constant_  :)  */
++
++/* 128, 192 or 256 */
++#define ESP_AES_KEY_SZ_MIN    16      /* 128 bit secret key */
++#define ESP_AES_KEY_SZ_MAX    32      /* 256 bit secret key */
++#define ESP_AES_CBC_BLK_LEN   16      /* AES-CBC block size */
++
++/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
++ * -kravietz
++ */
++#define ESP_AES_MAC_KEY_SZ    16      /* 128 bit MAC key */
++#define ESP_AES_MAC_BLK_LEN   16      /* 128 bit block */
++
++static int _aes_set_key(struct ipsec_alg_enc *alg,
++                      __u8 * key_e, const __u8 * key,
++                      size_t keysize)
++{
++      int ret;
++      AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
++      ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
++      if (debug_aes > 0)
++              printk(KERN_DEBUG "klips_debug:_aes_set_key:"
++                              "ret=%d key_e=%p key=%p keysize=%ld\n",
++                                ret, key_e, key, (unsigned long int) keysize);
++      return ret;
++}
++
++static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e,
++                          const __u8 * in, int ilen, const __u8 * iv,
++                          int encrypt)
++{
++      AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
++      if (debug_aes > 0)
++              printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
++                              "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
++                              key_e, in, ilen, iv, encrypt);
++      return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
++}
++#if CONFIG_KLIPS_ENC_AES_MAC
++static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
++      aes_context_mac *ctxm=(aes_context_mac *)key_a;
++      return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
++}
++static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
++      int ret;
++      char hash_buf[16];
++      aes_context_mac *ctxm=(aes_context_mac *)key_a;
++      ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
++      memcpy(hash, hash_buf, hashlen);
++      return ret;
++}
++static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
++      ixt_common: { ixt_version:      IPSEC_ALG_VERSION,
++                    ixt_refcnt:       ATOMIC_INIT(0),
++                    ixt_name:         "aes_mac",
++                    ixt_blocksize:    ESP_AES_MAC_BLK_LEN,
++                    ixt_support: {
++                      ias_exttype:    IPSEC_ALG_TYPE_AUTH,
++                      ias_id:         0,
++                      ias_keyminbits: ESP_AES_MAC_KEY_SZ*8,
++                      ias_keymaxbits: ESP_AES_MAC_KEY_SZ*8,
++              },
++      },
++#if defined(CONFIG_KLIPS_ENC_AES_MODULE)
++      ixt_module:     THIS_MODULE,
++#endif
++      ixt_a_keylen:   ESP_AES_MAC_KEY_SZ,
++      ixt_a_ctx_size: sizeof(aes_context_mac),
++      ixt_a_hmac_set_key:     _aes_mac_set_key,
++      ixt_a_hmac_hash:_aes_mac_hash,
++};
++#endif /* CONFIG_KLIPS_ENC_AES_MAC */
++static struct ipsec_alg_enc ipsec_alg_AES = {
++      ixt_common: { ixt_version:      IPSEC_ALG_VERSION,
++                    ixt_refcnt:       ATOMIC_INIT(0),
++                    ixt_name:         "aes",
++                    ixt_blocksize:    ESP_AES_CBC_BLK_LEN, 
++                    ixt_support: {
++                      ias_exttype:    IPSEC_ALG_TYPE_ENCRYPT,
++                      //ias_ivlen:      128,
++                      ias_id:         ESP_AES,
++                      ias_keyminbits: ESP_AES_KEY_SZ_MIN*8,
++                      ias_keymaxbits: ESP_AES_KEY_SZ_MAX*8,
++              },
++      },
++#if defined(CONFIG_KLIPS_ENC_AES_MODULE)
++      ixt_module:     THIS_MODULE,
++#endif
++      ixt_e_keylen:   ESP_AES_KEY_SZ_MAX,
++      ixt_e_ctx_size: sizeof(AES_CONTEXT_T),
++      ixt_e_set_key:  _aes_set_key,
++      ixt_e_cbc_encrypt:_aes_cbc_encrypt,
++};
++
++#if defined(CONFIG_KLIPS_ENC_AES_MODULE)
++IPSEC_ALG_MODULE_INIT_MOD( ipsec_aes_init )
++#else
++IPSEC_ALG_MODULE_INIT_STATIC( ipsec_aes_init )
++#endif
++{
++      int ret, test_ret;
++
++      if (keyminbits)
++              ipsec_alg_AES.ixt_common.ixt_support.ias_keyminbits=keyminbits;
++      if (keymaxbits) {
++              ipsec_alg_AES.ixt_common.ixt_support.ias_keymaxbits=keymaxbits;
++              if (keymaxbits*8>ipsec_alg_AES.ixt_common.ixt_support.ias_keymaxbits)
++                      ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
++      }
++      if (excl_aes) ipsec_alg_AES.ixt_common.ixt_state |= IPSEC_ALG_ST_EXCL;
++      ret=register_ipsec_alg_enc(&ipsec_alg_AES);
++      printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n", 
++                      ipsec_alg_AES.ixt_common.ixt_support.ias_exttype, 
++                      ipsec_alg_AES.ixt_common.ixt_support.ias_id, 
++                      ipsec_alg_AES.ixt_common.ixt_name, 
++                      ret);
++      if (ret==0 && test_aes) {
++              test_ret=ipsec_alg_test(
++                              ipsec_alg_AES.ixt_common.ixt_support.ias_exttype ,
++                              ipsec_alg_AES.ixt_common.ixt_support.ias_id, 
++                              test_aes);
++              printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n", 
++                              ipsec_alg_AES.ixt_common.ixt_support.ias_exttype , 
++                              ipsec_alg_AES.ixt_common.ixt_support.ias_id, 
++                              test_ret);
++      }
++#if CONFIG_KLIPS_ENC_AES_MAC
++      if (auth_id!=0){
++              int ret;
++              ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_id=auth_id;
++              ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
++              printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n", 
++                              ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_exttype, 
++                              ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_id, 
++                              ipsec_alg_AES_MAC.ixt_common.ixt_name, 
++                              ret);
++              if (ret==0 && test_aes) {
++                      test_ret=ipsec_alg_test(
++                                      ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_exttype,
++                                      ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_id, 
++                                      test_aes);
++                      printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n", 
++                                      ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_exttype, 
++                                      ipsec_alg_AES_MAC.ixt_common.ixt_support.ias_id, 
++                                      test_ret);
++              }
++      } else {
++              printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
++      }
++#endif /* CONFIG_KLIPS_ENC_AES_MAC */
++      return ret;
++}
++
++#if defined(CONFIG_KLIPS_ENC_AES_MODULE)
++IPSEC_ALG_MODULE_EXIT_MOD( ipsec_aes_fini )
++#else
++IPSEC_ALG_MODULE_EXIT_STATIC( ipsec_aes_fini )
++#endif
++{
++#if CONFIG_KLIPS_ENC_AES_MAC
++      if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
++#endif /* CONFIG_KLIPS_ENC_AES_MAC */
++      unregister_ipsec_alg_enc(&ipsec_alg_AES);
++      return;
++}
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++
++#if 0  /* +NOT_YET */
++#ifndef MODULE
++/*
++ *    This is intended for static module setups, currently
++ *    doesn't work for modular ipsec.o with static algos inside
++ */
++static int setup_keybits(const char *str)
++{
++      unsigned aux;
++      char *end;
++
++      aux = simple_strtoul(str,&end,0);
++      if (aux != 128 && aux != 192 && aux != 256)
++              return 0;
++      keyminbits = aux;
++
++      if (*end == 0 || *end != ',')
++              return 1;
++      str=end+1;
++      aux = simple_strtoul(str, NULL, 0);
++      if (aux != 128 && aux != 192 && aux != 256)
++              return 0;
++      if (aux >= keyminbits)
++              keymaxbits = aux;
++      return 1;
++}
++__setup("ipsec_aes_keybits=", setup_keybits);
++#endif
++#endif
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/Config.alg_aes.in     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,3 @@
++if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
++  tristate '        AES encryption algorithm' CONFIG_IPSEC_ENC_AES
++fi
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/Config.alg_cryptoapi.in     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,6 @@
++if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
++  dep_tristate '        CRYPTOAPI ciphers support (needs cryptoapi patch)' CONFIG_IPSEC_ALG_CRYPTOAPI $CONFIG_CRYPTO
++  if [ "$CONFIG_IPSEC_ALG_CRYPTOAPI" != "n" ]; then
++    bool '          CRYPTOAPI proprietary ciphers ' CONFIG_IPSEC_ALG_NON_LIBRE
++  fi
++fi
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/Config.in     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,3 @@
++#Placeholder
++source net/ipsec/alg/Config.alg_aes.in
++source net/ipsec/alg/Config.alg_cryptoapi.in
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/Makefile.alg_aes     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,18 @@
++MOD_AES := ipsec_aes.o
++
++ALG_MODULES += $(MOD_AES)
++ALG_SUBDIRS += libaes
++
++obj-$(CONFIG_IPSEC_ALG_AES) += $(MOD_AES)
++static_init-func-$(CONFIG_IPSEC_ALG_AES)+= ipsec_aes_init
++alg_obj-$(CONFIG_IPSEC_ALG_AES) += ipsec_alg_aes.o
++
++AES_OBJS := ipsec_alg_aes.o $(LIBCRYPTO)/libaes/libaes.a 
++
++
++$(MOD_AES): $(AES_OBJS) 
++      $(LD) $(EXTRA_LDFLAGS) -r $(AES_OBJS) -o $@
++
++$(LIBCRYPTO)/libaes/libaes.a: 
++        $(MAKE) -C $(LIBCRYPTO)/libaes CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' libaes.a
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/Makefile.alg_cryptoapi     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,14 @@
++MOD_CRYPTOAPI := ipsec_cryptoapi.o
++
++ifneq ($(wildcard $(TOPDIR)/include/linux/crypto.h),)
++ALG_MODULES += $(MOD_CRYPTOAPI)
++obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += $(MOD_CRYPTOAPI)
++static_init-func-$(CONFIG_IPSEC_ALG_CRYPTOAPI)+= ipsec_cryptoapi_init
++alg_obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += ipsec_alg_cryptoapi.o
++else
++$(warning "Linux CryptoAPI (2.4.22+ or 2.6.x) not found, not building ipsec_cryptoapi.o")
++endif
++
++CRYPTOAPI_OBJS := ipsec_alg_cryptoapi.o 
++$(MOD_CRYPTOAPI): $(CRYPTOAPI_OBJS)
++      $(LD) -r $(CRYPTOAPI_OBJS) -o $@
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/ipsec_alg_cryptoapi.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,442 @@
++/*
++ * ipsec_alg to linux cryptoapi GLUE
++ *
++ * Authors: CODE.ar TEAM
++ *    Harpo MAxx <harpo@linuxmendoza.org.ar>
++ *    JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ *    Luciano Ruete <docemeses@softhome.net>
++ * 
++ * ipsec_alg_cryptoapi.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * Example usage:
++ *   modinfo -p ipsec_cryptoapi   (quite useful info, including supported algos)
++ *   modprobe ipsec_cryptoapi
++ *   modprobe ipsec_cryptoapi test=1
++ *   modprobe ipsec_cryptoapi excl=1                     (exclusive cipher/algo)
++ *   modprobe ipsec_cryptoapi noauto=1  aes=1 twofish=1  (only these ciphers)
++ *   modprobe ipsec_cryptoapi aes=128,128                (force these keylens)
++ *   modprobe ipsec_cryptoapi des_ede3=0                 (everything but 3DES)
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++/*    
++ *    special case: ipsec core modular with this static algo inside:
++ *    must avoid MODULE magic for this file
++ */
++#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
++#undef MODULE
++#endif
++
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/string.h>
++
++/* Check if __exit is defined, if not null it */
++#ifndef __exit
++#define __exit
++#endif
++
++/* warn the innocent */
++#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
++#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
++#define NO_CRYPTOAPI_SUPPORT
++#endif
++/*    Low freeswan header coupling    */
++#include "openswan/ipsec_alg.h"
++
++#include <linux/crypto.h>
++#ifdef CRYPTO_API_VERSION_CODE
++#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
++#define NO_CRYPTOAPI_SUPPORT
++#endif
++
++#ifdef NO_CRYPTOAPI_SUPPORT
++#warning "Building an unusable module :P"
++/* Catch old CryptoAPI by not allowing module to load */
++IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
++{
++      printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
++      return -EINVAL;
++}
++#else
++#include <asm/scatterlist.h>
++#include <asm/pgtable.h>
++#include <linux/mm.h>
++
++#define CIPHERNAME_AES                "aes"
++#define CIPHERNAME_3DES               "des3_ede"
++#define CIPHERNAME_BLOWFISH   "blowfish"
++#define CIPHERNAME_CAST               "cast5"
++#define CIPHERNAME_SERPENT    "serpent"
++#define CIPHERNAME_TWOFISH    "twofish"
++
++#define ESP_3DES              3
++#define ESP_AES                       12
++#define ESP_BLOWFISH          7       /* truely _constant_  :)  */
++#define ESP_CAST              6       /* quite constant :) */
++#define ESP_SERPENT           252     /* from ipsec drafts */
++#define ESP_TWOFISH           253     /* from ipsec drafts */
++
++#define AH_MD5                        2
++#define AH_SHA                        3
++#define DIGESTNAME_MD5                "md5"
++#define DIGESTNAME_SHA1               "sha1"
++
++MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
++static int debug=0;
++static int test=0;
++static int excl=0;
++#ifdef module_param
++module_param(debug, int, 0664);
++module_param(test, int, 0664);
++module_param(excl, int, 0664);
++#else
++MODULE_PARM(debug, "i");
++MODULE_PARM(test, "i");
++MODULE_PARM(excl, "i");
++#endif
++
++static int noauto = 0;
++#ifdef module_param
++module_param(noauto,int, 0664);
++#else
++MODULE_PARM(noauto,"i");
++#endif
++MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
++
++static int des_ede3[] = {-1, -1};
++static int aes[] = {-1, -1};
++static int blowfish[] = {-1, -1};
++static int cast[] = {-1, -1};
++static int serpent[] = {-1, -1};
++static int twofish[] = {-1, -1};
++
++#ifdef module_param_array
++module_param_array(des_ede3,int,NULL,0);
++module_param_array(aes,int,NULL,0);
++module_param_array(blowfish,int,NULL,0);
++module_param_array(cast,int,NULL,0);
++module_param_array(serpent,int,NULL,0);
++module_param_array(twofish,int,NULL,0);
++#else
++MODULE_PARM(des_ede3,"1-2i");
++MODULE_PARM(aes,"1-2i");
++MODULE_PARM(blowfish,"1-2i");
++MODULE_PARM(cast,"1-2i");
++MODULE_PARM(serpent,"1-2i");
++MODULE_PARM(twofish,"1-2i");
++#endif
++MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
++MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
++
++struct ipsec_alg_capi_cipher {
++      const char *ciphername; /* cryptoapi's ciphername */
++      unsigned blocksize;
++      unsigned short minbits;
++      unsigned short maxbits;
++      int *parm;              /* lkm param for this cipher */
++      struct ipsec_alg_enc alg;       /* note it's not a pointer */
++};
++static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
++      { CIPHERNAME_AES ,     16, 128, 256, aes    , { ixt_alg_id: ESP_AES, }},
++      { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
++      { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
++      { CIPHERNAME_CAST ,     8, 128, 128, cast   , { ixt_alg_id: ESP_CAST, }},
++      { CIPHERNAME_BLOWFISH , 8,  96, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
++      { CIPHERNAME_3DES ,     8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
++      { NULL, 0, 0, 0, NULL, {} }
++};
++#ifdef NOT_YET
++struct ipsec_alg_capi_digest {
++      const char *digestname; /* cryptoapi's digestname */
++      struct digest_implementation *di;
++      struct ipsec_alg_auth alg;      /* note it's not a pointer */
++};
++static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
++      { DIGESTNAME_MD5,     NULL, { ixt_alg_id: AH_MD5, }},
++      { DIGESTNAME_SHA1,    NULL, { ixt_alg_id: AH_SHA, }},
++      { NULL, NULL, {} }
++};
++#endif
++/*
++ *    "generic" linux cryptoapi setup_cipher() function
++ */
++int setup_cipher(const char *ciphername)
++{
++      return crypto_alg_available(ciphername, 0);
++}
++
++/*
++ *    setups ipsec_alg_capi_cipher "hyper" struct components, calling
++ *    register_ipsec_alg for cointaned ipsec_alg object
++ */
++static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
++static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
++static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
++
++static int
++setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
++{
++      int ret;
++      cptr->alg.ixt_version = IPSEC_ALG_VERSION;
++      cptr->alg.ixt_module = THIS_MODULE;
++      atomic_set (& cptr->alg.ixt_refcnt, 0);
++      strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
++
++      cptr->alg.ixt_blocksize=cptr->blocksize;
++      cptr->alg.ixt_keyminbits=cptr->minbits;
++      cptr->alg.ixt_keymaxbits=cptr->maxbits;
++      cptr->alg.ixt_state = 0;
++      if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
++      cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
++      cptr->alg.ixt_e_ctx_size = 0;
++      cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
++      cptr->alg.ixt_e_new_key = _capi_new_key;
++      cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
++      cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
++      cptr->alg.ixt_data = cptr;
++
++      ret=register_ipsec_alg_enc(&cptr->alg);
++      printk("setup_ipsec_alg_capi_cipher(): " 
++                      "alg_type=%d alg_id=%d name=%s "
++                      "keyminbits=%d keymaxbits=%d, ret=%d\n", 
++                              cptr->alg.ixt_alg_type, 
++                              cptr->alg.ixt_alg_id, 
++                              cptr->alg.ixt_name, 
++                              cptr->alg.ixt_keyminbits,
++                              cptr->alg.ixt_keymaxbits,
++                              ret);
++      return ret;
++}
++/*
++ *    called in ipsec_sa_wipe() time, will destroy key contexts
++ *    and do 1 unbind()
++ */
++static void 
++_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
++{
++      struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
++      
++      if (debug > 0)
++              printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
++                              "name=%s key_e=%p \n",
++                              alg->ixt_name, key_e);
++      if (!key_e) {
++              printk(KERN_ERR "klips_debug: _capi_destroy_key:"
++                              "name=%s NULL key_e!\n",
++                              alg->ixt_name);
++              return;
++      }
++      crypto_free_tfm(tfm);
++}
++      
++/*
++ *    create new key context, need alg->ixt_data to know which
++ *    (of many) cipher inside this module is the target
++ */
++static __u8 *
++_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      struct crypto_tfm *tfm=NULL;
++
++      cptr = alg->ixt_data;
++      if (!cptr) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "NULL ixt_data (?!) for \"%s\" algo\n" 
++                              , alg->ixt_name);
++              goto err;
++      }
++      if (debug > 0)
++              printk(KERN_DEBUG "klips_debug:_capi_new_key:"
++                              "name=%s cptr=%p key=%p keysize=%d\n",
++                              alg->ixt_name, cptr, key, keylen);
++      
++      /*      
++       *      alloc tfm
++       */
++      tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
++      if (!tfm) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n" 
++                      , alg->ixt_name, cptr->ciphername);
++              goto err;
++      }
++      if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n" 
++                      , alg->ixt_name, keylen);
++              crypto_free_tfm(tfm);
++              tfm=NULL;
++      }
++err:
++      if (debug > 0)
++              printk(KERN_DEBUG "klips_debug:_capi_new_key:"
++                              "name=%s key=%p keylen=%d tfm=%p\n",
++                              alg->ixt_name, key, keylen, tfm);
++      return (__u8 *) tfm;
++}
++/*
++ *    core encryption function: will use cx->ci to call actual cipher's
++ *    cbc function
++ */
++static int 
++_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
++      int error =0;
++      struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
++      struct scatterlist sg = { 
++              .page = virt_to_page(in),
++              .offset = (unsigned long)(in) % PAGE_SIZE,
++              .length=ilen,
++      };
++      if (debug > 1)
++              printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
++                              "key_e=%p "
++                              "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
++                              , key_e
++                              , in, in, ilen, iv, encrypt);
++      crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
++      if (encrypt)
++              error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
++      else
++              error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
++      if (debug > 1)
++              printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
++                              "error=%d\n"
++                              , error);
++      return (error<0)? error : ilen;
++}
++/*
++ *    main initialization loop: for each cipher in list, do
++ *    1) setup cryptoapi cipher else continue
++ *    2) register ipsec_alg object
++ */
++static int
++setup_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              /* 
++               * see if cipher has been disabled (0) or
++               * if noauto set and not enabled (1)
++               */
++              if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
++                      if (debug>0)
++                              printk(KERN_INFO "setup_cipher_list(): "
++                                      "ciphername=%s skipped at user request: "
++                                      "noauto=%d parm[0]=%d parm[1]=%d\n"
++                                      , cptr->ciphername
++                                      , noauto
++                                      , cptr->parm[0]
++                                      , cptr->parm[1]);
++                      continue;
++              }
++              /* 
++               *      use a local ci to avoid touching cptr->ci,
++               *      if register ipsec_alg success then bind cipher
++               */
++              if( setup_cipher(cptr->ciphername) ) {
++                      if (debug > 0)
++                              printk(KERN_DEBUG "klips_debug:"
++                                              "setup_cipher_list():"
++                                              "ciphername=%s found\n"
++                              , cptr->ciphername);
++                      if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
++                              
++                              
++                      } else {
++                              printk(KERN_ERR "klips_debug:"
++                                              "setup_cipher_list():"
++                                              "ciphername=%s failed ipsec_alg_register\n"
++                              , cptr->ciphername);
++                      }
++              } else {
++                      if (debug>0)
++                              printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
++                              cptr->ciphername);
++              }
++      }
++      return 0;
++}
++/*
++ *    deregister ipsec_alg objects and unbind ciphers
++ */
++static int
++unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
++                      unregister_ipsec_alg_enc(&cptr->alg);
++              }
++      }
++      return 0;
++}
++/*
++ *    test loop for registered algos
++ */
++static int
++test_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      int test_ret;
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
++                      test_ret=ipsec_alg_test(
++                                      cptr->alg.ixt_alg_type,
++                                      cptr->alg.ixt_alg_id, 
++                                      test);
++                      printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n", 
++                                      cptr->alg.ixt_alg_type, 
++                                      cptr->alg.ixt_alg_id, 
++                                      test_ret);
++              }
++      }
++      return 0;
++}
++
++IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
++{
++      int ret, test_ret;
++      if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
++              return  -EPROTONOSUPPORT;
++      if (ret==0 && test) {
++              test_ret=test_cipher_list(alg_capi_carray);
++      }
++      return ret;
++}
++IPSEC_ALG_MODULE_EXIT( ipsec_cryptoapi_fini )
++{
++      unsetup_cipher_list(alg_capi_carray);
++      return;
++}
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++
++EXPORT_NO_SYMBOLS;
++#endif /* NO_CRYPTOAPI_SUPPORT */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/alg/scripts/mk-static_init.c.sh     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,18 @@
++#!/bin/sh
++cat << EOF
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include "freeswan/ipsec_alg.h"
++$(for i in $*; do
++      test -z "$i" && continue
++      echo "extern int $i(void);"
++done)
++void ipsec_alg_static_init(void){ 
++      int __attribute__ ((unused)) err=0;
++$(for i in $*; do
++      test -z "$i" && continue
++      echo "  if ((err=$i()) < 0)"
++      echo "          printk(KERN_WARNING \"$i() returned %d\", err);"
++done)
++}
++EOF
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/anyaddr.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,150 @@
++/*
++ * special addresses
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: anyaddr.c,v 1.10 2004/07/10 07:43:47 mcr Exp $
++ */
++#include "openswan.h"
++
++/* these are mostly fallbacks for the no-IPv6-support-in-library case */
++#ifndef IN6ADDR_ANY_INIT
++#define       IN6ADDR_ANY_INIT        {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
++#endif
++#ifndef IN6ADDR_LOOPBACK_INIT
++#define       IN6ADDR_LOOPBACK_INIT   {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
++#endif
++
++static struct in6_addr v6any = IN6ADDR_ANY_INIT;
++static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT;
++
++/*
++ - anyaddr - initialize to the any-address value
++ */
++err_t                         /* NULL for success, else string literal */
++anyaddr(af, dst)
++int af;                               /* address family */
++ip_address *dst;
++{
++      uint32_t v4any = htonl(INADDR_ANY);
++
++      switch (af) {
++      case AF_INET:
++              return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst);
++              break;
++      case AF_INET6:
++              return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst);
++              break;
++      default:
++              return "unknown address family in anyaddr/unspecaddr";
++              break;
++      }
++}
++
++/*
++ - unspecaddr - initialize to the unspecified-address value
++ */
++err_t                         /* NULL for success, else string literal */
++unspecaddr(af, dst)
++int af;                               /* address family */
++ip_address *dst;
++{
++      return anyaddr(af, dst);
++}
++
++/*
++ - loopbackaddr - initialize to the loopback-address value
++ */
++err_t                         /* NULL for success, else string literal */
++loopbackaddr(af, dst)
++int af;                               /* address family */
++ip_address *dst;
++{
++      uint32_t v4loop = htonl(INADDR_LOOPBACK);
++
++      switch (af) {
++      case AF_INET:
++              return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst);
++              break;
++      case AF_INET6:
++              return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst);
++              break;
++      default:
++              return "unknown address family in loopbackaddr";
++              break;
++      }
++}
++
++/*
++ - isanyaddr - test for the any-address value
++ */
++int
++isanyaddr(src)
++const ip_address *src;
++{
++      uint32_t v4any = htonl(INADDR_ANY);
++      int cmp;
++
++      switch (src->u.v4.sin_family) {
++      case AF_INET:
++              cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any));
++              break;
++      case AF_INET6:
++              cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any));
++              break;
++
++      case 0:
++              /* a zeroed structure is considered any address */
++              return 1;
++
++      default:
++              return 0;
++              break;
++      }
++
++      return (cmp == 0) ? 1 : 0;
++}
++
++/*
++ - isunspecaddr - test for the unspecified-address value
++ */
++int
++isunspecaddr(src)
++const ip_address *src;
++{
++      return isanyaddr(src);
++}
++
++/*
++ - isloopbackaddr - test for the loopback-address value
++ */
++int
++isloopbackaddr(src)
++const ip_address *src;
++{
++      uint32_t v4loop = htonl(INADDR_LOOPBACK);
++      int cmp;
++
++      switch (src->u.v4.sin_family) {
++      case AF_INET:
++              cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop));
++              break;
++      case AF_INET6:
++              cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop));
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      return (cmp == 0) ? 1 : 0;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/datatot.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,234 @@
++/*
++ * convert from binary data (e.g. key) to text form
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: datatot.c,v 1.9 2005/08/30 21:15:26 mcr Exp $
++ */
++#include "openswan.h"
++
++static void convert(const char *src, size_t nreal, int format, char *out);
++
++/*
++ - datatot - convert data bytes to text
++ */
++size_t                                /* true length (with NUL) for success */
++datatot(src, srclen, format, dst, dstlen)
++const unsigned char *src;
++size_t srclen;
++int format;                   /* character indicating what format */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t inblocksize;     /* process this many bytes at a time */
++      size_t outblocksize;    /* producing this many */
++      size_t breakevery;      /* add a _ every this many (0 means don't) */
++      size_t sincebreak;      /* output bytes since last _ */
++      char breakchar;         /* character used to break between groups */
++      unsigned char inblock[10];      /* enough for any format */
++      char outblock[10];      /* enough for any format */
++      char fake[1];           /* fake output area for dstlen == 0 */
++      size_t needed;          /* return value */
++      char *stop;             /* where the terminating NUL will go */
++      size_t ntodo;           /* remaining input */
++      size_t nreal;
++      char *out;
++      char *prefix;
++
++      breakevery = 0;
++      breakchar = '_';
++
++      switch (format) {
++      case 0:
++      case 'h':
++              format = 'x';
++              breakevery = 8;
++              /* FALLTHROUGH */
++      case 'x':
++              inblocksize = 1;
++              outblocksize = 2;
++              prefix = "0x";
++              break;
++      case ':':
++              format = 'x';
++              breakevery = 2;
++              breakchar = ':';
++              /* FALLTHROUGH */
++      case 16:
++              inblocksize = 1;
++              outblocksize = 2;
++              prefix = "";
++              format = 'x';
++              break;
++      case 's':
++              inblocksize = 3;
++              outblocksize = 4;
++              prefix = "0s";
++              break;
++      case 64:                /* beware, equals ' ' */
++              inblocksize = 3;
++              outblocksize = 4;
++              prefix = "";
++              format = 's';
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      user_assert(inblocksize < sizeof(inblock));
++      user_assert(outblocksize < sizeof(outblock));
++      user_assert(breakevery % outblocksize == 0);
++
++      if (srclen == 0)
++              return 0;
++      ntodo = srclen;
++
++      if (dstlen == 0) {      /* dispose of awkward special case */
++              dst = fake;
++              dstlen = 1;
++      }
++      stop = dst + dstlen - 1;
++
++      nreal = strlen(prefix);
++      needed = nreal;                 /* for starters */
++      if (dstlen <= nreal) {          /* prefix won't fit */
++              strncpy(dst, prefix, dstlen - 1);
++              dst += dstlen - 1;
++      } else {
++              strcpy(dst, prefix);
++              dst += nreal;
++      }
++
++      user_assert(dst <= stop);
++      sincebreak = 0;
++
++      while (ntodo > 0) {
++              if (ntodo < inblocksize) {      /* incomplete input */
++                      memset(inblock, 0, sizeof(inblock));
++                      memcpy(inblock, src, ntodo);
++                      src = inblock;
++                      nreal = ntodo;
++                      ntodo = inblocksize;
++              } else
++                      nreal = inblocksize;
++              out = (outblocksize > stop - dst) ? outblock : dst;
++
++              convert((const char *)src, nreal, format, out);
++              needed += outblocksize;
++              sincebreak += outblocksize;
++              if (dst < stop) {
++                      if (out != dst) {
++                              user_assert(outblocksize > stop - dst);
++                              memcpy(dst, out, stop - dst);
++                              dst = stop;
++                      } else
++                              dst += outblocksize;
++              }
++
++              src += inblocksize;
++              ntodo -= inblocksize;
++              if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) {
++                      if (dst < stop)
++                              *dst++ = breakchar;
++                      needed++;
++                      sincebreak = 0;
++              }
++      }
++
++      user_assert(dst <= stop);
++      *dst++ = '\0';
++      needed++;
++
++      return needed;
++}
++
++/*
++ - convert - convert one input block to one output block
++ */
++static void
++convert(src, nreal, format, out)
++const char *src;
++size_t nreal;                 /* how much of the input block is real */
++int format;
++char *out;
++{
++      static char hex[] = "0123456789abcdef";
++      static char base64[] =  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++                              "abcdefghijklmnopqrstuvwxyz"
++                              "0123456789+/";
++      unsigned char c;
++      unsigned char c1, c2, c3;
++
++      user_assert(nreal > 0);
++      switch (format) {
++      case 'x':
++              user_assert(nreal == 1);
++              c = (unsigned char)*src;
++              *out++ = hex[c >> 4];
++              *out++ = hex[c & 0xf];
++              break;
++      case 's':
++              c1 = (unsigned char)*src++;
++              c2 = (unsigned char)*src++;
++              c3 = (unsigned char)*src++;
++              *out++ = base64[c1 >> 2];       /* top 6 bits of c1 */
++              c = (c1 & 0x3) << 4;            /* bottom 2 of c1... */
++              c |= c2 >> 4;                   /* ...top 4 of c2 */
++              *out++ = base64[c];
++              if (nreal == 1)
++                      *out++ = '=';
++              else {
++                      c = (c2 & 0xf) << 2;    /* bottom 4 of c2... */
++                      c |= c3 >> 6;           /* ...top 2 of c3 */
++                      *out++ = base64[c];
++              }
++              if (nreal <= 2)
++                      *out++ = '=';
++              else
++                      *out++ = base64[c3 & 0x3f];     /* bottom 6 of c3 */
++              break;
++      default:
++              user_assert(nreal == 0);        /* unknown format */
++              break;
++      }
++}
++
++/*
++ - datatoa - convert data to ASCII
++ * backward-compatibility synonym for datatot
++ */
++size_t                                /* true length (with NUL) for success */
++datatoa(src, srclen, format, dst, dstlen)
++const unsigned char *src;
++size_t srclen;
++int format;                   /* character indicating what format */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      return datatot(src, srclen, format, dst, dstlen);
++}
++
++/*
++ - bytestoa - convert data bytes to ASCII
++ * backward-compatibility synonym for datatot
++ */
++size_t                                /* true length (with NUL) for success */
++bytestoa(src, srclen, format, dst, dstlen)
++const unsigned char *src;
++size_t srclen;
++int format;                   /* character indicating what format */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      return datatot(src, srclen, format, dst, dstlen);
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/defconfig     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,63 @@
++
++#
++# RCSID $Id: defconfig,v 1.30 2005/09/15 02:31:12 paul Exp $
++#
++
++#
++# Openswan IPSec implementation, KLIPS kernel config defaults
++#
++
++#
++# First, lets override stuff already set or not in the kernel config.
++#
++# We can't even think about leaving this off...
++CONFIG_INET=y
++
++#
++# This must be on for subnet protection.
++CONFIG_IP_FORWARD=y
++
++# Shut off IPSEC masquerading if it has been enabled, since it will 
++# break the compile.  IPPROTO_ESP and IPPROTO_AH were included in 
++# net/ipv4/ip_masq.c when they should have gone into include/linux/in.h.
++CONFIG_IP_MASQUERADE_IPSEC=n
++
++#
++# Next, lets set the recommended FreeS/WAN configuration.
++#
++
++# To config as static (preferred), 'y'.  To config as module, 'm'.
++CONFIG_KLIPS=m
++
++# To do tunnel mode IPSec, this must be enabled.
++CONFIG_KLIPS_IPIP=y
++
++# To enable authentication, say 'y'.   (Highly recommended)
++CONFIG_KLIPS_AH=y
++
++# Authentication algorithm(s):
++CONFIG_KLIPS_AUTH_HMAC_MD5=y
++CONFIG_KLIPS_AUTH_HMAC_SHA1=y
++
++# To enable encryption, say 'y'.   (Highly recommended)
++CONFIG_KLIPS_ESP=y
++
++# modular algo extensions (and new ALGOs)
++CONFIG_KLIPS_ALG=y
++
++# Encryption algorithm(s):
++CONFIG_KLIPS_ENC_3DES=y
++CONFIG_KLIPS_ENC_AES=y
++
++# Use CryptoAPI for ALG? - by default, no.
++CONFIG_KLIPS_ENC_CRYPTOAPI=n
++
++# IP Compression: new, probably still has minor bugs.
++CONFIG_KLIPS_IPCOMP=y
++
++# To enable userspace-switchable KLIPS debugging, say 'y'.
++CONFIG_KLIPS_DEBUG=y
++
++# OCF HW offloading, requires kernel patch
++# CONFIG_KLIPS_OCF is not set
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/deflate.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1351 @@
++/* deflate.c -- compress data using the deflation algorithm
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/*
++ *  ALGORITHM
++ *
++ *      The "deflation" process depends on being able to identify portions
++ *      of the input text which are identical to earlier input (within a
++ *      sliding window trailing behind the input currently being processed).
++ *
++ *      The most straightforward technique turns out to be the fastest for
++ *      most input files: try all possible matches and select the longest.
++ *      The key feature of this algorithm is that insertions into the string
++ *      dictionary are very simple and thus fast, and deletions are avoided
++ *      completely. Insertions are performed at each input character, whereas
++ *      string matches are performed only when the previous match ends. So it
++ *      is preferable to spend more time in matches to allow very fast string
++ *      insertions and avoid deletions. The matching algorithm for small
++ *      strings is inspired from that of Rabin & Karp. A brute force approach
++ *      is used to find longer strings when a small match has been found.
++ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
++ *      (by Leonid Broukhis).
++ *         A previous version of this file used a more sophisticated algorithm
++ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
++ *      time, but has a larger average cost, uses more memory and is patented.
++ *      However the F&G algorithm may be faster for some highly redundant
++ *      files if the parameter max_chain_length (described below) is too large.
++ *
++ *  ACKNOWLEDGEMENTS
++ *
++ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
++ *      I found it in 'freeze' written by Leonid Broukhis.
++ *      Thanks to many people for bug reports and testing.
++ *
++ *  REFERENCES
++ *
++ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
++ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
++ *
++ *      A description of the Rabin and Karp algorithm is given in the book
++ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
++ *
++ *      Fiala,E.R., and Greene,D.H.
++ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
++ *
++ */
++
++/* @(#) $Id: deflate.c,v 1.4 2004/07/10 07:48:37 mcr Exp $ */
++
++#include "deflate.h"
++
++local const char deflate_copyright[] =
++   " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly ";
++/*
++  If you use the zlib library in a product, an acknowledgment is welcome
++  in the documentation of your product. If for some reason you cannot
++  include such an acknowledgment, I would appreciate that you keep this
++  copyright string in the executable of your product.
++ */
++
++/* ===========================================================================
++ *  Function prototypes.
++ */
++typedef enum {
++    need_more,      /* block not completed, need more input or more output */
++    block_done,     /* block flush performed */
++    finish_started, /* finish started, need only more output at next deflate */
++    finish_done     /* finish done, accept no more input or output */
++} block_state;
++
++typedef block_state (*compress_func) OF((deflate_state *s, int flush));
++/* Compression function. Returns the block state after the call. */
++
++local void fill_window    OF((deflate_state *s));
++local block_state deflate_stored OF((deflate_state *s, int flush));
++local block_state deflate_fast   OF((deflate_state *s, int flush));
++local block_state deflate_slow   OF((deflate_state *s, int flush));
++local void lm_init        OF((deflate_state *s));
++local void putShortMSB    OF((deflate_state *s, uInt b));
++local void flush_pending  OF((z_streamp strm));
++local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
++#ifdef ASMV
++      void match_init OF((void)); /* asm code initialization */
++      uInt longest_match  OF((deflate_state *s, IPos cur_match));
++#else
++local uInt longest_match  OF((deflate_state *s, IPos cur_match));
++#endif
++
++#ifdef DEBUG
++local  void check_match OF((deflate_state *s, IPos start, IPos match,
++                            int length));
++#endif
++
++/* ===========================================================================
++ * Local data
++ */
++
++#define NIL 0
++/* Tail of hash chains */
++
++#ifndef TOO_FAR
++#  define TOO_FAR 4096
++#endif
++/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++/* Values for max_lazy_match, good_match and max_chain_length, depending on
++ * the desired pack level (0..9). The values given below have been tuned to
++ * exclude worst case performance for pathological files. Better values may be
++ * found for specific files.
++ */
++typedef struct config_s {
++   ush good_length; /* reduce lazy search above this match length */
++   ush max_lazy;    /* do not perform lazy search above this match length */
++   ush nice_length; /* quit search above this match length */
++   ush max_chain;
++   compress_func func;
++} config;
++
++local const config configuration_table[10] = {
++/*      good lazy nice chain */
++/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
++/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
++/* 2 */ {4,    5, 16,    8, deflate_fast},
++/* 3 */ {4,    6, 32,   32, deflate_fast},
++
++/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
++/* 5 */ {8,   16, 32,   32, deflate_slow},
++/* 6 */ {8,   16, 128, 128, deflate_slow},
++/* 7 */ {8,   32, 128, 256, deflate_slow},
++/* 8 */ {32, 128, 258, 1024, deflate_slow},
++/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
++
++/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
++ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
++ * meaning.
++ */
++
++#define EQUAL 0
++/* result of memcmp for equal strings */
++
++struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
++
++/* ===========================================================================
++ * Update a hash value with the given input byte
++ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
++ *    input characters, so that a running hash key can be computed from the
++ *    previous key instead of complete recalculation each time.
++ */
++#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
++
++
++/* ===========================================================================
++ * Insert string str in the dictionary and set match_head to the previous head
++ * of the hash chain (the most recent string with same hash key). Return
++ * the previous length of the hash chain.
++ * If this file is compiled with -DFASTEST, the compression level is forced
++ * to 1, and no hash chains are maintained.
++ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
++ *    input characters and the first MIN_MATCH bytes of str are valid
++ *    (except for the last MIN_MATCH-1 bytes of the input file).
++ */
++#ifdef FASTEST
++#define INSERT_STRING(s, str, match_head) \
++   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
++    match_head = s->head[s->ins_h], \
++    s->head[s->ins_h] = (Pos)(str))
++#else
++#define INSERT_STRING(s, str, match_head) \
++   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
++    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
++    s->head[s->ins_h] = (Pos)(str))
++#endif
++
++/* ===========================================================================
++ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
++ * prev[] will be initialized on the fly.
++ */
++#define CLEAR_HASH(s) \
++    s->head[s->hash_size-1] = NIL; \
++    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
++
++/* ========================================================================= */
++int ZEXPORT deflateInit_(strm, level, version, stream_size)
++    z_streamp strm;
++    int level;
++    const char *version;
++    int stream_size;
++{
++    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
++                       Z_DEFAULT_STRATEGY, version, stream_size);
++    /* To do: ignore strm->next_in if we use it as window */
++}
++
++/* ========================================================================= */
++int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
++                version, stream_size)
++    z_streamp strm;
++    int  level;
++    int  method;
++    int  windowBits;
++    int  memLevel;
++    int  strategy;
++    const char *version;
++    int stream_size;
++{
++    deflate_state *s;
++    int noheader = 0;
++    static const char* my_version = ZLIB_VERSION;
++
++    ushf *overlay;
++    /* We overlay pending_buf and d_buf+l_buf. This works since the average
++     * output size for (length,distance) codes is <= 24 bits.
++     */
++
++    if (version == Z_NULL || version[0] != my_version[0] ||
++        stream_size != sizeof(z_stream)) {
++      return Z_VERSION_ERROR;
++    }
++    if (strm == Z_NULL) return Z_STREAM_ERROR;
++
++    strm->msg = Z_NULL;
++    if (strm->zalloc == Z_NULL) {
++      return Z_STREAM_ERROR;
++/*    strm->zalloc = zcalloc;
++      strm->opaque = (voidpf)0;*/
++    }
++    if (strm->zfree == Z_NULL) return Z_STREAM_ERROR; /* strm->zfree = zcfree; */
++
++    if (level == Z_DEFAULT_COMPRESSION) level = 6;
++#ifdef FASTEST
++    level = 1;
++#endif
++
++    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
++        noheader = 1;
++        windowBits = -windowBits;
++    }
++    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
++        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
++      strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
++        return Z_STREAM_ERROR;
++    }
++    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
++    if (s == Z_NULL) return Z_MEM_ERROR;
++    strm->state = (struct internal_state FAR *)s;
++    s->strm = strm;
++
++    s->noheader = noheader;
++    s->w_bits = windowBits;
++    s->w_size = 1 << s->w_bits;
++    s->w_mask = s->w_size - 1;
++
++    s->hash_bits = memLevel + 7;
++    s->hash_size = 1 << s->hash_bits;
++    s->hash_mask = s->hash_size - 1;
++    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
++
++    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
++    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
++    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
++
++    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
++
++    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
++    s->pending_buf = (uchf *) overlay;
++    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
++
++    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
++        s->pending_buf == Z_NULL) {
++        strm->msg = ERR_MSG(Z_MEM_ERROR);
++        deflateEnd (strm);
++        return Z_MEM_ERROR;
++    }
++    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
++    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
++
++    s->level = level;
++    s->strategy = strategy;
++    s->method = (Byte)method;
++
++    return deflateReset(strm);
++}
++
++/* ========================================================================= */
++int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
++    z_streamp strm;
++    const Bytef *dictionary;
++    uInt  dictLength;
++{
++    deflate_state *s;
++    uInt length = dictLength;
++    uInt n;
++    IPos hash_head = 0;
++
++    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
++        strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
++
++    s = strm->state;
++    strm->adler = adler32(strm->adler, dictionary, dictLength);
++
++    if (length < MIN_MATCH) return Z_OK;
++    if (length > MAX_DIST(s)) {
++      length = MAX_DIST(s);
++#ifndef USE_DICT_HEAD
++      dictionary += dictLength - length; /* use the tail of the dictionary */
++#endif
++    }
++    zmemcpy(s->window, dictionary, length);
++    s->strstart = length;
++    s->block_start = (long)length;
++
++    /* Insert all strings in the hash table (except for the last two bytes).
++     * s->lookahead stays null, so s->ins_h will be recomputed at the next
++     * call of fill_window.
++     */
++    s->ins_h = s->window[0];
++    UPDATE_HASH(s, s->ins_h, s->window[1]);
++    for (n = 0; n <= length - MIN_MATCH; n++) {
++      INSERT_STRING(s, n, hash_head);
++    }
++    if (hash_head) hash_head = 0;  /* to make compiler happy */
++    return Z_OK;
++}
++
++/* ========================================================================= */
++int ZEXPORT deflateReset (strm)
++    z_streamp strm;
++{
++    deflate_state *s;
++    
++    if (strm == Z_NULL || strm->state == Z_NULL ||
++        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
++
++    strm->total_in = strm->total_out = 0;
++    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
++    strm->data_type = Z_UNKNOWN;
++
++    s = (deflate_state *)strm->state;
++    s->pending = 0;
++    s->pending_out = s->pending_buf;
++
++    if (s->noheader < 0) {
++        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
++    }
++    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
++    strm->adler = 1;
++    s->last_flush = Z_NO_FLUSH;
++
++    _tr_init(s);
++    lm_init(s);
++
++    return Z_OK;
++}
++
++/* ========================================================================= */
++int ZEXPORT deflateParams(strm, level, strategy)
++    z_streamp strm;
++    int level;
++    int strategy;
++{
++    deflate_state *s;
++    compress_func func;
++    int err = Z_OK;
++
++    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
++    s = strm->state;
++
++    if (level == Z_DEFAULT_COMPRESSION) {
++      level = 6;
++    }
++    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
++      return Z_STREAM_ERROR;
++    }
++    func = configuration_table[s->level].func;
++
++    if (func != configuration_table[level].func && strm->total_in != 0) {
++      /* Flush the last buffer: */
++      err = deflate(strm, Z_PARTIAL_FLUSH);
++    }
++    if (s->level != level) {
++      s->level = level;
++      s->max_lazy_match   = configuration_table[level].max_lazy;
++      s->good_match       = configuration_table[level].good_length;
++      s->nice_match       = configuration_table[level].nice_length;
++      s->max_chain_length = configuration_table[level].max_chain;
++    }
++    s->strategy = strategy;
++    return err;
++}
++
++/* =========================================================================
++ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
++ * IN assertion: the stream state is correct and there is enough room in
++ * pending_buf.
++ */
++local void putShortMSB (s, b)
++    deflate_state *s;
++    uInt b;
++{
++    put_byte(s, (Byte)(b >> 8));
++    put_byte(s, (Byte)(b & 0xff));
++}   
++
++/* =========================================================================
++ * Flush as much pending output as possible. All deflate() output goes
++ * through this function so some applications may wish to modify it
++ * to avoid allocating a large strm->next_out buffer and copying into it.
++ * (See also read_buf()).
++ */
++local void flush_pending(strm)
++    z_streamp strm;
++{
++    unsigned len = strm->state->pending;
++
++    if (len > strm->avail_out) len = strm->avail_out;
++    if (len == 0) return;
++
++    zmemcpy(strm->next_out, strm->state->pending_out, len);
++    strm->next_out  += len;
++    strm->state->pending_out  += len;
++    strm->total_out += len;
++    strm->avail_out  -= len;
++    strm->state->pending -= len;
++    if (strm->state->pending == 0) {
++        strm->state->pending_out = strm->state->pending_buf;
++    }
++}
++
++/* ========================================================================= */
++int ZEXPORT deflate (strm, flush)
++    z_streamp strm;
++    int flush;
++{
++    int old_flush; /* value of flush param for previous deflate call */
++    deflate_state *s;
++
++    if (strm == Z_NULL || strm->state == Z_NULL ||
++      flush > Z_FINISH || flush < 0) {
++        return Z_STREAM_ERROR;
++    }
++    s = strm->state;
++
++    if (strm->next_out == Z_NULL ||
++        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
++      (s->status == FINISH_STATE && flush != Z_FINISH)) {
++        ERR_RETURN(strm, Z_STREAM_ERROR);
++    }
++    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
++
++    s->strm = strm; /* just in case */
++    old_flush = s->last_flush;
++    s->last_flush = flush;
++
++    /* Write the zlib header */
++    if (s->status == INIT_STATE) {
++
++        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
++        uInt level_flags = (s->level-1) >> 1;
++
++        if (level_flags > 3) level_flags = 3;
++        header |= (level_flags << 6);
++      if (s->strstart != 0) header |= PRESET_DICT;
++        header += 31 - (header % 31);
++
++        s->status = BUSY_STATE;
++        putShortMSB(s, header);
++
++      /* Save the adler32 of the preset dictionary: */
++      if (s->strstart != 0) {
++          putShortMSB(s, (uInt)(strm->adler >> 16));
++          putShortMSB(s, (uInt)(strm->adler & 0xffff));
++      }
++      strm->adler = 1L;
++    }
++
++    /* Flush as much pending output as possible */
++    if (s->pending != 0) {
++        flush_pending(strm);
++        if (strm->avail_out == 0) {
++          /* Since avail_out is 0, deflate will be called again with
++           * more output space, but possibly with both pending and
++           * avail_in equal to zero. There won't be anything to do,
++           * but this is not an error situation so make sure we
++           * return OK instead of BUF_ERROR at next call of deflate:
++             */
++          s->last_flush = -1;
++          return Z_OK;
++      }
++
++    /* Make sure there is something to do and avoid duplicate consecutive
++     * flushes. For repeated and useless calls with Z_FINISH, we keep
++     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
++     */
++    } else if (strm->avail_in == 0 && flush <= old_flush &&
++             flush != Z_FINISH) {
++        ERR_RETURN(strm, Z_BUF_ERROR);
++    }
++
++    /* User must not provide more input after the first FINISH: */
++    if (s->status == FINISH_STATE && strm->avail_in != 0) {
++        ERR_RETURN(strm, Z_BUF_ERROR);
++    }
++
++    /* Start a new block or continue the current one.
++     */
++    if (strm->avail_in != 0 || s->lookahead != 0 ||
++        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
++        block_state bstate;
++
++      bstate = (*(configuration_table[s->level].func))(s, flush);
++
++        if (bstate == finish_started || bstate == finish_done) {
++            s->status = FINISH_STATE;
++        }
++        if (bstate == need_more || bstate == finish_started) {
++          if (strm->avail_out == 0) {
++              s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
++          }
++          return Z_OK;
++          /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
++           * of deflate should use the same flush parameter to make sure
++           * that the flush is complete. So we don't have to output an
++           * empty block here, this will be done at next call. This also
++           * ensures that for a very small output buffer, we emit at most
++           * one empty block.
++           */
++      }
++        if (bstate == block_done) {
++            if (flush == Z_PARTIAL_FLUSH) {
++                _tr_align(s);
++            } else { /* FULL_FLUSH or SYNC_FLUSH */
++                _tr_stored_block(s, (char*)0, 0L, 0);
++                /* For a full flush, this empty block will be recognized
++                 * as a special marker by inflate_sync().
++                 */
++                if (flush == Z_FULL_FLUSH) {
++                    CLEAR_HASH(s);             /* forget history */
++                }
++            }
++            flush_pending(strm);
++          if (strm->avail_out == 0) {
++            s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
++            return Z_OK;
++          }
++        }
++    }
++    Assert(strm->avail_out > 0, "bug2");
++
++    if (flush != Z_FINISH) return Z_OK;
++    if (s->noheader) return Z_STREAM_END;
++
++    /* Write the zlib trailer (adler32) */
++    putShortMSB(s, (uInt)(strm->adler >> 16));
++    putShortMSB(s, (uInt)(strm->adler & 0xffff));
++    flush_pending(strm);
++    /* If avail_out is zero, the application will call deflate again
++     * to flush the rest.
++     */
++    s->noheader = -1; /* write the trailer only once! */
++    return s->pending != 0 ? Z_OK : Z_STREAM_END;
++}
++
++/* ========================================================================= */
++int ZEXPORT deflateEnd (strm)
++    z_streamp strm;
++{
++    int status;
++
++    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
++
++    status = strm->state->status;
++    if (status != INIT_STATE && status != BUSY_STATE &&
++      status != FINISH_STATE) {
++      return Z_STREAM_ERROR;
++    }
++
++    /* Deallocate in reverse order of allocations: */
++    TRY_FREE(strm, strm->state->pending_buf);
++    TRY_FREE(strm, strm->state->head);
++    TRY_FREE(strm, strm->state->prev);
++    TRY_FREE(strm, strm->state->window);
++
++    ZFREE(strm, strm->state);
++    strm->state = Z_NULL;
++
++    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
++}
++
++/* =========================================================================
++ * Copy the source state to the destination state.
++ * To simplify the source, this is not supported for 16-bit MSDOS (which
++ * doesn't have enough memory anyway to duplicate compression states).
++ */
++int ZEXPORT deflateCopy (dest, source)
++    z_streamp dest;
++    z_streamp source;
++{
++#ifdef MAXSEG_64K
++    return Z_STREAM_ERROR;
++#else
++    deflate_state *ds;
++    deflate_state *ss;
++    ushf *overlay;
++
++
++    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
++        return Z_STREAM_ERROR;
++    }
++
++    ss = source->state;
++
++    *dest = *source;
++
++    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
++    if (ds == Z_NULL) return Z_MEM_ERROR;
++    dest->state = (struct internal_state FAR *) ds;
++    *ds = *ss;
++    ds->strm = dest;
++
++    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
++    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
++    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
++    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
++    ds->pending_buf = (uchf *) overlay;
++
++    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
++        ds->pending_buf == Z_NULL) {
++        deflateEnd (dest);
++        return Z_MEM_ERROR;
++    }
++    /* following zmemcpy do not work for 16-bit MSDOS */
++    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
++    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
++    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
++    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
++
++    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
++    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
++    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
++
++    ds->l_desc.dyn_tree = ds->dyn_ltree;
++    ds->d_desc.dyn_tree = ds->dyn_dtree;
++    ds->bl_desc.dyn_tree = ds->bl_tree;
++
++    return Z_OK;
++#endif
++}
++
++/* ===========================================================================
++ * Read a new buffer from the current input stream, update the adler32
++ * and total number of bytes read.  All deflate() input goes through
++ * this function so some applications may wish to modify it to avoid
++ * allocating a large strm->next_in buffer and copying from it.
++ * (See also flush_pending()).
++ */
++local int read_buf(strm, buf, size)
++    z_streamp strm;
++    Bytef *buf;
++    unsigned size;
++{
++    unsigned len = strm->avail_in;
++
++    if (len > size) len = size;
++    if (len == 0) return 0;
++
++    strm->avail_in  -= len;
++
++    if (!strm->state->noheader) {
++        strm->adler = adler32(strm->adler, strm->next_in, len);
++    }
++    zmemcpy(buf, strm->next_in, len);
++    strm->next_in  += len;
++    strm->total_in += len;
++
++    return (int)len;
++}
++
++/* ===========================================================================
++ * Initialize the "longest match" routines for a new zlib stream
++ */
++local void lm_init (s)
++    deflate_state *s;
++{
++    s->window_size = (ulg)2L*s->w_size;
++
++    CLEAR_HASH(s);
++
++    /* Set the default configuration parameters:
++     */
++    s->max_lazy_match   = configuration_table[s->level].max_lazy;
++    s->good_match       = configuration_table[s->level].good_length;
++    s->nice_match       = configuration_table[s->level].nice_length;
++    s->max_chain_length = configuration_table[s->level].max_chain;
++
++    s->strstart = 0;
++    s->block_start = 0L;
++    s->lookahead = 0;
++    s->match_length = s->prev_length = MIN_MATCH-1;
++    s->match_available = 0;
++    s->ins_h = 0;
++#ifdef ASMV
++    match_init(); /* initialize the asm code */
++#endif
++}
++
++/* ===========================================================================
++ * Set match_start to the longest match starting at the given string and
++ * return its length. Matches shorter or equal to prev_length are discarded,
++ * in which case the result is equal to prev_length and match_start is
++ * garbage.
++ * IN assertions: cur_match is the head of the hash chain for the current
++ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
++ * OUT assertion: the match length is not greater than s->lookahead.
++ */
++#ifndef ASMV
++/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
++ * match.S. The code will be functionally equivalent.
++ */
++#ifndef FASTEST
++local uInt longest_match(s, cur_match)
++    deflate_state *s;
++    IPos cur_match;                             /* current match */
++{
++    unsigned chain_length = s->max_chain_length;/* max hash chain length */
++    register Bytef *scan = s->window + s->strstart; /* current string */
++    register Bytef *match;                       /* matched string */
++    register int len;                           /* length of current match */
++    int best_len = s->prev_length;              /* best match length so far */
++    int nice_match = s->nice_match;             /* stop if match long enough */
++    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
++        s->strstart - (IPos)MAX_DIST(s) : NIL;
++    /* Stop when cur_match becomes <= limit. To simplify the code,
++     * we prevent matches with the string of window index 0.
++     */
++    Posf *prev = s->prev;
++    uInt wmask = s->w_mask;
++
++#ifdef UNALIGNED_OK
++    /* Compare two bytes at a time. Note: this is not always beneficial.
++     * Try with and without -DUNALIGNED_OK to check.
++     */
++    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
++    register ush scan_start = *(ushf*)scan;
++    register ush scan_end   = *(ushf*)(scan+best_len-1);
++#else
++    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
++    register Byte scan_end1  = scan[best_len-1];
++    register Byte scan_end   = scan[best_len];
++#endif
++
++    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
++     * It is easy to get rid of this optimization if necessary.
++     */
++    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
++
++    /* Do not waste too much time if we already have a good match: */
++    if (s->prev_length >= s->good_match) {
++        chain_length >>= 2;
++    }
++    /* Do not look for matches beyond the end of the input. This is necessary
++     * to make deflate deterministic.
++     */
++    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
++
++    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
++
++    do {
++        Assert(cur_match < s->strstart, "no future");
++        match = s->window + cur_match;
++
++        /* Skip to next match if the match length cannot increase
++         * or if the match length is less than 2:
++         */
++#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
++        /* This code assumes sizeof(unsigned short) == 2. Do not use
++         * UNALIGNED_OK if your compiler uses a different size.
++         */
++        if (*(ushf*)(match+best_len-1) != scan_end ||
++            *(ushf*)match != scan_start) continue;
++
++        /* It is not necessary to compare scan[2] and match[2] since they are
++         * always equal when the other bytes match, given that the hash keys
++         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
++         * strstart+3, +5, ... up to strstart+257. We check for insufficient
++         * lookahead only every 4th comparison; the 128th check will be made
++         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
++         * necessary to put more guard bytes at the end of the window, or
++         * to check more often for insufficient lookahead.
++         */
++        Assert(scan[2] == match[2], "scan[2]?");
++        scan++, match++;
++        do {
++        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
++                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
++                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
++                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
++                 scan < strend);
++        /* The funny "do {}" generates better code on most compilers */
++
++        /* Here, scan <= window+strstart+257 */
++        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
++        if (*scan == *match) scan++;
++
++        len = (MAX_MATCH - 1) - (int)(strend-scan);
++        scan = strend - (MAX_MATCH-1);
++
++#else /* UNALIGNED_OK */
++
++        if (match[best_len]   != scan_end  ||
++            match[best_len-1] != scan_end1 ||
++            *match            != *scan     ||
++            *++match          != scan[1])      continue;
++
++        /* The check at best_len-1 can be removed because it will be made
++         * again later. (This heuristic is not always a win.)
++         * It is not necessary to compare scan[2] and match[2] since they
++         * are always equal when the other bytes match, given that
++         * the hash keys are equal and that HASH_BITS >= 8.
++         */
++        scan += 2, match++;
++        Assert(*scan == *match, "match[2]?");
++
++        /* We check for insufficient lookahead only every 8th comparison;
++         * the 256th check will be made at strstart+258.
++         */
++        do {
++        } while (*++scan == *++match && *++scan == *++match &&
++                 *++scan == *++match && *++scan == *++match &&
++                 *++scan == *++match && *++scan == *++match &&
++                 *++scan == *++match && *++scan == *++match &&
++                 scan < strend);
++
++        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
++
++        len = MAX_MATCH - (int)(strend - scan);
++        scan = strend - MAX_MATCH;
++
++#endif /* UNALIGNED_OK */
++
++        if (len > best_len) {
++            s->match_start = cur_match;
++            best_len = len;
++            if (len >= nice_match) break;
++#ifdef UNALIGNED_OK
++            scan_end = *(ushf*)(scan+best_len-1);
++#else
++            scan_end1  = scan[best_len-1];
++            scan_end   = scan[best_len];
++#endif
++        }
++    } while ((cur_match = prev[cur_match & wmask]) > limit
++             && --chain_length != 0);
++
++    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
++    return s->lookahead;
++}
++
++#else /* FASTEST */
++/* ---------------------------------------------------------------------------
++ * Optimized version for level == 1 only
++ */
++local uInt longest_match(s, cur_match)
++    deflate_state *s;
++    IPos cur_match;                             /* current match */
++{
++    register Bytef *scan = s->window + s->strstart; /* current string */
++    register Bytef *match;                       /* matched string */
++    register int len;                           /* length of current match */
++    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
++
++    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
++     * It is easy to get rid of this optimization if necessary.
++     */
++    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
++
++    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
++
++    Assert(cur_match < s->strstart, "no future");
++
++    match = s->window + cur_match;
++
++    /* Return failure if the match length is less than 2:
++     */
++    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
++
++    /* The check at best_len-1 can be removed because it will be made
++     * again later. (This heuristic is not always a win.)
++     * It is not necessary to compare scan[2] and match[2] since they
++     * are always equal when the other bytes match, given that
++     * the hash keys are equal and that HASH_BITS >= 8.
++     */
++    scan += 2, match += 2;
++    Assert(*scan == *match, "match[2]?");
++
++    /* We check for insufficient lookahead only every 8th comparison;
++     * the 256th check will be made at strstart+258.
++     */
++    do {
++    } while (*++scan == *++match && *++scan == *++match &&
++           *++scan == *++match && *++scan == *++match &&
++           *++scan == *++match && *++scan == *++match &&
++           *++scan == *++match && *++scan == *++match &&
++           scan < strend);
++
++    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
++
++    len = MAX_MATCH - (int)(strend - scan);
++
++    if (len < MIN_MATCH) return MIN_MATCH - 1;
++
++    s->match_start = cur_match;
++    return len <= s->lookahead ? len : s->lookahead;
++}
++#endif /* FASTEST */
++#endif /* ASMV */
++
++#ifdef DEBUG
++/* ===========================================================================
++ * Check that the match at match_start is indeed a match.
++ */
++local void check_match(s, start, match, length)
++    deflate_state *s;
++    IPos start, match;
++    int length;
++{
++    /* check that the match is indeed a match */
++    if (zmemcmp(s->window + match,
++                s->window + start, length) != EQUAL) {
++        fprintf(stderr, " start %u, match %u, length %d\n",
++              start, match, length);
++        do {
++          fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
++      } while (--length != 0);
++        z_error("invalid match");
++    }
++    if (z_verbose > 1) {
++        fprintf(stderr,"\\[%d,%d]", start-match, length);
++        do { putc(s->window[start++], stderr); } while (--length != 0);
++    }
++}
++#else
++#  define check_match(s, start, match, length)
++#endif
++
++/* ===========================================================================
++ * Fill the window when the lookahead becomes insufficient.
++ * Updates strstart and lookahead.
++ *
++ * IN assertion: lookahead < MIN_LOOKAHEAD
++ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
++ *    At least one byte has been read, or avail_in == 0; reads are
++ *    performed for at least two bytes (required for the zip translate_eol
++ *    option -- not supported here).
++ */
++local void fill_window(s)
++    deflate_state *s;
++{
++    register unsigned n, m;
++    register Posf *p;
++    unsigned more;    /* Amount of free space at the end of the window. */
++    uInt wsize = s->w_size;
++
++    do {
++        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
++
++        /* Deal with !@#$% 64K limit: */
++        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
++            more = wsize;
++
++        } else if (more == (unsigned)(-1)) {
++            /* Very unlikely, but possible on 16 bit machine if strstart == 0
++             * and lookahead == 1 (input done one byte at time)
++             */
++            more--;
++
++        /* If the window is almost full and there is insufficient lookahead,
++         * move the upper half to the lower one to make room in the upper half.
++         */
++        } else if (s->strstart >= wsize+MAX_DIST(s)) {
++
++            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
++            s->match_start -= wsize;
++            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
++            s->block_start -= (long) wsize;
++
++            /* Slide the hash table (could be avoided with 32 bit values
++               at the expense of memory usage). We slide even when level == 0
++               to keep the hash table consistent if we switch back to level > 0
++               later. (Using level 0 permanently is not an optimal usage of
++               zlib, so we don't care about this pathological case.)
++             */
++          n = s->hash_size;
++          p = &s->head[n];
++          do {
++              m = *--p;
++              *p = (Pos)(m >= wsize ? m-wsize : NIL);
++          } while (--n);
++
++          n = wsize;
++#ifndef FASTEST
++          p = &s->prev[n];
++          do {
++              m = *--p;
++              *p = (Pos)(m >= wsize ? m-wsize : NIL);
++              /* If n is not on any hash chain, prev[n] is garbage but
++               * its value will never be used.
++               */
++          } while (--n);
++#endif
++            more += wsize;
++        }
++        if (s->strm->avail_in == 0) return;
++
++        /* If there was no sliding:
++         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
++         *    more == window_size - lookahead - strstart
++         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
++         * => more >= window_size - 2*WSIZE + 2
++         * In the BIG_MEM or MMAP case (not yet supported),
++         *   window_size == input_size + MIN_LOOKAHEAD  &&
++         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
++         * Otherwise, window_size == 2*WSIZE so more >= 2.
++         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
++         */
++        Assert(more >= 2, "more < 2");
++
++        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
++        s->lookahead += n;
++
++        /* Initialize the hash value now that we have some input: */
++        if (s->lookahead >= MIN_MATCH) {
++            s->ins_h = s->window[s->strstart];
++            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
++#if MIN_MATCH != 3
++            Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++        }
++        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
++         * but this is not important since only literal bytes will be emitted.
++         */
++
++    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
++}
++
++/* ===========================================================================
++ * Flush the current block, with given end-of-file flag.
++ * IN assertion: strstart is set to the end of the current match.
++ */
++#define FLUSH_BLOCK_ONLY(s, eof) { \
++   _tr_flush_block(s, (s->block_start >= 0L ? \
++                   (charf *)&s->window[(unsigned)s->block_start] : \
++                   (charf *)Z_NULL), \
++              (ulg)((long)s->strstart - s->block_start), \
++              (eof)); \
++   s->block_start = s->strstart; \
++   flush_pending(s->strm); \
++   Tracev((stderr,"[FLUSH]")); \
++}
++
++/* Same but force premature exit if necessary. */
++#define FLUSH_BLOCK(s, eof) { \
++   FLUSH_BLOCK_ONLY(s, eof); \
++   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
++}
++
++/* ===========================================================================
++ * Copy without compression as much as possible from the input stream, return
++ * the current block state.
++ * This function does not insert new strings in the dictionary since
++ * uncompressible data is probably not useful. This function is used
++ * only for the level=0 compression option.
++ * NOTE: this function should be optimized to avoid extra copying from
++ * window to pending_buf.
++ */
++local block_state deflate_stored(s, flush)
++    deflate_state *s;
++    int flush;
++{
++    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
++     * to pending_buf_size, and each stored block has a 5 byte header:
++     */
++    ulg max_block_size = 0xffff;
++    ulg max_start;
++
++    if (max_block_size > s->pending_buf_size - 5) {
++        max_block_size = s->pending_buf_size - 5;
++    }
++
++    /* Copy as much as possible from input to output: */
++    for (;;) {
++        /* Fill the window as much as possible: */
++        if (s->lookahead <= 1) {
++
++            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
++                 s->block_start >= (long)s->w_size, "slide too late");
++
++            fill_window(s);
++            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
++
++            if (s->lookahead == 0) break; /* flush the current block */
++        }
++      Assert(s->block_start >= 0L, "block gone");
++
++      s->strstart += s->lookahead;
++      s->lookahead = 0;
++
++      /* Emit a stored block if pending_buf will be full: */
++      max_start = s->block_start + max_block_size;
++        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
++          /* strstart == 0 is possible when wraparound on 16-bit machine */
++          s->lookahead = (uInt)(s->strstart - max_start);
++          s->strstart = (uInt)max_start;
++            FLUSH_BLOCK(s, 0);
++      }
++      /* Flush if we may have to slide, otherwise block_start may become
++         * negative and the data will be gone:
++         */
++        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
++            FLUSH_BLOCK(s, 0);
++      }
++    }
++    FLUSH_BLOCK(s, flush == Z_FINISH);
++    return flush == Z_FINISH ? finish_done : block_done;
++}
++
++/* ===========================================================================
++ * Compress as much as possible from the input stream, return the current
++ * block state.
++ * This function does not perform lazy evaluation of matches and inserts
++ * new strings in the dictionary only for unmatched strings or for short
++ * matches. It is used only for the fast compression options.
++ */
++local block_state deflate_fast(s, flush)
++    deflate_state *s;
++    int flush;
++{
++    IPos hash_head = NIL; /* head of the hash chain */
++    int bflush;           /* set if current block must be flushed */
++
++    for (;;) {
++        /* Make sure that we always have enough lookahead, except
++         * at the end of the input file. We need MAX_MATCH bytes
++         * for the next match, plus MIN_MATCH bytes to insert the
++         * string following the next match.
++         */
++        if (s->lookahead < MIN_LOOKAHEAD) {
++            fill_window(s);
++            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
++              return need_more;
++          }
++            if (s->lookahead == 0) break; /* flush the current block */
++        }
++
++        /* Insert the string window[strstart .. strstart+2] in the
++         * dictionary, and set hash_head to the head of the hash chain:
++         */
++        if (s->lookahead >= MIN_MATCH) {
++            INSERT_STRING(s, s->strstart, hash_head);
++        }
++
++        /* Find the longest match, discarding those <= prev_length.
++         * At this point we have always match_length < MIN_MATCH
++         */
++        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
++            /* To simplify the code, we prevent matches with the string
++             * of window index 0 (in particular we have to avoid a match
++             * of the string with itself at the start of the input file).
++             */
++            if (s->strategy != Z_HUFFMAN_ONLY) {
++                s->match_length = longest_match (s, hash_head);
++            }
++            /* longest_match() sets match_start */
++        }
++        if (s->match_length >= MIN_MATCH) {
++            check_match(s, s->strstart, s->match_start, s->match_length);
++
++            _tr_tally_dist(s, s->strstart - s->match_start,
++                           s->match_length - MIN_MATCH, bflush);
++
++            s->lookahead -= s->match_length;
++
++            /* Insert new strings in the hash table only if the match length
++             * is not too large. This saves time but degrades compression.
++             */
++#ifndef FASTEST
++            if (s->match_length <= s->max_insert_length &&
++                s->lookahead >= MIN_MATCH) {
++                s->match_length--; /* string at strstart already in hash table */
++                do {
++                    s->strstart++;
++                    INSERT_STRING(s, s->strstart, hash_head);
++                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
++                     * always MIN_MATCH bytes ahead.
++                     */
++                } while (--s->match_length != 0);
++                s->strstart++; 
++            } else
++#endif
++          {
++                s->strstart += s->match_length;
++                s->match_length = 0;
++                s->ins_h = s->window[s->strstart];
++                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
++#if MIN_MATCH != 3
++                Call UPDATE_HASH() MIN_MATCH-3 more times
++#endif
++                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
++                 * matter since it will be recomputed at next deflate call.
++                 */
++            }
++        } else {
++            /* No match, output a literal byte */
++            Tracevv((stderr,"%c", s->window[s->strstart]));
++            _tr_tally_lit (s, s->window[s->strstart], bflush);
++            s->lookahead--;
++            s->strstart++; 
++        }
++        if (bflush) FLUSH_BLOCK(s, 0);
++    }
++    FLUSH_BLOCK(s, flush == Z_FINISH);
++    return flush == Z_FINISH ? finish_done : block_done;
++}
++
++/* ===========================================================================
++ * Same as above, but achieves better compression. We use a lazy
++ * evaluation for matches: a match is finally adopted only if there is
++ * no better match at the next window position.
++ */
++local block_state deflate_slow(s, flush)
++    deflate_state *s;
++    int flush;
++{
++    IPos hash_head = NIL;    /* head of hash chain */
++    int bflush;              /* set if current block must be flushed */
++
++    /* Process the input block. */
++    for (;;) {
++        /* Make sure that we always have enough lookahead, except
++         * at the end of the input file. We need MAX_MATCH bytes
++         * for the next match, plus MIN_MATCH bytes to insert the
++         * string following the next match.
++         */
++        if (s->lookahead < MIN_LOOKAHEAD) {
++            fill_window(s);
++            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
++              return need_more;
++          }
++            if (s->lookahead == 0) break; /* flush the current block */
++        }
++
++        /* Insert the string window[strstart .. strstart+2] in the
++         * dictionary, and set hash_head to the head of the hash chain:
++         */
++        if (s->lookahead >= MIN_MATCH) {
++            INSERT_STRING(s, s->strstart, hash_head);
++        }
++
++        /* Find the longest match, discarding those <= prev_length.
++         */
++        s->prev_length = s->match_length, s->prev_match = s->match_start;
++        s->match_length = MIN_MATCH-1;
++
++        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
++            s->strstart - hash_head <= MAX_DIST(s)) {
++            /* To simplify the code, we prevent matches with the string
++             * of window index 0 (in particular we have to avoid a match
++             * of the string with itself at the start of the input file).
++             */
++            if (s->strategy != Z_HUFFMAN_ONLY) {
++                s->match_length = longest_match (s, hash_head);
++            }
++            /* longest_match() sets match_start */
++
++            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
++                 (s->match_length == MIN_MATCH &&
++                  s->strstart - s->match_start > TOO_FAR))) {
++
++                /* If prev_match is also MIN_MATCH, match_start is garbage
++                 * but we will ignore the current match anyway.
++                 */
++                s->match_length = MIN_MATCH-1;
++            }
++        }
++        /* If there was a match at the previous step and the current
++         * match is not better, output the previous match:
++         */
++        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
++            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
++            /* Do not insert strings in hash table beyond this. */
++
++            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
++
++            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
++                         s->prev_length - MIN_MATCH, bflush);
++
++            /* Insert in hash table all strings up to the end of the match.
++             * strstart-1 and strstart are already inserted. If there is not
++             * enough lookahead, the last two strings are not inserted in
++             * the hash table.
++             */
++            s->lookahead -= s->prev_length-1;
++            s->prev_length -= 2;
++            do {
++                if (++s->strstart <= max_insert) {
++                    INSERT_STRING(s, s->strstart, hash_head);
++                }
++            } while (--s->prev_length != 0);
++            s->match_available = 0;
++            s->match_length = MIN_MATCH-1;
++            s->strstart++;
++
++            if (bflush) FLUSH_BLOCK(s, 0);
++
++        } else if (s->match_available) {
++            /* If there was no match at the previous position, output a
++             * single literal. If there was a match but the current match
++             * is longer, truncate the previous match to a single literal.
++             */
++            Tracevv((stderr,"%c", s->window[s->strstart-1]));
++          _tr_tally_lit(s, s->window[s->strstart-1], bflush);
++          if (bflush) {
++                FLUSH_BLOCK_ONLY(s, 0);
++            }
++            s->strstart++;
++            s->lookahead--;
++            if (s->strm->avail_out == 0) return need_more;
++        } else {
++            /* There is no previous match to compare with, wait for
++             * the next step to decide.
++             */
++            s->match_available = 1;
++            s->strstart++;
++            s->lookahead--;
++        }
++    }
++    Assert (flush != Z_NO_FLUSH, "no flush?");
++    if (s->match_available) {
++        Tracevv((stderr,"%c", s->window[s->strstart-1]));
++        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
++        s->match_available = 0;
++    }
++    FLUSH_BLOCK(s, flush == Z_FINISH);
++    return flush == Z_FINISH ? finish_done : block_done;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/deflate.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,318 @@
++/* deflate.h -- internal compression state
++ * Copyright (C) 1995-2002 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++/* @(#) $Id: deflate.h,v 1.5 2004/07/10 07:48:38 mcr Exp $ */
++
++#ifndef _DEFLATE_H
++#define _DEFLATE_H
++
++#include "zlib/zutil.h"
++
++/* ===========================================================================
++ * Internal compression state.
++ */
++
++#define LENGTH_CODES 29
++/* number of length codes, not counting the special END_BLOCK code */
++
++#define LITERALS  256
++/* number of literal bytes 0..255 */
++
++#define L_CODES (LITERALS+1+LENGTH_CODES)
++/* number of Literal or Length codes, including the END_BLOCK code */
++
++#define D_CODES   30
++/* number of distance codes */
++
++#define BL_CODES  19
++/* number of codes used to transfer the bit lengths */
++
++#define HEAP_SIZE (2*L_CODES+1)
++/* maximum heap size */
++
++#define MAX_BITS 15
++/* All codes must not exceed MAX_BITS bits */
++
++#define INIT_STATE    42
++#define BUSY_STATE   113
++#define FINISH_STATE 666
++/* Stream status */
++
++
++/* Data structure describing a single value and its code string. */
++typedef struct ct_data_s {
++    union {
++        ush  freq;       /* frequency count */
++        ush  code;       /* bit string */
++    } fc;
++    union {
++        ush  dad;        /* father node in Huffman tree */
++        ush  len;        /* length of bit string */
++    } dl;
++} FAR ct_data;
++
++#define Freq fc.freq
++#define Code fc.code
++#define Dad  dl.dad
++#define Len  dl.len
++
++typedef struct static_tree_desc_s  static_tree_desc;
++
++typedef struct tree_desc_s {
++    ct_data *dyn_tree;           /* the dynamic tree */
++    int     max_code;            /* largest code with non zero frequency */
++    static_tree_desc *stat_desc; /* the corresponding static tree */
++} FAR tree_desc;
++
++typedef ush Pos;
++typedef Pos FAR Posf;
++typedef unsigned IPos;
++
++/* A Pos is an index in the character window. We use short instead of int to
++ * save space in the various tables. IPos is used only for parameter passing.
++ */
++
++typedef struct internal_state {
++    z_streamp strm;      /* pointer back to this zlib stream */
++    int   status;        /* as the name implies */
++    Bytef *pending_buf;  /* output still pending */
++    ulg   pending_buf_size; /* size of pending_buf */
++    Bytef *pending_out;  /* next pending byte to output to the stream */
++    int   pending;       /* nb of bytes in the pending buffer */
++    int   noheader;      /* suppress zlib header and adler32 */
++    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
++    Byte  method;        /* STORED (for zip only) or DEFLATED */
++    int   last_flush;    /* value of flush param for previous deflate call */
++
++                /* used by deflate.c: */
++
++    uInt  w_size;        /* LZ77 window size (32K by default) */
++    uInt  w_bits;        /* log2(w_size)  (8..16) */
++    uInt  w_mask;        /* w_size - 1 */
++
++    Bytef *window;
++    /* Sliding window. Input bytes are read into the second half of the window,
++     * and move to the first half later to keep a dictionary of at least wSize
++     * bytes. With this organization, matches are limited to a distance of
++     * wSize-MAX_MATCH bytes, but this ensures that IO is always
++     * performed with a length multiple of the block size. Also, it limits
++     * the window size to 64K, which is quite useful on MSDOS.
++     * To do: use the user input buffer as sliding window.
++     */
++
++    ulg window_size;
++    /* Actual size of window: 2*wSize, except when the user input buffer
++     * is directly used as sliding window.
++     */
++
++    Posf *prev;
++    /* Link to older string with same hash index. To limit the size of this
++     * array to 64K, this link is maintained only for the last 32K strings.
++     * An index in this array is thus a window index modulo 32K.
++     */
++
++    Posf *head; /* Heads of the hash chains or NIL. */
++
++    uInt  ins_h;          /* hash index of string to be inserted */
++    uInt  hash_size;      /* number of elements in hash table */
++    uInt  hash_bits;      /* log2(hash_size) */
++    uInt  hash_mask;      /* hash_size-1 */
++
++    uInt  hash_shift;
++    /* Number of bits by which ins_h must be shifted at each input
++     * step. It must be such that after MIN_MATCH steps, the oldest
++     * byte no longer takes part in the hash key, that is:
++     *   hash_shift * MIN_MATCH >= hash_bits
++     */
++
++    long block_start;
++    /* Window position at the beginning of the current output block. Gets
++     * negative when the window is moved backwards.
++     */
++
++    uInt match_length;           /* length of best match */
++    IPos prev_match;             /* previous match */
++    int match_available;         /* set if previous match exists */
++    uInt strstart;               /* start of string to insert */
++    uInt match_start;            /* start of matching string */
++    uInt lookahead;              /* number of valid bytes ahead in window */
++
++    uInt prev_length;
++    /* Length of the best match at previous step. Matches not greater than this
++     * are discarded. This is used in the lazy match evaluation.
++     */
++
++    uInt max_chain_length;
++    /* To speed up deflation, hash chains are never searched beyond this
++     * length.  A higher limit improves compression ratio but degrades the
++     * speed.
++     */
++
++    uInt max_lazy_match;
++    /* Attempt to find a better match only when the current match is strictly
++     * smaller than this value. This mechanism is used only for compression
++     * levels >= 4.
++     */
++#   define max_insert_length  max_lazy_match
++    /* Insert new strings in the hash table only if the match length is not
++     * greater than this length. This saves time but degrades compression.
++     * max_insert_length is used only for compression levels <= 3.
++     */
++
++    int level;    /* compression level (1..9) */
++    int strategy; /* favor or force Huffman coding*/
++
++    uInt good_match;
++    /* Use a faster search when the previous match is longer than this */
++
++    int nice_match; /* Stop searching when current match exceeds this */
++
++                /* used by trees.c: */
++    /* Didn't use ct_data typedef below to supress compiler warning */
++    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
++    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
++    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
++
++    struct tree_desc_s l_desc;               /* desc. for literal tree */
++    struct tree_desc_s d_desc;               /* desc. for distance tree */
++    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
++
++    ush bl_count[MAX_BITS+1];
++    /* number of codes at each bit length for an optimal tree */
++
++    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
++    int heap_len;               /* number of elements in the heap */
++    int heap_max;               /* element of largest frequency */
++    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
++     * The same heap array is used to build all trees.
++     */
++
++    uch depth[2*L_CODES+1];
++    /* Depth of each subtree used as tie breaker for trees of equal frequency
++     */
++
++    uchf *l_buf;          /* buffer for literals or lengths */
++
++    uInt  lit_bufsize;
++    /* Size of match buffer for literals/lengths.  There are 4 reasons for
++     * limiting lit_bufsize to 64K:
++     *   - frequencies can be kept in 16 bit counters
++     *   - if compression is not successful for the first block, all input
++     *     data is still in the window so we can still emit a stored block even
++     *     when input comes from standard input.  (This can also be done for
++     *     all blocks if lit_bufsize is not greater than 32K.)
++     *   - if compression is not successful for a file smaller than 64K, we can
++     *     even emit a stored file instead of a stored block (saving 5 bytes).
++     *     This is applicable only for zip (not gzip or zlib).
++     *   - creating new Huffman trees less frequently may not provide fast
++     *     adaptation to changes in the input data statistics. (Take for
++     *     example a binary file with poorly compressible code followed by
++     *     a highly compressible string table.) Smaller buffer sizes give
++     *     fast adaptation but have of course the overhead of transmitting
++     *     trees more frequently.
++     *   - I can't count above 4
++     */
++
++    uInt last_lit;      /* running index in l_buf */
++
++    ushf *d_buf;
++    /* Buffer for distances. To simplify the code, d_buf and l_buf have
++     * the same number of elements. To use different lengths, an extra flag
++     * array would be necessary.
++     */
++
++    ulg opt_len;        /* bit length of current block with optimal trees */
++    ulg static_len;     /* bit length of current block with static trees */
++    uInt matches;       /* number of string matches in current block */
++    int last_eob_len;   /* bit length of EOB code for last block */
++
++#ifdef DEBUG
++    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
++    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
++#endif
++
++    ush bi_buf;
++    /* Output buffer. bits are inserted starting at the bottom (least
++     * significant bits).
++     */
++    int bi_valid;
++    /* Number of valid bits in bi_buf.  All bits above the last valid bit
++     * are always zero.
++     */
++
++} FAR deflate_state;
++
++/* Output a byte on the stream.
++ * IN assertion: there is enough room in pending_buf.
++ */
++#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
++
++
++#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
++/* Minimum amount of lookahead, except at the end of the input file.
++ * See deflate.c for comments about the MIN_MATCH+1.
++ */
++
++#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
++/* In order to simplify the code, particularly on 16 bit machines, match
++ * distances are limited to MAX_DIST instead of WSIZE.
++ */
++
++        /* in trees.c */
++void _tr_init         OF((deflate_state *s));
++int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
++void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
++                        int eof));
++void _tr_align        OF((deflate_state *s));
++void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
++                          int eof));
++
++#define d_code(dist) \
++   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
++/* Mapping from a distance to a distance code. dist is the distance - 1 and
++ * must not have side effects. _dist_code[256] and _dist_code[257] are never
++ * used.
++ */
++
++#ifndef DEBUG
++/* Inline versions of _tr_tally for speed: */
++
++#if defined(GEN_TREES_H) || !defined(STDC)
++  extern uch _length_code[];
++  extern uch _dist_code[];
++#else
++  extern const uch _length_code[];
++  extern const uch _dist_code[];
++#endif
++
++# define _tr_tally_lit(s, c, flush) \
++  { uch cc = (c); \
++    s->d_buf[s->last_lit] = 0; \
++    s->l_buf[s->last_lit++] = cc; \
++    s->dyn_ltree[cc].Freq++; \
++    flush = (s->last_lit == s->lit_bufsize-1); \
++   }
++# define _tr_tally_dist(s, distance, length, flush) \
++  { uch len = (length); \
++    ush dist = (distance); \
++    s->d_buf[s->last_lit] = dist; \
++    s->l_buf[s->last_lit++] = len; \
++    dist--; \
++    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
++    s->dyn_dtree[d_code(dist)].Freq++; \
++    flush = (s->last_lit == s->lit_bufsize-1); \
++  }
++#else
++# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
++# define _tr_tally_dist(s, distance, length, flush) \
++              flush = _tr_tally(s, distance, length) 
++#endif
++
++#endif /* _DEFLATE_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/COPYRIGHT     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,50 @@
++Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++All rights reserved.
++
++This package is an DES implementation written by Eric Young (eay@cryptsoft.com).
++The implementation was written so as to conform with MIT's libdes.
++
++This library is free for commercial and non-commercial use as long as
++the following conditions are aheared to.  The following conditions
++apply to all code found in this distribution.
++
++Copyright remains Eric Young's, and as such any Copyright notices in
++the code are not to be removed.
++If this package is used in a product, Eric Young should be given attribution
++as the author of that the SSL library.  This can be in the form of a textual
++message at program startup or in documentation (online or textual) provided
++with the package.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions
++are met:
++1. Redistributions of source code must retain the copyright
++   notice, this list of conditions and the following disclaimer.
++2. Redistributions in binary form must reproduce the above copyright
++   notice, this list of conditions and the following disclaimer in the
++   documentation and/or other materials provided with the distribution.
++3. All advertising materials mentioning features or use of this software
++   must display the following acknowledgement:
++   This product includes software developed by Eric Young (eay@cryptsoft.com)
++
++THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++SUCH DAMAGE.
++
++The license and distribution terms for any publically available version or
++derivative of this code cannot be changed.  i.e. this code cannot simply be
++copied and put under another distrubution license
++[including the GNU Public License.]
++
++The reason behind this being stated in this direct manner is past
++experience in code simply being copied and the attribution removed
++from it and then being distributed as part of other packages. This
++implementation was a non-trivial and unpaid effort.
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/INSTALL     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,69 @@
++Check the CC and CFLAGS lines in the makefile
++
++If your C library does not support the times(3) function, change the
++#define TIMES to
++#undef TIMES in speed.c
++If it does, check the HZ value for the times(3) function.
++If your system does not define CLK_TCK it will be assumed to
++be 100.0.
++
++If possible use gcc v 2.7.?
++Turn on the maximum optimising (normally '-O3 -fomit-frame-pointer' for gcc)
++In recent times, some system compilers give better performace.
++
++type 'make'
++
++run './destest' to check things are ok.
++run './rpw' to check the tty code for reading passwords works.
++run './speed' to see how fast those optimisations make the library run :-)
++run './des_opts' to determin the best compile time options.
++
++The output from des_opts should be put in the makefile options and des_enc.c
++should be rebuilt.  For 64 bit computers, do not use the DES_PTR option.
++For the DEC Alpha, edit des.h and change DES_LONG to 'unsigned int'
++and then you can use the 'DES_PTR' option.
++
++The file options.txt has the options listed for best speed on quite a
++few systems.  Look and the options (UNROLL, PTR, RISC2 etc) and then
++turn on the relevent option in the Makefile
++
++There are some special Makefile targets that make life easier.
++make cc               - standard cc build
++make gcc      - standard gcc build
++make x86-elf  - x86 assembler (elf), linux-elf.
++make x86-out  - x86 assembler (a.out), FreeBSD
++make x86-solaris- x86 assembler
++make x86-bsdi - x86 assembler (a.out with primative assembler).
++
++If at all possible use the assembler (for Windows NT/95, use
++asm/win32.obj to link with).  The x86 assembler is very very fast.
++
++A make install will by default install
++libdes.a      in /usr/local/lib/libdes.a
++des           in /usr/local/bin/des
++des_crypt.man in /usr/local/man/man3/des_crypt.3
++des.man       in /usr/local/man/man1/des.1
++des.h         in /usr/include/des.h
++
++des(1) should be compatible with sunOS's but I have been unable to
++test it.
++
++These routines should compile on MSDOS, most 32bit and 64bit version
++of Unix (BSD and SYSV) and VMS, without modification.
++The only problems should be #include files that are in the wrong places.
++
++These routines can be compiled under MSDOS.
++I have successfully encrypted files using des(1) under MSDOS and then
++decrypted the files on a SparcStation.
++I have been able to compile and test the routines with
++Microsoft C v 5.1 and Turbo C v 2.0.
++The code in this library is in no way optimised for the 16bit
++operation of MSDOS.
++
++When building for glibc, ignore all of the above and just unpack into
++glibc-1.??/des and then gmake as per normal.
++
++As a final note on performace.  Certain CPUs like sparcs and Alpha often give
++a %10 speed difference depending on the link order.  It is rather anoying
++when one program reports 'x' DES encrypts a second and another reports
++'x*0.9' the speed.
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/Makefile     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,60 @@
++# Makefile for KLIPS kernel code as a module    for 2.6 kernels
++#
++# Makefile for KLIPS kernel code as a module
++# Copyright (C) 1998, 1999, 2000,2001  Richard Guy Briggs.
++# Copyright (C) 2002-2004     Michael Richardson <mcr@freeswan.org>
++# 
++# This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++# 
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++# for more details.
++#
++# RCSID $Id: Makefile.fs2_6,v 1.3 2005/08/12 14:13:59 mcr Exp $
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++obj-$(CONFIG_KLIPS_ENC_3DES) += ipsec_alg_3des.o
++obj-$(CONFIG_KLIPS_ENC_3DES) += cbc_enc.o
++obj-$(CONFIG_KLIPS_ENC_3DES) += ecb_enc.o
++obj-$(CONFIG_KLIPS_ENC_3DES) += set_key.o
++
++ifeq ($(strip ${SUBARCH}),)
++SUBARCH:=${ARCH}
++endif
++
++# the assembly version expects frame pointers, which are
++# optional in many kernel builds. If you want speed, you should
++# probably use cryptoapi code instead.
++USEASSEMBLY=${SUBARCH}${CONFIG_FRAME_POINTER}
++ifeq (${USEASSEMBLY},i386y)
++obj-$(CONFIG_KLIPS_ENC_3DES) += dx86unix.o
++else
++obj-$(CONFIG_KLIPS_ENC_3DES) += des_enc.o
++endif
++
++#
++# $Log: Makefile.fs2_6,v $
++# Revision 1.3  2005/08/12 14:13:59  mcr
++#     do not use assembly code with there are no frame pointers,
++#     as it does not have the right linkages.
++#
++# Revision 1.2  2005/04/29 05:13:07  mcr
++#     3DES algorithm code.
++#
++# Revision 1.1  2004/08/17 03:27:30  mcr
++#     klips 2.6 edits.
++#
++#
++# Local Variables:
++# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
++# End Variables:
++#
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/README     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,54 @@
++
++              libdes, Version 4.01 10-Jan-97
++
++              Copyright (c) 1997, Eric Young
++                        All rights reserved.
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms specified in COPYRIGHT.
++    
++--
++The primary ftp site for this library is
++ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-x.xx.tar.gz
++libdes is now also shipped with SSLeay.  Primary ftp site of
++ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/SSLeay-x.x.x.tar.gz
++
++The best way to build this library is to build it as part of SSLeay.
++
++This kit builds a DES encryption library and a DES encryption program.
++It supports ecb, cbc, ofb, cfb, triple ecb, triple cbc, triple ofb,
++triple cfb, desx, and MIT's pcbc encryption modes and also has a fast
++implementation of crypt(3).
++It contains support routines to read keys from a terminal,
++generate a random key, generate a key from an arbitrary length string,
++read/write encrypted data from/to a file descriptor.
++
++The implementation was written so as to conform with the manual entry
++for the des_crypt(3) library routines from MIT's project Athena.
++
++destest should be run after compilation to test the des routines.
++rpw should be run after compilation to test the read password routines.
++The des program is a replacement for the sun des command.  I believe it
++conforms to the sun version.
++
++The Imakefile is setup for use in the kerberos distribution.
++
++These routines are best compiled with gcc or any other good
++optimising compiler.
++Just turn you optimiser up to the highest settings and run destest
++after the build to make sure everything works.
++
++I believe these routines are close to the fastest and most portable DES
++routines that use small lookup tables (4.5k) that are publicly available.
++The fcrypt routine is faster than ufc's fcrypt (when compiling with
++gcc2 -O2) on the sparc 2 (1410 vs 1270) but is not so good on other machines
++(on a sun3/260 168 vs 336).  It is a function of CPU on chip cache size.
++[ 10-Jan-97 and a function of an incorrect speed testing program in
++  ufc which gave much better test figures that reality ].
++
++It is worth noting that on sparc and Alpha CPUs, performance of the DES
++library can vary by upto %10 due to the positioning of files after application
++linkage.
++
++Eric Young (eay@cryptsoft.com)
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/README.freeswan     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,33 @@
++The only changes the FreeS/WAN project has made to libdes-lite 4.04b are:
++
++We #ifdef-ed the declaration of DES_LONG in des.h, so it's more efficient
++on the Alpha, instead of just noting the issue in a comment. 
++
++We #ifdef-ed out the des_options() function in ecb_enc.c, because we don't
++use it, and its call to sprintf() can cause subtle difficulties when KLIPS
++is built as a module (depending on details of Linux configuration options).
++
++We changed some instances of CC=$(CC) in the Makefile to CC='$(CC)' to make
++it cope better with Linux kernel Makefile stupidities, and took out an
++explicit CC=gcc (unwise on systems with strange compilers).
++
++We deleted some references to <stdio.h> and <stdlib.h>, and a declaration
++of one function found only in the full libdes (not in libdes-lite), to
++avoid dragging in bits of stdio/stdlib unnecessarily.  (Our thanks to Hans
++Schultz for spotting this and pointing out the fixes.)
++
++We deleted a couple of .obj files in the asm subdirectory, which appear to
++have been included in the original library by accident. 
++
++We have added an include of our Makefile.inc file, to permit overriding
++things like choice of compiler (although the libdes Makefile would
++probably need some work to make this effective).
++
++
++
++Note that Eric Young is no longer at the email address listed in these
++files, and is (alas) no longer working on free crypto software. 
++
++
++
++This file is RCSID $Id: README.freeswan,v 1.12 2004/07/10 08:06:51 mcr Exp $
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/VERSION     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,406 @@
++Version 4.04
++      Fixed a few tests in destest.  Also added x86 assember for
++      des_ncbc_encrypt() which is the standard cbc mode function.
++      This makes a very very large performace difference.
++      Ariel Glenn ariel@columbia.edu reports that the terminal
++      'turn echo off' can return (errno == EINVAL) under solaris
++      when redirection is used.  So I now catch that as well as ENOTTY.
++
++
++Version 4.03
++      Left a static out of enc_write.c, which caused to buffer to be
++      continiously malloc()ed.  Does anyone use these functions?  I keep
++      on feeling like removing them since I only had these in there
++      for a version of kerberised login.  Anyway, this was pointed out
++      by Theo de Raadt <deraadt@cvs.openbsd.org>
++      The 'n' bit ofb code was wrong, it was not shifting the shift
++      register. It worked correctly for n == 64.  Thanks to
++      Gigi Ankeny <Gigi.Ankeny@Eng.Sun.COM> for pointing this one out.
++
++Version 4.02
++      I was doing 'if (memcmp(weak_keys[i],key,sizeof(key)) == 0)'
++      when checking for weak keys which is wrong :-(, pointed out by
++      Markus F.X.J. Oberhumer <markus.oberhumer@jk.uni-linz.ac.at>.
++
++Version 4.01
++      Even faster inner loop in the DES assembler for x86 and a modification
++      for IP/FP which is faster on x86.  Both of these changes are
++      from Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>.  His
++      changes make the assembler run %40 faster on a pentium.  This is just
++      a case of getting the instruction sequence 'just right'.
++      All credit to 'Svend' :-)
++      Quite a few special x86 'make' targets.
++      A libdes-l (lite) distribution.
++
++Version 4.00
++      After a bit of a pause, I'll up the major version number since this
++      is mostly a performace release.  I've added x86 assembler and
++      added more options for performance.  A %28 speedup for gcc 
++      on a pentium and the assembler is a %50 speedup.
++      MIPS CPU's, sparc and Alpha are the main CPU's with speedups.
++      Run des_opts to work out which options should be used.
++      DES_RISC1/DES_RISC2 use alternative inner loops which use
++      more registers but should give speedups on any CPU that does
++      dual issue (pentium).  DES_UNROLL unrolls the inner loop,
++      which costs in code size.
++
++Version 3.26
++      I've finally removed one of the shifts in D_ENCRYPT.  This
++      meant I've changed the des_SPtrans table (spr.h), the set_key()
++      function and some things in des_enc.c.  This has definitly
++      made things faster :-).  I've known about this one for some
++      time but I've been too lazy to follow it up :-).
++      Noticed that in the D_ENCRYPT() macro, we can just do L^=(..)^(..)^..
++      instead of L^=((..)|(..)|(..)..  This should save a register at
++      least.
++      Assember for x86.  The file to replace is des_enc.c, which is replaced
++      by one of the assembler files found in asm.  Look at des/asm/readme
++      for more info.
++
++      /* Modification to fcrypt so it can be compiled to support
++      HPUX 10.x's long password format, define -DLONGCRYPT to use this.
++      Thanks to Jens Kupferschmidt <bt1cu@hpboot.rz.uni-leipzig.de>. */
++
++      SIGWINCH case put in des_read_passwd() so the function does not
++      'exit' if this function is recieved.
++
++Version 3.25 17/07/96
++      Modified read_pwd.c so that stdin can be read if not a tty.
++      Thanks to Jeff Barber <jeffb@issl.atl.hp.com> for the patches.
++      des_init_random_number_generator() shortened due to VMS linker
++      limits.
++      Added RSA's DESX cbc mode.  It is a form of cbc encryption, with 2
++      8 byte quantites xored before and after encryption.
++      des_xcbc_encryption() - the name is funny to preserve the des_
++      prefix on all functions.
++
++Version 3.24 20/04/96
++      The DES_PTR macro option checked and used by SSLeay configuration
++
++Version 3.23 11/04/96
++      Added DES_LONG.  If defined to 'unsigned int' on the DEC Alpha,
++      it gives a %20 speedup :-)
++      Fixed the problem with des.pl under perl5.  The patches were
++      sent by Ed Kubaitis (ejk@uiuc.edu).
++      if fcrypt.c, changed values to handle illegal salt values the way
++      normal crypt() implementations do.  Some programs apparently use
++      them :-(. The patch was sent by Bjorn Gronvall <bg@sics.se>
++
++Version 3.22 29/11/95
++      Bug in des(1), an error with the uuencoding stuff when the
++      'data' is small, thanks to Geoff Keating <keagchon@mehta.anu.edu.au>
++      for the patch.
++
++Version 3.21 22/11/95
++      After some emailing back and forth with 
++      Colin Plumb <colin@nyx10.cs.du.edu>, I've tweaked a few things
++      and in a future version I will probably put in some of the
++      optimisation he suggested for use with the DES_USE_PTR option.
++      Extra routines from Mark Murray <mark@grondar.za> for use in
++      freeBSD.  They mostly involve random number generation for use
++      with kerberos.  They involve evil machine specific system calls
++      etc so I would normally suggest pushing this stuff into the
++      application and/or using RAND_seed()/RAND_bytes() if you are
++      using this DES library as part of SSLeay.
++      Redone the read_pw() function so that it is cleaner and
++      supports termios, thanks to Sameer Parekh <sameer@c2.org>
++      for the initial patches for this.
++      Renamed 3ecb_encrypt() to ecb3_encrypt().  This has been
++       done just to make things more consistent.
++      I have also now added triple DES versions of cfb and ofb.
++
++Version 3.20
++      Damn, Damn, Damn, as pointed out by Mike_Spreitzer.PARC@xerox.com,
++      my des_random_seed() function was only copying 4 bytes of the
++      passed seed into the init structure.  It is now fixed to copy 8.
++      My own suggestion is to used something like MD5 :-)
++
++Version 3.19 
++      While looking at my code one day, I though, why do I keep on
++      calling des_encrypt(in,out,ks,enc) when every function that
++      calls it has in and out the same.  So I dropped the 'out'
++      parameter, people should not be using this function.
++
++Version 3.18 30/08/95
++      Fixed a few bit with the distribution and the filenames.
++      3.17 had been munged via a move to DOS and back again.
++      NO CODE CHANGES
++
++Version 3.17 14/07/95
++      Fixed ede3 cbc which I had broken in 3.16.  I have also
++      removed some unneeded variables in 7-8 of the routines.
++
++Version 3.16 26/06/95
++      Added des_encrypt2() which does not use IP/FP, used by triple
++      des routines.  Tweaked things a bit elsewhere. %13 speedup on
++      sparc and %6 on a R4400 for ede3 cbc mode.
++
++Version 3.15 06/06/95
++      Added des_ncbc_encrypt(), it is des_cbc mode except that it is
++      'normal' and copies the new iv value back over the top of the
++      passed parameter.
++      CHANGED des_ede3_cbc_encrypt() so that it too now overwrites
++      the iv.  THIS WILL BREAK EXISTING CODE, but since this function
++      only new, I feel I can change it, not so with des_cbc_encrypt :-(.
++      I need to update the documentation.
++
++Version 3.14 31/05/95
++      New release upon the world, as part of my SSL implementation.
++      New copyright and usage stuff.  Basically free for all to use
++      as long as you say it came from me :-)
++
++Version 3.13 31/05/95
++      A fix in speed.c, if HZ is not defined, I set it to 100.0
++      which is reasonable for most unixes except SunOS 4.x.
++      I now have a #ifdef sun but timing for SunOS 4.x looked very
++      good :-(.  At my last job where I used SunOS 4.x, it was
++      defined to be 60.0 (look at the old INSTALL documentation), at
++      the last release had it changed to 100.0 since I now work with
++      Solaris2 and SVR4 boxes.
++      Thanks to  Rory Chisholm <rchishol@math.ethz.ch> for pointing this
++      one out.
++
++Version 3.12 08/05/95
++      As pointed out by The Crypt Keeper <tck@bend.UCSD.EDU>,
++      my D_ENCRYPT macro in crypt() had an un-necessary variable.
++      It has been removed.
++
++Version 3.11 03/05/95
++      Added des_ede3_cbc_encrypt() which is cbc mode des with 3 keys
++      and one iv.  It is a standard and I needed it for my SSL code.
++      It makes more sense to use this for triple DES than
++      3cbc_encrypt().  I have also added (or should I say tested :-)
++      cfb64_encrypt() which is cfb64 but it will encrypt a partial
++      number of bytes - 3 bytes in 3 bytes out.  Again this is for
++      my SSL library, as a form of encryption to use with SSL
++      telnet.
++
++Version 3.10 22/03/95
++      Fixed a bug in 3cbc_encrypt() :-(.  When making repeated calls
++      to cbc3_encrypt, the 2 iv values that were being returned to
++      be used in the next call were reversed :-(.
++      Many thanks to Bill Wade <wade@Stoner.COM> for pointing out
++      this error.
++
++Version 3.09 01/02/95
++      Fixed des_random_key to far more random, it was rather feeble
++      with regards to picking the initial seed.  The problem was
++      pointed out by Olaf Kirch <okir@monad.swb.de>.
++
++Version 3.08 14/12/94
++      Added Makefile.PL so libdes can be built into perl5.
++      Changed des_locl.h so RAND is always defined.
++
++Version 3.07 05/12/94
++      Added GNUmake and stuff so the library can be build with
++      glibc.
++
++Version 3.06 30/08/94
++      Added rpc_enc.c which contains _des_crypt.  This is for use in
++      secure_rpc v 4.0
++      Finally fixed the cfb_enc problems.
++      Fixed a few parameter parsing bugs in des (-3 and -b), thanks
++      to Rob McMillan <R.McMillan@its.gu.edu.au>
++
++Version 3.05 21/04/94
++      for unsigned long l; gcc does not produce ((l>>34) == 0)
++      This causes bugs in cfb_enc.
++      Thanks to Hadmut Danisch <danisch@ira.uka.de>
++
++Version 3.04 20/04/94
++      Added a version number to des.c and libdes.a
++
++Version 3.03 12/01/94
++      Fixed a bug in non zero iv in 3cbc_enc.
++
++Version 3.02 29/10/93
++      I now work in a place where there are 6+ architectures and 14+
++      OS versions :-).
++      Fixed TERMIO definition so the most sys V boxes will work :-)
++
++Release upon comp.sources.misc
++Version 3.01 08/10/93
++      Added des_3cbc_encrypt()
++
++Version 3.00 07/10/93
++      Fixed up documentation.
++      quad_cksum definitely compatible with MIT's now.
++
++Version 2.30 24/08/93
++      Triple DES now defaults to triple cbc but can do triple ecb
++       with the -b flag.
++      Fixed some MSDOS uuen/uudecoding problems, thanks to
++      Added prototypes.
++      
++Version 2.22 29/06/93
++      Fixed a bug in des_is_weak_key() which stopped it working :-(
++      thanks to engineering@MorningStar.Com.
++
++Version 2.21 03/06/93
++      des(1) with no arguments gives quite a bit of help.
++      Added -c (generate ckecksum) flag to des(1).
++      Added -3 (triple DES) flag to des(1).
++      Added cfb and ofb routines to the library.
++
++Version 2.20 11/03/93
++      Added -u (uuencode) flag to des(1).
++      I have been playing with byte order in quad_cksum to make it
++       compatible with MIT's version.  All I can say is avid this
++       function if possible since MIT's output is endian dependent.
++
++Version 2.12 14/10/92
++      Added MSDOS specific macro in ecb_encrypt which gives a %70
++       speed up when the code is compiled with turbo C.
++
++Version 2.11 12/10/92
++      Speedup in set_key (recoding of PC-1)
++       I now do it in 47 simple operations, down from 60.
++       Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
++       for motivating me to look for a faster system :-)
++       The speedup is probably less that 1% but it is still 13
++       instructions less :-).
++
++Version 2.10 06/10/92
++      The code now works on the 64bit ETA10 and CRAY without modifications or
++       #defines.  I believe the code should work on any machine that
++       defines long, int or short to be 8 bytes long.
++      Thanks to Shabbir J. Safdar (shabby@mentor.cc.purdue.edu)
++       for helping me fix the code to run on 64bit machines (he had
++       access to an ETA10).
++      Thanks also to John Fletcher <john_fletcher@lccmail.ocf.llnl.gov>
++       for testing the routines on a CRAY.
++      read_password.c has been renamed to read_passwd.c
++      string_to_key.c has been renamed to string2key.c
++
++Version 2.00 14/09/92
++      Made mods so that the library should work on 64bit CPU's.
++      Removed all my uchar and ulong defs.  To many different
++       versions of unix define them in their header files in too many
++       different combinations :-)
++      IRIX - Sillicon Graphics mods (mostly in read_password.c).
++       Thanks to Andrew Daviel (advax@erich.triumf.ca)
++
++Version 1.99 26/08/92
++      Fixed a bug or 2 in enc_read.c
++      Fixed a bug in enc_write.c
++      Fixed a pseudo bug in fcrypt.c (very obscure).
++
++Version 1.98 31/07/92
++      Support for the ETA10.  This is a strange machine that defines
++      longs and ints as 8 bytes and shorts as 4 bytes.
++      Since I do evil things with long * that assume that they are 4
++      bytes.  Look in the Makefile for the option to compile for
++      this machine.  quad_cksum appears to have problems but I
++      will don't have the time to fix it right now, and this is not
++      a function that uses DES and so will not effect the main uses
++      of the library.
++
++Version 1.97 20/05/92 eay
++      Fixed the Imakefile and made some changes to des.h to fix some
++      problems when building this package with Kerberos v 4.
++
++Version 1.96 18/05/92 eay
++      Fixed a small bug in string_to_key() where problems could
++      occur if des_check_key was set to true and the string
++      generated a weak key.
++
++Patch2 posted to comp.sources.misc
++Version 1.95 13/05/92 eay
++      Added an alternative version of the D_ENCRYPT macro in
++      ecb_encrypt and fcrypt.  Depending on the compiler, one version or the
++      other will be faster.  This was inspired by 
++      Dana How <how@isl.stanford.edu>, and her pointers about doing the
++      *(ulong *)((uchar *)ptr+(value&0xfc))
++      vs
++      ptr[value&0x3f]
++      to stop the C compiler doing a <<2 to convert the long array index.
++
++Version 1.94 05/05/92 eay
++      Fixed an incompatibility between my string_to_key and the MIT
++       version.  When the key is longer than 8 chars, I was wrapping
++       with a different method.  To use the old version, define
++       OLD_STR_TO_KEY in the makefile.  Thanks to
++       viktor@newsu.shearson.com (Viktor Dukhovni).
++
++Version 1.93 28/04/92 eay
++      Fixed the VMS mods so that echo is now turned off in
++       read_password.  Thanks again to brennan@coco.cchs.su.oz.AU.
++      MSDOS support added.  The routines can be compiled with
++       Turbo C (v2.0) and MSC (v5.1).  Make sure MSDOS is defined.
++
++Patch1 posted to comp.sources.misc
++Version 1.92 13/04/92 eay
++      Changed D_ENCRYPT so that the rotation of R occurs outside of
++       the loop.  This required rotating all the longs in sp.h (now
++       called spr.h). Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
++      speed.c has been changed so it will work without SIGALRM.  If
++       times(3) is not present it will try to use ftime() instead.
++
++Version 1.91 08/04/92 eay
++      Added -E/-D options to des(1) so it can use string_to_key.
++      Added SVR4 mods suggested by witr@rwwa.COM
++      Added VMS mods suggested by brennan@coco.cchs.su.oz.AU.  If
++      anyone knows how to turn of tty echo in VMS please tell me or
++      implement it yourself :-).
++      Changed FILE *IN/*OUT to *DES_IN/*DES_OUT since it appears VMS
++      does not like IN/OUT being used.
++
++Libdes posted to comp.sources.misc
++Version 1.9 24/03/92 eay
++      Now contains a fast small crypt replacement.
++      Added des(1) command.
++      Added des_rw_mode so people can use cbc encryption with
++      enc_read and enc_write.
++
++Version 1.8 15/10/91 eay
++      Bug in cbc_cksum.
++      Many thanks to Keith Reynolds (keithr@sco.COM) for pointing this
++      one out.
++
++Version 1.7 24/09/91 eay
++      Fixed set_key :-)
++      set_key is 4 times faster and takes less space.
++      There are a few minor changes that could be made.
++
++Version 1.6 19/09/1991 eay
++      Finally go IP and FP finished.
++      Now I need to fix set_key.
++      This version is quite a bit faster that 1.51
++
++Version 1.52 15/06/1991 eay
++      20% speedup in ecb_encrypt by changing the E bit selection
++      to use 2 32bit words.  This also required modification of the
++      sp table.  There is still a way to speedup the IP and IP-1
++      (hints from outer@sq.com) still working on this one :-(.
++
++Version 1.51 07/06/1991 eay
++      Faster des_encrypt by loop unrolling
++      Fixed bug in quad_cksum.c (thanks to hughes@logos.ucs.indiana.edu)
++
++Version 1.50 28/05/1991 eay
++      Optimised the code a bit more for the sparc.  I have improved the
++      speed of the inner des_encrypt by speeding up the initial and
++      final permutations.
++
++Version 1.40 23/10/1990 eay
++      Fixed des_random_key, it did not produce a random key :-(
++
++Version 1.30  2/10/1990 eay
++      Have made des_quad_cksum the same as MIT's, the full package
++      should be compatible with MIT's
++      Have tested on a DECstation 3100
++      Still need to fix des_set_key (make it faster).
++      Does des_cbc_encrypts at 70.5k/sec on a 3100.
++
++Version 1.20 18/09/1990 eay
++      Fixed byte order dependencies.
++      Fixed (I hope) all the word alignment problems.
++      Speedup in des_ecb_encrypt.
++
++Version 1.10 11/09/1990 eay
++      Added des_enc_read and des_enc_write.
++      Still need to fix des_quad_cksum.
++      Still need to document des_enc_read and des_enc_write.
++
++Version 1.00 27/08/1990 eay
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/asm/des-586.pl     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,251 @@
++#!/usr/local/bin/perl
++#
++# The inner loop instruction sequence and the IP/FP modifications are from
++# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
++#
++
++push(@INC,"perlasm","../../perlasm");
++require "x86asm.pl";
++require "cbc.pl";
++require "desboth.pl";
++
++# base code is in microsft
++# op dest, source
++# format.
++#
++
++&asm_init($ARGV[0],"des-586.pl");
++
++$L="edi";
++$R="esi";
++
++&external_label("des_SPtrans");
++&des_encrypt("des_encrypt",1);
++&des_encrypt("des_encrypt2",0);
++&des_encrypt3("des_encrypt3",1);
++&des_encrypt3("des_decrypt3",0);
++&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
++&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
++
++&asm_finish();
++
++sub des_encrypt
++      {
++      local($name,$do_ip)=@_;
++
++      &function_begin_B($name,"EXTRN   _des_SPtrans:DWORD");
++
++      &push("esi");
++      &push("edi");
++
++      &comment("");
++      &comment("Load the 2 words");
++      $ks="ebp";
++
++      if ($do_ip)
++              {
++              &mov($R,&wparam(0));
++               &xor(  "ecx",          "ecx"           );
++
++              &push("ebx");
++              &push("ebp");
++
++              &mov("eax",&DWP(0,$R,"",0));
++               &mov("ebx",&wparam(2));        # get encrypt flag
++              &mov($L,&DWP(4,$R,"",0));
++              &comment("");
++              &comment("IP");
++              &IP_new("eax",$L,$R,3);
++              }
++      else
++              {
++              &mov("eax",&wparam(0));
++               &xor(  "ecx",          "ecx"           );
++
++              &push("ebx");
++              &push("ebp");
++
++              &mov($R,&DWP(0,"eax","",0));
++               &mov("ebx",&wparam(2));        # get encrypt flag
++              &rotl($R,3);
++              &mov($L,&DWP(4,"eax","",0));
++              &rotl($L,3);
++              }
++
++      &mov(   $ks,            &wparam(1)      );
++      &cmp("ebx","0");
++      &je(&label("start_decrypt"));
++
++      for ($i=0; $i<16; $i+=2)
++              {
++              &comment("");
++              &comment("Round $i");
++              &D_ENCRYPT($i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
++
++              &comment("");
++              &comment("Round ".sprintf("%d",$i+1));
++              &D_ENCRYPT($i+1,$R,$L,($i+1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
++              }
++      &jmp(&label("end"));
++
++      &set_label("start_decrypt");
++
++      for ($i=15; $i>0; $i-=2)
++              {
++              &comment("");
++              &comment("Round $i");
++              &D_ENCRYPT(15-$i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
++              &comment("");
++              &comment("Round ".sprintf("%d",$i-1));
++              &D_ENCRYPT(15-$i+1,$R,$L,($i-1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
++              }
++
++      &set_label("end");
++
++      if ($do_ip)
++              {
++              &comment("");
++              &comment("FP");
++              &mov("edx",&wparam(0));
++              &FP_new($L,$R,"eax",3);
++
++              &mov(&DWP(0,"edx","",0),"eax");
++              &mov(&DWP(4,"edx","",0),$R);
++              }
++      else
++              {
++              &comment("");
++              &comment("Fixup");
++              &rotr($L,3);            # r
++               &mov("eax",&wparam(0));
++              &rotr($R,3);            # l
++               &mov(&DWP(0,"eax","",0),$L);
++               &mov(&DWP(4,"eax","",0),$R);
++              }
++
++      &pop("ebp");
++      &pop("ebx");
++      &pop("edi");
++      &pop("esi");
++      &ret();
++
++      &function_end_B($name);
++      }
++
++sub D_ENCRYPT
++      {
++      local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
++
++       &mov(  $u,             &DWP(&n2a($S*4),$ks,"",0));
++      &xor(   $tmp1,          $tmp1);
++       &mov(  $t,             &DWP(&n2a(($S+1)*4),$ks,"",0));
++      &xor(   $u,             $R);
++       &xor(  $t,             $R);
++      &and(   $u,             "0xfcfcfcfc"    );
++       &and(  $t,             "0xcfcfcfcf"    );
++      &movb(  &LB($tmp1),     &LB($u) );
++       &movb( &LB($tmp2),     &HB($u) );
++      &rotr(  $t,             4               );
++      &mov(   $ks,            &DWP("      $desSP",$tmp1,"",0));
++       &movb( &LB($tmp1),     &LB($t) );
++      &xor(   $L,             $ks);
++       &mov(  $ks,            &DWP("0x200+$desSP",$tmp2,"",0));
++      &xor(   $L,             $ks); ######
++       &movb( &LB($tmp2),     &HB($t) );
++      &shr(   $u,             16);
++       &mov(  $ks,            &DWP("0x100+$desSP",$tmp1,"",0));
++      &xor(   $L,             $ks); ######
++       &movb( &LB($tmp1),     &HB($u) );
++      &shr(   $t,             16);
++       &mov(  $ks,            &DWP("0x300+$desSP",$tmp2,"",0));
++      &xor(   $L,             $ks);
++       &mov(  $ks,            &wparam(1)      );
++      &movb(  &LB($tmp2),     &HB($t) );
++       &and(  $u,             "0xff"  );
++      &and(   $t,             "0xff"  );
++       &mov(  $tmp1,          &DWP("0x600+$desSP",$tmp1,"",0));
++      &xor(   $L,             $tmp1);
++       &mov(  $tmp1,          &DWP("0x700+$desSP",$tmp2,"",0));
++      &xor(   $L,             $tmp1);
++       &mov(  $tmp1,          &DWP("0x400+$desSP",$u,"",0));
++      &xor(   $L,             $tmp1);
++       &mov(  $tmp1,          &DWP("0x500+$desSP",$t,"",0));
++      &xor(   $L,             $tmp1);
++      }
++
++sub n2a
++      {
++      sprintf("%d",$_[0]);
++      }
++
++# now has a side affect of rotating $a by $shift
++sub R_PERM_OP
++      {
++      local($a,$b,$tt,$shift,$mask,$last)=@_;
++
++      &rotl(  $a,             $shift          ) if ($shift != 0);
++      &mov(   $tt,            $a              );
++      &xor(   $a,             $b              );
++      &and(   $a,             $mask           );
++      if (!$last eq $b)
++              {
++              &xor(   $b,             $a              );
++              &xor(   $tt,            $a              );
++              }
++      else
++              {
++              &xor(   $tt,            $a              );
++              &xor(   $b,             $a              );
++              }
++      &comment("");
++      }
++
++sub IP_new
++      {
++      local($l,$r,$tt,$lr)=@_;
++
++      &R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
++      &R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
++      &R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
++      &R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
++      &R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
++      
++      if ($lr != 3)
++              {
++              if (($lr-3) < 0)
++                      { &rotr($tt,    3-$lr); }
++              else    { &rotl($tt,    $lr-3); }
++              }
++      if ($lr != 2)
++              {
++              if (($lr-2) < 0)
++                      { &rotr($r,     2-$lr); }
++              else    { &rotl($r,     $lr-2); }
++              }
++      }
++
++sub FP_new
++      {
++      local($l,$r,$tt,$lr)=@_;
++
++      if ($lr != 2)
++              {
++              if (($lr-2) < 0)
++                      { &rotl($r,     2-$lr); }
++              else    { &rotr($r,     $lr-2); }
++              }
++      if ($lr != 3)
++              {
++              if (($lr-3) < 0)
++                      { &rotl($l,     3-$lr); }
++              else    { &rotr($l,     $lr-3); }
++              }
++
++      &R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
++      &R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
++      &R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
++      &R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
++      &R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
++      &rotr($tt       , 4);
++      }
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/asm/des686.pl     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,230 @@
++#!/usr/local/bin/perl
++
++$prog="des686.pl";
++
++# base code is in microsft
++# op dest, source
++# format.
++#
++
++# WILL NOT WORK ANYMORE WITH desboth.pl
++require "desboth.pl";
++
++if (  ($ARGV[0] eq "elf"))
++      { require "x86unix.pl"; }
++elsif (       ($ARGV[0] eq "a.out"))
++      { $aout=1; require "x86unix.pl"; }
++elsif (       ($ARGV[0] eq "sol"))
++      { $sol=1; require "x86unix.pl"; }
++elsif ( ($ARGV[0] eq "cpp"))
++      { $cpp=1; require "x86unix.pl"; }
++elsif (       ($ARGV[0] eq "win32"))
++      { require "x86ms.pl"; }
++else
++      {
++      print STDERR <<"EOF";
++Pick one target type from
++      elf     - linux, FreeBSD etc
++      a.out   - old linux
++      sol     - x86 solaris
++      cpp     - format so x86unix.cpp can be used
++      win32   - Windows 95/Windows NT
++EOF
++      exit(1);
++      }
++
++&comment("Don't even think of reading this code");
++&comment("It was automatically generated by $prog");
++&comment("Which is a perl program used to generate the x86 assember for");
++&comment("any of elf, a.out, Win32, or Solaris");
++&comment("It can be found in SSLeay 0.6.5+ or in libdes 3.26+");
++&comment("eric <eay\@cryptsoft.com>");
++&comment("");
++
++&file("dx86xxxx");
++
++$L="edi";
++$R="esi";
++
++&des_encrypt("des_encrypt",1);
++&des_encrypt("des_encrypt2",0);
++
++&des_encrypt3("des_encrypt3",1);
++&des_encrypt3("des_decrypt3",0);
++
++&file_end();
++
++sub des_encrypt
++      {
++      local($name,$do_ip)=@_;
++
++      &function_begin($name,"EXTRN   _des_SPtrans:DWORD");
++
++      &comment("");
++      &comment("Load the 2 words");
++      &mov("eax",&wparam(0));
++      &mov($L,&DWP(0,"eax","",0));
++      &mov($R,&DWP(4,"eax","",0));
++
++      $ksp=&wparam(1);
++
++      if ($do_ip)
++              {
++              &comment("");
++              &comment("IP");
++              &IP_new($L,$R,"eax");
++              }
++
++      &comment("");
++      &comment("fixup rotate");
++      &rotl($R,3);
++      &rotl($L,3);
++      &exch($L,$R);
++
++      &comment("");
++      &comment("load counter, key_schedule and enc flag");
++      &mov("eax",&wparam(2)); # get encrypt flag
++      &mov("ebp",&wparam(1)); # get ks
++      &cmp("eax","0");
++      &je(&label("start_decrypt"));
++
++      # encrypting part
++
++      for ($i=0; $i<16; $i+=2)
++              {
++              &comment("");
++              &comment("Round $i");
++              &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
++
++              &comment("");
++              &comment("Round ".sprintf("%d",$i+1));
++              &D_ENCRYPT($R,$L,($i+1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
++              }
++      &jmp(&label("end"));
++
++      &set_label("start_decrypt");
++
++      for ($i=15; $i>0; $i-=2)
++              {
++              &comment("");
++              &comment("Round $i");
++              &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
++              &comment("");
++              &comment("Round ".sprintf("%d",$i-1));
++              &D_ENCRYPT($R,$L,($i-1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
++              }
++
++      &set_label("end");
++
++      &comment("");
++      &comment("Fixup");
++      &rotr($L,3);            # r
++      &rotr($R,3);            # l
++
++      if ($do_ip)
++              {
++              &comment("");
++              &comment("FP");
++              &FP_new($R,$L,"eax");
++              }
++
++      &mov("eax",&wparam(0));
++      &mov(&DWP(0,"eax","",0),$L);
++      &mov(&DWP(4,"eax","",0),$R);
++
++      &function_end($name);
++      }
++
++
++# The logic is to load R into 2 registers and operate on both at the same time.
++# We also load the 2 R's into 2 more registers so we can do the 'move word down a byte'
++# while also masking the other copy and doing a lookup.  We then also accumulate the
++# L value in 2 registers then combine them at the end.
++sub D_ENCRYPT
++      {
++      local($L,$R,$S,$ks,$desSP,$u,$t,$tmp1,$tmp2,$tmp3)=@_;
++
++      &mov(   $u,             &DWP(&n2a($S*4),$ks,"",0));
++      &mov(   $t,             &DWP(&n2a(($S+1)*4),$ks,"",0));
++      &xor(   $u,             $R              );
++      &xor(   $t,             $R              );
++      &rotr(  $t,             4               );
++
++      # the numbers at the end of the line are origional instruction order
++      &mov(   $tmp2,          $u              );                      # 1 2
++      &mov(   $tmp1,          $t              );                      # 1 1
++      &and(   $tmp2,          "0xfc"          );                      # 1 4
++      &and(   $tmp1,          "0xfc"          );                      # 1 3
++      &shr(   $t,             8               );                      # 1 5
++      &xor(   $L,             &DWP("0x100+$desSP",$tmp1,"",0));       # 1 7
++      &shr(   $u,             8               );                      # 1 6
++      &mov(   $tmp1,          &DWP("      $desSP",$tmp2,"",0));       # 1 8
++
++      &mov(   $tmp2,          $u              );                      # 2 2
++      &xor(   $L,             $tmp1           );                      # 1 9
++      &and(   $tmp2,          "0xfc"          );                      # 2 4
++      &mov(   $tmp1,          $t              );                      # 2 1
++      &and(   $tmp1,          "0xfc"          );                      # 2 3
++      &shr(   $t,             8               );                      # 2 5
++      &xor(   $L,             &DWP("0x300+$desSP",$tmp1,"",0));       # 2 7
++      &shr(   $u,             8               );                      # 2 6
++      &mov(   $tmp1,          &DWP("0x200+$desSP",$tmp2,"",0));       # 2 8
++      &mov(   $tmp2,          $u              );                      # 3 2
++
++      &xor(   $L,             $tmp1           );                      # 2 9
++      &and(   $tmp2,          "0xfc"          );                      # 3 4
++
++      &mov(   $tmp1,          $t              );                      # 3 1 
++      &shr(   $u,             8               );                      # 3 6
++      &and(   $tmp1,          "0xfc"          );                      # 3 3
++      &shr(   $t,             8               );                      # 3 5
++      &xor(   $L,             &DWP("0x500+$desSP",$tmp1,"",0));       # 3 7
++      &mov(   $tmp1,          &DWP("0x400+$desSP",$tmp2,"",0));       # 3 8
++
++      &and(   $t,             "0xfc"          );                      # 4 1
++      &xor(   $L,             $tmp1           );                      # 3 9
++
++      &and(   $u,             "0xfc"          );                      # 4 2
++      &xor(   $L,             &DWP("0x700+$desSP",$t,"",0));          # 4 3
++      &xor(   $L,             &DWP("0x600+$desSP",$u,"",0));          # 4 4
++      }
++
++sub PERM_OP
++      {
++      local($a,$b,$tt,$shift,$mask)=@_;
++
++      &mov(   $tt,            $a              );
++      &shr(   $tt,            $shift          );
++      &xor(   $tt,            $b              );
++      &and(   $tt,            $mask           );
++      &xor(   $b,             $tt             );
++      &shl(   $tt,            $shift          );
++      &xor(   $a,             $tt             );
++      }
++
++sub IP_new
++      {
++      local($l,$r,$tt)=@_;
++
++      &PERM_OP($r,$l,$tt, 4,"0x0f0f0f0f");
++      &PERM_OP($l,$r,$tt,16,"0x0000ffff");
++      &PERM_OP($r,$l,$tt, 2,"0x33333333");
++      &PERM_OP($l,$r,$tt, 8,"0x00ff00ff");
++      &PERM_OP($r,$l,$tt, 1,"0x55555555");
++      }
++
++sub FP_new
++      {
++      local($l,$r,$tt)=@_;
++
++      &PERM_OP($l,$r,$tt, 1,"0x55555555");
++        &PERM_OP($r,$l,$tt, 8,"0x00ff00ff");
++        &PERM_OP($l,$r,$tt, 2,"0x33333333");
++        &PERM_OP($r,$l,$tt,16,"0x0000ffff");
++        &PERM_OP($l,$r,$tt, 4,"0x0f0f0f0f");
++      }
++
++sub n2a
++      {
++      sprintf("%d",$_[0]);
++      }
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/asm/desboth.pl     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,79 @@
++#!/usr/local/bin/perl
++
++$L="edi";
++$R="esi";
++
++sub des_encrypt3
++      {
++      local($name,$enc)=@_;
++
++      &function_begin_B($name,"");
++      &push("ebx");
++      &mov("ebx",&wparam(0));
++
++      &push("ebp");
++      &push("esi");
++
++      &push("edi");
++
++      &comment("");
++      &comment("Load the data words");
++      &mov($L,&DWP(0,"ebx","",0));
++      &mov($R,&DWP(4,"ebx","",0));
++      &stack_push(3);
++
++      &comment("");
++      &comment("IP");
++      &IP_new($L,$R,"edx",0);
++
++      # put them back
++      
++      if ($enc)
++              {
++              &mov(&DWP(4,"ebx","",0),$R);
++               &mov("eax",&wparam(1));
++              &mov(&DWP(0,"ebx","",0),"edx");
++               &mov("edi",&wparam(2));
++               &mov("esi",&wparam(3));
++              }
++      else
++              {
++              &mov(&DWP(4,"ebx","",0),$R);
++               &mov("esi",&wparam(1));
++              &mov(&DWP(0,"ebx","",0),"edx");
++               &mov("edi",&wparam(2));
++               &mov("eax",&wparam(3));
++              }
++      &mov(&swtmp(2), (($enc)?"1":"0"));
++      &mov(&swtmp(1), "eax");
++      &mov(&swtmp(0), "ebx");
++      &call("des_encrypt2");
++      &mov(&swtmp(2), (($enc)?"0":"1"));
++      &mov(&swtmp(1), "edi");
++      &mov(&swtmp(0), "ebx");
++      &call("des_encrypt2");
++      &mov(&swtmp(2), (($enc)?"1":"0"));
++      &mov(&swtmp(1), "esi");
++      &mov(&swtmp(0), "ebx");
++      &call("des_encrypt2");
++
++      &stack_pop(3);
++      &mov($L,&DWP(0,"ebx","",0));
++      &mov($R,&DWP(4,"ebx","",0));
++
++      &comment("");
++      &comment("FP");
++      &FP_new($L,$R,"eax",0);
++
++      &mov(&DWP(0,"ebx","",0),"eax");
++      &mov(&DWP(4,"ebx","",0),$R);
++
++      &pop("edi");
++      &pop("esi");
++      &pop("ebp");
++      &pop("ebx");
++      &ret();
++      &function_end_B($name);
++      }
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/asm/readme     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,131 @@
++First up, let me say I don't like writing in assembler.  It is not portable,
++dependant on the particular CPU architecture release and is generally a pig
++to debug and get right.  Having said that, the x86 architecture is probably
++the most important for speed due to number of boxes and since
++it appears to be the worst architecture to to get
++good C compilers for.  So due to this, I have lowered myself to do
++assembler for the inner DES routines in libdes :-).
++
++The file to implement in assembler is des_enc.c.  Replace the following
++4 functions
++des_encrypt(DES_LONG data[2],des_key_schedule ks, int encrypt);
++des_encrypt2(DES_LONG data[2],des_key_schedule ks, int encrypt);
++des_encrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
++des_decrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
++
++They encrypt/decrypt the 64 bits held in 'data' using
++the 'ks' key schedules.   The only difference between the 4 functions is that
++des_encrypt2() does not perform IP() or FP() on the data (this is an
++optimization for when doing triple DES and des_encrypt3() and des_decrypt3()
++perform triple des.  The triple DES routines are in here because it does
++make a big difference to have them located near the des_encrypt2 function
++at link time..
++
++Now as we all know, there are lots of different operating systems running on
++x86 boxes, and unfortunately they normally try to make sure their assembler
++formating is not the same as the other peoples.
++The 4 main formats I know of are
++Microsoft     Windows 95/Windows NT
++Elf           Includes Linux and FreeBSD(?).
++a.out         The older Linux.
++Solaris               Same as Elf but different comments :-(.
++
++Now I was not overly keen to write 4 different copies of the same code,
++so I wrote a few perl routines to output the correct assembler, given
++a target assembler type.  This code is ugly and is just a hack.
++The libraries are x86unix.pl and x86ms.pl.
++des586.pl, des686.pl and des-som[23].pl are the programs to actually
++generate the assembler.
++
++So to generate elf assembler
++perl des-som3.pl elf >dx86-elf.s
++For Windows 95/NT
++perl des-som2.pl win32 >win32.asm
++
++[ update 4 Jan 1996 ]
++I have added another way to do things.
++perl des-som3.pl cpp >dx86-cpp.s
++generates a file that will be included by dx86unix.cpp when it is compiled.
++To build for elf, a.out, solaris, bsdi etc,
++cc -E -DELF asm/dx86unix.cpp | as -o asm/dx86-elf.o
++cc -E -DSOL asm/dx86unix.cpp | as -o asm/dx86-sol.o
++cc -E -DOUT asm/dx86unix.cpp | as -o asm/dx86-out.o
++cc -E -DBSDI asm/dx86unix.cpp | as -o asm/dx86bsdi.o
++This was done to cut down the number of files in the distribution.
++
++Now the ugly part.  I acquired my copy of Intels
++"Optimization's For Intel's 32-Bit Processors" and found a few interesting
++things.  First, the aim of the exersize is to 'extract' one byte at a time
++from a word and do an array lookup.  This involves getting the byte from
++the 4 locations in the word and moving it to a new word and doing the lookup.
++The most obvious way to do this is
++xor   eax,    eax                             # clear word
++movb  al,     cl                              # get low byte
++xor   edi     DWORD PTR 0x100+des_SP[eax]     # xor in word
++movb  al,     ch                              # get next byte
++xor   edi     DWORD PTR 0x300+des_SP[eax]     # xor in word
++shr   ecx     16
++which seems ok.  For the pentium, this system appears to be the best.
++One has to do instruction interleaving to keep both functional units
++operating, but it is basically very efficient.
++
++Now the crunch.  When a full register is used after a partial write, eg.
++mov   al,     cl
++xor   edi,    DWORD PTR 0x100+des_SP[eax]
++386   - 1 cycle stall
++486   - 1 cycle stall
++586   - 0 cycle stall
++686   - at least 7 cycle stall (page 22 of the above mentioned document).
++
++So the technique that produces the best results on a pentium, according to
++the documentation, will produce hideous results on a pentium pro.
++
++To get around this, des686.pl will generate code that is not as fast on
++a pentium, should be very good on a pentium pro.
++mov   eax,    ecx                             # copy word 
++shr   ecx,    8                               # line up next byte
++and   eax,    0fch                            # mask byte
++xor   edi     DWORD PTR 0x100+des_SP[eax]     # xor in array lookup
++mov   eax,    ecx                             # get word
++shr   ecx     8                               # line up next byte
++and   eax,    0fch                            # mask byte
++xor   edi     DWORD PTR 0x300+des_SP[eax]     # xor in array lookup
++
++Due to the execution units in the pentium, this actually works quite well.
++For a pentium pro it should be very good.  This is the type of output
++Visual C++ generates.
++
++There is a third option.  instead of using
++mov   al,     ch
++which is bad on the pentium pro, one may be able to use
++movzx eax,    ch
++which may not incur the partial write penalty.  On the pentium,
++this instruction takes 4 cycles so is not worth using but on the
++pentium pro it appears it may be worth while.  I need access to one to
++experiment :-).
++
++eric (20 Oct 1996)
++
++22 Nov 1996 - I have asked people to run the 2 different version on pentium
++pros and it appears that the intel documentation is wrong.  The
++mov al,bh is still faster on a pentium pro, so just use the des586.pl
++install des686.pl
++
++3 Dec 1996 - I added des_encrypt3/des_decrypt3 because I have moved these
++functions into des_enc.c because it does make a massive performance
++difference on some boxes to have the functions code located close to
++the des_encrypt2() function.
++
++9 Jan 1997 - des-som2.pl is now the correct perl script to use for
++pentiums.  It contains an inner loop from
++Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk> which does raw ecb DES calls at
++273,000 per second.  He had a previous version at 250,000 and the best
++I was able to get was 203,000.  The content has not changed, this is all
++due to instruction sequencing (and actual instructions choice) which is able
++to keep both functional units of the pentium going.
++We may have lost the ugly register usage restrictions when x86 went 32 bit
++but for the pentium it has been replaced by evil instruction ordering tricks.
++
++13 Jan 1997 - des-som3.pl, more optimizations from Svend Olaf.
++raw DES at 281,000 per second on a pentium 100.
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/cbc_enc.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,142 @@
++/* crypto/des/cbc_enc.c */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++#include "des/des_locl.h"
++
++void des_cbc_encrypt(input, output, length, schedule, ivec, enc)
++des_cblock (*input);
++des_cblock (*output);
++long length;
++des_key_schedule schedule;
++des_cblock (*ivec);
++int enc;
++      {
++      register DES_LONG tin0,tin1;
++      register DES_LONG tout0,tout1,xor0,xor1;
++      register unsigned char *in,*out;
++      register long l=length;
++      DES_LONG tin[2];
++      unsigned char *iv;
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
++              ocf_des_cbc_encrypt(input, output, length, schedule, ivec, enc);
++              return;
++      }
++#endif
++
++      in=(unsigned char *)input;
++      out=(unsigned char *)output;
++      iv=(unsigned char *)ivec;
++
++      if (enc)
++              {
++              c2l(iv,tout0);
++              c2l(iv,tout1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0);
++                      c2l(in,tin1);
++                      tin0^=tout0; tin[0]=tin0;
++                      tin1^=tout1; tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++                      tout0=tin[0]; l2c(tout0,out);
++                      tout1=tin[1]; l2c(tout1,out);
++                      }
++              if (l != -8)
++                      {
++                      c2ln(in,tin0,tin1,l+8);
++                      tin0^=tout0; tin[0]=tin0;
++                      tin1^=tout1; tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++                      tout0=tin[0]; l2c(tout0,out);
++                      tout1=tin[1]; l2c(tout1,out);
++                      }
++              }
++      else
++              {
++              c2l(iv,xor0);
++              c2l(iv,xor1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0); tin[0]=tin0;
++                      c2l(in,tin1); tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
++                      tout0=tin[0]^xor0;
++                      tout1=tin[1]^xor1;
++                      l2c(tout0,out);
++                      l2c(tout1,out);
++                      xor0=tin0;
++                      xor1=tin1;
++                      }
++              if (l != -8)
++                      {
++                      c2l(in,tin0); tin[0]=tin0;
++                      c2l(in,tin1); tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
++                      tout0=tin[0]^xor0;
++                      tout1=tin[1]^xor1;
++                      l2cn(tout0,tout1,out,l+8);
++              /*      xor0=tin0;
++                      xor1=tin1; */
++                      }
++              }
++      tin0=tin1=tout0=tout1=xor0=xor1=0;
++      tin[0]=tin[1]=0;
++      }
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/des.doc     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,505 @@
++The DES library.
++
++Please note that this library was originally written to operate with
++eBones, a version of Kerberos that had had encryption removed when it left
++the USA and then put back in.  As such there are some routines that I will
++advise not using but they are still in the library for historical reasons.
++For all calls that have an 'input' and 'output' variables, they can be the
++same.
++
++This library requires the inclusion of 'des.h'.
++
++All of the encryption functions take what is called a des_key_schedule as an 
++argument.  A des_key_schedule is an expanded form of the des key.
++A des_key is 8 bytes of odd parity, the type used to hold the key is a
++des_cblock.  A des_cblock is an array of 8 bytes, often in this library
++description I will refer to input bytes when the function specifies
++des_cblock's as input or output, this just means that the variable should
++be a multiple of 8 bytes.
++
++The define DES_ENCRYPT is passed to specify encryption, DES_DECRYPT to
++specify decryption.  The functions and global variable are as follows:
++
++int des_check_key;
++      DES keys are supposed to be odd parity.  If this variable is set to
++      a non-zero value, des_set_key() will check that the key has odd
++      parity and is not one of the known weak DES keys.  By default this
++      variable is turned off;
++      
++void des_set_odd_parity(
++des_cblock *key );
++      This function takes a DES key (8 bytes) and sets the parity to odd.
++      
++int des_is_weak_key(
++des_cblock *key );
++      This function returns a non-zero value if the DES key passed is a
++      weak, DES key.  If it is a weak key, don't use it, try a different
++      one.  If you are using 'random' keys, the chances of hitting a weak
++      key are 1/2^52 so it is probably not worth checking for them.
++      
++int des_set_key(
++des_cblock *key,
++des_key_schedule schedule);
++      Des_set_key converts an 8 byte DES key into a des_key_schedule.
++      A des_key_schedule is an expanded form of the key which is used to
++      perform actual encryption.  It can be regenerated from the DES key
++      so it only needs to be kept when encryption or decryption is about
++      to occur.  Don't save or pass around des_key_schedule's since they
++      are CPU architecture dependent, DES keys are not.  If des_check_key
++      is non zero, zero is returned if the key has the wrong parity or
++      the key is a weak key, else 1 is returned.
++      
++int des_key_sched(
++des_cblock *key,
++des_key_schedule schedule);
++      An alternative name for des_set_key().
++
++int des_rw_mode;              /* defaults to DES_PCBC_MODE */
++      This flag holds either DES_CBC_MODE or DES_PCBC_MODE (default).
++      This specifies the function to use in the enc_read() and enc_write()
++      functions.
++
++void des_encrypt(
++unsigned long *data,
++des_key_schedule ks,
++int enc);
++      This is the DES encryption function that gets called by just about
++      every other DES routine in the library.  You should not use this
++      function except to implement 'modes' of DES.  I say this because the
++      functions that call this routine do the conversion from 'char *' to
++      long, and this needs to be done to make sure 'non-aligned' memory
++      access do not occur.  The characters are loaded 'little endian',
++      have a look at my source code for more details on how I use this
++      function.
++      Data is a pointer to 2 unsigned long's and ks is the
++      des_key_schedule to use.  enc, is non zero specifies encryption,
++      zero if decryption.
++
++void des_encrypt2(
++unsigned long *data,
++des_key_schedule ks,
++int enc);
++      This functions is the same as des_encrypt() except that the DES
++      initial permutation (IP) and final permutation (FP) have been left
++      out.  As for des_encrypt(), you should not use this function.
++      It is used by the routines in my library that implement triple DES.
++      IP() des_encrypt2() des_encrypt2() des_encrypt2() FP() is the same
++      as des_encrypt() des_encrypt() des_encrypt() except faster :-).
++
++void des_ecb_encrypt(
++des_cblock *input,
++des_cblock *output,
++des_key_schedule ks,
++int enc);
++      This is the basic Electronic Code Book form of DES, the most basic
++      form.  Input is encrypted into output using the key represented by
++      ks.  If enc is non zero (DES_ENCRYPT), encryption occurs, otherwise
++      decryption occurs.  Input is 8 bytes long and output is 8 bytes.
++      (the des_cblock structure is 8 chars).
++      
++void des_ecb3_encrypt(
++des_cblock *input,
++des_cblock *output,
++des_key_schedule ks1,
++des_key_schedule ks2,
++des_key_schedule ks3,
++int enc);
++      This is the 3 key EDE mode of ECB DES.  What this means is that 
++      the 8 bytes of input is encrypted with ks1, decrypted with ks2 and
++      then encrypted again with ks3, before being put into output;
++      C=E(ks3,D(ks2,E(ks1,M))).  There is a macro, des_ecb2_encrypt()
++      that only takes 2 des_key_schedules that implements,
++      C=E(ks1,D(ks2,E(ks1,M))) in that the final encrypt is done with ks1.
++      
++void des_cbc_encrypt(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule ks,
++des_cblock *ivec,
++int enc);
++      This routine implements DES in Cipher Block Chaining mode.
++      Input, which should be a multiple of 8 bytes is encrypted
++      (or decrypted) to output which will also be a multiple of 8 bytes.
++      The number of bytes is in length (and from what I've said above,
++      should be a multiple of 8).  If length is not a multiple of 8, I'm
++      not being held responsible :-).  ivec is the initialisation vector.
++      This function does not modify this variable.  To correctly implement
++      cbc mode, you need to do one of 2 things; copy the last 8 bytes of
++      cipher text for use as the next ivec in your application,
++      or use des_ncbc_encrypt(). 
++      Only this routine has this problem with updating the ivec, all
++      other routines that are implementing cbc mode update ivec.
++      
++void des_ncbc_encrypt(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule sk,
++des_cblock *ivec,
++int enc);
++      For historical reasons, des_cbc_encrypt() did not update the
++      ivec with the value requires so that subsequent calls to
++      des_cbc_encrypt() would 'chain'.  This was needed so that the same
++      'length' values would not need to be used when decrypting.
++      des_ncbc_encrypt() does the right thing.  It is the same as
++      des_cbc_encrypt accept that ivec is updates with the correct value
++      to pass in subsequent calls to des_ncbc_encrypt().  I advise using
++      des_ncbc_encrypt() instead of des_cbc_encrypt();
++
++void des_xcbc_encrypt(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule sk,
++des_cblock *ivec,
++des_cblock *inw,
++des_cblock *outw,
++int enc);
++      This is RSA's DESX mode of DES.  It uses inw and outw to
++      'whiten' the encryption.  inw and outw are secret (unlike the iv)
++      and are as such, part of the key.  So the key is sort of 24 bytes.
++      This is much better than cbc des.
++      
++void des_3cbc_encrypt(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule sk1,
++des_key_schedule sk2,
++des_cblock *ivec1,
++des_cblock *ivec2,
++int enc);
++      This function is flawed, do not use it.  I have left it in the
++      library because it is used in my des(1) program and will function
++      correctly when used by des(1).  If I removed the function, people
++      could end up unable to decrypt files.
++      This routine implements outer triple cbc encryption using 2 ks and
++      2 ivec's.  Use des_ede2_cbc_encrypt() instead.
++      
++void des_ede3_cbc_encrypt(
++des_cblock *input,
++des_cblock *output, 
++long length,
++des_key_schedule ks1,
++des_key_schedule ks2, 
++des_key_schedule ks3, 
++des_cblock *ivec,
++int enc);
++      This function implements inner triple CBC DES encryption with 3
++      keys.  What this means is that each 'DES' operation
++      inside the cbc mode is really an C=E(ks3,D(ks2,E(ks1,M))).
++      Again, this is cbc mode so an ivec is requires.
++      This mode is used by SSL.
++      There is also a des_ede2_cbc_encrypt() that only uses 2
++      des_key_schedule's, the first being reused for the final
++      encryption.  C=E(ks1,D(ks2,E(ks1,M))).  This form of triple DES
++      is used by the RSAref library.
++      
++void des_pcbc_encrypt(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule ks,
++des_cblock *ivec,
++int enc);
++      This is Propagating Cipher Block Chaining mode of DES.  It is used
++      by Kerberos v4.  It's parameters are the same as des_ncbc_encrypt().
++      
++void des_cfb_encrypt(
++unsigned char *in,
++unsigned char *out,
++int numbits,
++long length,
++des_key_schedule ks,
++des_cblock *ivec,
++int enc);
++      Cipher Feedback Back mode of DES.  This implementation 'feeds back'
++      in numbit blocks.  The input (and output) is in multiples of numbits
++      bits.  numbits should to be a multiple of 8 bits.  Length is the
++      number of bytes input.  If numbits is not a multiple of 8 bits,
++      the extra bits in the bytes will be considered padding.  So if
++      numbits is 12, for each 2 input bytes, the 4 high bits of the
++      second byte will be ignored.  So to encode 72 bits when using
++      a numbits of 12 take 12 bytes.  To encode 72 bits when using
++      numbits of 9 will take 16 bytes.  To encode 80 bits when using
++      numbits of 16 will take 10 bytes. etc, etc.  This padding will
++      apply to both input and output.
++
++      
++void des_cfb64_encrypt(
++unsigned char *in,
++unsigned char *out,
++long length,
++des_key_schedule ks,
++des_cblock *ivec,
++int *num,
++int enc);
++      This is one of the more useful functions in this DES library, it
++      implements CFB mode of DES with 64bit feedback.  Why is this
++      useful you ask?  Because this routine will allow you to encrypt an
++      arbitrary number of bytes, no 8 byte padding.  Each call to this
++      routine will encrypt the input bytes to output and then update ivec
++      and num.  num contains 'how far' we are though ivec.  If this does
++      not make much sense, read more about cfb mode of DES :-).
++      
++void des_ede3_cfb64_encrypt(
++unsigned char *in,
++unsigned char *out,
++long length,
++des_key_schedule ks1,
++des_key_schedule ks2,
++des_key_schedule ks3,
++des_cblock *ivec,
++int *num,
++int enc);
++      Same as des_cfb64_encrypt() accept that the DES operation is
++      triple DES.  As usual, there is a macro for
++      des_ede2_cfb64_encrypt() which reuses ks1.
++
++void des_ofb_encrypt(
++unsigned char *in,
++unsigned char *out,
++int numbits,
++long length,
++des_key_schedule ks,
++des_cblock *ivec);
++      This is a implementation of Output Feed Back mode of DES.  It is
++      the same as des_cfb_encrypt() in that numbits is the size of the
++      units dealt with during input and output (in bits).
++      
++void des_ofb64_encrypt(
++unsigned char *in,
++unsigned char *out,
++long length,
++des_key_schedule ks,
++des_cblock *ivec,
++int *num);
++      The same as des_cfb64_encrypt() except that it is Output Feed Back
++      mode.
++
++void des_ede3_ofb64_encrypt(
++unsigned char *in,
++unsigned char *out,
++long length,
++des_key_schedule ks1,
++des_key_schedule ks2,
++des_key_schedule ks3,
++des_cblock *ivec,
++int *num);
++      Same as des_ofb64_encrypt() accept that the DES operation is
++      triple DES.  As usual, there is a macro for
++      des_ede2_ofb64_encrypt() which reuses ks1.
++
++int des_read_pw_string(
++char *buf,
++int length,
++char *prompt,
++int verify);
++      This routine is used to get a password from the terminal with echo
++      turned off.  Buf is where the string will end up and length is the
++      size of buf.  Prompt is a string presented to the 'user' and if
++      verify is set, the key is asked for twice and unless the 2 copies
++      match, an error is returned.  A return code of -1 indicates a
++      system error, 1 failure due to use interaction, and 0 is success.
++
++unsigned long des_cbc_cksum(
++des_cblock *input,
++des_cblock *output,
++long length,
++des_key_schedule ks,
++des_cblock *ivec);
++      This function produces an 8 byte checksum from input that it puts in
++      output and returns the last 4 bytes as a long.  The checksum is
++      generated via cbc mode of DES in which only the last 8 byes are
++      kept.  I would recommend not using this function but instead using
++      the EVP_Digest routines, or at least using MD5 or SHA.  This
++      function is used by Kerberos v4 so that is why it stays in the
++      library.
++      
++char *des_fcrypt(
++const char *buf,
++const char *salt
++char *ret);
++      This is my fast version of the unix crypt(3) function.  This version
++      takes only a small amount of space relative to other fast
++      crypt() implementations.  This is different to the normal crypt
++      in that the third parameter is the buffer that the return value
++      is written into.  It needs to be at least 14 bytes long.  This
++      function is thread safe, unlike the normal crypt.
++
++char *crypt(
++const char *buf,
++const char *salt);
++      This function calls des_fcrypt() with a static array passed as the
++      third parameter.  This emulates the normal non-thread safe semantics
++      of crypt(3).
++
++void des_string_to_key(
++char *str,
++des_cblock *key);
++      This function takes str and converts it into a DES key.  I would
++      recommend using MD5 instead and use the first 8 bytes of output.
++      When I wrote the first version of these routines back in 1990, MD5
++      did not exist but I feel these routines are still sound.  This
++      routines is compatible with the one in MIT's libdes.
++      
++void des_string_to_2keys(
++char *str,
++des_cblock *key1,
++des_cblock *key2);
++      This function takes str and converts it into 2 DES keys.
++      I would recommend using MD5 and using the 16 bytes as the 2 keys.
++      I have nothing against these 2 'string_to_key' routines, it's just
++      that if you say that your encryption key is generated by using the
++      16 bytes of an MD5 hash, every-one knows how you generated your
++      keys.
++
++int des_read_password(
++des_cblock *key,
++char *prompt,
++int verify);
++      This routine combines des_read_pw_string() with des_string_to_key().
++
++int des_read_2passwords(
++des_cblock *key1,
++des_cblock *key2,
++char *prompt,
++int verify);
++      This routine combines des_read_pw_string() with des_string_to_2key().
++
++void des_random_seed(
++des_cblock key);
++      This routine sets a starting point for des_random_key().
++      
++void des_random_key(
++des_cblock ret);
++      This function return a random key.  Make sure to 'seed' the random
++      number generator (with des_random_seed()) before using this function.
++      I personally now use a MD5 based random number system.
++
++int des_enc_read(
++int fd,
++char *buf,
++int len,
++des_key_schedule ks,
++des_cblock *iv);
++      This function will write to a file descriptor the encrypted data
++      from buf.  This data will be preceded by a 4 byte 'byte count' and
++      will be padded out to 8 bytes.  The encryption is either CBC of
++      PCBC depending on the value of des_rw_mode.  If it is DES_PCBC_MODE,
++      pcbc is used, if DES_CBC_MODE, cbc is used.  The default is to use
++      DES_PCBC_MODE.
++
++int des_enc_write(
++int fd,
++char *buf,
++int len,
++des_key_schedule ks,
++des_cblock *iv);
++      This routines read stuff written by des_enc_read() and decrypts it.
++      I have used these routines quite a lot but I don't believe they are
++      suitable for non-blocking io.  If you are after a full
++      authentication/encryption over networks, have a look at SSL instead.
++
++unsigned long des_quad_cksum(
++des_cblock *input,
++des_cblock *output,
++long length,
++int out_count,
++des_cblock *seed);
++      This is a function from Kerberos v4 that is not anything to do with
++      DES but was needed.  It is a cksum that is quicker to generate than
++      des_cbc_cksum();  I personally would use MD5 routines now.
++=====
++Modes of DES
++Quite a bit of the following information has been taken from
++      AS 2805.5.2
++      Australian Standard
++      Electronic funds transfer - Requirements for interfaces,
++      Part 5.2: Modes of operation for an n-bit block cipher algorithm
++      Appendix A
++
++There are several different modes in which DES can be used, they are
++as follows.
++
++Electronic Codebook Mode (ECB) (des_ecb_encrypt())
++- 64 bits are enciphered at a time.
++- The order of the blocks can be rearranged without detection.
++- The same plaintext block always produces the same ciphertext block
++  (for the same key) making it vulnerable to a 'dictionary attack'.
++- An error will only affect one ciphertext block.
++
++Cipher Block Chaining Mode (CBC) (des_cbc_encrypt())
++- a multiple of 64 bits are enciphered at a time.
++- The CBC mode produces the same ciphertext whenever the same
++  plaintext is encrypted using the same key and starting variable.
++- The chaining operation makes the ciphertext blocks dependent on the
++  current and all preceding plaintext blocks and therefore blocks can not
++  be rearranged.
++- The use of different starting variables prevents the same plaintext
++  enciphering to the same ciphertext.
++- An error will affect the current and the following ciphertext blocks.
++
++Cipher Feedback Mode (CFB) (des_cfb_encrypt())
++- a number of bits (j) <= 64 are enciphered at a time.
++- The CFB mode produces the same ciphertext whenever the same
++  plaintext is encrypted using the same key and starting variable.
++- The chaining operation makes the ciphertext variables dependent on the
++  current and all preceding variables and therefore j-bit variables are
++  chained together and can not be rearranged.
++- The use of different starting variables prevents the same plaintext
++  enciphering to the same ciphertext.
++- The strength of the CFB mode depends on the size of k (maximal if
++  j == k).  In my implementation this is always the case.
++- Selection of a small value for j will require more cycles through
++  the encipherment algorithm per unit of plaintext and thus cause
++  greater processing overheads.
++- Only multiples of j bits can be enciphered.
++- An error will affect the current and the following ciphertext variables.
++
++Output Feedback Mode (OFB) (des_ofb_encrypt())
++- a number of bits (j) <= 64 are enciphered at a time.
++- The OFB mode produces the same ciphertext whenever the same
++  plaintext enciphered using the same key and starting variable.  More
++  over, in the OFB mode the same key stream is produced when the same
++  key and start variable are used.  Consequently, for security reasons
++  a specific start variable should be used only once for a given key.
++- The absence of chaining makes the OFB more vulnerable to specific attacks.
++- The use of different start variables values prevents the same
++  plaintext enciphering to the same ciphertext, by producing different
++  key streams.
++- Selection of a small value for j will require more cycles through
++  the encipherment algorithm per unit of plaintext and thus cause
++  greater processing overheads.
++- Only multiples of j bits can be enciphered.
++- OFB mode of operation does not extend ciphertext errors in the
++  resultant plaintext output.  Every bit error in the ciphertext causes
++  only one bit to be in error in the deciphered plaintext.
++- OFB mode is not self-synchronising.  If the two operation of
++  encipherment and decipherment get out of synchronism, the system needs
++  to be re-initialised.
++- Each re-initialisation should use a value of the start variable
++ different from the start variable values used before with the same
++ key.  The reason for this is that an identical bit stream would be
++ produced each time from the same parameters.  This would be
++ susceptible to a ' known plaintext' attack.
++
++Triple ECB Mode (des_ecb3_encrypt())
++- Encrypt with key1, decrypt with key2 and encrypt with key3 again.
++- As for ECB encryption but increases the key length to 168 bits.
++  There are theoretic attacks that can be used that make the effective
++  key length 112 bits, but this attack also requires 2^56 blocks of
++  memory, not very likely, even for the NSA.
++- If both keys are the same it is equivalent to encrypting once with
++  just one key.
++- If the first and last key are the same, the key length is 112 bits.
++  There are attacks that could reduce the key space to 55 bit's but it
++  requires 2^56 blocks of memory.
++- If all 3 keys are the same, this is effectively the same as normal
++  ecb mode.
++
++Triple CBC Mode (des_ede3_cbc_encrypt())
++- Encrypt with key1, decrypt with key2 and then encrypt with key3.
++- As for CBC encryption but increases the key length to 168 bits with
++  the same restrictions as for triple ecb mode.
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/des_enc.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,524 @@
++/* crypto/des/des_enc.c */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++#include "des/des_locl.h"
++
++void des_encrypt(data, ks, enc)
++DES_LONG *data;
++des_key_schedule ks;
++int enc;
++      {
++      register DES_LONG l,r,t,u;
++#ifdef DES_PTR
++      register unsigned char *des_SP=(unsigned char *)des_SPtrans;
++#endif
++#ifndef DES_UNROLL
++      register int i;
++#endif
++      register DES_LONG *s;
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
++              ocf_des_encrypt(data, ks, enc);
++              return;
++      }
++#endif
++
++      r=data[0];
++      l=data[1];
++
++      IP(r,l);
++      /* Things have been modified so that the initial rotate is
++       * done outside the loop.  This required the
++       * des_SPtrans values in sp.h to be rotated 1 bit to the right.
++       * One perl script later and things have a 5% speed up on a sparc2.
++       * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
++       * for pointing this out. */
++      /* clear the top bits on machines with 8byte longs */
++      /* shift left by 2 */
++      r=ROTATE(r,29)&0xffffffffL;
++      l=ROTATE(l,29)&0xffffffffL;
++
++      s=(DES_LONG *)ks;
++      /* I don't know if it is worth the effort of loop unrolling the
++       * inner loop */
++      if (enc)
++              {
++#ifdef DES_UNROLL
++              D_ENCRYPT(l,r, 0); /*  1 */
++              D_ENCRYPT(r,l, 2); /*  2 */
++              D_ENCRYPT(l,r, 4); /*  3 */
++              D_ENCRYPT(r,l, 6); /*  4 */
++              D_ENCRYPT(l,r, 8); /*  5 */
++              D_ENCRYPT(r,l,10); /*  6 */
++              D_ENCRYPT(l,r,12); /*  7 */
++              D_ENCRYPT(r,l,14); /*  8 */
++              D_ENCRYPT(l,r,16); /*  9 */
++              D_ENCRYPT(r,l,18); /*  10 */
++              D_ENCRYPT(l,r,20); /*  11 */
++              D_ENCRYPT(r,l,22); /*  12 */
++              D_ENCRYPT(l,r,24); /*  13 */
++              D_ENCRYPT(r,l,26); /*  14 */
++              D_ENCRYPT(l,r,28); /*  15 */
++              D_ENCRYPT(r,l,30); /*  16 */
++#else
++              for (i=0; i<32; i+=8)
++                      {
++                      D_ENCRYPT(l,r,i+0); /*  1 */
++                      D_ENCRYPT(r,l,i+2); /*  2 */
++                      D_ENCRYPT(l,r,i+4); /*  3 */
++                      D_ENCRYPT(r,l,i+6); /*  4 */
++                      }
++#endif
++              }
++      else
++              {
++#ifdef DES_UNROLL
++              D_ENCRYPT(l,r,30); /* 16 */
++              D_ENCRYPT(r,l,28); /* 15 */
++              D_ENCRYPT(l,r,26); /* 14 */
++              D_ENCRYPT(r,l,24); /* 13 */
++              D_ENCRYPT(l,r,22); /* 12 */
++              D_ENCRYPT(r,l,20); /* 11 */
++              D_ENCRYPT(l,r,18); /* 10 */
++              D_ENCRYPT(r,l,16); /*  9 */
++              D_ENCRYPT(l,r,14); /*  8 */
++              D_ENCRYPT(r,l,12); /*  7 */
++              D_ENCRYPT(l,r,10); /*  6 */
++              D_ENCRYPT(r,l, 8); /*  5 */
++              D_ENCRYPT(l,r, 6); /*  4 */
++              D_ENCRYPT(r,l, 4); /*  3 */
++              D_ENCRYPT(l,r, 2); /*  2 */
++              D_ENCRYPT(r,l, 0); /*  1 */
++#else
++              for (i=30; i>0; i-=8)
++                      {
++                      D_ENCRYPT(l,r,i-0); /* 16 */
++                      D_ENCRYPT(r,l,i-2); /* 15 */
++                      D_ENCRYPT(l,r,i-4); /* 14 */
++                      D_ENCRYPT(r,l,i-6); /* 13 */
++                      }
++#endif
++              }
++
++      /* rotate and clear the top bits on machines with 8byte longs */
++      l=ROTATE(l,3)&0xffffffffL;
++      r=ROTATE(r,3)&0xffffffffL;
++
++      FP(r,l);
++      data[0]=l;
++      data[1]=r;
++      l=r=t=u=0;
++      }
++
++void des_encrypt2(data, ks, enc)
++DES_LONG *data;
++des_key_schedule ks;
++int enc;
++      {
++      register DES_LONG l,r,t,u;
++#ifdef DES_PTR
++      register unsigned char *des_SP=(unsigned char *)des_SPtrans;
++#endif
++#ifndef DES_UNROLL
++      register int i;
++#endif
++      register DES_LONG *s;
++
++      r=data[0];
++      l=data[1];
++
++      /* Things have been modified so that the initial rotate is
++       * done outside the loop.  This required the
++       * des_SPtrans values in sp.h to be rotated 1 bit to the right.
++       * One perl script later and things have a 5% speed up on a sparc2.
++       * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
++       * for pointing this out. */
++      /* clear the top bits on machines with 8byte longs */
++      r=ROTATE(r,29)&0xffffffffL;
++      l=ROTATE(l,29)&0xffffffffL;
++
++      s=(DES_LONG *)ks;
++      /* I don't know if it is worth the effort of loop unrolling the
++       * inner loop */
++      if (enc)
++              {
++#ifdef DES_UNROLL
++              D_ENCRYPT(l,r, 0); /*  1 */
++              D_ENCRYPT(r,l, 2); /*  2 */
++              D_ENCRYPT(l,r, 4); /*  3 */
++              D_ENCRYPT(r,l, 6); /*  4 */
++              D_ENCRYPT(l,r, 8); /*  5 */
++              D_ENCRYPT(r,l,10); /*  6 */
++              D_ENCRYPT(l,r,12); /*  7 */
++              D_ENCRYPT(r,l,14); /*  8 */
++              D_ENCRYPT(l,r,16); /*  9 */
++              D_ENCRYPT(r,l,18); /*  10 */
++              D_ENCRYPT(l,r,20); /*  11 */
++              D_ENCRYPT(r,l,22); /*  12 */
++              D_ENCRYPT(l,r,24); /*  13 */
++              D_ENCRYPT(r,l,26); /*  14 */
++              D_ENCRYPT(l,r,28); /*  15 */
++              D_ENCRYPT(r,l,30); /*  16 */
++#else
++              for (i=0; i<32; i+=8)
++                      {
++                      D_ENCRYPT(l,r,i+0); /*  1 */
++                      D_ENCRYPT(r,l,i+2); /*  2 */
++                      D_ENCRYPT(l,r,i+4); /*  3 */
++                      D_ENCRYPT(r,l,i+6); /*  4 */
++                      }
++#endif
++              }
++      else
++              {
++#ifdef DES_UNROLL
++              D_ENCRYPT(l,r,30); /* 16 */
++              D_ENCRYPT(r,l,28); /* 15 */
++              D_ENCRYPT(l,r,26); /* 14 */
++              D_ENCRYPT(r,l,24); /* 13 */
++              D_ENCRYPT(l,r,22); /* 12 */
++              D_ENCRYPT(r,l,20); /* 11 */
++              D_ENCRYPT(l,r,18); /* 10 */
++              D_ENCRYPT(r,l,16); /*  9 */
++              D_ENCRYPT(l,r,14); /*  8 */
++              D_ENCRYPT(r,l,12); /*  7 */
++              D_ENCRYPT(l,r,10); /*  6 */
++              D_ENCRYPT(r,l, 8); /*  5 */
++              D_ENCRYPT(l,r, 6); /*  4 */
++              D_ENCRYPT(r,l, 4); /*  3 */
++              D_ENCRYPT(l,r, 2); /*  2 */
++              D_ENCRYPT(r,l, 0); /*  1 */
++#else
++              for (i=30; i>0; i-=8)
++                      {
++                      D_ENCRYPT(l,r,i-0); /* 16 */
++                      D_ENCRYPT(r,l,i-2); /* 15 */
++                      D_ENCRYPT(l,r,i-4); /* 14 */
++                      D_ENCRYPT(r,l,i-6); /* 13 */
++                      }
++#endif
++              }
++      /* rotate and clear the top bits on machines with 8byte longs */
++      data[0]=ROTATE(l,3)&0xffffffffL;
++      data[1]=ROTATE(r,3)&0xffffffffL;
++      l=r=t=u=0;
++      }
++
++void des_encrypt3(data,ks1,ks2,ks3)
++DES_LONG *data;
++des_key_schedule ks1;
++des_key_schedule ks2;
++des_key_schedule ks3;
++      {
++      register DES_LONG l,r;
++
++      l=data[0];
++      r=data[1];
++      IP(l,r);
++      data[0]=l;
++      data[1]=r;
++      des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
++      des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
++      des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
++      l=data[0];
++      r=data[1];
++      FP(r,l);
++      data[0]=l;
++      data[1]=r;
++      }
++
++void des_decrypt3(data,ks1,ks2,ks3)
++DES_LONG *data;
++des_key_schedule ks1;
++des_key_schedule ks2;
++des_key_schedule ks3;
++      {
++      register DES_LONG l,r;
++
++      l=data[0];
++      r=data[1];
++      IP(l,r);
++      data[0]=l;
++      data[1]=r;
++      des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
++      des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
++      des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
++      l=data[0];
++      r=data[1];
++      FP(r,l);
++      data[0]=l;
++      data[1]=r;
++      }
++
++#ifndef DES_DEFAULT_OPTIONS
++
++void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
++des_cblock (*input);
++des_cblock (*output);
++long length;
++des_key_schedule schedule;
++des_cblock (*ivec);
++int enc;
++      {
++      register DES_LONG tin0,tin1;
++      register DES_LONG tout0,tout1,xor0,xor1;
++      register unsigned char *in,*out;
++      register long l=length;
++      DES_LONG tin[2];
++      unsigned char *iv;
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
++              ocf_des_ncbc_encrypt(input, output, length, schedule, ivec, enc);
++              return;
++      }
++#endif 
++
++      in=(unsigned char *)input;
++      out=(unsigned char *)output;
++      iv=(unsigned char *)ivec;
++
++      if (enc)
++              {
++              c2l(iv,tout0);
++              c2l(iv,tout1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0);
++                      c2l(in,tin1);
++                      tin0^=tout0; tin[0]=tin0;
++                      tin1^=tout1; tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++                      tout0=tin[0]; l2c(tout0,out);
++                      tout1=tin[1]; l2c(tout1,out);
++                      }
++              if (l != -8)
++                      {
++                      c2ln(in,tin0,tin1,l+8);
++                      tin0^=tout0; tin[0]=tin0;
++                      tin1^=tout1; tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++                      tout0=tin[0]; l2c(tout0,out);
++                      tout1=tin[1]; l2c(tout1,out);
++                      }
++              iv=(unsigned char *)ivec;
++              l2c(tout0,iv);
++              l2c(tout1,iv);
++              }
++      else
++              {
++              c2l(iv,xor0);
++              c2l(iv,xor1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0); tin[0]=tin0;
++                      c2l(in,tin1); tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
++                      tout0=tin[0]^xor0;
++                      tout1=tin[1]^xor1;
++                      l2c(tout0,out);
++                      l2c(tout1,out);
++                      xor0=tin0;
++                      xor1=tin1;
++                      }
++              if (l != -8)
++                      {
++                      c2l(in,tin0); tin[0]=tin0;
++                      c2l(in,tin1); tin[1]=tin1;
++                      des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
++                      tout0=tin[0]^xor0;
++                      tout1=tin[1]^xor1;
++                      l2cn(tout0,tout1,out,l+8);
++                      xor0=tin0;
++                      xor1=tin1;
++                      }
++
++              iv=(unsigned char *)ivec;
++              l2c(xor0,iv);
++              l2c(xor1,iv);
++              }
++      tin0=tin1=tout0=tout1=xor0=xor1=0;
++      tin[0]=tin[1]=0;
++      }
++
++void des_ede3_cbc_encrypt(input, output, length, ks1, ks2, ks3, ivec, enc)
++des_cblock (*input);
++des_cblock (*output);
++long length;
++des_key_schedule ks1;
++des_key_schedule ks2;
++des_key_schedule ks3;
++des_cblock (*ivec);
++int enc;
++      {
++      register DES_LONG tin0,tin1;
++      register DES_LONG tout0,tout1,xor0,xor1;
++      register unsigned char *in,*out;
++      register long l=length;
++      DES_LONG tin[2];
++      unsigned char *iv;
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
++              ocf_des_ede3_cbc_encrypt(input,output,length,ks1,ks2,ks3,ivec,enc);
++              return;
++      }
++#endif
++
++
++      in=(unsigned char *)input;
++      out=(unsigned char *)output;
++      iv=(unsigned char *)ivec;
++
++      if (enc)
++              {
++              c2l(iv,tout0);
++              c2l(iv,tout1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0);
++                      c2l(in,tin1);
++                      tin0^=tout0;
++                      tin1^=tout1;
++
++                      tin[0]=tin0;
++                      tin[1]=tin1;
++                      des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
++                      tout0=tin[0];
++                      tout1=tin[1];
++
++                      l2c(tout0,out);
++                      l2c(tout1,out);
++                      }
++              if (l != -8)
++                      {
++                      c2ln(in,tin0,tin1,l+8);
++                      tin0^=tout0;
++                      tin1^=tout1;
++
++                      tin[0]=tin0;
++                      tin[1]=tin1;
++                      des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
++                      tout0=tin[0];
++                      tout1=tin[1];
++
++                      l2c(tout0,out);
++                      l2c(tout1,out);
++                      }
++              iv=(unsigned char *)ivec;
++              l2c(tout0,iv);
++              l2c(tout1,iv);
++              }
++      else
++              {
++              register DES_LONG t0,t1;
++
++              c2l(iv,xor0);
++              c2l(iv,xor1);
++              for (l-=8; l>=0; l-=8)
++                      {
++                      c2l(in,tin0);
++                      c2l(in,tin1);
++
++                      t0=tin0;
++                      t1=tin1;
++
++                      tin[0]=tin0;
++                      tin[1]=tin1;
++                      des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
++                      tout0=tin[0];
++                      tout1=tin[1];
++
++                      tout0^=xor0;
++                      tout1^=xor1;
++                      l2c(tout0,out);
++                      l2c(tout1,out);
++                      xor0=t0;
++                      xor1=t1;
++                      }
++              if (l != -8)
++                      {
++                      c2l(in,tin0);
++                      c2l(in,tin1);
++                      
++                      t0=tin0;
++                      t1=tin1;
++
++                      tin[0]=tin0;
++                      tin[1]=tin1;
++                      des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
++                      tout0=tin[0];
++                      tout1=tin[1];
++              
++                      tout0^=xor0;
++                      tout1^=xor1;
++                      l2cn(tout0,tout1,out,l+8);
++                      xor0=t0;
++                      xor1=t1;
++                      }
++
++              iv=(unsigned char *)ivec;
++              l2c(xor0,iv);
++              l2c(xor1,iv);
++              }
++      tin0=tin1=tout0=tout1=xor0=xor1=0;
++      tin[0]=tin[1]=0;
++      }
++
++#endif /* DES_DEFAULT_OPTIONS */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/des_opts.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,620 @@
++/* crypto/des/des_opts.c */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++/* define PART1, PART2, PART3 or PART4 to build only with a few of the options.
++ * This is for machines with 64k code segment size restrictions. */
++
++#ifndef MSDOS
++#define TIMES
++#endif
++
++#include <stdio.h>
++#ifndef MSDOS
++#include <unistd.h>
++#else
++#include <io.h>
++extern void exit();
++#endif
++#include <signal.h>
++#ifndef VMS
++#ifndef _IRIX
++#include <time.h>
++#endif
++#ifdef TIMES
++#include <sys/types.h>
++#include <sys/times.h>
++#endif
++#else /* VMS */
++#include <types.h>
++struct tms {
++      time_t tms_utime;
++      time_t tms_stime;
++      time_t tms_uchild;      /* I dunno...  */
++      time_t tms_uchildsys;   /* so these names are a guess :-) */
++      }
++#endif
++#ifndef TIMES
++#include <sys/timeb.h>
++#endif
++
++#ifdef sun
++#include <limits.h>
++#include <sys/param.h>
++#endif
++
++#include "des/des_locl.h"
++#include "des/spr.h"
++
++#define DES_DEFAULT_OPTIONS
++
++#if !defined(PART1) && !defined(PART2) && !defined(PART3) && !defined(PART4)
++#define PART1
++#define PART2
++#define PART3
++#define PART4
++#endif
++
++#ifdef PART1
++
++#undef DES_UNROLL
++#undef DES_RISC1
++#undef DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#define des_encrypt  des_encrypt_u4_cisc_idx
++#define des_encrypt2 des_encrypt2_u4_cisc_idx
++#define des_encrypt3 des_encrypt3_u4_cisc_idx
++#define des_decrypt3 des_decrypt3_u4_cisc_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#undef DES_RISC1
++#undef DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_cisc_idx
++#define des_encrypt2 des_encrypt2_u16_cisc_idx
++#define des_encrypt3 des_encrypt3_u16_cisc_idx
++#define des_decrypt3 des_decrypt3_u16_cisc_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#undef DES_UNROLL
++#define DES_RISC1
++#undef DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u4_risc1_idx
++#define des_encrypt2 des_encrypt2_u4_risc1_idx
++#define des_encrypt3 des_encrypt3_u4_risc1_idx
++#define des_decrypt3 des_decrypt3_u4_risc1_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#endif
++
++#ifdef PART2
++
++#undef DES_UNROLL
++#undef DES_RISC1
++#define DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u4_risc2_idx
++#define des_encrypt2 des_encrypt2_u4_risc2_idx
++#define des_encrypt3 des_encrypt3_u4_risc2_idx
++#define des_decrypt3 des_decrypt3_u4_risc2_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#define DES_RISC1
++#undef DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_risc1_idx
++#define des_encrypt2 des_encrypt2_u16_risc1_idx
++#define des_encrypt3 des_encrypt3_u16_risc1_idx
++#define des_decrypt3 des_decrypt3_u16_risc1_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#undef DES_RISC1
++#define DES_RISC2
++#undef DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_risc2_idx
++#define des_encrypt2 des_encrypt2_u16_risc2_idx
++#define des_encrypt3 des_encrypt3_u16_risc2_idx
++#define des_decrypt3 des_decrypt3_u16_risc2_idx
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#endif
++
++#ifdef PART3
++
++#undef DES_UNROLL
++#undef DES_RISC1
++#undef DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u4_cisc_ptr
++#define des_encrypt2 des_encrypt2_u4_cisc_ptr
++#define des_encrypt3 des_encrypt3_u4_cisc_ptr
++#define des_decrypt3 des_decrypt3_u4_cisc_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#undef DES_RISC1
++#undef DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_cisc_ptr
++#define des_encrypt2 des_encrypt2_u16_cisc_ptr
++#define des_encrypt3 des_encrypt3_u16_cisc_ptr
++#define des_decrypt3 des_decrypt3_u16_cisc_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#undef DES_UNROLL
++#define DES_RISC1
++#undef DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u4_risc1_ptr
++#define des_encrypt2 des_encrypt2_u4_risc1_ptr
++#define des_encrypt3 des_encrypt3_u4_risc1_ptr
++#define des_decrypt3 des_decrypt3_u4_risc1_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#endif
++
++#ifdef PART4
++
++#undef DES_UNROLL
++#undef DES_RISC1
++#define DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u4_risc2_ptr
++#define des_encrypt2 des_encrypt2_u4_risc2_ptr
++#define des_encrypt3 des_encrypt3_u4_risc2_ptr
++#define des_decrypt3 des_decrypt3_u4_risc2_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#define DES_RISC1
++#undef DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_risc1_ptr
++#define des_encrypt2 des_encrypt2_u16_risc1_ptr
++#define des_encrypt3 des_encrypt3_u16_risc1_ptr
++#define des_decrypt3 des_decrypt3_u16_risc1_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#define DES_UNROLL
++#undef DES_RISC1
++#define DES_RISC2
++#define DES_PTR
++#undef D_ENCRYPT
++#undef des_encrypt
++#undef des_encrypt2
++#undef des_encrypt3
++#undef des_decrypt3
++#define des_encrypt  des_encrypt_u16_risc2_ptr
++#define des_encrypt2 des_encrypt2_u16_risc2_ptr
++#define des_encrypt3 des_encrypt3_u16_risc2_ptr
++#define des_decrypt3 des_decrypt3_u16_risc2_ptr
++#undef HEADER_DES_LOCL_H
++#include "des_enc.c"
++
++#endif
++
++/* The following if from times(3) man page.  It may need to be changed */
++#ifndef HZ
++# ifndef CLK_TCK
++#  ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
++#   ifndef VMS
++#    define HZ        100.0
++#   else /* VMS */
++#    define HZ        100.0
++#   endif
++#  else /* _BSD_CLK_TCK_ */
++#   define HZ ((double)_BSD_CLK_TCK_)
++#  endif
++# else /* CLK_TCK */
++#  define HZ ((double)CLK_TCK)
++# endif
++#endif
++
++#define BUFSIZE       ((long)1024)
++long run=0;
++
++#ifndef NOPROTO
++double Time_F(int s);
++#else
++double Time_F();
++#endif
++
++#ifdef SIGALRM
++#if defined(__STDC__) || defined(sgi)
++#define SIGRETTYPE void
++#else
++#define SIGRETTYPE int
++#endif
++
++#ifndef NOPROTO
++SIGRETTYPE sig_done(int sig);
++#else
++SIGRETTYPE sig_done();
++#endif
++
++SIGRETTYPE sig_done(sig)
++int sig;
++      {
++      signal(SIGALRM,sig_done);
++      run=0;
++#ifdef LINT
++      sig=sig;
++#endif
++      }
++#endif
++
++#define START 0
++#define STOP  1
++
++double Time_F(s)
++int s;
++      {
++      double ret;
++#ifdef TIMES
++      static struct tms tstart,tend;
++
++      if (s == START)
++              {
++              times(&tstart);
++              return(0);
++              }
++      else
++              {
++              times(&tend);
++              ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
++              return((ret == 0.0)?1e-6:ret);
++              }
++#else /* !times() */
++      static struct timeb tstart,tend;
++      long i;
++
++      if (s == START)
++              {
++              ftime(&tstart);
++              return(0);
++              }
++      else
++              {
++              ftime(&tend);
++              i=(long)tend.millitm-(long)tstart.millitm;
++              ret=((double)(tend.time-tstart.time))+((double)i)/1000.0;
++              return((ret == 0.0)?1e-6:ret);
++              }
++#endif
++      }
++
++#ifdef SIGALRM
++#define print_name(name) fprintf(stderr,"Doing %s's for 10 seconds\n",name); alarm(10);
++#else
++#define print_name(name) fprintf(stderr,"Doing %s %ld times\n",name,cb);
++#endif
++      
++#define time_it(func,name,index) \
++      print_name(name); \
++      Time_F(START); \
++      for (count=0,run=1; COND(cb); count++) \
++              { \
++              unsigned long d[2]; \
++              func(d,&(sch[0]),DES_ENCRYPT); \
++              } \
++      tm[index]=Time_F(STOP); \
++      fprintf(stderr,"%ld %s's in %.2f second\n",count,name,tm[index]); \
++      tm[index]=((double)COUNT(cb))/tm[index];
++
++#define print_it(name,index) \
++      fprintf(stderr,"%s bytes per sec = %12.2f (%5.1fuS)\n",name, \
++              tm[index]*8,1.0e6/tm[index]);
++
++int main(argc,argv)
++int argc;
++char **argv;
++      {
++      long count;
++      static unsigned char buf[BUFSIZE];
++      static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
++      static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
++      static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
++      des_key_schedule sch,sch2,sch3;
++      double d,tm[16],max=0;
++      int rank[16];
++      char *str[16];
++      int max_idx=0,i,num=0,j;
++#ifndef SIGALARM
++      long ca,cb,cc,cd,ce;
++#endif
++
++      for (i=0; i<12; i++)
++              {
++              tm[i]=0.0;
++              rank[i]=0;
++              }
++
++#ifndef TIMES
++      fprintf(stderr,"To get the most acurate results, try to run this\n");
++      fprintf(stderr,"program when this computer is idle.\n");
++#endif
++
++      des_set_key((C_Block *)key,sch);
++      des_set_key((C_Block *)key2,sch2);
++      des_set_key((C_Block *)key3,sch3);
++
++#ifndef SIGALRM
++      fprintf(stderr,"First we calculate the approximate speed ...\n");
++      des_set_key((C_Block *)key,sch);
++      count=10;
++      do      {
++              long i;
++              unsigned long data[2];
++
++              count*=2;
++              Time_F(START);
++              for (i=count; i; i--)
++                      des_encrypt(data,&(sch[0]),DES_ENCRYPT);
++              d=Time_F(STOP);
++              } while (d < 3.0);
++      ca=count;
++      cb=count*3;
++      cc=count*3*8/BUFSIZE+1;
++      cd=count*8/BUFSIZE+1;
++
++      ce=count/20+1;
++#define COND(d) (count != (d))
++#define COUNT(d) (d)
++#else
++#define COND(c) (run)
++#define COUNT(d) (count)
++        signal(SIGALRM,sig_done);
++        alarm(10);
++#endif
++
++#ifdef PART1
++      time_it(des_encrypt_u4_cisc_idx,  "des_encrypt_u4_cisc_idx  ", 0);
++      time_it(des_encrypt_u16_cisc_idx, "des_encrypt_u16_cisc_idx ", 1);
++      time_it(des_encrypt_u4_risc1_idx, "des_encrypt_u4_risc1_idx ", 2);
++      num+=3;
++#endif
++#ifdef PART2
++      time_it(des_encrypt_u16_risc1_idx,"des_encrypt_u16_risc1_idx", 3);
++      time_it(des_encrypt_u4_risc2_idx, "des_encrypt_u4_risc2_idx ", 4);
++      time_it(des_encrypt_u16_risc2_idx,"des_encrypt_u16_risc2_idx", 5);
++      num+=3;
++#endif
++#ifdef PART3
++      time_it(des_encrypt_u4_cisc_ptr,  "des_encrypt_u4_cisc_ptr  ", 6);
++      time_it(des_encrypt_u16_cisc_ptr, "des_encrypt_u16_cisc_ptr ", 7);
++      time_it(des_encrypt_u4_risc1_ptr, "des_encrypt_u4_risc1_ptr ", 8);
++      num+=3;
++#endif
++#ifdef PART4
++      time_it(des_encrypt_u16_risc1_ptr,"des_encrypt_u16_risc1_ptr", 9);
++      time_it(des_encrypt_u4_risc2_ptr, "des_encrypt_u4_risc2_ptr ",10);
++      time_it(des_encrypt_u16_risc2_ptr,"des_encrypt_u16_risc2_ptr",11);
++      num+=3;
++#endif
++
++#ifdef PART1
++      str[0]=" 4  c i";
++      print_it("des_encrypt_u4_cisc_idx  ",0);
++      max=tm[0];
++      max_idx=0;
++      str[1]="16  c i";
++      print_it("des_encrypt_u16_cisc_idx ",1);
++      if (max < tm[1]) { max=tm[1]; max_idx=1; }
++      str[2]=" 4 r1 i";
++      print_it("des_encrypt_u4_risc1_idx ",2);
++      if (max < tm[2]) { max=tm[2]; max_idx=2; }
++#endif
++#ifdef PART2
++      str[3]="16 r1 i";
++      print_it("des_encrypt_u16_risc1_idx",3);
++      if (max < tm[3]) { max=tm[3]; max_idx=3; }
++      str[4]=" 4 r2 i";
++      print_it("des_encrypt_u4_risc2_idx ",4);
++      if (max < tm[4]) { max=tm[4]; max_idx=4; }
++      str[5]="16 r2 i";
++      print_it("des_encrypt_u16_risc2_idx",5);
++      if (max < tm[5]) { max=tm[5]; max_idx=5; }
++#endif
++#ifdef PART3
++      str[6]=" 4  c p";
++      print_it("des_encrypt_u4_cisc_ptr  ",6);
++      if (max < tm[6]) { max=tm[6]; max_idx=6; }
++      str[7]="16  c p";
++      print_it("des_encrypt_u16_cisc_ptr ",7);
++      if (max < tm[7]) { max=tm[7]; max_idx=7; }
++      str[8]=" 4 r1 p";
++      print_it("des_encrypt_u4_risc1_ptr ",8);
++      if (max < tm[8]) { max=tm[8]; max_idx=8; }
++#endif
++#ifdef PART4
++      str[9]="16 r1 p";
++      print_it("des_encrypt_u16_risc1_ptr",9);
++      if (max < tm[9]) { max=tm[9]; max_idx=9; }
++      str[10]=" 4 r2 p";
++      print_it("des_encrypt_u4_risc2_ptr ",10);
++      if (max < tm[10]) { max=tm[10]; max_idx=10; }
++      str[11]="16 r2 p";
++      print_it("des_encrypt_u16_risc2_ptr",11);
++      if (max < tm[11]) { max=tm[11]; max_idx=11; }
++#endif
++      printf("options    des ecb/s\n");
++      printf("%s %12.2f 100.0%%\n",str[max_idx],tm[max_idx]);
++      d=tm[max_idx];
++      tm[max_idx]= -2.0;
++      max= -1.0;
++      for (;;)
++              {
++              for (i=0; i<12; i++)
++                      {
++                      if (max < tm[i]) { max=tm[i]; j=i; }
++                      }
++              if (max < 0.0) break;
++              printf("%s %12.2f  %4.1f%%\n",str[j],tm[j],tm[j]/d*100.0);
++              tm[j]= -2.0;
++              max= -1.0;
++              }
++
++      switch (max_idx)
++              {
++      case 0:
++              printf("-DDES_DEFAULT_OPTIONS\n");
++              break;
++      case 1:
++              printf("-DDES_UNROLL\n");
++              break;
++      case 2:
++              printf("-DDES_RISC1\n");
++              break;
++      case 3:
++              printf("-DDES_UNROLL -DDES_RISC1\n");
++              break;
++      case 4:
++              printf("-DDES_RISC2\n");
++              break;
++      case 5:
++              printf("-DDES_UNROLL -DDES_RISC2\n");
++              break;
++      case 6:
++              printf("-DDES_PTR\n");
++              break;
++      case 7:
++              printf("-DDES_UNROLL -DDES_PTR\n");
++              break;
++      case 8:
++              printf("-DDES_RISC1 -DDES_PTR\n");
++              break;
++      case 9:
++              printf("-DDES_UNROLL -DDES_RISC1 -DDES_PTR\n");
++              break;
++      case 10:
++              printf("-DDES_RISC2 -DDES_PTR\n");
++              break;
++      case 11:
++              printf("-DDES_UNROLL -DDES_RISC2 -DDES_PTR\n");
++              break;
++              }
++      exit(0);
++#if defined(LINT) || defined(MSDOS)
++      return(0);
++#endif
++      }
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/dx86unix.S     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,3160 @@
++/* 
++ * This file was originally generated by Michael Richardson <mcr@freeswan.org>
++ * via the perl scripts found in the ASM subdir. It remains copyright of
++ * Eric Young, see the file COPYRIGHT.
++ *
++ * This was last done on October 9, 2002.
++ *
++ * While this file does not need to go through cpp, we pass it through
++ * CPP by naming it dx86unix.S instead of dx86unix.s because there is
++ * a bug in Rules.make for .s builds - specifically it references EXTRA_CFLAGS
++ * which may contain stuff that AS doesn't understand instead of
++ * referencing EXTRA_AFLAGS.
++ */    
++
++      .file   "dx86unix.S"
++      .version        "01.01"
++.text
++      .align 16 
++.globl des_encrypt
++      .type    des_encrypt , @function  
++des_encrypt:
++      pushl   %esi
++      pushl   %edi
++
++       
++      movl    12(%esp),       %esi
++      xorl    %ecx,           %ecx
++      pushl   %ebx
++      pushl   %ebp
++      movl    (%esi),         %eax
++      movl    28(%esp),       %ebx
++      movl    4(%esi),        %edi
++
++       
++      roll    $4,             %eax
++      movl    %eax,           %esi
++      xorl    %edi,           %eax
++      andl    $0xf0f0f0f0,    %eax
++      xorl    %eax,           %esi
++      xorl    %eax,           %edi
++
++      roll    $20,            %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0xfff0000f,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $14,            %eax
++      movl    %eax,           %edi
++      xorl    %esi,           %eax
++      andl    $0x33333333,    %eax
++      xorl    %eax,           %edi
++      xorl    %eax,           %esi
++
++      roll    $22,            %esi
++      movl    %esi,           %eax
++      xorl    %edi,           %esi
++      andl    $0x03fc03fc,    %esi
++      xorl    %esi,           %eax
++      xorl    %esi,           %edi
++
++      roll    $9,             %eax
++      movl    %eax,           %esi
++      xorl    %edi,           %eax
++      andl    $0xaaaaaaaa,    %eax
++      xorl    %eax,           %esi
++      xorl    %eax,           %edi
++
++.byte 209
++.byte 199              
++      movl    24(%esp),       %ebp
++      cmpl    $0,             %ebx
++      je      .L000start_decrypt
++
++       
++      movl    (%ebp),         %eax
++      xorl    %ebx,           %ebx
++      movl    4(%ebp),        %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    8(%ebp),        %eax
++      xorl    %ebx,           %ebx
++      movl    12(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    16(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    20(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    24(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    28(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    32(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    36(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    40(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    44(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    48(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    52(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    56(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    60(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    64(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    68(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    72(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    76(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    80(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    84(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    88(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    92(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    96(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    100(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    104(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    108(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    112(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    116(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    120(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    124(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++      jmp     .L001end
++.L000start_decrypt:
++
++       
++      movl    120(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    124(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    112(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    116(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    104(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    108(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    96(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    100(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    88(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    92(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    80(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    84(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    72(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    76(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    64(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    68(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    56(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    60(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    48(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    52(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    40(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    44(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    32(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    36(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    24(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    28(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    16(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    20(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    8(%ebp),        %eax
++      xorl    %ebx,           %ebx
++      movl    12(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    (%ebp),         %eax
++      xorl    %ebx,           %ebx
++      movl    4(%ebp),        %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++.L001end:
++
++       
++      movl    20(%esp),       %edx
++.byte 209
++.byte 206              
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0xaaaaaaaa,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $23,            %eax
++      movl    %eax,           %edi
++      xorl    %esi,           %eax
++      andl    $0x03fc03fc,    %eax
++      xorl    %eax,           %edi
++      xorl    %eax,           %esi
++
++      roll    $10,            %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0x33333333,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $18,            %esi
++      movl    %esi,           %edi
++      xorl    %eax,           %esi
++      andl    $0xfff0000f,    %esi
++      xorl    %esi,           %edi
++      xorl    %esi,           %eax
++
++      roll    $12,            %edi
++      movl    %edi,           %esi
++      xorl    %eax,           %edi
++      andl    $0xf0f0f0f0,    %edi
++      xorl    %edi,           %esi
++      xorl    %edi,           %eax
++
++      rorl    $4,             %eax
++      movl    %eax,           (%edx)
++      movl    %esi,           4(%edx)
++      popl    %ebp
++      popl    %ebx
++      popl    %edi
++      popl    %esi
++      ret
++.des_encrypt_end:
++      .size    des_encrypt , .des_encrypt_end-des_encrypt  
++.ident        "desasm.pl"
++.text
++      .align 16 
++.globl des_encrypt2
++      .type    des_encrypt2 , @function  
++des_encrypt2:
++      pushl   %esi
++      pushl   %edi
++
++       
++      movl    12(%esp),       %eax
++      xorl    %ecx,           %ecx
++      pushl   %ebx
++      pushl   %ebp
++      movl    (%eax),         %esi
++      movl    28(%esp),       %ebx
++      roll    $3,             %esi
++      movl    4(%eax),        %edi
++      roll    $3,             %edi
++      movl    24(%esp),       %ebp
++      cmpl    $0,             %ebx
++      je      .L002start_decrypt
++
++       
++      movl    (%ebp),         %eax
++      xorl    %ebx,           %ebx
++      movl    4(%ebp),        %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    8(%ebp),        %eax
++      xorl    %ebx,           %ebx
++      movl    12(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    16(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    20(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    24(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    28(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    32(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    36(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    40(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    44(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    48(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    52(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    56(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    60(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    64(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    68(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    72(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    76(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    80(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    84(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    88(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    92(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    96(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    100(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    104(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    108(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    112(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    116(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    120(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    124(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++      jmp     .L003end
++.L002start_decrypt:
++
++       
++      movl    120(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    124(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    112(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    116(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    104(%ebp),      %eax
++      xorl    %ebx,           %ebx
++      movl    108(%ebp),      %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    96(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    100(%ebp),      %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    88(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    92(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    80(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    84(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    72(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    76(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    64(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    68(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    56(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    60(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    48(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    52(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    40(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    44(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    32(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    36(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    24(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    28(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    16(%ebp),       %eax
++      xorl    %ebx,           %ebx
++      movl    20(%ebp),       %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++
++       
++      movl    8(%ebp),        %eax
++      xorl    %ebx,           %ebx
++      movl    12(%ebp),       %edx
++      xorl    %esi,           %eax
++      xorl    %esi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %edi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %edi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %edi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %edi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %edi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %edi
++
++       
++      movl    (%ebp),         %eax
++      xorl    %ebx,           %ebx
++      movl    4(%ebp),        %edx
++      xorl    %edi,           %eax
++      xorl    %edi,           %edx
++      andl    $0xfcfcfcfc,    %eax
++      andl    $0xcfcfcfcf,    %edx
++      movb    %al,            %bl
++      movb    %ah,            %cl
++      rorl    $4,             %edx
++      movl          des_SPtrans(%ebx),%ebp
++      movb    %dl,            %bl
++      xorl    %ebp,           %esi
++      movl    0x200+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movb    %dh,            %cl
++      shrl    $16,            %eax
++      movl    0x100+des_SPtrans(%ebx),%ebp
++      xorl    %ebp,           %esi
++      movb    %ah,            %bl
++      shrl    $16,            %edx
++      movl    0x300+des_SPtrans(%ecx),%ebp
++      xorl    %ebp,           %esi
++      movl    24(%esp),       %ebp
++      movb    %dh,            %cl
++      andl    $0xff,          %eax
++      andl    $0xff,          %edx
++      movl    0x600+des_SPtrans(%ebx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x700+des_SPtrans(%ecx),%ebx
++      xorl    %ebx,           %esi
++      movl    0x400+des_SPtrans(%eax),%ebx
++      xorl    %ebx,           %esi
++      movl    0x500+des_SPtrans(%edx),%ebx
++      xorl    %ebx,           %esi
++.L003end:
++
++       
++      rorl    $3,             %edi
++      movl    20(%esp),       %eax
++      rorl    $3,             %esi
++      movl    %edi,           (%eax)
++      movl    %esi,           4(%eax)
++      popl    %ebp
++      popl    %ebx
++      popl    %edi
++      popl    %esi
++      ret
++.des_encrypt2_end:
++      .size    des_encrypt2 , .des_encrypt2_end-des_encrypt2  
++.ident        "desasm.pl"
++.text
++      .align 16 
++.globl des_encrypt3
++      .type    des_encrypt3 , @function  
++des_encrypt3:
++      pushl   %ebx
++      movl    8(%esp),        %ebx
++      pushl   %ebp
++      pushl   %esi
++      pushl   %edi
++
++       
++      movl    (%ebx),         %edi
++      movl    4(%ebx),        %esi
++      subl    $12,            %esp
++
++       
++      roll    $4,             %edi
++      movl    %edi,           %edx
++      xorl    %esi,           %edi
++      andl    $0xf0f0f0f0,    %edi
++      xorl    %edi,           %edx
++      xorl    %edi,           %esi
++
++      roll    $20,            %esi
++      movl    %esi,           %edi
++      xorl    %edx,           %esi
++      andl    $0xfff0000f,    %esi
++      xorl    %esi,           %edi
++      xorl    %esi,           %edx
++
++      roll    $14,            %edi
++      movl    %edi,           %esi
++      xorl    %edx,           %edi
++      andl    $0x33333333,    %edi
++      xorl    %edi,           %esi
++      xorl    %edi,           %edx
++
++      roll    $22,            %edx
++      movl    %edx,           %edi
++      xorl    %esi,           %edx
++      andl    $0x03fc03fc,    %edx
++      xorl    %edx,           %edi
++      xorl    %edx,           %esi
++
++      roll    $9,             %edi
++      movl    %edi,           %edx
++      xorl    %esi,           %edi
++      andl    $0xaaaaaaaa,    %edi
++      xorl    %edi,           %edx
++      xorl    %edi,           %esi
++
++      rorl    $3,             %edx
++      rorl    $2,             %esi
++      movl    %esi,           4(%ebx)
++      movl    36(%esp),       %eax
++      movl    %edx,           (%ebx)
++      movl    40(%esp),       %edi
++      movl    44(%esp),       %esi
++      movl    $1,             8(%esp)
++      movl    %eax,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      movl    $0,             8(%esp)
++      movl    %edi,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      movl    $1,             8(%esp)
++      movl    %esi,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      addl    $12,            %esp
++      movl    (%ebx),         %edi
++      movl    4(%ebx),        %esi
++
++       
++      roll    $2,             %esi
++      roll    $3,             %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0xaaaaaaaa,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $23,            %eax
++      movl    %eax,           %edi
++      xorl    %esi,           %eax
++      andl    $0x03fc03fc,    %eax
++      xorl    %eax,           %edi
++      xorl    %eax,           %esi
++
++      roll    $10,            %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0x33333333,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $18,            %esi
++      movl    %esi,           %edi
++      xorl    %eax,           %esi
++      andl    $0xfff0000f,    %esi
++      xorl    %esi,           %edi
++      xorl    %esi,           %eax
++
++      roll    $12,            %edi
++      movl    %edi,           %esi
++      xorl    %eax,           %edi
++      andl    $0xf0f0f0f0,    %edi
++      xorl    %edi,           %esi
++      xorl    %edi,           %eax
++
++      rorl    $4,             %eax
++      movl    %eax,           (%ebx)
++      movl    %esi,           4(%ebx)
++      popl    %edi
++      popl    %esi
++      popl    %ebp
++      popl    %ebx
++      ret
++.des_encrypt3_end:
++      .size    des_encrypt3 , .des_encrypt3_end-des_encrypt3  
++.ident        "desasm.pl"
++.text
++      .align 16 
++.globl des_decrypt3
++      .type    des_decrypt3 , @function  
++des_decrypt3:
++      pushl   %ebx
++      movl    8(%esp),        %ebx
++      pushl   %ebp
++      pushl   %esi
++      pushl   %edi
++
++       
++      movl    (%ebx),         %edi
++      movl    4(%ebx),        %esi
++      subl    $12,            %esp
++
++       
++      roll    $4,             %edi
++      movl    %edi,           %edx
++      xorl    %esi,           %edi
++      andl    $0xf0f0f0f0,    %edi
++      xorl    %edi,           %edx
++      xorl    %edi,           %esi
++
++      roll    $20,            %esi
++      movl    %esi,           %edi
++      xorl    %edx,           %esi
++      andl    $0xfff0000f,    %esi
++      xorl    %esi,           %edi
++      xorl    %esi,           %edx
++
++      roll    $14,            %edi
++      movl    %edi,           %esi
++      xorl    %edx,           %edi
++      andl    $0x33333333,    %edi
++      xorl    %edi,           %esi
++      xorl    %edi,           %edx
++
++      roll    $22,            %edx
++      movl    %edx,           %edi
++      xorl    %esi,           %edx
++      andl    $0x03fc03fc,    %edx
++      xorl    %edx,           %edi
++      xorl    %edx,           %esi
++
++      roll    $9,             %edi
++      movl    %edi,           %edx
++      xorl    %esi,           %edi
++      andl    $0xaaaaaaaa,    %edi
++      xorl    %edi,           %edx
++      xorl    %edi,           %esi
++
++      rorl    $3,             %edx
++      rorl    $2,             %esi
++      movl    %esi,           4(%ebx)
++      movl    36(%esp),       %esi
++      movl    %edx,           (%ebx)
++      movl    40(%esp),       %edi
++      movl    44(%esp),       %eax
++      movl    $0,             8(%esp)
++      movl    %eax,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      movl    $1,             8(%esp)
++      movl    %edi,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      movl    $0,             8(%esp)
++      movl    %esi,           4(%esp)
++      movl    %ebx,           (%esp)
++      call    des_encrypt2
++      addl    $12,            %esp
++      movl    (%ebx),         %edi
++      movl    4(%ebx),        %esi
++
++       
++      roll    $2,             %esi
++      roll    $3,             %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0xaaaaaaaa,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $23,            %eax
++      movl    %eax,           %edi
++      xorl    %esi,           %eax
++      andl    $0x03fc03fc,    %eax
++      xorl    %eax,           %edi
++      xorl    %eax,           %esi
++
++      roll    $10,            %edi
++      movl    %edi,           %eax
++      xorl    %esi,           %edi
++      andl    $0x33333333,    %edi
++      xorl    %edi,           %eax
++      xorl    %edi,           %esi
++
++      roll    $18,            %esi
++      movl    %esi,           %edi
++      xorl    %eax,           %esi
++      andl    $0xfff0000f,    %esi
++      xorl    %esi,           %edi
++      xorl    %esi,           %eax
++
++      roll    $12,            %edi
++      movl    %edi,           %esi
++      xorl    %eax,           %edi
++      andl    $0xf0f0f0f0,    %edi
++      xorl    %edi,           %esi
++      xorl    %edi,           %eax
++
++      rorl    $4,             %eax
++      movl    %eax,           (%ebx)
++      movl    %esi,           4(%ebx)
++      popl    %edi
++      popl    %esi
++      popl    %ebp
++      popl    %ebx
++      ret
++.des_decrypt3_end:
++      .size    des_decrypt3 , .des_decrypt3_end-des_decrypt3  
++.ident        "desasm.pl"
++.text
++      .align 16 
++.globl des_ncbc_encrypt
++      .type    des_ncbc_encrypt , @function  
++des_ncbc_encrypt:
++
++      pushl   %ebp
++      pushl   %ebx
++      pushl   %esi
++      pushl   %edi
++      movl    28(%esp),       %ebp
++       
++      movl    36(%esp),       %ebx
++      movl    (%ebx),         %esi
++      movl    4(%ebx),        %edi
++      pushl   %edi
++      pushl   %esi
++      pushl   %edi
++      pushl   %esi
++      movl    %esp,           %ebx
++      movl    36(%esp),       %esi
++      movl    40(%esp),       %edi
++       
++      movl    56(%esp),       %ecx
++       
++      pushl   %ecx
++       
++      movl    52(%esp),       %eax
++      pushl   %eax
++      pushl   %ebx
++      cmpl    $0,             %ecx
++      jz      .L004decrypt
++      andl    $4294967288,    %ebp
++      movl    12(%esp),       %eax
++      movl    16(%esp),       %ebx
++      jz      .L005encrypt_finish
++.L006encrypt_loop:
++      movl    (%esi),         %ecx
++      movl    4(%esi),        %edx
++      xorl    %ecx,           %eax
++      xorl    %edx,           %ebx
++      movl    %eax,           12(%esp)
++      movl    %ebx,           16(%esp)
++      call    des_encrypt
++      movl    12(%esp),       %eax
++      movl    16(%esp),       %ebx
++      movl    %eax,           (%edi)
++      movl    %ebx,           4(%edi)
++      addl    $8,             %esi
++      addl    $8,             %edi
++      subl    $8,             %ebp
++      jnz     .L006encrypt_loop
++.L005encrypt_finish:
++      movl    56(%esp),       %ebp
++      andl    $7,             %ebp
++      jz      .L007finish
++      xorl    %ecx,           %ecx
++      xorl    %edx,           %edx
++      movl    .L008cbc_enc_jmp_table(,%ebp,4),%ebp
++      jmp     *%ebp
++.L009ej7:
++      movb    6(%esi),        %dh
++      sall    $8,             %edx
++.L010ej6:
++      movb    5(%esi),        %dh
++.L011ej5:
++      movb    4(%esi),        %dl
++.L012ej4:
++      movl    (%esi),         %ecx
++      jmp     .L013ejend
++.L014ej3:
++      movb    2(%esi),        %ch
++      sall    $8,             %ecx
++.L015ej2:
++      movb    1(%esi),        %ch
++.L016ej1:
++      movb    (%esi),         %cl
++.L013ejend:
++      xorl    %ecx,           %eax
++      xorl    %edx,           %ebx
++      movl    %eax,           12(%esp)
++      movl    %ebx,           16(%esp)
++      call    des_encrypt
++      movl    12(%esp),       %eax
++      movl    16(%esp),       %ebx
++      movl    %eax,           (%edi)
++      movl    %ebx,           4(%edi)
++      jmp     .L007finish
++.align 16 
++.L004decrypt:
++      andl    $4294967288,    %ebp
++      movl    20(%esp),       %eax
++      movl    24(%esp),       %ebx
++      jz      .L017decrypt_finish
++.L018decrypt_loop:
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %eax,           12(%esp)
++      movl    %ebx,           16(%esp)
++      call    des_encrypt
++      movl    12(%esp),       %eax
++      movl    16(%esp),       %ebx
++      movl    20(%esp),       %ecx
++      movl    24(%esp),       %edx
++      xorl    %eax,           %ecx
++      xorl    %ebx,           %edx
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %ecx,           (%edi)
++      movl    %edx,           4(%edi)
++      movl    %eax,           20(%esp)
++      movl    %ebx,           24(%esp)
++      addl    $8,             %esi
++      addl    $8,             %edi
++      subl    $8,             %ebp
++      jnz     .L018decrypt_loop
++.L017decrypt_finish:
++      movl    56(%esp),       %ebp
++      andl    $7,             %ebp
++      jz      .L007finish
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %eax,           12(%esp)
++      movl    %ebx,           16(%esp)
++      call    des_encrypt
++      movl    12(%esp),       %eax
++      movl    16(%esp),       %ebx
++      movl    20(%esp),       %ecx
++      movl    24(%esp),       %edx
++      xorl    %eax,           %ecx
++      xorl    %ebx,           %edx
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++.L019dj7:
++      rorl    $16,            %edx
++      movb    %dl,            6(%edi)
++      shrl    $16,            %edx
++.L020dj6:
++      movb    %dh,            5(%edi)
++.L021dj5:
++      movb    %dl,            4(%edi)
++.L022dj4:
++      movl    %ecx,           (%edi)
++      jmp     .L023djend
++.L024dj3:
++      rorl    $16,            %ecx
++      movb    %cl,            2(%edi)
++      sall    $16,            %ecx
++.L025dj2:
++      movb    %ch,            1(%esi)
++.L026dj1:
++      movb    %cl,            (%esi)
++.L023djend:
++      jmp     .L007finish
++.align 16 
++.L007finish:
++      movl    64(%esp),       %ecx
++      addl    $28,            %esp
++      movl    %eax,           (%ecx)
++      movl    %ebx,           4(%ecx)
++      popl    %edi
++      popl    %esi
++      popl    %ebx
++      popl    %ebp
++      ret
++.align 16 
++.L008cbc_enc_jmp_table:
++      .long 0
++      .long .L016ej1
++      .long .L015ej2
++      .long .L014ej3
++      .long .L012ej4
++      .long .L011ej5
++      .long .L010ej6
++      .long .L009ej7
++.align 16 
++.L027cbc_dec_jmp_table:
++      .long 0
++      .long .L026dj1
++      .long .L025dj2
++      .long .L024dj3
++      .long .L022dj4
++      .long .L021dj5
++      .long .L020dj6
++      .long .L019dj7
++.des_ncbc_encrypt_end:
++      .size    des_ncbc_encrypt , .des_ncbc_encrypt_end-des_ncbc_encrypt  
++.ident        "desasm.pl"
++.text
++      .align 16 
++.globl des_ede3_cbc_encrypt
++      .type    des_ede3_cbc_encrypt , @function  
++des_ede3_cbc_encrypt:
++
++      pushl   %ebp
++      pushl   %ebx
++      pushl   %esi
++      pushl   %edi
++      movl    28(%esp),       %ebp
++       
++      movl    44(%esp),       %ebx
++      movl    (%ebx),         %esi
++      movl    4(%ebx),        %edi
++      pushl   %edi
++      pushl   %esi
++      pushl   %edi
++      pushl   %esi
++      movl    %esp,           %ebx
++      movl    36(%esp),       %esi
++      movl    40(%esp),       %edi
++       
++      movl    64(%esp),       %ecx
++       
++      movl    56(%esp),       %eax
++      pushl   %eax
++       
++      movl    56(%esp),       %eax
++      pushl   %eax
++       
++      movl    56(%esp),       %eax
++      pushl   %eax
++      pushl   %ebx
++      cmpl    $0,             %ecx
++      jz      .L028decrypt
++      andl    $4294967288,    %ebp
++      movl    16(%esp),       %eax
++      movl    20(%esp),       %ebx
++      jz      .L029encrypt_finish
++.L030encrypt_loop:
++      movl    (%esi),         %ecx
++      movl    4(%esi),        %edx
++      xorl    %ecx,           %eax
++      xorl    %edx,           %ebx
++      movl    %eax,           16(%esp)
++      movl    %ebx,           20(%esp)
++      call    des_encrypt3
++      movl    16(%esp),       %eax
++      movl    20(%esp),       %ebx
++      movl    %eax,           (%edi)
++      movl    %ebx,           4(%edi)
++      addl    $8,             %esi
++      addl    $8,             %edi
++      subl    $8,             %ebp
++      jnz     .L030encrypt_loop
++.L029encrypt_finish:
++      movl    60(%esp),       %ebp
++      andl    $7,             %ebp
++      jz      .L031finish
++      xorl    %ecx,           %ecx
++      xorl    %edx,           %edx
++      movl    .L032cbc_enc_jmp_table(,%ebp,4),%ebp
++      jmp     *%ebp
++.L033ej7:
++      movb    6(%esi),        %dh
++      sall    $8,             %edx
++.L034ej6:
++      movb    5(%esi),        %dh
++.L035ej5:
++      movb    4(%esi),        %dl
++.L036ej4:
++      movl    (%esi),         %ecx
++      jmp     .L037ejend
++.L038ej3:
++      movb    2(%esi),        %ch
++      sall    $8,             %ecx
++.L039ej2:
++      movb    1(%esi),        %ch
++.L040ej1:
++      movb    (%esi),         %cl
++.L037ejend:
++      xorl    %ecx,           %eax
++      xorl    %edx,           %ebx
++      movl    %eax,           16(%esp)
++      movl    %ebx,           20(%esp)
++      call    des_encrypt3
++      movl    16(%esp),       %eax
++      movl    20(%esp),       %ebx
++      movl    %eax,           (%edi)
++      movl    %ebx,           4(%edi)
++      jmp     .L031finish
++.align 16 
++.L028decrypt:
++      andl    $4294967288,    %ebp
++      movl    24(%esp),       %eax
++      movl    28(%esp),       %ebx
++      jz      .L041decrypt_finish
++.L042decrypt_loop:
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %eax,           16(%esp)
++      movl    %ebx,           20(%esp)
++      call    des_decrypt3
++      movl    16(%esp),       %eax
++      movl    20(%esp),       %ebx
++      movl    24(%esp),       %ecx
++      movl    28(%esp),       %edx
++      xorl    %eax,           %ecx
++      xorl    %ebx,           %edx
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %ecx,           (%edi)
++      movl    %edx,           4(%edi)
++      movl    %eax,           24(%esp)
++      movl    %ebx,           28(%esp)
++      addl    $8,             %esi
++      addl    $8,             %edi
++      subl    $8,             %ebp
++      jnz     .L042decrypt_loop
++.L041decrypt_finish:
++      movl    60(%esp),       %ebp
++      andl    $7,             %ebp
++      jz      .L031finish
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++      movl    %eax,           16(%esp)
++      movl    %ebx,           20(%esp)
++      call    des_decrypt3
++      movl    16(%esp),       %eax
++      movl    20(%esp),       %ebx
++      movl    24(%esp),       %ecx
++      movl    28(%esp),       %edx
++      xorl    %eax,           %ecx
++      xorl    %ebx,           %edx
++      movl    (%esi),         %eax
++      movl    4(%esi),        %ebx
++.L043dj7:
++      rorl    $16,            %edx
++      movb    %dl,            6(%edi)
++      shrl    $16,            %edx
++.L044dj6:
++      movb    %dh,            5(%edi)
++.L045dj5:
++      movb    %dl,            4(%edi)
++.L046dj4:
++      movl    %ecx,           (%edi)
++      jmp     .L047djend
++.L048dj3:
++      rorl    $16,            %ecx
++      movb    %cl,            2(%edi)
++      sall    $16,            %ecx
++.L049dj2:
++      movb    %ch,            1(%esi)
++.L050dj1:
++      movb    %cl,            (%esi)
++.L047djend:
++      jmp     .L031finish
++.align 16 
++.L031finish:
++      movl    76(%esp),       %ecx
++      addl    $32,            %esp
++      movl    %eax,           (%ecx)
++      movl    %ebx,           4(%ecx)
++      popl    %edi
++      popl    %esi
++      popl    %ebx
++      popl    %ebp
++      ret
++.align 16 
++.L032cbc_enc_jmp_table:
++      .long 0
++      .long .L040ej1
++      .long .L039ej2
++      .long .L038ej3
++      .long .L036ej4
++      .long .L035ej5
++      .long .L034ej6
++      .long .L033ej7
++.align 16 
++.L051cbc_dec_jmp_table:
++      .long 0
++      .long .L050dj1
++      .long .L049dj2
++      .long .L048dj3
++      .long .L046dj4
++      .long .L045dj5
++      .long .L044dj6
++      .long .L043dj7
++.des_ede3_cbc_encrypt_end:
++      .size    des_ede3_cbc_encrypt , .des_ede3_cbc_encrypt_end-des_ede3_cbc_encrypt  
++.ident        "desasm.pl"
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/ecb_enc.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,135 @@
++/* crypto/des/ecb_enc.c */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++#include "des/des_locl.h"
++#include "des/spr.h"
++
++char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay";
++char *DES_version="DES part of SSLeay 0.8.2b 08-Jan-1998";
++
++/* RCSID $Id: ecb_enc.c,v 1.8 2004/08/04 15:57:22 mcr Exp $ */
++/* This function ifdef'ed out for FreeS/WAN project. */
++#ifdef notdef
++char *des_options()
++      {
++      static int init=1;
++      static char buf[32];
++
++      if (init)
++              {
++              char *ptr,*unroll,*risc,*size;
++
++              init=0;
++#ifdef DES_PTR
++              ptr="ptr";
++#else
++              ptr="idx";
++#endif
++#if defined(DES_RISC1) || defined(DES_RISC2)
++#ifdef DES_RISC1
++              risc="risc1";
++#endif
++#ifdef DES_RISC2
++              risc="risc2";
++#endif
++#else
++              risc="cisc";
++#endif
++#ifdef DES_UNROLL
++              unroll="16";
++#else
++              unroll="4";
++#endif
++              if (sizeof(DES_LONG) != sizeof(long))
++                      size="int";
++              else
++                      size="long";
++              sprintf(buf,"des(%s,%s,%s,%s)",ptr,risc,unroll,size);
++              }
++      return(buf);
++      }
++#endif
++              
++
++void des_ecb_encrypt(input, output, ks, enc)
++des_cblock (*input);
++des_cblock (*output);
++des_key_schedule ks;
++int enc;
++      {
++      register DES_LONG l;
++      register unsigned char *in,*out;
++      DES_LONG ll[2];
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
++              ocf_des_ecb_encrypt(input, output, ks, enc);
++              return;
++      }
++#endif
++
++      in=(unsigned char *)input;
++      out=(unsigned char *)output;
++      c2l(in,l); ll[0]=l;
++      c2l(in,l); ll[1]=l;
++      des_encrypt(ll,ks,enc);
++      l=ll[0]; l2c(l,out);
++      l=ll[1]; l2c(l,out);
++      l=ll[0]=ll[1]=0;
++      }
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/ipsec_alg_3des.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,182 @@
++/*
++ * ipsec_alg 3DES cipher stubs
++ *
++ * Copyright (C) 2005 Michael Richardson <mcr@xelerance.com> 
++ *
++ * Adapted from ipsec_alg_aes.c by JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ * 
++ * ipsec_alg_aes.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++/*    
++ *    special case: ipsec core modular with this static algo inside:
++ *    must avoid MODULE magic for this file
++ */
++#if defined(CONFIG_KLIPS_MODULE) && defined(CONFIG_KLIPS_ENC_3DES)
++#undef MODULE
++#endif
++
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/string.h>
++
++/*    Low freeswan header coupling    */
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_alg.h"
++#include "klips-crypto/des.h"
++#include "openswan/ipsec_alg_3des.h"
++
++#define AES_CONTEXT_T aes_context
++static int debug_3des=0;
++static int test_3des=0;
++static int excl_3des=0;
++
++#if defined(CONFIG_KLIPS_ENC_3DES_MODULE)
++MODULE_AUTHOR("Michael Richardson <mcr@xelerance.com>");
++#ifdef module_param
++module_param(debug_3des, int, 0664);
++module_param(test_des, int, 0664);
++module_param(excl_des, int, 0664);
++#else
++MODULE_PARM(debug_3des, "i");
++MODULE_PARM(test_des, "i");
++MODULE_PARM(excl_des, "i");
++#endif
++#endif
++
++#define ESP_AES_MAC_KEY_SZ    16      /* 128 bit MAC key */
++#define ESP_AES_MAC_BLK_LEN   16      /* 128 bit block */
++
++static int _3des_set_key(struct ipsec_alg_enc *alg,
++                       __u8 * key_e, const __u8 * key,
++                       size_t keysize)
++{
++      int ret = 0;
++      TripleDES_context *ctx = (TripleDES_context*)key_e;
++
++      if(keysize != 192/8) {
++        return EINVAL;
++      }
++      
++      des_set_key((des_cblock *)(key + DES_KEY_SZ*0), ctx->s1);
++      des_set_key((des_cblock *)(key + DES_KEY_SZ*1), ctx->s2);
++      des_set_key((des_cblock *)(key + DES_KEY_SZ*2), ctx->s3);
++      
++      if (debug_3des > 0)
++              printk(KERN_DEBUG "klips_debug:_3des_set_key:"
++                              "ret=%d key_e=%p key=%p keysize=%ld\n",
++                                ret, key_e, key, (unsigned long int) keysize);
++      return ret;
++}
++
++static int _3des_cbc_encrypt(struct ipsec_alg_enc *alg,
++                           __u8 * key_e,
++                           const __u8 * in,
++                           int ilen, const __u8 * iv,
++                           int encrypt)
++{
++      TripleDES_context *ctx=(TripleDES_context*)key_e;
++      des_cblock miv;
++
++      memcpy(&miv, iv, sizeof(miv));
++
++      if (debug_3des > 0)
++              printk(KERN_DEBUG "klips_debug:_3des_cbc_encrypt:"
++                              "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
++                              key_e, in, ilen, iv, encrypt);
++
++      des_ede3_cbc_encrypt((des_cblock *)in,
++                           (des_cblock *)in,
++                           ilen,
++                           ctx->s1,
++                           ctx->s2,
++                           ctx->s3,
++                           &miv, encrypt);
++      return 1;
++}
++
++static struct ipsec_alg_enc ipsec_alg_3DES = {
++      ixt_common: {   ixt_version:    IPSEC_ALG_VERSION,
++                      ixt_refcnt:     ATOMIC_INIT(0),
++                      ixt_name:       "3des",
++                      ixt_blocksize:  ESP_3DES_CBC_BLK_LEN, 
++                      ixt_support: {
++                        ias_exttype:    IPSEC_ALG_TYPE_ENCRYPT,
++                        ias_id:         ESP_3DES,
++                        //ias_ivlen:      64,
++                        ias_keyminbits: ESP_3DES_KEY_SZ*8,
++                        ias_keymaxbits: ESP_3DES_KEY_SZ*8,
++              },
++      },
++#if defined(MODULE_KLIPS_ENC_3DES_MODULE)
++      ixt_module:     THIS_MODULE,
++#endif
++      ixt_e_keylen:   ESP_3DES_KEY_SZ*8,
++      ixt_e_ctx_size: sizeof(TripleDES_context),
++      ixt_e_set_key:  _3des_set_key,
++      ixt_e_cbc_encrypt:_3des_cbc_encrypt,
++};
++
++#if defined(CONFIG_KLIPS_ENC_3DES_MODULE)
++IPSEC_ALG_MODULE_INIT_MOD( ipsec_3des_init )
++#else
++IPSEC_ALG_MODULE_INIT_STATIC( ipsec_3des_init )
++#endif
++{
++      int ret, test_ret;
++
++      if (excl_3des) ipsec_alg_3DES.ixt_common.ixt_state |= IPSEC_ALG_ST_EXCL;
++      ret=register_ipsec_alg_enc(&ipsec_alg_3DES);
++      printk("ipsec_3des_init(alg_type=%d alg_id=%d name=%s): ret=%d\n", 
++                      ipsec_alg_3DES.ixt_common.ixt_support.ias_exttype, 
++                      ipsec_alg_3DES.ixt_common.ixt_support.ias_id, 
++                      ipsec_alg_3DES.ixt_common.ixt_name, 
++                      ret);
++      if (ret==0 && test_3des) {
++              test_ret=ipsec_alg_test(
++                              ipsec_alg_3DES.ixt_common.ixt_support.ias_exttype,
++                              ipsec_alg_3DES.ixt_common.ixt_support.ias_id, 
++                              test_3des);
++              printk("ipsec_3des_init(alg_type=%d alg_id=%d): test_ret=%d\n", 
++                              ipsec_alg_3DES.ixt_common.ixt_support.ias_exttype, 
++                              ipsec_alg_3DES.ixt_common.ixt_support.ias_id, 
++                              test_ret);
++      }
++      return ret;
++}
++
++#if defined(CONFIG_KLIPS_ENC_3DES_MODULE)
++IPSEC_ALG_MODULE_EXIT_MOD( ipsec_3des_fini )
++#else
++IPSEC_ALG_MODULE_EXIT_STATIC( ipsec_3des_fini )
++#endif
++{
++      unregister_ipsec_alg_enc(&ipsec_alg_3DES);
++      return;
++}
++
++/* Dual, because 3des code is 4-clause BSD licensed */
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Dual BSD/GPL");
++#endif
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/des/set_key.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,251 @@
++/* crypto/des/set_key.c */
++/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
++ * All rights reserved.
++ *
++ * This package is an SSL implementation written
++ * by Eric Young (eay@cryptsoft.com).
++ * The implementation was written so as to conform with Netscapes SSL.
++ * 
++ * This library is free for commercial and non-commercial use as long as
++ * the following conditions are aheared to.  The following conditions
++ * apply to all code found in this distribution, be it the RC4, RSA,
++ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
++ * included with this distribution is covered by the same copyright terms
++ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
++ * 
++ * Copyright remains Eric Young's, and as such any Copyright notices in
++ * the code are not to be removed.
++ * If this package is used in a product, Eric Young should be given attribution
++ * as the author of the parts of the library used.
++ * This can be in the form of a textual message at program startup or
++ * in documentation (online or textual) provided with the package.
++ * 
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    "This product includes cryptographic software written by
++ *     Eric Young (eay@cryptsoft.com)"
++ *    The word 'cryptographic' can be left out if the rouines from the library
++ *    being used are not cryptographic related :-).
++ * 4. If you include any Windows specific code (or a derivative thereof) from 
++ *    the apps directory (application code) you must include an acknowledgement:
++ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
++ * 
++ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ * 
++ * The licence and distribution terms for any publically available version or
++ * derivative of this code cannot be changed.  i.e. this code cannot simply be
++ * copied and put under another distribution licence
++ * [including the GNU Public Licence.]
++ */
++
++/* set_key.c v 1.4 eay 24/9/91
++ * 1.4 Speed up by 400% :-)
++ * 1.3 added register declarations.
++ * 1.2 unrolled make_key_sched a bit more
++ * 1.1 added norm_expand_bits
++ * 1.0 First working version
++ */
++#include "des/des_locl.h"
++#include "des/podd.h"
++#include "des/sk.h"
++
++#ifndef NOPROTO
++static int check_parity(des_cblock (*key));
++#else
++static int check_parity();
++#endif
++
++int des_check_key=0;
++
++void des_set_odd_parity(key)
++des_cblock (*key);
++      {
++      int i;
++
++      for (i=0; i<DES_KEY_SZ; i++)
++              (*key)[i]=odd_parity[(*key)[i]];
++      }
++
++static int check_parity(key)
++des_cblock (*key);
++      {
++      int i;
++
++      for (i=0; i<DES_KEY_SZ; i++)
++              {
++              if ((*key)[i] != odd_parity[(*key)[i]])
++                      return(0);
++              }
++      return(1);
++      }
++
++/* Weak and semi week keys as take from
++ * %A D.W. Davies
++ * %A W.L. Price
++ * %T Security for Computer Networks
++ * %I John Wiley & Sons
++ * %D 1984
++ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
++ * (and actual cblock values).
++ */
++#define NUM_WEAK_KEY  16
++static des_cblock weak_keys[NUM_WEAK_KEY]={
++      /* weak keys */
++      {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
++      {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
++      {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
++      {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
++      /* semi-weak keys */
++      {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
++      {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
++      {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
++      {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
++      {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
++      {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
++      {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
++      {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
++      {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
++      {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
++      {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
++      {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
++
++int des_is_weak_key(key)
++des_cblock (*key);
++      {
++      int i;
++
++      for (i=0; i<NUM_WEAK_KEY; i++)
++              /* Added == 0 to comparision, I obviously don't run
++               * this section very often :-(, thanks to
++               * engineering@MorningStar.Com for the fix
++               * eay 93/06/29
++               * Another problem, I was comparing only the first 4
++               * bytes, 97/03/18 */
++              if (memcmp(weak_keys[i],key,sizeof(des_cblock)) == 0) return(1);
++      return(0);
++      }
++
++/* NOW DEFINED IN des_local.h
++ * See ecb_encrypt.c for a pseudo description of these macros. 
++ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
++ *    (b)^=(t),\
++ *    (a)=((a)^((t)<<(n))))
++ */
++
++#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
++      (a)=(a)^(t)^(t>>(16-(n))))
++
++/* return 0 if key parity is odd (correct),
++ * return -1 if key parity error,
++ * return -2 if illegal weak key.
++ */
++int des_set_key(key, schedule)
++des_cblock (*key);
++des_key_schedule schedule;
++      {
++      static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
++      register DES_LONG c,d,t,s,t2;
++      register unsigned char *in;
++      register DES_LONG *k;
++      register int i;
++
++      if (des_check_key)
++              {
++              if (!check_parity(key))
++                      return(-1);
++
++              if (des_is_weak_key(key))
++                      return(-2);
++              }
++
++#ifdef OCF_ASSIST
++      if (ocf_des_assist() & OCF_PROVIDES_DES_3DES)
++              return(ocf_des_set_key(key, schedule));
++#endif
++
++      k=(DES_LONG *)schedule;
++      in=(unsigned char *)key;
++
++      c2l(in,c);
++      c2l(in,d);
++
++      /* do PC1 in 60 simple operations */ 
++/*    PERM_OP(d,c,t,4,0x0f0f0f0fL);
++      HPERM_OP(c,t,-2, 0xcccc0000L);
++      HPERM_OP(c,t,-1, 0xaaaa0000L);
++      HPERM_OP(c,t, 8, 0x00ff0000L);
++      HPERM_OP(c,t,-1, 0xaaaa0000L);
++      HPERM_OP(d,t,-8, 0xff000000L);
++      HPERM_OP(d,t, 8, 0x00ff0000L);
++      HPERM_OP(d,t, 2, 0x33330000L);
++      d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
++      d=(d>>8)|((c&0xf0000000L)>>4);
++      c&=0x0fffffffL; */
++
++      /* I now do it in 47 simple operations :-)
++       * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
++       * for the inspiration. :-) */
++      PERM_OP (d,c,t,4,0x0f0f0f0fL);
++      HPERM_OP(c,t,-2,0xcccc0000L);
++      HPERM_OP(d,t,-2,0xcccc0000L);
++      PERM_OP (d,c,t,1,0x55555555L);
++      PERM_OP (c,d,t,8,0x00ff00ffL);
++      PERM_OP (d,c,t,1,0x55555555L);
++      d=      (((d&0x000000ffL)<<16L)| (d&0x0000ff00L)     |
++               ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
++      c&=0x0fffffffL;
++
++      for (i=0; i<ITERATIONS; i++)
++              {
++              if (shifts2[i])
++                      { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
++              else
++                      { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
++              c&=0x0fffffffL;
++              d&=0x0fffffffL;
++              /* could be a few less shifts but I am to lazy at this
++               * point in time to investigate */
++              s=      des_skb[0][ (c    )&0x3f                ]|
++                      des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
++                      des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
++                      des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
++                                                ((c>>22L)&0x38)];
++              t=      des_skb[4][ (d    )&0x3f                ]|
++                      des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
++                      des_skb[6][ (d>>15L)&0x3f                ]|
++                      des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
++
++              /* table contained 0213 4657 */
++              t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
++              *(k++)=ROTATE(t2,30)&0xffffffffL;
++
++              t2=((s>>16L)|(t&0xffff0000L));
++              *(k++)=ROTATE(t2,26)&0xffffffffL;
++              }
++      return(0);
++      }
++
++int des_key_sched(key, schedule)
++des_cblock (*key);
++des_key_schedule schedule;
++      {
++      return(des_set_key(key,schedule));
++      }
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/goodmask.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,150 @@
++/*
++ * minor utilities for subnet-mask manipulation
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: goodmask.c,v 1.12 2004/07/10 07:43:47 mcr Exp $
++ */
++#include "openswan.h"
++
++#ifndef ABITS
++#define       ABITS   32      /* bits in an IPv4 address */
++#endif
++
++/* This file does not use sysdep.h, otherwise this should go into
++ * ports/darwin/include/sysdep.h
++ */
++#ifndef s6_addr32
++#define s6_addr32 __u6_addr.__u6_addr32
++#endif
++
++/*
++ - goodmask - is this a good (^1*0*$) subnet mask?
++ * You are not expected to understand this.  See Henry S. Warren Jr, 
++ * "Functions realizable with word-parallel logical and two's-complement
++ * addition instructions", CACM 20.6 (June 1977), p.439.
++ */
++int                           /* predicate */
++goodmask(mask)
++struct in_addr mask;
++{
++      unsigned long x = ntohl(mask.s_addr);
++      /* clear rightmost contiguous string of 1-bits */
++#     define  CRCS1B(x)       (((x|(x-1))+1)&x)
++#     define  TOPBIT          (1UL << 31)
++
++      /* either zero, or has one string of 1-bits which is left-justified */
++      if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT)))
++              return 1;
++      return 0;
++}
++
++/*
++ - masktobits - how many bits in this mask?
++ * The algorithm is essentially a binary search, but highly optimized
++ * for this particular task.
++ */
++int                           /* -1 means !goodmask() */
++masktobits(mask)
++struct in_addr mask;
++{
++      unsigned long m = ntohl(mask.s_addr);
++      int masklen;
++
++      if (!goodmask(mask))
++              return -1;
++
++      if (m&0x00000001UL)
++              return 32;
++      masklen = 0;
++      if (m&(0x0000ffffUL<<1)) {      /* <<1 for 1-origin numbering */
++              masklen |= 0x10;
++              m <<= 16;
++      }
++      if (m&(0x00ff0000UL<<1)) {
++              masklen |= 0x08;
++              m <<= 8;
++      }
++      if (m&(0x0f000000UL<<1)) {
++              masklen |= 0x04;
++              m <<= 4;
++      }
++      if (m&(0x30000000UL<<1)) {
++              masklen |= 0x02;
++              m <<= 2;
++      }
++      if (m&(0x40000000UL<<1))
++              masklen |= 0x01;
++
++      return masklen;
++}
++
++/*
++ - bitstomask - return a mask with this many high bits on
++ */
++struct in_addr
++bitstomask(n)
++int n;
++{
++      struct in_addr result;
++
++      if (n > 0 && n <= ABITS)
++              result.s_addr = htonl(~((1UL << (ABITS - n)) - 1));
++      else if (n == 0)
++              result.s_addr = 0;
++      else
++              result.s_addr = 0;      /* best error report we can do */
++      return result;
++}
++
++/*
++ - bitstomask6 - return a mask with this many high bits on
++ */
++struct in6_addr
++bitstomask6(n)
++int n;
++{
++      struct in6_addr result;
++
++      if (n > 0 && n <= 32) {
++              result.s6_addr32[0] = htonl(~((1UL << (32 - n)) - 1));
++              result.s6_addr32[1]=0;
++              result.s6_addr32[2]=0;
++              result.s6_addr32[3]=0;
++      }
++      else if (n > 32 && n <= 64) {
++              result.s6_addr32[0]=0xffffffffUL;
++              result.s6_addr32[1] = htonl(~((1UL << (64 - n)) - 1));
++              result.s6_addr32[2]=0;
++              result.s6_addr32[3]=0;
++      }
++      else if (n > 64 && n <= 96) {
++              result.s6_addr32[0]=0xffffffffUL;
++              result.s6_addr32[1]=0xffffffffUL;
++              result.s6_addr32[2] = htonl(~((1UL << (96 - n)) - 1));
++              result.s6_addr32[3]=0;
++      }
++      else if (n > 96 && n <= 128) {
++              result.s6_addr32[0]=0xffffffff;
++              result.s6_addr32[1]=0xffffffff;
++              result.s6_addr32[2]=0xffffffff;
++              result.s6_addr32[3] = htonl(~((1UL << (128 - n)) - 1));
++      }
++      else {
++              result.s6_addr32[0] = 0;
++              result.s6_addr32[0] = 0;
++              result.s6_addr32[0] = 0;
++              result.s6_addr32[0] = 0;
++      } 
++
++      return result;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infblock.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,403 @@
++/* infblock.c -- interpret and process block types to last block
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "infblock.h"
++#include "inftrees.h"
++#include "infcodes.h"
++#include "infutil.h"
++
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* Table for deflate from PKZIP's appnote.txt. */
++local const uInt border[] = { /* Order of the bit length code lengths */
++        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
++
++/*
++   Notes beyond the 1.93a appnote.txt:
++
++   1. Distance pointers never point before the beginning of the output
++      stream.
++   2. Distance pointers can point back across blocks, up to 32k away.
++   3. There is an implied maximum of 7 bits for the bit length table and
++      15 bits for the actual data.
++   4. If only one code exists, then it is encoded using one bit.  (Zero
++      would be more efficient, but perhaps a little confusing.)  If two
++      codes exist, they are coded using one bit each (0 and 1).
++   5. There is no way of sending zero distance codes--a dummy must be
++      sent if there are none.  (History: a pre 2.0 version of PKZIP would
++      store blocks with no distance codes, but this was discovered to be
++      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
++      zero distance codes, which is sent as one code of zero bits in
++      length.
++   6. There are up to 286 literal/length codes.  Code 256 represents the
++      end-of-block.  Note however that the static length tree defines
++      288 codes just to fill out the Huffman codes.  Codes 286 and 287
++      cannot be used though, since there is no length base or extra bits
++      defined for them.  Similarily, there are up to 30 distance codes.
++      However, static trees define 32 codes (all 5 bits) to fill out the
++      Huffman codes, but the last two had better not show up in the data.
++   7. Unzip can check dynamic Huffman blocks for complete code sets.
++      The exception is that a single code would not be complete (see #4).
++   8. The five bits following the block type is really the number of
++      literal codes sent minus 257.
++   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
++      (1+6+6).  Therefore, to output three times the length, you output
++      three codes (1+1+1), whereas to output four times the same length,
++      you only need two codes (1+3).  Hmm.
++  10. In the tree reconstruction algorithm, Code = Code + Increment
++      only if BitLength(i) is not zero.  (Pretty obvious.)
++  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
++  12. Note: length code 284 can represent 227-258, but length code 285
++      really is 258.  The last length deserves its own, short code
++      since it gets used a lot in very redundant files.  The length
++      258 is special since 258 - 3 (the min match length) is 255.
++  13. The literal/length and distance code bit lengths are read as a
++      single stream of lengths.  It is possible (and advantageous) for
++      a repeat code (16, 17, or 18) to go across the boundary between
++      the two sets of lengths.
++ */
++
++
++void inflate_blocks_reset(s, z, c)
++inflate_blocks_statef *s;
++z_streamp z;
++uLongf *c;
++{
++  if (c != Z_NULL)
++    *c = s->check;
++  if (s->mode == BTREE || s->mode == DTREE)
++    ZFREE(z, s->sub.trees.blens);
++  if (s->mode == CODES)
++    inflate_codes_free(s->sub.decode.codes, z);
++  s->mode = TYPE;
++  s->bitk = 0;
++  s->bitb = 0;
++  s->read = s->write = s->window;
++  if (s->checkfn != Z_NULL)
++    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
++  Tracev((stderr, "inflate:   blocks reset\n"));
++}
++
++
++inflate_blocks_statef *inflate_blocks_new(z, c, w)
++z_streamp z;
++check_func c;
++uInt w;
++{
++  inflate_blocks_statef *s;
++
++  if ((s = (inflate_blocks_statef *)ZALLOC
++       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
++    return s;
++  if ((s->hufts =
++       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
++  {
++    ZFREE(z, s);
++    return Z_NULL;
++  }
++  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
++  {
++    ZFREE(z, s->hufts);
++    ZFREE(z, s);
++    return Z_NULL;
++  }
++  s->end = s->window + w;
++  s->checkfn = c;
++  s->mode = TYPE;
++  Tracev((stderr, "inflate:   blocks allocated\n"));
++  inflate_blocks_reset(s, z, Z_NULL);
++  return s;
++}
++
++
++int inflate_blocks(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++  uInt t;               /* temporary storage */
++  uLong b;              /* bit buffer */
++  uInt k;               /* bits in bit buffer */
++  Bytef *p;             /* input data pointer */
++  uInt n;               /* bytes available there */
++  Bytef *q;             /* output window write pointer */
++  uInt m;               /* bytes to end of window or read pointer */
++
++  /* copy input/output information to locals (UPDATE macro restores) */
++  LOAD
++
++  /* process input based on current state */
++  while (1) switch (s->mode)
++  {
++    case TYPE:
++      NEEDBITS(3)
++      t = (uInt)b & 7;
++      s->last = t & 1;
++      switch (t >> 1)
++      {
++        case 0:                         /* stored */
++          Tracev((stderr, "inflate:     stored block%s\n",
++                 s->last ? " (last)" : ""));
++          DUMPBITS(3)
++          t = k & 7;                    /* go to byte boundary */
++          DUMPBITS(t)
++          s->mode = LENS;               /* get length of stored block */
++          break;
++        case 1:                         /* fixed */
++          Tracev((stderr, "inflate:     fixed codes block%s\n",
++                 s->last ? " (last)" : ""));
++          {
++            uInt bl, bd;
++            inflate_huft *tl, *td;
++
++            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
++            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
++            if (s->sub.decode.codes == Z_NULL)
++            {
++              r = Z_MEM_ERROR;
++              LEAVE
++            }
++          }
++          DUMPBITS(3)
++          s->mode = CODES;
++          break;
++        case 2:                         /* dynamic */
++          Tracev((stderr, "inflate:     dynamic codes block%s\n",
++                 s->last ? " (last)" : ""));
++          DUMPBITS(3)
++          s->mode = TABLE;
++          break;
++        case 3:                         /* illegal */
++          DUMPBITS(3)
++          s->mode = BAD;
++          z->msg = (char*)"invalid block type";
++          r = Z_DATA_ERROR;
++          LEAVE
++      }
++      break;
++    case LENS:
++      NEEDBITS(32)
++      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
++      {
++        s->mode = BAD;
++        z->msg = (char*)"invalid stored block lengths";
++        r = Z_DATA_ERROR;
++        LEAVE
++      }
++      s->sub.left = (uInt)b & 0xffff;
++      b = k = 0;                      /* dump bits */
++      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
++      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
++      break;
++    case STORED:
++      if (n == 0)
++        LEAVE
++      NEEDOUT
++      t = s->sub.left;
++      if (t > n) t = n;
++      if (t > m) t = m;
++      zmemcpy(q, p, t);
++      p += t;  n -= t;
++      q += t;  m -= t;
++      if ((s->sub.left -= t) != 0)
++        break;
++      Tracev((stderr, "inflate:       stored end, %lu total out\n",
++              z->total_out + (q >= s->read ? q - s->read :
++              (s->end - s->read) + (q - s->window))));
++      s->mode = s->last ? DRY : TYPE;
++      break;
++    case TABLE:
++      NEEDBITS(14)
++      s->sub.trees.table = t = (uInt)b & 0x3fff;
++#ifndef PKZIP_BUG_WORKAROUND
++      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
++      {
++        s->mode = BAD;
++        z->msg = (char*)"too many length or distance symbols";
++        r = Z_DATA_ERROR;
++        LEAVE
++      }
++#endif
++      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
++      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
++      {
++        r = Z_MEM_ERROR;
++        LEAVE
++      }
++      DUMPBITS(14)
++      s->sub.trees.index = 0;
++      Tracev((stderr, "inflate:       table sizes ok\n"));
++      s->mode = BTREE;
++    case BTREE:
++      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
++      {
++        NEEDBITS(3)
++        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
++        DUMPBITS(3)
++      }
++      while (s->sub.trees.index < 19)
++        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
++      s->sub.trees.bb = 7;
++      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
++                             &s->sub.trees.tb, s->hufts, z);
++      if (t != Z_OK)
++      {
++        r = t;
++        if (r == Z_DATA_ERROR)
++        {
++          ZFREE(z, s->sub.trees.blens);
++          s->mode = BAD;
++        }
++        LEAVE
++      }
++      s->sub.trees.index = 0;
++      Tracev((stderr, "inflate:       bits tree ok\n"));
++      s->mode = DTREE;
++    case DTREE:
++      while (t = s->sub.trees.table,
++             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
++      {
++        inflate_huft *h;
++        uInt i, j, c;
++
++        t = s->sub.trees.bb;
++        NEEDBITS(t)
++        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
++        t = h->bits;
++        c = h->base;
++        if (c < 16)
++        {
++          DUMPBITS(t)
++          s->sub.trees.blens[s->sub.trees.index++] = c;
++        }
++        else /* c == 16..18 */
++        {
++          i = c == 18 ? 7 : c - 14;
++          j = c == 18 ? 11 : 3;
++          NEEDBITS(t + i)
++          DUMPBITS(t)
++          j += (uInt)b & inflate_mask[i];
++          DUMPBITS(i)
++          i = s->sub.trees.index;
++          t = s->sub.trees.table;
++          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
++              (c == 16 && i < 1))
++          {
++            ZFREE(z, s->sub.trees.blens);
++            s->mode = BAD;
++            z->msg = (char*)"invalid bit length repeat";
++            r = Z_DATA_ERROR;
++            LEAVE
++          }
++          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
++          do {
++            s->sub.trees.blens[i++] = c;
++          } while (--j);
++          s->sub.trees.index = i;
++        }
++      }
++      s->sub.trees.tb = Z_NULL;
++      {
++        uInt bl, bd;
++        inflate_huft *tl, *td;
++        inflate_codes_statef *c;
++
++        bl = 9;         /* must be <= 9 for lookahead assumptions */
++        bd = 6;         /* must be <= 9 for lookahead assumptions */
++        t = s->sub.trees.table;
++        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
++                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
++                                  s->hufts, z);
++        if (t != Z_OK)
++        {
++          if (t == (uInt)Z_DATA_ERROR)
++          {
++            ZFREE(z, s->sub.trees.blens);
++            s->mode = BAD;
++          }
++          r = t;
++          LEAVE
++        }
++        Tracev((stderr, "inflate:       trees ok\n"));
++        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
++        {
++          r = Z_MEM_ERROR;
++          LEAVE
++        }
++        s->sub.decode.codes = c;
++      }
++      ZFREE(z, s->sub.trees.blens);
++      s->mode = CODES;
++    case CODES:
++      UPDATE
++      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
++        return inflate_flush(s, z, r);
++      r = Z_OK;
++      inflate_codes_free(s->sub.decode.codes, z);
++      LOAD
++      Tracev((stderr, "inflate:       codes end, %lu total out\n",
++              z->total_out + (q >= s->read ? q - s->read :
++              (s->end - s->read) + (q - s->window))));
++      if (!s->last)
++      {
++        s->mode = TYPE;
++        break;
++      }
++      s->mode = DRY;
++    case DRY:
++      FLUSH
++      if (s->read != s->write)
++        LEAVE
++      s->mode = DONE;
++    case DONE:
++      r = Z_STREAM_END;
++      LEAVE
++    case BAD:
++      r = Z_DATA_ERROR;
++      LEAVE
++    default:
++      r = Z_STREAM_ERROR;
++      LEAVE
++  }
++}
++
++
++int inflate_blocks_free(s, z)
++inflate_blocks_statef *s;
++z_streamp z;
++{
++  inflate_blocks_reset(s, z, Z_NULL);
++  ZFREE(z, s->window);
++  ZFREE(z, s->hufts);
++  ZFREE(z, s);
++  Tracev((stderr, "inflate:   blocks freed\n"));
++  return Z_OK;
++}
++
++
++void inflate_set_dictionary(s, d, n)
++inflate_blocks_statef *s;
++const Bytef *d;
++uInt  n;
++{
++  zmemcpy(s->window, d, n);
++  s->read = s->write = s->window + n;
++}
++
++
++/* Returns true if inflate is currently at the end of a block generated
++ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
++ * IN assertion: s != Z_NULL
++ */
++int inflate_blocks_sync_point(s)
++inflate_blocks_statef *s;
++{
++  return s->mode == LENS;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infblock.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,39 @@
++/* infblock.h -- header to use infblock.c
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++struct inflate_blocks_state;
++typedef struct inflate_blocks_state FAR inflate_blocks_statef;
++
++extern inflate_blocks_statef * inflate_blocks_new OF((
++    z_streamp z,
++    check_func c,               /* check function */
++    uInt w));                   /* window size */
++
++extern int inflate_blocks OF((
++    inflate_blocks_statef *,
++    z_streamp ,
++    int));                      /* initial return code */
++
++extern void inflate_blocks_reset OF((
++    inflate_blocks_statef *,
++    z_streamp ,
++    uLongf *));                  /* check value on output */
++
++extern int inflate_blocks_free OF((
++    inflate_blocks_statef *,
++    z_streamp));
++
++extern void inflate_set_dictionary OF((
++    inflate_blocks_statef *s,
++    const Bytef *d,  /* dictionary */
++    uInt  n));       /* dictionary length */
++
++extern int inflate_blocks_sync_point OF((
++    inflate_blocks_statef *s));
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infcodes.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,251 @@
++/* infcodes.c -- process literals and length/distance pairs
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "inftrees.h"
++#include "infblock.h"
++#include "infcodes.h"
++#include "infutil.h"
++#include "inffast.h"
++
++/* simplify the use of the inflate_huft type with some defines */
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
++      START,    /* x: set up for LEN */
++      LEN,      /* i: get length/literal/eob next */
++      LENEXT,   /* i: getting length extra (have base) */
++      DIST,     /* i: get distance next */
++      DISTEXT,  /* i: getting distance extra */
++      COPY,     /* o: copying bytes in window, waiting for space */
++      LIT,      /* o: got literal, waiting for output space */
++      WASH,     /* o: got eob, possibly still output waiting */
++      END,      /* x: got eob and all data flushed */
++      BADCODE}  /* x: got error */
++inflate_codes_mode;
++
++/* inflate codes private state */
++struct inflate_codes_state {
++
++  /* mode */
++  inflate_codes_mode mode;      /* current inflate_codes mode */
++
++  /* mode dependent information */
++  uInt len;
++  union {
++    struct {
++      inflate_huft *tree;       /* pointer into tree */
++      uInt need;                /* bits needed */
++    } code;             /* if LEN or DIST, where in tree */
++    uInt lit;           /* if LIT, literal */
++    struct {
++      uInt get;                 /* bits to get for extra */
++      uInt dist;                /* distance back to copy from */
++    } copy;             /* if EXT or COPY, where and how much */
++  } sub;                /* submode */
++
++  /* mode independent information */
++  Byte lbits;           /* ltree bits decoded per branch */
++  Byte dbits;           /* dtree bits decoder per branch */
++  inflate_huft *ltree;          /* literal/length/eob tree */
++  inflate_huft *dtree;          /* distance tree */
++
++};
++
++
++inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
++uInt bl, bd;
++inflate_huft *tl;
++inflate_huft *td; /* need separate declaration for Borland C++ */
++z_streamp z;
++{
++  inflate_codes_statef *c;
++
++  if ((c = (inflate_codes_statef *)
++       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
++  {
++    c->mode = START;
++    c->lbits = (Byte)bl;
++    c->dbits = (Byte)bd;
++    c->ltree = tl;
++    c->dtree = td;
++    Tracev((stderr, "inflate:       codes new\n"));
++  }
++  return c;
++}
++
++
++int inflate_codes(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++  uInt j;               /* temporary storage */
++  inflate_huft *t;      /* temporary pointer */
++  uInt e;               /* extra bits or operation */
++  uLong b;              /* bit buffer */
++  uInt k;               /* bits in bit buffer */
++  Bytef *p;             /* input data pointer */
++  uInt n;               /* bytes available there */
++  Bytef *q;             /* output window write pointer */
++  uInt m;               /* bytes to end of window or read pointer */
++  Bytef *f;             /* pointer to copy strings from */
++  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
++
++  /* copy input/output information to locals (UPDATE macro restores) */
++  LOAD
++
++  /* process input and output based on current state */
++  while (1) switch (c->mode)
++  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
++    case START:         /* x: set up for LEN */
++#ifndef SLOW
++      if (m >= 258 && n >= 10)
++      {
++        UPDATE
++        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
++        LOAD
++        if (r != Z_OK)
++        {
++          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
++          break;
++        }
++      }
++#endif /* !SLOW */
++      c->sub.code.need = c->lbits;
++      c->sub.code.tree = c->ltree;
++      c->mode = LEN;
++    case LEN:           /* i: get length/literal/eob next */
++      j = c->sub.code.need;
++      NEEDBITS(j)
++      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
++      DUMPBITS(t->bits)
++      e = (uInt)(t->exop);
++      if (e == 0)               /* literal */
++      {
++        c->sub.lit = t->base;
++        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
++                 "inflate:         literal '%c'\n" :
++                 "inflate:         literal 0x%02x\n", t->base));
++        c->mode = LIT;
++        break;
++      }
++      if (e & 16)               /* length */
++      {
++        c->sub.copy.get = e & 15;
++        c->len = t->base;
++        c->mode = LENEXT;
++        break;
++      }
++      if ((e & 64) == 0)        /* next table */
++      {
++        c->sub.code.need = e;
++        c->sub.code.tree = t + t->base;
++        break;
++      }
++      if (e & 32)               /* end of block */
++      {
++        Tracevv((stderr, "inflate:         end of block\n"));
++        c->mode = WASH;
++        break;
++      }
++      c->mode = BADCODE;        /* invalid code */
++      z->msg = (char*)"invalid literal/length code";
++      r = Z_DATA_ERROR;
++      LEAVE
++    case LENEXT:        /* i: getting length extra (have base) */
++      j = c->sub.copy.get;
++      NEEDBITS(j)
++      c->len += (uInt)b & inflate_mask[j];
++      DUMPBITS(j)
++      c->sub.code.need = c->dbits;
++      c->sub.code.tree = c->dtree;
++      Tracevv((stderr, "inflate:         length %u\n", c->len));
++      c->mode = DIST;
++    case DIST:          /* i: get distance next */
++      j = c->sub.code.need;
++      NEEDBITS(j)
++      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
++      DUMPBITS(t->bits)
++      e = (uInt)(t->exop);
++      if (e & 16)               /* distance */
++      {
++        c->sub.copy.get = e & 15;
++        c->sub.copy.dist = t->base;
++        c->mode = DISTEXT;
++        break;
++      }
++      if ((e & 64) == 0)        /* next table */
++      {
++        c->sub.code.need = e;
++        c->sub.code.tree = t + t->base;
++        break;
++      }
++      c->mode = BADCODE;        /* invalid code */
++      z->msg = (char*)"invalid distance code";
++      r = Z_DATA_ERROR;
++      LEAVE
++    case DISTEXT:       /* i: getting distance extra */
++      j = c->sub.copy.get;
++      NEEDBITS(j)
++      c->sub.copy.dist += (uInt)b & inflate_mask[j];
++      DUMPBITS(j)
++      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
++      c->mode = COPY;
++    case COPY:          /* o: copying bytes in window, waiting for space */
++      f = q - c->sub.copy.dist;
++      while (f < s->window)             /* modulo window size-"while" instead */
++        f += s->end - s->window;        /* of "if" handles invalid distances */
++      while (c->len)
++      {
++        NEEDOUT
++        OUTBYTE(*f++)
++        if (f == s->end)
++          f = s->window;
++        c->len--;
++      }
++      c->mode = START;
++      break;
++    case LIT:           /* o: got literal, waiting for output space */
++      NEEDOUT
++      OUTBYTE(c->sub.lit)
++      c->mode = START;
++      break;
++    case WASH:          /* o: got eob, possibly more output */
++      if (k > 7)        /* return unused byte, if any */
++      {
++        Assert(k < 16, "inflate_codes grabbed too many bytes")
++        k -= 8;
++        n++;
++        p--;            /* can always return one */
++      }
++      FLUSH
++      if (s->read != s->write)
++        LEAVE
++      c->mode = END;
++    case END:
++      r = Z_STREAM_END;
++      LEAVE
++    case BADCODE:       /* x: got error */
++      r = Z_DATA_ERROR;
++      LEAVE
++    default:
++      r = Z_STREAM_ERROR;
++      LEAVE
++  }
++#ifdef NEED_DUMMY_RETURN
++  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
++#endif
++}
++
++
++void inflate_codes_free(c, z)
++inflate_codes_statef *c;
++z_streamp z;
++{
++  ZFREE(z, c);
++  Tracev((stderr, "inflate:       codes free\n"));
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infcodes.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,31 @@
++/* infcodes.h -- header to use infcodes.c
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++#ifndef _INFCODES_H
++#define _INFCODES_H
++
++struct inflate_codes_state;
++typedef struct inflate_codes_state FAR inflate_codes_statef;
++
++extern inflate_codes_statef *inflate_codes_new OF((
++    uInt, uInt,
++    inflate_huft *, inflate_huft *,
++    z_streamp ));
++
++extern int inflate_codes OF((
++    inflate_blocks_statef *,
++    z_streamp ,
++    int));
++
++extern void inflate_codes_free OF((
++    inflate_codes_statef *,
++    z_streamp ));
++
++#endif /* _INFCODES_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inffast.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,183 @@
++/* inffast.c -- process literals and length/distance pairs fast
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "inftrees.h"
++#include "infblock.h"
++#include "infcodes.h"
++#include "infutil.h"
++#include "inffast.h"
++
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++/* macros for bit input with no checking and for returning unused bytes */
++#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
++#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
++
++/* Called with number of bytes left to write in window at least 258
++   (the maximum string length) and number of input bytes available
++   at least ten.  The ten bytes are six bytes for the longest length/
++   distance pair plus four bytes for overloading the bit buffer. */
++
++int inflate_fast(bl, bd, tl, td, s, z)
++uInt bl, bd;
++inflate_huft *tl;
++inflate_huft *td; /* need separate declaration for Borland C++ */
++inflate_blocks_statef *s;
++z_streamp z;
++{
++  inflate_huft *t;      /* temporary pointer */
++  uInt e;               /* extra bits or operation */
++  uLong b;              /* bit buffer */
++  uInt k;               /* bits in bit buffer */
++  Bytef *p;             /* input data pointer */
++  uInt n;               /* bytes available there */
++  Bytef *q;             /* output window write pointer */
++  uInt m;               /* bytes to end of window or read pointer */
++  uInt ml;              /* mask for literal/length tree */
++  uInt md;              /* mask for distance tree */
++  uInt c;               /* bytes to copy */
++  uInt d;               /* distance back to copy from */
++  Bytef *r;             /* copy source pointer */
++
++  /* load input, output, bit values */
++  LOAD
++
++  /* initialize masks */
++  ml = inflate_mask[bl];
++  md = inflate_mask[bd];
++
++  /* do until not enough input or output space for fast loop */
++  do {                          /* assume called with m >= 258 && n >= 10 */
++    /* get literal/length code */
++    GRABBITS(20)                /* max bits for literal/length code */
++    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
++    {
++      DUMPBITS(t->bits)
++      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
++                "inflate:         * literal '%c'\n" :
++                "inflate:         * literal 0x%02x\n", t->base));
++      *q++ = (Byte)t->base;
++      m--;
++      continue;
++    }
++    do {
++      DUMPBITS(t->bits)
++      if (e & 16)
++      {
++        /* get extra bits for length */
++        e &= 15;
++        c = t->base + ((uInt)b & inflate_mask[e]);
++        DUMPBITS(e)
++        Tracevv((stderr, "inflate:         * length %u\n", c));
++
++        /* decode distance base of block to copy */
++        GRABBITS(15);           /* max bits for distance code */
++        e = (t = td + ((uInt)b & md))->exop;
++        do {
++          DUMPBITS(t->bits)
++          if (e & 16)
++          {
++            /* get extra bits to add to distance base */
++            e &= 15;
++            GRABBITS(e)         /* get extra bits (up to 13) */
++            d = t->base + ((uInt)b & inflate_mask[e]);
++            DUMPBITS(e)
++            Tracevv((stderr, "inflate:         * distance %u\n", d));
++
++            /* do the copy */
++            m -= c;
++            r = q - d;
++            if (r < s->window)                  /* wrap if needed */
++            {
++              do {
++                r += s->end - s->window;        /* force pointer in window */
++              } while (r < s->window);          /* covers invalid distances */
++              e = s->end - r;
++              if (c > e)
++              {
++                c -= e;                         /* wrapped copy */
++                do {
++                    *q++ = *r++;
++                } while (--e);
++                r = s->window;
++                do {
++                    *q++ = *r++;
++                } while (--c);
++              }
++              else                              /* normal copy */
++              {
++                *q++ = *r++;  c--;
++                *q++ = *r++;  c--;
++                do {
++                    *q++ = *r++;
++                } while (--c);
++              }
++            }
++            else                                /* normal copy */
++            {
++              *q++ = *r++;  c--;
++              *q++ = *r++;  c--;
++              do {
++                *q++ = *r++;
++              } while (--c);
++            }
++            break;
++          }
++          else if ((e & 64) == 0)
++          {
++            t += t->base;
++            e = (t += ((uInt)b & inflate_mask[e]))->exop;
++          }
++          else
++          {
++            z->msg = (char*)"invalid distance code";
++            UNGRAB
++            UPDATE
++            return Z_DATA_ERROR;
++          }
++        } while (1);
++        break;
++      }
++      if ((e & 64) == 0)
++      {
++        t += t->base;
++        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
++        {
++          DUMPBITS(t->bits)
++          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
++                    "inflate:         * literal '%c'\n" :
++                    "inflate:         * literal 0x%02x\n", t->base));
++          *q++ = (Byte)t->base;
++          m--;
++          break;
++        }
++      }
++      else if (e & 32)
++      {
++        Tracevv((stderr, "inflate:         * end of block\n"));
++        UNGRAB
++        UPDATE
++        return Z_STREAM_END;
++      }
++      else
++      {
++        z->msg = (char*)"invalid literal/length code";
++        UNGRAB
++        UPDATE
++        return Z_DATA_ERROR;
++      }
++    } while (1);
++  } while (m >= 258 && n >= 10);
++
++  /* not enough input or output--restore pointers and return */
++  UNGRAB
++  UPDATE
++  return Z_OK;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inffast.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,22 @@
++/* inffast.h -- header to use inffast.c
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++#ifndef _INFFAST_H
++#define _INFFAST_H
++
++extern int inflate_fast OF((
++    uInt,
++    uInt,
++    inflate_huft *,
++    inflate_huft *,
++    inflate_blocks_statef *,
++    z_streamp ));
++
++#endif /* _INFFAST_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inffixed.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,151 @@
++/* inffixed.h -- table for decoding fixed codes
++ * Generated automatically by the maketree.c program
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++local uInt fixed_bl = 9;
++local uInt fixed_bd = 5;
++local inflate_huft fixed_tl[] = {
++    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
++    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
++    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
++    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
++    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
++    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
++    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
++    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
++    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
++    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
++    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
++    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
++    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
++    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
++    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
++    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
++    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
++    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
++    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
++    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
++    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
++    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
++    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
++    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
++    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
++    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
++    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
++    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
++    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
++    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
++    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
++    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
++    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
++    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
++    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
++    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
++    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
++    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
++    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
++    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
++    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
++    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
++    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
++    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
++    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
++    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
++    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
++    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
++    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
++    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
++    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
++    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
++    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
++    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
++    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
++    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
++    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
++    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
++    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
++    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
++    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
++    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
++    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
++    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
++    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
++    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
++    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
++    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
++    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
++    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
++    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
++    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
++    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
++    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
++    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
++    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
++    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
++    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
++    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
++    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
++    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
++    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
++    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
++    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
++    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
++    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
++    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
++    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
++    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
++    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
++    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
++    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
++    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
++    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
++    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
++    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
++    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
++    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
++    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
++    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
++    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
++    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
++    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
++    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
++    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
++    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
++    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
++    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
++    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
++    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
++    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
++    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
++    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
++    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
++    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
++    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
++    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
++    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
++    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
++    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
++    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
++    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
++    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
++    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
++    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
++    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
++    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
++    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
++  };
++local inflate_huft fixed_td[] = {
++    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
++    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
++    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
++    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
++    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
++    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
++    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
++    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
++  };
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inflate.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,368 @@
++/* inflate.c -- zlib interface to inflate modules
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "infblock.h"
++
++struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
++
++typedef enum {
++      METHOD,   /* waiting for method byte */
++      FLAG,     /* waiting for flag byte */
++      DICT4,    /* four dictionary check bytes to go */
++      DICT3,    /* three dictionary check bytes to go */
++      DICT2,    /* two dictionary check bytes to go */
++      DICT1,    /* one dictionary check byte to go */
++      DICT0,    /* waiting for inflateSetDictionary */
++      BLOCKS,   /* decompressing blocks */
++      CHECK4,   /* four check bytes to go */
++      CHECK3,   /* three check bytes to go */
++      CHECK2,   /* two check bytes to go */
++      CHECK1,   /* one check byte to go */
++      DONE,     /* finished check, done */
++      BAD}      /* got an error--stay here */
++inflate_mode;
++
++/* inflate private state */
++struct internal_state {
++
++  /* mode */
++  inflate_mode  mode;   /* current inflate mode */
++
++  /* mode dependent information */
++  union {
++    uInt method;        /* if FLAGS, method byte */
++    struct {
++      uLong was;                /* computed check value */
++      uLong need;               /* stream check value */
++    } check;            /* if CHECK, check values to compare */
++    uInt marker;        /* if BAD, inflateSync's marker bytes count */
++  } sub;        /* submode */
++
++  /* mode independent information */
++  int  nowrap;          /* flag for no wrapper */
++  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
++  inflate_blocks_statef 
++    *blocks;            /* current inflate_blocks state */
++
++};
++
++
++int ZEXPORT inflateReset(z)
++z_streamp z;
++{
++  if (z == Z_NULL || z->state == Z_NULL)
++    return Z_STREAM_ERROR;
++  z->total_in = z->total_out = 0;
++  z->msg = Z_NULL;
++  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
++  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
++  Tracev((stderr, "inflate: reset\n"));
++  return Z_OK;
++}
++
++
++int ZEXPORT inflateEnd(z)
++z_streamp z;
++{
++  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
++    return Z_STREAM_ERROR;
++  if (z->state->blocks != Z_NULL)
++    inflate_blocks_free(z->state->blocks, z);
++  ZFREE(z, z->state);
++  z->state = Z_NULL;
++  Tracev((stderr, "inflate: end\n"));
++  return Z_OK;
++}
++
++
++int ZEXPORT inflateInit2_(z, w, version, stream_size)
++z_streamp z;
++int w;
++const char *version;
++int stream_size;
++{
++  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
++      stream_size != sizeof(z_stream))
++      return Z_VERSION_ERROR;
++
++  /* initialize state */
++  if (z == Z_NULL)
++    return Z_STREAM_ERROR;
++  z->msg = Z_NULL;
++  if (z->zalloc == Z_NULL)
++  {
++    return Z_STREAM_ERROR;
++/*    z->zalloc = zcalloc;
++    z->opaque = (voidpf)0;
++*/
++  }
++  if (z->zfree == Z_NULL) return Z_STREAM_ERROR; /* z->zfree = zcfree; */
++  if ((z->state = (struct internal_state FAR *)
++       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
++    return Z_MEM_ERROR;
++  z->state->blocks = Z_NULL;
++
++  /* handle undocumented nowrap option (no zlib header or check) */
++  z->state->nowrap = 0;
++  if (w < 0)
++  {
++    w = - w;
++    z->state->nowrap = 1;
++  }
++
++  /* set window size */
++  if (w < 8 || w > 15)
++  {
++    inflateEnd(z);
++    return Z_STREAM_ERROR;
++  }
++  z->state->wbits = (uInt)w;
++
++  /* create inflate_blocks state */
++  if ((z->state->blocks =
++      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
++      == Z_NULL)
++  {
++    inflateEnd(z);
++    return Z_MEM_ERROR;
++  }
++  Tracev((stderr, "inflate: allocated\n"));
++
++  /* reset state */
++  inflateReset(z);
++  return Z_OK;
++}
++
++
++int ZEXPORT inflateInit_(z, version, stream_size)
++z_streamp z;
++const char *version;
++int stream_size;
++{
++  return inflateInit2_(z, DEF_WBITS, version, stream_size);
++}
++
++
++#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
++#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
++
++int ZEXPORT inflate(z, f)
++z_streamp z;
++int f;
++{
++  int r;
++  uInt b;
++
++  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
++    return Z_STREAM_ERROR;
++  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
++  r = Z_BUF_ERROR;
++  while (1) switch (z->state->mode)
++  {
++    case METHOD:
++      NEEDBYTE
++      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
++      {
++        z->state->mode = BAD;
++        z->msg = (char*)"unknown compression method";
++        z->state->sub.marker = 5;       /* can't try inflateSync */
++        break;
++      }
++      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
++      {
++        z->state->mode = BAD;
++        z->msg = (char*)"invalid window size";
++        z->state->sub.marker = 5;       /* can't try inflateSync */
++        break;
++      }
++      z->state->mode = FLAG;
++    case FLAG:
++      NEEDBYTE
++      b = NEXTBYTE;
++      if (((z->state->sub.method << 8) + b) % 31)
++      {
++        z->state->mode = BAD;
++        z->msg = (char*)"incorrect header check";
++        z->state->sub.marker = 5;       /* can't try inflateSync */
++        break;
++      }
++      Tracev((stderr, "inflate: zlib header ok\n"));
++      if (!(b & PRESET_DICT))
++      {
++        z->state->mode = BLOCKS;
++        break;
++      }
++      z->state->mode = DICT4;
++    case DICT4:
++      NEEDBYTE
++      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
++      z->state->mode = DICT3;
++    case DICT3:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
++      z->state->mode = DICT2;
++    case DICT2:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
++      z->state->mode = DICT1;
++    case DICT1:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE;
++      z->adler = z->state->sub.check.need;
++      z->state->mode = DICT0;
++      return Z_NEED_DICT;
++    case DICT0:
++      z->state->mode = BAD;
++      z->msg = (char*)"need dictionary";
++      z->state->sub.marker = 0;       /* can try inflateSync */
++      return Z_STREAM_ERROR;
++    case BLOCKS:
++      r = inflate_blocks(z->state->blocks, z, r);
++      if (r == Z_DATA_ERROR)
++      {
++        z->state->mode = BAD;
++        z->state->sub.marker = 0;       /* can try inflateSync */
++        break;
++      }
++      if (r == Z_OK)
++        r = f;
++      if (r != Z_STREAM_END)
++        return r;
++      r = f;
++      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
++      if (z->state->nowrap)
++      {
++        z->state->mode = DONE;
++        break;
++      }
++      z->state->mode = CHECK4;
++    case CHECK4:
++      NEEDBYTE
++      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
++      z->state->mode = CHECK3;
++    case CHECK3:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
++      z->state->mode = CHECK2;
++    case CHECK2:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
++      z->state->mode = CHECK1;
++    case CHECK1:
++      NEEDBYTE
++      z->state->sub.check.need += (uLong)NEXTBYTE;
++
++      if (z->state->sub.check.was != z->state->sub.check.need)
++      {
++        z->state->mode = BAD;
++        z->msg = (char*)"incorrect data check";
++        z->state->sub.marker = 5;       /* can't try inflateSync */
++        break;
++      }
++      Tracev((stderr, "inflate: zlib check ok\n"));
++      z->state->mode = DONE;
++    case DONE:
++      return Z_STREAM_END;
++    case BAD:
++      return Z_DATA_ERROR;
++    default:
++      return Z_STREAM_ERROR;
++  }
++#ifdef NEED_DUMMY_RETURN
++  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
++#endif
++}
++
++
++int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
++z_streamp z;
++const Bytef *dictionary;
++uInt  dictLength;
++{
++  uInt length = dictLength;
++
++  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
++    return Z_STREAM_ERROR;
++
++  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
++  z->adler = 1L;
++
++  if (length >= ((uInt)1<<z->state->wbits))
++  {
++    length = (1<<z->state->wbits)-1;
++    dictionary += dictLength - length;
++  }
++  inflate_set_dictionary(z->state->blocks, dictionary, length);
++  z->state->mode = BLOCKS;
++  return Z_OK;
++}
++
++
++int ZEXPORT inflateSync(z)
++z_streamp z;
++{
++  uInt n;       /* number of bytes to look at */
++  Bytef *p;     /* pointer to bytes */
++  uInt m;       /* number of marker bytes found in a row */
++  uLong r, w;   /* temporaries to save total_in and total_out */
++
++  /* set up */
++  if (z == Z_NULL || z->state == Z_NULL)
++    return Z_STREAM_ERROR;
++  if (z->state->mode != BAD)
++  {
++    z->state->mode = BAD;
++    z->state->sub.marker = 0;
++  }
++  if ((n = z->avail_in) == 0)
++    return Z_BUF_ERROR;
++  p = z->next_in;
++  m = z->state->sub.marker;
++
++  /* search */
++  while (n && m < 4)
++  {
++    static const Byte mark[4] = {0, 0, 0xff, 0xff};
++    if (*p == mark[m])
++      m++;
++    else if (*p)
++      m = 0;
++    else
++      m = 4 - m;
++    p++, n--;
++  }
++
++  /* restore */
++  z->total_in += p - z->next_in;
++  z->next_in = p;
++  z->avail_in = n;
++  z->state->sub.marker = m;
++
++  /* return no joy or set up to restart on a new block */
++  if (m != 4)
++    return Z_DATA_ERROR;
++  r = z->total_in;  w = z->total_out;
++  inflateReset(z);
++  z->total_in = r;  z->total_out = w;
++  z->state->mode = BLOCKS;
++  return Z_OK;
++}
++
++
++/* Returns true if inflate is currently at the end of a block generated
++ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
++ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
++ * but removes the length bytes of the resulting empty stored block. When
++ * decompressing, PPP checks that at the end of input packet, inflate is
++ * waiting for these length bytes.
++ */
++int ZEXPORT inflateSyncPoint(z)
++z_streamp z;
++{
++  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
++    return Z_STREAM_ERROR;
++  return inflate_blocks_sync_point(z->state->blocks);
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inftrees.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,454 @@
++/* inftrees.c -- generate Huffman trees for efficient decoding
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "inftrees.h"
++
++#if !defined(BUILDFIXED) && !defined(STDC)
++#  define BUILDFIXED   /* non ANSI compilers may not accept inffixed.h */
++#endif
++
++local const char inflate_copyright[] =
++   " inflate 1.1.4 Copyright 1995-2002 Mark Adler ";
++/*
++  If you use the zlib library in a product, an acknowledgment is welcome
++  in the documentation of your product. If for some reason you cannot
++  include such an acknowledgment, I would appreciate that you keep this
++  copyright string in the executable of your product.
++ */
++struct internal_state  {int dummy;}; /* for buggy compilers */
++
++/* simplify the use of the inflate_huft type with some defines */
++#define exop word.what.Exop
++#define bits word.what.Bits
++
++
++local int huft_build OF((
++    uIntf *,            /* code lengths in bits */
++    uInt,               /* number of codes */
++    uInt,               /* number of "simple" codes */
++    const uIntf *,      /* list of base values for non-simple codes */
++    const uIntf *,      /* list of extra bits for non-simple codes */
++    inflate_huft * FAR*,/* result: starting table */
++    uIntf *,            /* maximum lookup bits (returns actual) */
++    inflate_huft *,     /* space for trees */
++    uInt *,             /* hufts used in space */
++    uIntf * ));         /* space for values */
++
++/* Tables for deflate from PKZIP's appnote.txt. */
++local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
++        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
++        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
++        /* see note #13 above about 258 */
++local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
++        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
++        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
++local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
++        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
++        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
++        8193, 12289, 16385, 24577};
++local const uInt cpdext[30] = { /* Extra bits for distance codes */
++        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
++        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
++        12, 12, 13, 13};
++
++/*
++   Huffman code decoding is performed using a multi-level table lookup.
++   The fastest way to decode is to simply build a lookup table whose
++   size is determined by the longest code.  However, the time it takes
++   to build this table can also be a factor if the data being decoded
++   is not very long.  The most common codes are necessarily the
++   shortest codes, so those codes dominate the decoding time, and hence
++   the speed.  The idea is you can have a shorter table that decodes the
++   shorter, more probable codes, and then point to subsidiary tables for
++   the longer codes.  The time it costs to decode the longer codes is
++   then traded against the time it takes to make longer tables.
++
++   This results of this trade are in the variables lbits and dbits
++   below.  lbits is the number of bits the first level table for literal/
++   length codes can decode in one step, and dbits is the same thing for
++   the distance codes.  Subsequent tables are also less than or equal to
++   those sizes.  These values may be adjusted either when all of the
++   codes are shorter than that, in which case the longest code length in
++   bits is used, or when the shortest code is *longer* than the requested
++   table size, in which case the length of the shortest code in bits is
++   used.
++
++   There are two different values for the two tables, since they code a
++   different number of possibilities each.  The literal/length table
++   codes 286 possible values, or in a flat code, a little over eight
++   bits.  The distance table codes 30 possible values, or a little less
++   than five bits, flat.  The optimum values for speed end up being
++   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
++   The optimum values may differ though from machine to machine, and
++   possibly even between compilers.  Your mileage may vary.
++ */
++
++
++/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
++#define BMAX 15         /* maximum bit length of any code */
++
++local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
++uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
++uInt n;                 /* number of codes (assumed <= 288) */
++uInt s;                 /* number of simple-valued codes (0..s-1) */
++const uIntf *d;         /* list of base values for non-simple codes */
++const uIntf *e;         /* list of extra bits for non-simple codes */
++inflate_huft * FAR *t;  /* result: starting table */
++uIntf *m;               /* maximum lookup bits, returns actual */
++inflate_huft *hp;       /* space for trees */
++uInt *hn;               /* hufts used in space */
++uIntf *v;               /* working area: values in order of bit length */
++/* Given a list of code lengths and a maximum table size, make a set of
++   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
++   if the given code set is incomplete (the tables are still built in this
++   case), or Z_DATA_ERROR if the input is invalid. */
++{
++
++  uInt a;                       /* counter for codes of length k */
++  uInt c[BMAX+1];               /* bit length count table */
++  uInt f;                       /* i repeats in table every f entries */
++  int g;                        /* maximum code length */
++  int h;                        /* table level */
++  register uInt i;              /* counter, current code */
++  register uInt j;              /* counter */
++  register int k;               /* number of bits in current code */
++  int l;                        /* bits per table (returned in m) */
++  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
++  register uIntf *p;            /* pointer into c[], b[], or v[] */
++  inflate_huft *q;              /* points to current table */
++  struct inflate_huft_s r;      /* table entry for structure assignment */
++  inflate_huft *u[BMAX];        /* table stack */
++  register int w;               /* bits before this table == (l * h) */
++  uInt x[BMAX+1];               /* bit offsets, then code stack */
++  uIntf *xp;                    /* pointer into x */
++  int y;                        /* number of dummy codes added */
++  uInt z;                       /* number of entries in current table */
++
++
++  /* Generate counts for each bit length */
++  p = c;
++#define C0 *p++ = 0;
++#define C2 C0 C0 C0 C0
++#define C4 C2 C2 C2 C2
++  C4                            /* clear c[]--assume BMAX+1 is 16 */
++  p = b;  i = n;
++  do {
++    c[*p++]++;                  /* assume all entries <= BMAX */
++  } while (--i);
++  if (c[0] == n)                /* null input--all zero length codes */
++  {
++    *t = (inflate_huft *)Z_NULL;
++    *m = 0;
++    return Z_OK;
++  }
++
++
++  /* Find minimum and maximum length, bound *m by those */
++  l = *m;
++  for (j = 1; j <= BMAX; j++)
++    if (c[j])
++      break;
++  k = j;                        /* minimum code length */
++  if ((uInt)l < j)
++    l = j;
++  for (i = BMAX; i; i--)
++    if (c[i])
++      break;
++  g = i;                        /* maximum code length */
++  if ((uInt)l > i)
++    l = i;
++  *m = l;
++
++
++  /* Adjust last length count to fill out codes, if needed */
++  for (y = 1 << j; j < i; j++, y <<= 1)
++    if ((y -= c[j]) < 0)
++      return Z_DATA_ERROR;
++  if ((y -= c[i]) < 0)
++    return Z_DATA_ERROR;
++  c[i] += y;
++
++
++  /* Generate starting offsets into the value table for each length */
++  x[1] = j = 0;
++  p = c + 1;  xp = x + 2;
++  while (--i) {                 /* note that i == g from above */
++    *xp++ = (j += *p++);
++  }
++
++
++  /* Make a table of values in order of bit lengths */
++  p = b;  i = 0;
++  do {
++    if ((j = *p++) != 0)
++      v[x[j]++] = i;
++  } while (++i < n);
++  n = x[g];                     /* set n to length of v */
++
++
++  /* Generate the Huffman codes and for each, make the table entries */
++  x[0] = i = 0;                 /* first Huffman code is zero */
++  p = v;                        /* grab values in bit order */
++  h = -1;                       /* no tables yet--level -1 */
++  w = -l;                       /* bits decoded == (l * h) */
++  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
++  q = (inflate_huft *)Z_NULL;   /* ditto */
++  z = 0;                        /* ditto */
++
++  /* go through the bit lengths (k already is bits in shortest code) */
++  for (; k <= g; k++)
++  {
++    a = c[k];
++    while (a--)
++    {
++      /* here i is the Huffman code of length k bits for value *p */
++      /* make tables up to required level */
++      while (k > w + l)
++      {
++        h++;
++        w += l;                 /* previous table always l bits */
++
++        /* compute minimum size table less than or equal to l bits */
++        z = g - w;
++        z = z > (uInt)l ? l : z;        /* table size upper limit */
++        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
++        {                       /* too few codes for k-w bit table */
++          f -= a + 1;           /* deduct codes from patterns left */
++          xp = c + k;
++          if (j < z)
++            while (++j < z)     /* try smaller tables up to z bits */
++            {
++              if ((f <<= 1) <= *++xp)
++                break;          /* enough codes to use up j bits */
++              f -= *xp;         /* else deduct codes from patterns */
++            }
++        }
++        z = 1 << j;             /* table entries for j-bit table */
++
++        /* allocate new table */
++        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
++          return Z_DATA_ERROR;  /* overflow of MANY */
++        u[h] = q = hp + *hn;
++        *hn += z;
++
++        /* connect to last table, if there is one */
++        if (h)
++        {
++          x[h] = i;             /* save pattern for backing up */
++          r.bits = (Byte)l;     /* bits to dump before this table */
++          r.exop = (Byte)j;     /* bits in this table */
++          j = i >> (w - l);
++          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
++          u[h-1][j] = r;        /* connect to last table */
++        }
++        else
++          *t = q;               /* first table is returned result */
++      }
++
++      /* set up table entry in r */
++      r.bits = (Byte)(k - w);
++      if (p >= v + n)
++        r.exop = 128 + 64;      /* out of values--invalid code */
++      else if (*p < s)
++      {
++        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
++        r.base = *p++;          /* simple code is just the value */
++      }
++      else
++      {
++        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
++        r.base = d[*p++ - s];
++      }
++
++      /* fill code-like entries with r */
++      f = 1 << (k - w);
++      for (j = i >> w; j < z; j += f)
++        q[j] = r;
++
++      /* backwards increment the k-bit code i */
++      for (j = 1 << (k - 1); i & j; j >>= 1)
++        i ^= j;
++      i ^= j;
++
++      /* backup over finished tables */
++      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
++      while ((i & mask) != x[h])
++      {
++        h--;                    /* don't need to update q */
++        w -= l;
++        mask = (1 << w) - 1;
++      }
++    }
++  }
++
++
++  /* Return Z_BUF_ERROR if we were given an incomplete table */
++  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
++}
++
++
++int inflate_trees_bits(c, bb, tb, hp, z)
++uIntf *c;               /* 19 code lengths */
++uIntf *bb;              /* bits tree desired/actual depth */
++inflate_huft * FAR *tb; /* bits tree result */
++inflate_huft *hp;       /* space for trees */
++z_streamp z;            /* for messages */
++{
++  int r;
++  uInt hn = 0;          /* hufts used in space */
++  uIntf *v;             /* work area for huft_build */
++
++  if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
++    return Z_MEM_ERROR;
++  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
++                 tb, bb, hp, &hn, v);
++  if (r == Z_DATA_ERROR)
++    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
++  else if (r == Z_BUF_ERROR || *bb == 0)
++  {
++    z->msg = (char*)"incomplete dynamic bit lengths tree";
++    r = Z_DATA_ERROR;
++  }
++  ZFREE(z, v);
++  return r;
++}
++
++
++int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
++uInt nl;                /* number of literal/length codes */
++uInt nd;                /* number of distance codes */
++uIntf *c;               /* that many (total) code lengths */
++uIntf *bl;              /* literal desired/actual bit depth */
++uIntf *bd;              /* distance desired/actual bit depth */
++inflate_huft * FAR *tl; /* literal/length tree result */
++inflate_huft * FAR *td; /* distance tree result */
++inflate_huft *hp;       /* space for trees */
++z_streamp z;            /* for messages */
++{
++  int r;
++  uInt hn = 0;          /* hufts used in space */
++  uIntf *v;             /* work area for huft_build */
++
++  /* allocate work area */
++  if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
++    return Z_MEM_ERROR;
++
++  /* build literal/length tree */
++  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
++  if (r != Z_OK || *bl == 0)
++  {
++    if (r == Z_DATA_ERROR)
++      z->msg = (char*)"oversubscribed literal/length tree";
++    else if (r != Z_MEM_ERROR)
++    {
++      z->msg = (char*)"incomplete literal/length tree";
++      r = Z_DATA_ERROR;
++    }
++    ZFREE(z, v);
++    return r;
++  }
++
++  /* build distance tree */
++  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
++  if (r != Z_OK || (*bd == 0 && nl > 257))
++  {
++    if (r == Z_DATA_ERROR)
++      z->msg = (char*)"oversubscribed distance tree";
++    else if (r == Z_BUF_ERROR) {
++#ifdef PKZIP_BUG_WORKAROUND
++      r = Z_OK;
++    }
++#else
++      z->msg = (char*)"incomplete distance tree";
++      r = Z_DATA_ERROR;
++    }
++    else if (r != Z_MEM_ERROR)
++    {
++      z->msg = (char*)"empty distance tree with lengths";
++      r = Z_DATA_ERROR;
++    }
++    ZFREE(z, v);
++    return r;
++#endif
++  }
++
++  /* done */
++  ZFREE(z, v);
++  return Z_OK;
++}
++
++
++/* build fixed tables only once--keep them here */
++#ifdef BUILDFIXED
++local int fixed_built = 0;
++#define FIXEDH 544      /* number of hufts used by fixed tables */
++local inflate_huft fixed_mem[FIXEDH];
++local uInt fixed_bl;
++local uInt fixed_bd;
++local inflate_huft *fixed_tl;
++local inflate_huft *fixed_td;
++#else
++#include "inffixed.h"
++#endif
++
++
++int inflate_trees_fixed(bl, bd, tl, td, z)
++uIntf *bl;               /* literal desired/actual bit depth */
++uIntf *bd;               /* distance desired/actual bit depth */
++inflate_huft * FAR *tl;  /* literal/length tree result */
++inflate_huft * FAR *td;  /* distance tree result */
++z_streamp z;             /* for memory allocation */
++{
++#ifdef BUILDFIXED
++  /* build fixed tables if not already */
++  if (!fixed_built)
++  {
++    int k;              /* temporary variable */
++    uInt f = 0;         /* number of hufts used in fixed_mem */
++    uIntf *c;           /* length list for huft_build */
++    uIntf *v;           /* work area for huft_build */
++
++    /* allocate memory */
++    if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
++      return Z_MEM_ERROR;
++    if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
++    {
++      ZFREE(z, c);
++      return Z_MEM_ERROR;
++    }
++
++    /* literal table */
++    for (k = 0; k < 144; k++)
++      c[k] = 8;
++    for (; k < 256; k++)
++      c[k] = 9;
++    for (; k < 280; k++)
++      c[k] = 7;
++    for (; k < 288; k++)
++      c[k] = 8;
++    fixed_bl = 9;
++    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
++               fixed_mem, &f, v);
++
++    /* distance table */
++    for (k = 0; k < 30; k++)
++      c[k] = 5;
++    fixed_bd = 5;
++    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
++               fixed_mem, &f, v);
++
++    /* done */
++    ZFREE(z, v);
++    ZFREE(z, c);
++    fixed_built = 1;
++  }
++#endif
++  *bl = fixed_bl;
++  *bd = fixed_bd;
++  *tl = fixed_tl;
++  *td = fixed_td;
++  return Z_OK;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/inftrees.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,63 @@
++/* inftrees.h -- header to use inftrees.c
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++/* Huffman code lookup table entry--this entry is four bytes for machines
++   that have 16-bit pointers (e.g. PC's in the small or medium model). */
++
++#ifndef _INFTREES_H
++#define _INFTREES_H
++
++typedef struct inflate_huft_s FAR inflate_huft;
++
++struct inflate_huft_s {
++  union {
++    struct {
++      Byte Exop;        /* number of extra bits or operation */
++      Byte Bits;        /* number of bits in this code or subcode */
++    } what;
++    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
++  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
++  uInt base;            /* literal, length base, distance base,
++                           or table offset */
++};
++
++/* Maximum size of dynamic tree.  The maximum found in a long but non-
++   exhaustive search was 1004 huft structures (850 for length/literals
++   and 154 for distances, the latter actually the result of an
++   exhaustive search).  The actual maximum is not known, but the
++   value below is more than safe. */
++#define MANY 1440
++
++extern int inflate_trees_bits OF((
++    uIntf *,                    /* 19 code lengths */
++    uIntf *,                    /* bits tree desired/actual depth */
++    inflate_huft * FAR *,       /* bits tree result */
++    inflate_huft *,             /* space for trees */
++    z_streamp));                /* for messages */
++
++extern int inflate_trees_dynamic OF((
++    uInt,                       /* number of literal/length codes */
++    uInt,                       /* number of distance codes */
++    uIntf *,                    /* that many (total) code lengths */
++    uIntf *,                    /* literal desired/actual bit depth */
++    uIntf *,                    /* distance desired/actual bit depth */
++    inflate_huft * FAR *,       /* literal/length tree result */
++    inflate_huft * FAR *,       /* distance tree result */
++    inflate_huft *,             /* space for trees */
++    z_streamp));                /* for messages */
++
++extern int inflate_trees_fixed OF((
++    uIntf *,                    /* literal desired/actual bit depth */
++    uIntf *,                    /* distance desired/actual bit depth */
++    inflate_huft * FAR *,       /* literal/length tree result */
++    inflate_huft * FAR *,       /* distance tree result */
++    z_streamp));                /* for memory allocation */
++
++#endif /* _INFTREES_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infutil.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,87 @@
++/* inflate_util.c -- data and routines common to blocks and codes
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++#include <zlib/zutil.h>
++#include "infblock.h"
++#include "inftrees.h"
++#include "infcodes.h"
++#include "infutil.h"
++
++struct inflate_codes_state {int dummy;}; /* for buggy compilers */
++
++/* And'ing with mask[n] masks the lower n bits */
++uInt inflate_mask[17] = {
++    0x0000,
++    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
++    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
++};
++
++
++/* copy as much as possible from the sliding window to the output area */
++int inflate_flush(s, z, r)
++inflate_blocks_statef *s;
++z_streamp z;
++int r;
++{
++  uInt n;
++  Bytef *p;
++  Bytef *q;
++
++  /* local copies of source and destination pointers */
++  p = z->next_out;
++  q = s->read;
++
++  /* compute number of bytes to copy as far as end of window */
++  n = (uInt)((q <= s->write ? s->write : s->end) - q);
++  if (n > z->avail_out) n = z->avail_out;
++  if (n && r == Z_BUF_ERROR) r = Z_OK;
++
++  /* update counters */
++  z->avail_out -= n;
++  z->total_out += n;
++
++  /* update check information */
++  if (s->checkfn != Z_NULL)
++    z->adler = s->check = (*s->checkfn)(s->check, q, n);
++
++  /* copy as far as end of window */
++  zmemcpy(p, q, n);
++  p += n;
++  q += n;
++
++  /* see if more to copy at beginning of window */
++  if (q == s->end)
++  {
++    /* wrap pointers */
++    q = s->window;
++    if (s->write == s->end)
++      s->write = s->window;
++
++    /* compute bytes to copy */
++    n = (uInt)(s->write - q);
++    if (n > z->avail_out) n = z->avail_out;
++    if (n && r == Z_BUF_ERROR) r = Z_OK;
++
++    /* update counters */
++    z->avail_out -= n;
++    z->total_out += n;
++
++    /* update check information */
++    if (s->checkfn != Z_NULL)
++      z->adler = s->check = (*s->checkfn)(s->check, q, n);
++
++    /* copy */
++    zmemcpy(p, q, n);
++    p += n;
++    q += n;
++  }
++
++  /* update pointers */
++  z->next_out = p;
++  s->read = q;
++
++  /* done */
++  return r;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/infutil.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,98 @@
++/* infutil.h -- types and macros common to blocks and codes
++ * Copyright (C) 1995-2002 Mark Adler
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++#ifndef _INFUTIL_H
++#define _INFUTIL_H
++
++typedef enum {
++      TYPE,     /* get type bits (3, including end bit) */
++      LENS,     /* get lengths for stored */
++      STORED,   /* processing stored block */
++      TABLE,    /* get table lengths */
++      BTREE,    /* get bit lengths tree for a dynamic block */
++      DTREE,    /* get length, distance trees for a dynamic block */
++      CODES,    /* processing fixed or dynamic block */
++      DRY,      /* output remaining window bytes */
++      DONE,     /* finished last block, done */
++      BAD}      /* got a data error--stuck here */
++inflate_block_mode;
++
++/* inflate blocks semi-private state */
++struct inflate_blocks_state {
++
++  /* mode */
++  inflate_block_mode  mode;     /* current inflate_block mode */
++
++  /* mode dependent information */
++  union {
++    uInt left;          /* if STORED, bytes left to copy */
++    struct {
++      uInt table;               /* table lengths (14 bits) */
++      uInt index;               /* index into blens (or border) */
++      uIntf *blens;             /* bit lengths of codes */
++      uInt bb;                  /* bit length tree depth */
++      inflate_huft *tb;         /* bit length decoding tree */
++    } trees;            /* if DTREE, decoding info for trees */
++    struct {
++      inflate_codes_statef 
++         *codes;
++    } decode;           /* if CODES, current state */
++  } sub;                /* submode */
++  uInt last;            /* true if this block is the last block */
++
++  /* mode independent information */
++  uInt bitk;            /* bits in bit buffer */
++  uLong bitb;           /* bit buffer */
++  inflate_huft *hufts;  /* single malloc for tree space */
++  Bytef *window;        /* sliding window */
++  Bytef *end;           /* one byte after sliding window */
++  Bytef *read;          /* window read pointer */
++  Bytef *write;         /* window write pointer */
++  check_func checkfn;   /* check function */
++  uLong check;          /* check on output */
++
++};
++
++
++/* defines for inflate input/output */
++/*   update pointers and return */
++#define UPDBITS {s->bitb=b;s->bitk=k;}
++#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
++#define UPDOUT {s->write=q;}
++#define UPDATE {UPDBITS UPDIN UPDOUT}
++#define LEAVE {UPDATE return inflate_flush(s,z,r);}
++/*   get bytes and bits */
++#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
++#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
++#define NEXTBYTE (n--,*p++)
++#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
++#define DUMPBITS(j) {b>>=(j);k-=(j);}
++/*   output bytes */
++#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
++#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
++#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
++#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
++#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
++#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
++/*   load local pointers */
++#define LOAD {LOADIN LOADOUT}
++
++/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
++extern uInt inflate_mask[17];
++
++/* copy as much as possible from the sliding window to the output area */
++extern int inflate_flush OF((
++    inflate_blocks_statef *,
++    z_streamp ,
++    int));
++
++struct internal_state      {int dummy;}; /* for buggy compilers */
++
++#endif /* _INFUTIL_H */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/initaddr.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,85 @@
++/*
++ * initialize address structure
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: initaddr.c,v 1.6 2004/07/10 07:43:47 mcr Exp $
++ */
++#include "openswan.h"
++
++err_t
++add_port(af, addr, port)
++int af;
++ip_address *addr;
++unsigned short port;
++{
++      switch (af) {
++      case AF_INET:
++              addr->u.v4.sin_port = port;
++              break;
++      case AF_INET6:
++              addr->u.v6.sin6_port = port;
++              break;
++      default:
++              return "unknown address family in add_port";
++              break;
++      }
++      return NULL;
++}
++
++/*
++ - initaddr - initialize ip_address from bytes
++ */
++err_t                         /* NULL for success, else string literal */
++initaddr(src, srclen, af, dst)
++const unsigned char *src;
++size_t srclen;
++int af;                               /* address family */
++ip_address *dst;
++{
++      switch (af) {
++      case AF_INET:
++              if (srclen != 4)
++                      return "IPv4 address must be exactly 4 bytes";
++#if !defined(__KERNEL__)
++              /* On BSD, the kernel compares the entire struct sockaddr when
++               * using bind(). However, this is as large as the largest
++               * address family, so the 'remainder' has to be 0. Linux
++               * compares interface addresses with the length of sa_len,
++               * instead of sizeof(struct sockaddr), so in that case padding
++               * is not needed.
++               *
++               * Patch by Stefan Arentz <stefan@soze.com>
++               */
++              bzero(&dst->u.v4, sizeof(dst->u.v4));
++#endif
++              dst->u.v4.sin_family = af;
++              dst->u.v4.sin_port = 0;
++              memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen);
++              break;
++      case AF_INET6:
++              if (srclen != 16)
++                      return "IPv6 address must be exactly 16 bytes";
++#if !defined(__KERNEL__)
++              bzero(&dst->u.v6, sizeof(dst->u.v6));
++#endif
++              dst->u.v6.sin6_family = af;
++              dst->u.v6.sin6_flowinfo = 0;            /* unused */
++              dst->u.v6.sin6_port = 0;
++              memcpy((char *)&dst->u.v6.sin6_addr, src, srclen);
++              break;
++      default:
++              return "unknown address family in initaddr";
++              break;
++      }
++      return NULL;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipcomp.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,694 @@
++/*
++ * IPCOMP zlib interface code.
++ * implementation of RFC 3173.
++ *
++ * Copyright (C) 2000  Svenning Soerensen <svenning@post5.tele.dk>
++ * Copyright (C) 2000, 2001  Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++/* SSS */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <asm/uaccess.h>
++#include <asm/checksum.h>
++
++#include <openswan.h>
++
++#include <net/ip.h>
++
++#include "openswan/ipsec_kern24.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipcomp.h"
++#include "zlib/zlib.h"
++#include "zlib/zutil.h"
++
++#include <openswan/pfkeyv2.h> /* SADB_X_CALG_DEFLATE */
++
++static
++struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask);
++
++static
++voidpf my_zcalloc(voidpf opaque, uInt items, uInt size)
++{
++      return (voidpf) kmalloc(items*size, GFP_ATOMIC);
++}
++
++static
++void my_zfree(voidpf opaque, voidpf address)
++{
++      kfree(address);
++}
++
++/* 
++ * We use this function because sometimes we want to pass a negative offset
++ * into skb_put(), this does not work on 64bit platforms because long to
++ * unsigned int casting.
++ */
++static inline unsigned char *
++safe_skb_put(struct sk_buff *skb, int extend)
++{
++        unsigned char *ptr;
++
++        if (extend>0) {
++                // increase the size of the packet
++                ptr = skb_put(skb, extend);
++        } else {
++                // shrink the size of the packet
++                ptr = skb_tail_pointer(skb);
++                skb_trim (skb, skb->len + extend);
++        }
++
++        return ptr;
++}
++
++struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
++{
++      struct iphdr *iph;
++      unsigned int iphlen, pyldsz, cpyldsz;
++      unsigned char *buffer;
++      z_stream zs;
++      int zresult;
++      
++      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                  "klips_debug:skb_compress: .\n");
++
++      if(skb == NULL) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "passed in NULL skb, returning ERROR.\n");
++              if(flags != NULL) {
++                      *flags |= IPCOMP_PARMERROR;
++              }
++              return skb;
++      }
++
++      if(ips == NULL) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n");
++              if(flags) {
++                      *flags |= IPCOMP_PARMERROR;
++              }
++              return skb;
++      }
++
++      if (flags == NULL) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "passed in NULL flags, returning ERROR.\n");
++              ipsec_kfree_skb(skb);
++              return NULL;
++      }
++      
++#ifdef NET_21
++      iph = ip_hdr(skb);
++#else /* NET_21 */
++      iph = skb->ip_hdr;
++#endif /* NET_21 */
++
++      switch (iph->protocol) {
++      case IPPROTO_COMP:
++      case IPPROTO_AH:
++      case IPPROTO_ESP:
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "skipping compression of packet with ip protocol %d.\n",
++                          iph->protocol);
++              *flags |= IPCOMP_UNCOMPRESSABLE;
++              return skb;
++      }
++      
++      /* Don't compress packets already fragmented */
++      if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "skipping compression of fragmented packet.\n");
++              *flags |= IPCOMP_UNCOMPRESSABLE;
++              return skb;
++      }
++      
++      iphlen = iph->ihl << 2;
++      pyldsz = ntohs(iph->tot_len) - iphlen;
++
++      /* Don't compress less than 90 bytes (rfc 2394) */
++      if (pyldsz < 90) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "skipping compression of tiny packet, len=%d.\n",
++                          pyldsz);
++              *flags |= IPCOMP_UNCOMPRESSABLE;
++              return skb;
++      }
++      
++      /* Adaptive decision */
++      if (ips->ips_comp_adapt_skip) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_compress: "
++                          "skipping compression: ips_comp_adapt_skip=%d.\n",
++                          ips->ips_comp_adapt_skip);
++              ips->ips_comp_adapt_skip--;
++              *flags |= IPCOMP_UNCOMPRESSABLE;
++              return skb;
++      }
++
++      zs.zalloc = my_zcalloc;
++      zs.zfree = my_zfree;
++      zs.opaque = 0;
++      
++      /* We want to use deflateInit2 because we don't want the adler
++         header. */
++      zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11,
++                             DEF_MEM_LEVEL,  Z_DEFAULT_STRATEGY);
++      if (zresult != Z_OK) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_compress: "
++                          "deflateInit2() returned error %d (%s), "
++                          "skipping compression.\n",
++                          zresult,
++                          zs.msg ? zs.msg : zError(zresult));
++              *flags |= IPCOMP_COMPRESSIONERROR;
++              return skb;
++      }
++      
++
++      /* Max output size. Result should be max this size.
++       * Implementation specific tweak:
++       * If it's not at least 32 bytes and 6.25% smaller than
++       * the original packet, it's probably not worth wasting
++       * the receiver's CPU cycles decompressing it.
++       * Your mileage may vary.
++       */
++      cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4);
++
++      buffer = kmalloc(cpyldsz, GFP_ATOMIC);
++      if (!buffer) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_compress: "
++                          "unable to kmalloc(%d, GFP_ATOMIC), "
++                          "skipping compression.\n",
++                          cpyldsz);
++              *flags |= IPCOMP_COMPRESSIONERROR;
++              deflateEnd(&zs);
++              return skb;
++      }
++      
++#ifdef CONFIG_KLIPS_DEBUG
++      if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
++              __u8 *c;
++
++              c = (__u8*)iph + iphlen;
++              ipsec_dmp_block("compress before", c, pyldsz);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      zs.next_in = (char *) iph + iphlen; /* start of payload */
++      zs.avail_in = pyldsz;
++      zs.next_out = buffer;     /* start of compressed payload */
++      zs.avail_out = cpyldsz;
++      
++      /* Finish compression in one step */
++      zresult = deflate(&zs, Z_FINISH);
++
++      /* Free all dynamically allocated buffers */
++      deflateEnd(&zs);
++      if (zresult != Z_STREAM_END) {
++              *flags |= IPCOMP_UNCOMPRESSABLE;
++              kfree(buffer);
++
++              /* Adjust adaptive counters */
++              if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) {
++                      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                                  "klips_debug:skb_compress: "
++                                  "first %d packets didn't compress, "
++                                  "skipping next %d\n",
++                                  IPCOMP_ADAPT_INITIAL_TRIES,
++                                  IPCOMP_ADAPT_INITIAL_SKIP);
++                      ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP;
++              }
++              else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) {
++                      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                                  "klips_debug:skb_compress: "
++                                  "next %d packets didn't compress, "
++                                  "skipping next %d\n",
++                                  IPCOMP_ADAPT_SUBSEQ_TRIES,
++                                  IPCOMP_ADAPT_SUBSEQ_SKIP);
++                      ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP;
++                      ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES;
++              }
++
++              return skb;
++      }
++      
++      /* resulting compressed size */
++      cpyldsz -= zs.avail_out;
++      
++      /* Insert IPCOMP header */
++      ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol;
++      ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0;
++      /* use the bottom 16 bits of the spi for the cpi.  The top 16 bits are
++         for internal reference only. */
++      ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff));
++      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                  "klips_debug:skb_compress: "
++                  "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n",
++                  ntohl(ips->ips_said.spi),
++                  ntohl(ips->ips_said.spi) & 0x0000ffff,
++                  ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi),
++                  pyldsz,
++                  cpyldsz);
++      
++      /* Update IP header */
++      iph->protocol = IPPROTO_COMP;
++      iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz);
++#if 1 /* XXX checksum is done by ipsec_tunnel ? */
++      iph->check = 0;
++      iph->check = ip_fast_csum((char *) iph, iph->ihl);
++#endif
++      
++      /* Copy compressed payload */
++      memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr),
++             buffer,
++             cpyldsz);
++      kfree(buffer);
++      
++      /* Update skb length/tail by "unputting" the shrinkage */
++        safe_skb_put (skb, cpyldsz + sizeof(struct ipcomphdr) - pyldsz);
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
++              __u8 *c;
++              
++              c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr);
++              ipsec_dmp_block("compress result", c, cpyldsz);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      
++      ips->ips_comp_adapt_skip = 0;
++      ips->ips_comp_adapt_tries = 0;
++      
++      return skb;
++}
++
++struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
++{
++      struct sk_buff *nskb = NULL;
++
++      /* original ip header */
++      struct iphdr *oiph, *iph;
++      unsigned int iphlen, pyldsz, cpyldsz;
++      z_stream zs;
++      int zresult;
++
++      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                  "klips_debug:skb_decompress: .\n");
++
++      if(!skb) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "passed in NULL skb, returning ERROR.\n");
++              if (flags) *flags |= IPCOMP_PARMERROR;
++              return skb;
++      }
++
++      if(!ips && sysctl_ipsec_inbound_policy_check) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n");
++              if (flags) *flags |= IPCOMP_PARMERROR;
++              return skb;
++      }
++
++      if (!flags) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "passed in NULL flags, returning ERROR.\n");
++              ipsec_kfree_skb(skb);
++              return NULL;
++      }
++      
++#ifdef NET_21
++      oiph = ip_hdr(skb);
++#else /* NET_21 */
++      oiph = skb->ip_hdr;
++#endif /* NET_21 */
++      
++      iphlen = oiph->ihl << 2;
++      
++      if (oiph->protocol != IPPROTO_COMP) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "called with non-IPCOMP packet (protocol=%d),"
++                          "skipping decompression.\n",
++                          oiph->protocol);
++              *flags |= IPCOMP_PARMERROR;
++              return skb;
++      }
++      
++      if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0)
++           || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi
++              != htons(SADB_X_CALG_DEFLATE))
++               && sysctl_ipsec_inbound_policy_check
++               && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "called with incompatible IPCOMP packet (flags=%d, "
++                          "cpi=%d), ips-compalg=%d, skipping decompression.\n",
++                          ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags),
++                          ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi),
++                          ips ? ips->ips_encalg : 0);
++              *flags |= IPCOMP_PARMERROR;
++              
++              return skb;
++      }
++      
++      if (ntohs(oiph->frag_off) & ~0x4000) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "called with fragmented IPCOMP packet, "
++                          "skipping decompression.\n");
++              *flags |= IPCOMP_PARMERROR;
++              return skb;
++      }
++      
++      /* original compressed payload size */
++      cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr);
++
++      zs.zalloc = my_zcalloc;
++      zs.zfree = my_zfree;
++      zs.opaque = 0;
++      
++      zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr);
++      zs.avail_in = cpyldsz;
++      
++      /* Maybe we should be a bit conservative about memory
++         requirements and use inflateInit2 */
++      /* Beware, that this might make us unable to decompress packets
++         from other implementations - HINT: check PGPnet source code */
++      /* We want to use inflateInit2 because we don't want the adler
++         header. */
++      zresult = inflateInit2(&zs, -15); 
++      if (zresult != Z_OK) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "inflateInit2() returned error %d (%s), "
++                          "skipping decompression.\n",
++                          zresult,
++                          zs.msg ? zs.msg : zError(zresult));
++              *flags |= IPCOMP_DECOMPRESSIONERROR;
++
++              return skb;
++      }
++      
++      /* We have no way of knowing the exact length of the resulting
++         decompressed output before we have actually done the decompression.
++         For now, we guess that the packet will not be bigger than the
++         attached ipsec device's mtu or 16260, whichever is biggest.
++         This may be wrong, since the sender's mtu may be bigger yet.
++         XXX This must be dealt with later XXX
++      */
++      
++      /* max payload size */
++      pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu)
++                        : (65520 - iphlen);
++      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                  "klips_debug:skb_decompress: "
++                  "max payload size: %d\n", pyldsz);
++      
++      while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) && 
++             (nskb = skb_copy_ipcomp(skb,
++                                     pyldsz - cpyldsz - sizeof(struct ipcomphdr),
++                                     GFP_ATOMIC)) == NULL) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), "
++                          "trying with less payload size.\n",
++                          (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr)));
++              pyldsz >>=1;
++      }
++      
++      if (!nskb) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "unable to allocate memory, dropping packet.\n");
++              *flags |= IPCOMP_DECOMPRESSIONERROR;
++              inflateEnd(&zs);
++
++              return skb;
++      }
++      
++#ifdef CONFIG_KLIPS_DEBUG
++      if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
++              __u8 *c;
++              
++              c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr);
++              ipsec_dmp_block("decompress before", c, cpyldsz);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++#ifdef NET_21
++      iph = ip_hdr(nskb);
++#else /* NET_21 */
++      iph = nskb->ip_hdr;
++#endif /* NET_21 */
++      zs.next_out = (char *)iph + iphlen;
++      zs.avail_out = pyldsz;
++
++      zresult = inflate(&zs, Z_SYNC_FLUSH);
++
++      /* work around a bug in zlib, which sometimes wants to taste an extra
++       * byte when being used in the (undocumented) raw deflate mode.
++       */
++      if (zresult == Z_OK && !zs.avail_in && zs.avail_out) {
++              __u8 zerostuff = 0;
++              
++              zs.next_in = &zerostuff;
++              zs.avail_in = 1;
++              zresult = inflate(&zs, Z_FINISH);
++      }
++
++      inflateEnd(&zs);
++      if (zresult != Z_STREAM_END) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_error:skb_decompress: "
++                          "inflate() returned error %d (%s), "
++                          "skipping decompression.\n",
++                          zresult,
++                          zs.msg ? zs.msg : zError(zresult));
++              *flags |= IPCOMP_DECOMPRESSIONERROR;
++              ipsec_kfree_skb(nskb);
++
++              return skb;
++      }
++      
++      /* Update IP header */
++      /* resulting decompressed size */
++      pyldsz -= zs.avail_out;
++      iph->tot_len = htons(iphlen + pyldsz);
++      iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh;
++      KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                  "klips_debug:skb_decompress: "
++                  "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n",
++                  ips ? ntohl(ips->ips_said.spi) : 0,
++                  ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0,
++                  ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi),
++                  cpyldsz,
++                  pyldsz,
++                  iph->protocol);
++      
++#if 1 /* XXX checksum is done by ipsec_rcv ? */
++      iph->check = 0;
++      iph->check = ip_fast_csum((char*) iph, iph->ihl);
++#endif
++      
++      /* Update skb length/tail by "unputting" the unused data area */
++      safe_skb_put(nskb, -zs.avail_out);
++      
++      ipsec_kfree_skb(skb);
++      
++      if (iph->protocol == IPPROTO_COMP)
++      {
++#ifdef CONFIG_KLIPS_DEBUG
++              if(sysctl_ipsec_debug_ipcomp)
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_decompress: "
++                          "Eh? inner packet is also compressed, dropping.\n");
++#endif /* CONFIG_KLIPS_DEBUG */
++              
++              ipsec_kfree_skb(nskb);
++              return NULL;
++      }
++      
++#ifdef CONFIG_KLIPS_DEBUG
++      if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
++              __u8 *c;
++              
++              c = (__u8*)iph + iphlen;
++              ipsec_dmp_block("decompress result", c, pyldsz);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      
++      return nskb;
++}
++
++
++/* this is derived from skb_copy() in linux 2.2.14 */
++/* May be incompatible with other kernel versions!! */
++static
++struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask)
++{
++        struct sk_buff *n;
++      struct iphdr *iph;
++        unsigned long offset;
++        unsigned int iphlen;
++      
++      if(!skb) {
++              KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
++                          "klips_debug:skb_copy_ipcomp: "
++                          "passed in NULL skb, returning NULL.\n");
++              return NULL;
++      }
++
++        /*
++         *      Allocate the copy buffer
++         */
++      
++#ifdef NET_21
++      iph = ip_hdr(skb);
++#else /* NET_21 */
++      iph = skb->ip_hdr;
++#endif /* NET_21 */
++        if (!iph) return NULL;
++        iphlen = iph->ihl << 2;
++
++        n=alloc_skb(skb_end_pointer(skb) - skb->head + data_growth, gfp_mask);
++        if(n==NULL)
++                return NULL;
++      
++        /*
++         *      Shift between the two data areas in bytes
++         */
++      
++        offset=n->head-skb->head;
++
++        /* Set the data pointer */
++        skb_reserve(n,skb->data-skb->head);
++        /* Set the tail pointer and length */
++        safe_skb_put(n,skb->len+data_growth);
++        /* Copy the bytes up to and including the ip header */
++        memcpy(n->head,
++             skb->head,
++             ((char *)iph - (char *)skb->head) + iphlen);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++        n->list=NULL;
++#endif
++      n->next=NULL;
++      n->prev=NULL;
++        n->sk=NULL;
++        n->dev=skb->dev;
++      if (skb_transport_header(skb))
++              skb_set_transport_header(n, offset);
++        n->protocol=skb->protocol;
++#ifdef NET_21
++        n->csum = 0;
++        n->priority=skb->priority;
++        n->dst=dst_clone(skb->dst);
++        skb_set_network_header(n, offset);
++#ifndef NETDEV_23
++        n->is_clone=0;
++#endif /* NETDEV_23 */
++        atomic_set(&n->users, 1);
++        n->destructor = NULL;
++#ifdef HAVE_SOCK_SECURITY
++        n->security=skb->security;
++#endif
++        memcpy(n->cb, skb->cb, sizeof(skb->cb));
++#ifdef CONFIG_IP_FIREWALL
++        n->fwmark = skb->fwmark;
++#endif
++#else /* NET_21 */
++      n->link3=NULL;
++      n->when=skb->when;
++      n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
++      n->saddr=skb->saddr;
++      n->daddr=skb->daddr;
++      n->raddr=skb->raddr;
++      n->seq=skb->seq;
++      n->end_seq=skb->end_seq;
++      n->ack_seq=skb->ack_seq;
++      n->acked=skb->acked;
++      n->free=1;
++      n->arp=skb->arp;
++      n->tries=0;
++      n->lock=0;
++      n->users=0;
++      memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
++#endif /* NET_21 */
++      if (skb_mac_header(skb))
++              skb_set_mac_header(n, offset);
++#ifndef NETDEV_23
++      n->used=skb->used;
++#endif /* !NETDEV_23 */
++        n->pkt_type=skb->pkt_type;
++#ifndef NETDEV_23
++      n->pkt_bridged=skb->pkt_bridged;
++#endif /* NETDEV_23 */
++      n->ip_summed=0;
++#ifdef HAVE_TSTAMP
++      n->tstamp = skb->tstamp;
++#else
++        n->stamp=skb->stamp;
++#endif
++#ifndef NETDEV_23 /* this seems to have been removed in 2.4 */
++#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
++        n->shapelatency=skb->shapelatency;       /* Latency on frame */
++        n->shapeclock=skb->shapeclock;           /* Time it should go out */
++        n->shapelen=skb->shapelen;               /* Frame length in clocks */
++        n->shapestamp=skb->shapestamp;           /* Stamp for shaper    */
++        n->shapepend=skb->shapepend;             /* Pending */
++#endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */
++#endif /* NETDEV_23 */
++
++        return n;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_ah.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,369 @@
++/*
++ * processing code for AH
++ * Copyright (C) 2003-2004   Michael Richardson <mcr@xelerance.com>
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>  /* struct device, and other headers */
++#include <linux/etherdevice.h>        /* eth_type_trans */
++#include <linux/ip.h>         /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++#include <net/protocol.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h" 
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_auth.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_proto.h"
++
++#include "ipsec_ocf.h"
++
++__u32 zeroes[AH_AMAX];
++
++enum ipsec_rcv_value
++ipsec_rcv_ah_checks(struct ipsec_rcv_state *irs,
++                  struct sk_buff *skb)
++{
++      int ahminlen;
++
++      ahminlen = irs->hard_header_len + sizeof(struct iphdr);
++
++      /* take care not to deref this pointer until we check the minlen though */
++      irs->protostuff.ahstuff.ahp = (struct ahhdr *)skb_transport_header(skb);
++
++      if((skb->len < ahminlen+sizeof(struct ahhdr)) ||
++         (skb->len < ahminlen+(irs->protostuff.ahstuff.ahp->ah_hl << 2))) {
++              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                          "klips_debug:ipsec_rcv: "
++                          "runt ah packet of skb->len=%d received from %s, dropped.\n",
++                          skb->len,
++                          irs->ipsaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADLEN;
++      }
++
++      irs->said.spi = irs->protostuff.ahstuff.ahp->ah_spi;
++
++      /* XXX we only support the one 12-byte authenticator for now */
++      if(irs->protostuff.ahstuff.ahp->ah_hl != ((AHHMAC_HASHLEN+AHHMAC_RPLLEN) >> 2)) {
++              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                          "klips_debug:ipsec_rcv: "
++                          "bad authenticator length %ld, expected %lu from %s.\n",
++                          (long)(irs->protostuff.ahstuff.ahp->ah_hl << 2),
++                          (unsigned long) sizeof(struct ahhdr),
++                          irs->ipsaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADLEN;
++      }
++
++      return IPSEC_RCV_OK;
++}
++
++
++enum ipsec_rcv_value
++ipsec_rcv_ah_setup_auth(struct ipsec_rcv_state *irs,
++                      struct sk_buff *skb,
++                      __u32          *replay,
++                      unsigned char **authenticator)
++{
++      struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
++
++      *replay = ntohl(ahp->ah_rpl);
++      *authenticator = ahp->ah_data;
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_rcv_value
++ipsec_rcv_ah_authcalc(struct ipsec_rcv_state *irs,
++                    struct sk_buff *skb)
++{
++      struct auth_alg *aa;
++      struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
++      union {
++              MD5_CTX         md5;
++              SHA1_CTX        sha1;
++      } tctx;
++      struct iphdr ipo;
++      int ahhlen;
++
++#ifdef CONFIG_KLIPS_OCF
++      if (irs->ipsp->ocf_in_use)
++              return(ipsec_ocf_rcv(irs));
++#endif
++
++      aa = irs->authfuncs;
++
++      /* copy the initialized keying material */
++      memcpy(&tctx, irs->ictx, irs->ictx_len);
++
++      ipo = *irs->ipp;
++      ipo.tos = 0;    /* mutable RFC 2402 3.3.3.1.1.1 */
++      ipo.frag_off = 0;
++      ipo.ttl = 0;
++      ipo.check = 0;
++
++
++      /* do the sanitized header */
++      (*aa->update)((void*)&tctx, (caddr_t)&ipo, sizeof(struct iphdr));
++
++      /* XXX we didn't do the options here! */
++
++      /* now do the AH header itself */
++      ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
++      (*aa->update)((void*)&tctx, (caddr_t)ahp,  ahhlen - AHHMAC_HASHLEN);
++
++      /* now, do some zeroes */
++      (*aa->update)((void*)&tctx, (caddr_t)zeroes,  AHHMAC_HASHLEN);
++
++      /* finally, do the packet contents themselves */
++      (*aa->update)((void*)&tctx,
++                    (caddr_t)skb_transport_header(skb) + ahhlen,
++                    skb->len - ahhlen);
++
++      (*aa->final)(irs->hash, (void *)&tctx);
++
++      memcpy(&tctx, irs->octx, irs->octx_len);
++
++      (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
++      (*aa->final)(irs->hash, (void *)&tctx);
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_rcv_value
++ipsec_rcv_ah_decap(struct ipsec_rcv_state *irs)
++{
++      struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
++      struct sk_buff *skb;
++      int ahhlen;
++
++      skb=irs->skb;
++
++      ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
++
++      irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - ahhlen);
++      irs->next_header  = ahp->ah_nh;
++
++      /*
++       * move the IP header forward by the size of the AH header, which
++       * will remove the the AH header from the packet.
++       */
++      memmove((void *)(skb_network_header(skb) + ahhlen),
++              (void *)(skb_network_header(skb)), irs->iphlen);
++
++      ipsec_rcv_dmp("ah postmove", skb->data, skb->len);
++
++      /* skb_pull below, will move up by ahhlen */
++
++      /* XXX not clear how this can happen, as the message indicates */
++      if(skb->len < ahhlen) {
++              printk(KERN_WARNING
++                     "klips_error:ipsec_rcv: "
++                     "tried to skb_pull ahhlen=%d, %d available.  This should never happen, please report.\n",
++                     ahhlen,
++                     (int)(skb->len));
++              return IPSEC_RCV_DECAPFAIL;
++      }
++      skb_pull(skb, ahhlen);
++
++      skb_set_network_header(skb, ahhlen);
++      irs->ipp = ip_hdr(skb);
++
++      ipsec_rcv_dmp("ah postpull", (void *)ip_hdr(skb), skb->len);
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_xmit_value
++ipsec_xmit_ah_setup(struct ipsec_xmit_state *ixs)
++{
++  struct iphdr ipo;
++  struct ahhdr *ahp;
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++  __u8 hash[AH_AMAX];
++  union {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++    MD5_CTX md5;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++    SHA1_CTX sha1;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++  } tctx;
++#endif
++  unsigned char *dat = (unsigned char *)ixs->iph;
++
++  ahp = (struct ahhdr *)(dat + ixs->iphlen);
++  ahp->ah_spi = ixs->ipsp->ips_said.spi;
++  ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
++  ahp->ah_rv = 0;
++  ahp->ah_nh = ixs->iph->protocol;
++  ahp->ah_hl = (sizeof(struct ahhdr) >> 2) - sizeof(__u64)/sizeof(__u32);
++  ixs->iph->protocol = IPPROTO_AH;
++  ipsec_xmit_dmp("ahp", (char*)ahp, sizeof(*ahp));
++  
++  ipo = *ixs->iph;
++  ipo.tos = 0;
++  ipo.frag_off = 0;
++  ipo.ttl = 0;
++  ipo.check = 0;
++  ipsec_xmit_dmp("ipo", (char*)&ipo, sizeof(ipo));
++  
++  switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++  case AH_MD5:
++    tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++    ipsec_xmit_dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
++    ipsec_xmit_dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, (unsigned char *)ahp,
++            sizeof(struct ahhdr) - sizeof(ahp->ah_data));
++    ipsec_xmit_dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++    ipsec_xmit_dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5,  dat + ixs->iphlen + sizeof(struct ahhdr),
++            ixs->skb->len - ixs->iphlen - sizeof(struct ahhdr));
++    ipsec_xmit_dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Final(hash, &tctx.md5);
++    ipsec_xmit_dmp("ictx hash", (char*)&hash, sizeof(hash));
++    tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
++    ipsec_xmit_dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
++    ipsec_xmit_dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Final(hash, &tctx.md5);
++    ipsec_xmit_dmp("octx hash", (char*)&hash, sizeof(hash));
++    
++    memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
++    
++    /* paranoid */
++    memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
++    memset((caddr_t)hash, 0, sizeof(*hash));
++    break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++  case AH_SHA:
++    tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++    SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
++    SHA1Update(&tctx.sha1, (unsigned char *)ahp, sizeof(struct ahhdr) - sizeof(ahp->ah_data));
++    SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++    SHA1Update(&tctx.sha1, dat + ixs->iphlen + sizeof(struct ahhdr),
++             ixs->skb->len - ixs->iphlen - sizeof(struct ahhdr));
++    SHA1Final(hash, &tctx.sha1);
++    tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
++    SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++    SHA1Final(hash, &tctx.sha1);
++    
++    memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
++    
++    /* paranoid */
++    memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
++    memset((caddr_t)hash, 0, sizeof(*hash));
++    break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++  default:
++    ixs->stats->tx_errors++;
++    return IPSEC_XMIT_AH_BADALG;
++  }
++#ifdef NET_21
++  skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ahp));
++#endif /* NET_21 */
++
++  return IPSEC_XMIT_OK;
++}
++
++struct xform_functions ah_xform_funcs[]={
++      {
++              protocol:           IPPROTO_AH,
++              rcv_checks:         ipsec_rcv_ah_checks,
++              rcv_setup_auth:     ipsec_rcv_ah_setup_auth,
++              rcv_calc_auth:      ipsec_rcv_ah_authcalc,
++              rcv_decrypt:        ipsec_rcv_ah_decap,
++
++              xmit_setup:         ipsec_xmit_ah_setup,
++              xmit_headroom:      sizeof(struct ahhdr),
++              xmit_needtailroom:  0,
++      },
++};
++
++
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++#ifdef NET_26
++struct inet_protocol ah_protocol = {
++  .handler = ipsec_rcv,
++  .no_policy = 1,
++};
++#else
++struct inet_protocol ah_protocol =
++{
++      ipsec_rcv,                              /* AH handler */
++      NULL,                           /* TUNNEL error control */
++#ifdef NETDEV_25
++      1,                              /* no policy */
++#else
++      0,                              /* next */
++      IPPROTO_AH,                     /* protocol ID */
++      0,                              /* copy */
++      NULL,                           /* data */
++      "AH"                            /* name */
++#endif
++};
++#endif /* NET_26 */
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_alg.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1045 @@
++/*
++ * Modular extensions service and registration functions
++ *
++ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ * 
++ * Version: 0.8.1
++ *
++ * ipsec_alg.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/in.h>
++#include <linux/types.h>
++#include <linux/string.h>     /* memcmp() */
++#include <linux/random.h>     /* get_random_bytes() */
++#include <linux/errno.h>  /* error codes */
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include "openswan/ipsec_param.h"
++#include <openswan.h>
++#include "openswan/ipsec_sa.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h"
++#if defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH)
++# include "openswan/ipsec_ah.h"
++#endif /* defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH) */
++#ifdef CONFIG_KLIPS_ESP
++# include "openswan/ipsec_esp.h"
++#endif /* !CONFIG_KLIPS_ESP */
++#ifdef CONFIG_KLIPS_IPCOMP
++# include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_COMP */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_alg.h"
++#include "openswan/ipsec_proto.h"
++
++#if K_SADB_EALG_MAX < 255
++#warning Compiling with limited ESP support ( K_SADB_EALG_MAX < 256 )
++#endif
++
++static rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;
++#define IPSEC_ALG_HASHSZ      16      /* must be power of 2, even 2^0=1 */
++static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];
++
++/*    Old gcc's will fail here        */
++#define barf_out(fmt, args...)  do { struct ipsec_alg *ixtc = (struct ipsec_alg *)ixt; printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixtc->ixt_name , ## args) \
++      ; goto out; } while(0)
++
++#ifdef NET_26
++/* 
++ *    Must be already protected by lock 
++ */
++static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt)
++{
++#ifdef MODULE
++      if (ixt->ixt_module)
++              try_module_get(ixt->ixt_module);
++#endif
++      atomic_inc(&ixt->ixt_refcnt);
++}
++static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
++      atomic_dec(&ixt->ixt_refcnt);
++#ifdef MODULE
++      if (ixt->ixt_module)
++              module_put(ixt->ixt_module);
++#endif
++}
++
++#else
++
++/* 
++ *    Must be already protected by lock 
++ */
++static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {
++#ifdef MODULE
++      if (ixt->ixt_module) {
++              __MOD_INC_USE_COUNT(ixt->ixt_module);
++      }
++#endif
++      atomic_inc(&ixt->ixt_refcnt);
++}
++static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
++      atomic_dec(&ixt->ixt_refcnt);
++#ifdef MODULE
++      if (ixt->ixt_module)
++              __MOD_DEC_USE_COUNT(ixt->ixt_module);
++#endif
++}
++#endif
++
++/*
++ *    simple hash function, optimized for 0-hash (1 list) special
++ *    case
++ */
++#if IPSEC_ALG_HASHSZ > 1
++static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {
++      return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));
++}
++#else
++#define ipsec_alg_hashfn(x,y) (0)
++#endif
++
++/*****************************************************************
++ *
++ *    INTERNAL table handling: insert, delete, find
++ *
++ *****************************************************************/
++
++/*    
++ *    hash table initialization, called from ipsec_alg_init()
++ */
++static void ipsec_alg_hash_init(void) {
++      struct list_head *head = ipsec_alg_hash_table;
++      int i = IPSEC_ALG_HASHSZ;
++      do {
++              INIT_LIST_HEAD(head);
++              head++;
++              i--;
++      } while (i);
++}
++/*
++ *    hash list lookup by {alg_type, alg_id} and table head,
++ *    must be already protected by lock
++ */
++static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {
++      struct list_head *p;
++      struct ipsec_alg *ixt=NULL;
++      for (p=head->next; p!=head; p=p->next) {
++              ixt = list_entry(p, struct ipsec_alg, ixt_list);
++              if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {
++                      goto out;
++              }
++      }
++      ixt=NULL;
++out:
++      return ixt;
++}
++/*
++ *    inserts (in front) a new entry in hash table, 
++ *    called from ipsec_alg_register() when new algorithm is registered.
++ */
++static int ipsec_alg_insert(struct ipsec_alg *ixt) {
++      int ret=-EINVAL;
++      unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);
++      struct list_head *head= ipsec_alg_hash_table + hashval;
++      struct ipsec_alg *ixt_cur;
++
++      /*      new element must be virgin ... */
++      if (ixt->ixt_list.next != &ixt->ixt_list || 
++              ixt->ixt_list.prev != &ixt->ixt_list) {
++              printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" "
++                              "list head not initialized\n",
++                              ixt->ixt_name);
++              return ret;
++      }
++      write_lock_bh(&ipsec_alg_lock);
++
++      ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head);
++
++      /* if previous (current) ipsec_alg found check excl flag of _anyone_ */
++      if (ixt_cur
++          && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL)) {
++        barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. "
++                 "Not loaded (ret=%d).\n",
++                 ixt->ixt_alg_type,
++                 ixt->ixt_alg_id, ret=-EEXIST);
++      }
++      list_add(&ixt->ixt_list, head);
++      ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED;
++      ret=0;
++out:
++      write_unlock_bh(&ipsec_alg_lock);
++      return ret;
++}
++
++/*
++ *    deletes an existing entry in hash table, 
++ *    called from ipsec_alg_unregister() when algorithm is unregistered.
++ */
++static int ipsec_alg_delete(struct ipsec_alg *ixt) {
++      write_lock_bh(&ipsec_alg_lock);
++      list_del(&ixt->ixt_list);
++      write_unlock_bh(&ipsec_alg_lock);
++      return 0;
++}
++
++/*
++ *    here @user context (read-only when @kernel bh context) 
++ *    -> no bh disabling
++ *
++ *    called from ipsec_sa_init() -> ipsec_alg_sa_init()
++ */
++static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id)
++{
++      unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);
++      struct list_head *head= ipsec_alg_hash_table + hashval;
++      struct ipsec_alg *ixt;
++
++      read_lock(&ipsec_alg_lock);
++      ixt=__ipsec_alg_find(alg_type, alg_id, head);
++      if (ixt) __ipsec_alg_usage_inc(ixt);
++      read_unlock(&ipsec_alg_lock);
++
++      return ixt;
++}
++
++static void ipsec_alg_put(struct ipsec_alg *ixt) {
++      __ipsec_alg_usage_dec((struct ipsec_alg *)ixt);
++}
++
++/*****************************************************************
++ *
++ *    INTERFACE for ENC services: key creation, encrypt function
++ *
++ *****************************************************************/
++
++/*
++ *    main encrypt service entry point
++ *    called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and
++ *    ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT
++ */
++int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat,
++                        int ilen, __u8 * iv, int encrypt)
++{
++      int ret;
++      struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
++#ifdef CONFIG_KLIPS_DEBUG
++      int debug_flag = (encrypt==IPSEC_ALG_ENCRYPT ?
++                        debug_tunnel : debug_rcv);
++#endif
++
++      KLIPS_PRINT(debug_flag,
++                  "klips_debug:ipsec_alg_esp_encrypt: "
++                  "entering with encalg=%d, ixt_e=%p\n",
++                  sa_p->ips_encalg, ixt_e);
++      if (ixt_e == NULL) {
++        KLIPS_ERROR(debug_flag,
++                    "klips_debug:ipsec_alg_esp_encrypt: "
++                    "NULL ipsec_alg_enc object\n");
++              return -1;
++      }
++      KLIPS_PRINT(debug_flag,
++                  "klips_debug:ipsec_alg_esp_encrypt: "
++                  "calling cbc_encrypt encalg=%d "
++                  "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",
++                      sa_p->ips_encalg, 
++                      sa_p->ips_key_e, idat, ilen, iv, encrypt);
++      ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat,
++                                   ilen, iv, encrypt);
++      KLIPS_PRINT(debug_flag,
++                  "klips_debug:ipsec_alg_esp_encrypt: "
++                  "returned ret=%d\n",
++                  ret);
++      return ret;
++}
++
++/*
++ *    encryption key context creation function
++ *    called from pfkey_v2_parser.c:pfkey_ips_init() 
++ */
++int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {
++      int ret=-EINVAL;
++      int keyminbits, keymaxbits;
++      caddr_t ekp;
++      struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:ipsec_alg_enc_key_create: "
++                  "entering with encalg=%d ixt_e=%p\n",
++                  sa_p->ips_encalg, ixt_e);
++      if (!ixt_e) {
++              KLIPS_ERROR(debug_pfkey,
++                          "klips_debug:ipsec_alg_enc_key_create: "
++                          "NULL ipsec_alg_enc object\n");
++              return -EPROTO;
++      }
++
++      /* 
++       * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo 
++       */
++      switch(ixt_e->ixt_common.ixt_support.ias_id) {
++              case ESP_3DES:
++                      keyminbits=keymaxbits=192;break;
++              case ESP_DES:
++                      keyminbits=keymaxbits=64;break;
++              default:
++                      keyminbits=ixt_e->ixt_common.ixt_support.ias_keyminbits;
++                      keymaxbits=ixt_e->ixt_common.ixt_support.ias_keymaxbits;
++      }
++      if(sa_p->ips_key_bits_e<keyminbits || 
++                      sa_p->ips_key_bits_e>keymaxbits) {
++              KLIPS_PRINT(debug_pfkey,
++                              "klips_debug:ipsec_alg_enc_key_create: "
++                              "incorrect encryption key size for id=%d: %d bits -- "
++                              "must be between %d,%d bits\n" /*octets (bytes)\n"*/,
++                              ixt_e->ixt_common.ixt_support.ias_id,
++                              sa_p->ips_key_bits_e, keyminbits, keymaxbits);
++              ret=-EINVAL;
++              goto ixt_out;
++      }
++      /* save encryption key pointer */
++      ekp = sa_p->ips_key_e;
++
++
++      if (ixt_e->ixt_e_new_key) {
++              sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e,
++                              ekp, sa_p->ips_key_bits_e/8);
++              ret =  (sa_p->ips_key_e)? 0 : -EINVAL;
++      } else {
++              if((sa_p->ips_key_e = (caddr_t)
++                  kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
++                          GFP_ATOMIC)) == NULL) {
++                      ret=-ENOMEM;
++                      goto ixt_out;
++              }
++              /* zero-out key_e */
++              memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);
++
++              /* I cast here to allow more decoupling in alg module */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_alg_enc_key_create: about to call:"
++                                  "set_key(key_e=%p, ekp=%p, key_size=%d)\n",
++                                  (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
++              ret = ixt_e->ixt_e_set_key(ixt_e, (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
++      }
++      /* paranoid */
++      memset(ekp, 0, sa_p->ips_key_bits_e/8);
++      kfree(ekp);
++ixt_out:
++      return ret;
++}
++
++/***************************************************************
++ *
++ *    INTERFACE for AUTH services: key creation, hash functions
++ *
++ ***************************************************************/
++
++/*
++ *    auth key context creation function
++ *    called from pfkey_v2_parser.c:pfkey_ips_init() 
++ */
++int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {
++      int ret=-EINVAL;
++      struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
++      int keyminbits, keymaxbits;
++      unsigned char *akp;
++      unsigned int aks;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:ipsec_alg_auth_key_create: "
++                  "entering with authalg=%d ixt_a=%p\n",
++                  sa_p->ips_authalg, ixt_a);
++      if (!ixt_a) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_alg_auth_key_create: "
++                          "NULL ipsec_alg_auth object\n");
++              return -EPROTO;
++      }
++      keyminbits=ixt_a->ixt_common.ixt_support.ias_keyminbits;
++      keymaxbits=ixt_a->ixt_common.ixt_support.ias_keymaxbits;
++      if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_alg_auth_key_create: incorrect auth"
++                          "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,
++                          sa_p->ips_key_bits_a, keyminbits, keymaxbits);
++              ret=-EINVAL;
++              goto ixt_out;
++      }
++      /* save auth key pointer */
++      sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */
++      akp = sa_p->ips_key_a;
++      aks = sa_p->ips_key_a_size;
++
++      /* will hold: 2 ctx and a blocksize buffer: kb */
++      sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;
++      if((sa_p->ips_key_a = 
++              (caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {
++              ret=-ENOMEM;
++              goto ixt_out;
++      }
++      ixt_a->ixt_a_hmac_set_key(ixt_a, sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */
++      ret=0;
++      memset(akp, 0, aks);
++      kfree(akp);
++                      
++ixt_out:
++      return ret;
++}
++
++
++int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp,
++                        int len, __u8 *hash, int hashlen)
++{
++      struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
++      if (!ixt_a) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_sa_esp_hash: "
++                          "NULL ipsec_alg_auth object\n");
++              return -EPROTO;
++      }
++      KLIPS_PRINT(debug_tunnel|debug_rcv,
++                      "klips_debug:ipsec_sa_esp_hash: "
++                      "hashing %p (%d bytes) to %p (%d bytes)\n",
++                      espp, len,
++                      hash, hashlen);
++      ixt_a->ixt_a_hmac_hash(ixt_a,
++                      sa_p->ips_key_a, 
++                      espp, len,
++                      hash, hashlen);
++      return 0;
++}
++
++/***************************************************************
++ *
++ *    INTERFACE for module loading,testing, and unloading
++ *
++ ***************************************************************/
++
++/* validation for registering (enc) module */
++static int check_enc(struct ipsec_alg_enc *ixt)
++{
++      int ret=-EINVAL;
++      if (ixt->ixt_common.ixt_blocksize==0) /*  || ixt->ixt_common.ixt_blocksize%2) need for ESP_NULL */
++              barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_common.ixt_blocksize);
++      if (ixt->ixt_common.ixt_support.ias_keyminbits==0
++          && ixt->ixt_common.ixt_support.ias_keymaxbits==0
++          && ixt->ixt_e_keylen==0)
++              goto zero_key_ok;
++      
++      if (ixt->ixt_common.ixt_support.ias_keyminbits==0)
++              barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_common.ixt_support.ias_keyminbits);
++      
++      if (ixt->ixt_common.ixt_support.ias_keymaxbits==0)
++              barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_common.ixt_support.ias_keymaxbits);
++      
++      if (ixt->ixt_e_keylen==0)
++              barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);
++      
++zero_key_ok:
++      if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL)
++              barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size);
++      if (ixt->ixt_e_cbc_encrypt==NULL)
++              barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");
++      ret=0;
++out:
++      return ret;
++}
++
++/* validation for registering (auth) module */
++static int check_auth(struct ipsec_alg_auth *ixt)
++{
++      int ret=-EINVAL;
++      if (ixt->ixt_common.ixt_support.ias_id==0 || ixt->ixt_common.ixt_support.ias_id > K_SADB_AALG_MAX)
++              barf_out("invalid alg_id=%d > %d (K_SADB_AALG_MAX)\n",
++                       ixt->ixt_common.ixt_support.ias_id, K_SADB_AALG_MAX);
++
++      if (ixt->ixt_common.ixt_blocksize==0
++          || ixt->ixt_common.ixt_blocksize%2)
++              barf_out(KERN_ERR "invalid blocksize=%d\n",
++                       ixt->ixt_common.ixt_blocksize);
++
++      if (ixt->ixt_common.ixt_blocksize>AH_BLKLEN_MAX)
++              barf_out(KERN_ERR "sorry blocksize=%d > %d. "
++                      "Please increase AH_BLKLEN_MAX and recompile\n", 
++                      ixt->ixt_common.ixt_blocksize,
++                      AH_BLKLEN_MAX);
++      if (ixt->ixt_common.ixt_support.ias_keyminbits==0 && ixt->ixt_common.ixt_support.ias_keymaxbits==0 && ixt->ixt_a_keylen==0)
++              goto zero_key_ok;
++      if (ixt->ixt_common.ixt_support.ias_keyminbits==0)
++              barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_common.ixt_support.ias_keyminbits);
++      if (ixt->ixt_common.ixt_support.ias_keymaxbits==0)
++              barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_common.ixt_support.ias_keymaxbits);
++      if (ixt->ixt_common.ixt_support.ias_keymaxbits!=ixt->ixt_common.ixt_support.ias_keyminbits)
++              barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");
++      if (ixt->ixt_a_keylen==0)
++              barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);
++zero_key_ok:
++      if (ixt->ixt_a_ctx_size==0)
++              barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);
++      if (ixt->ixt_a_hmac_set_key==NULL)
++              barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");
++      if (ixt->ixt_a_hmac_hash==NULL)
++              barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");
++      ret=0;
++out:
++      return ret;
++}
++
++/* 
++ * Generic (enc, auth) registration entry point 
++ */
++int register_ipsec_alg(struct ipsec_alg *ixt)
++{
++      int ret=-EINVAL;
++      /*      Validation      */
++      if (ixt==NULL)
++              barf_out("NULL ipsec_alg object passed\n");
++      if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00))
++              barf_out("incorrect version: %d.%d.%d-%d, "
++                      "must be %d.%d.%d[-%d]\n",
++                              IPSEC_ALG_VERSION_QUAD(ixt->ixt_version), 
++                              IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION));
++
++      switch(ixt->ixt_alg_type) {
++              case IPSEC_ALG_TYPE_AUTH:
++                      if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0))
++                              goto out;
++                      break;
++              case IPSEC_ALG_TYPE_ENCRYPT: 
++                      if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0))
++                              goto out;
++                      /* 
++                       * Adapted two lines below: 
++                       *      ivlen == 0 is possible (NULL enc has blocksize==1)
++                       *
++                       * fixed NULL support by David De Reu <DeReu@tComLabs.com>
++                       */
++                      if (ixt->ixt_support.ias_ivlen == 0
++                          && ixt->ixt_blocksize > 1) {
++                              ixt->ixt_support.ias_ivlen = ixt->ixt_blocksize*8;
++                      }
++                      break;
++              default:
++                      barf_out("alg_type=%d not supported\n", ixt->ixt_alg_type);
++      }
++      INIT_LIST_HEAD(&ixt->ixt_list);
++      ret = ipsec_alg_insert(ixt);
++      if (ret<0) 
++              barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed."
++                              "Not loaded (ret=%d).\n",
++                              ixt->ixt_support.ias_id, ret);
++
++
++      ret = pfkey_list_insert_supported((struct ipsec_alg_supported *)&ixt->ixt_support
++                                        , &(pfkey_supported_list[K_SADB_SATYPE_ESP]));
++
++      if (ret==0) {
++              ixt->ixt_state |= IPSEC_ALG_ST_SUPP;
++              /*      send register event to userspace        */
++              pfkey_register_reply(K_SADB_SATYPE_ESP, NULL);
++      } else
++              printk(KERN_ERR "pfkey_list_insert_supported returned %d. "
++                              "Loading anyway.\n", ret);
++      ret=0;
++out:
++      return ret;
++}
++
++/* 
++ *    unregister ipsec_alg object from own tables, if 
++ *    success => calls pfkey_list_remove_supported()
++ */
++int unregister_ipsec_alg(struct ipsec_alg *ixt) {
++      int ret= -EINVAL;
++      switch(ixt->ixt_alg_type) {
++              case IPSEC_ALG_TYPE_AUTH:
++              case IPSEC_ALG_TYPE_ENCRYPT: 
++                      break;
++              default:
++                      /*      this is not a typo :) */
++                      barf_out("frog found in list (\"%s\"): ixt_p=NULL\n", 
++                              ixt->ixt_name);
++      }
++
++      ret=ipsec_alg_delete(ixt);
++      if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) {
++              ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP;
++              pfkey_list_remove_supported((struct ipsec_alg_supported *)&ixt->ixt_support
++                                          , &(pfkey_supported_list[K_SADB_SATYPE_ESP]));
++
++              /*      send register event to userspace        */
++              pfkey_register_reply(K_SADB_SATYPE_ESP, NULL);
++      }
++
++out:
++      return ret;
++}
++
++/*
++ *    Must be called from user context
++ *    used at module load type for testing algo implementation
++ */
++static int ipsec_alg_test_encrypt(int enc_alg, int test) {
++      int ret;
++      caddr_t buf = NULL;
++      int iv_size, keysize, key_e_size;
++      struct ipsec_alg_enc *ixt_e;
++      void *tmp_key_e = NULL;
++      #define BUFSZ   1024
++      #define MARGIN  0
++      #define test_enc   (buf+MARGIN)
++      #define test_dec   (test_enc+BUFSZ+MARGIN)
++      #define test_tmp   (test_dec+BUFSZ+MARGIN)
++      #define test_key_e (test_tmp+BUFSZ+MARGIN)
++      #define test_iv    (test_key_e+key_e_size+MARGIN)
++      #define test_key   (test_iv+iv_size+MARGIN)
++      #define test_size  (BUFSZ*3+key_e_size+iv_size+keysize+MARGIN*7)
++      ixt_e=(struct ipsec_alg_enc *)ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, enc_alg);
++      if (ixt_e==NULL) {
++              KLIPS_PRINT(1, 
++                          "klips_debug: ipsec_alg_test_encrypt: "
++                          "encalg=%d object not found\n",
++                          enc_alg);
++              ret=-EINVAL;
++              goto out;
++      }
++      iv_size=ixt_e->ixt_common.ixt_support.ias_ivlen / 8;
++      key_e_size=ixt_e->ixt_e_ctx_size;
++      keysize=ixt_e->ixt_e_keylen;
++      KLIPS_PRINT(1, 
++                  "klips_debug: ipsec_alg_test_encrypt: "
++                  "enc_alg=%d blocksize=%d key_e_size=%d keysize=%d\n",
++                  enc_alg, iv_size, key_e_size, keysize);
++      if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
++              ret= -ENOMEM;
++              goto out;
++      }
++      get_random_bytes(test_key, keysize);
++      get_random_bytes(test_iv, iv_size);
++      if (ixt_e->ixt_e_new_key) {
++              tmp_key_e = ixt_e->ixt_e_new_key(ixt_e, test_key, keysize);
++              ret = tmp_key_e ? 0 : -EINVAL;
++      } else {
++              tmp_key_e = test_key_e;
++              ret = ixt_e->ixt_e_set_key(ixt_e, test_key_e, test_key, keysize);
++      }
++      if (ret < 0)
++              goto out;
++      get_random_bytes(test_enc, BUFSZ);
++      memcpy(test_tmp, test_enc, BUFSZ);
++      ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_enc, BUFSZ, test_iv, 1);
++      printk(KERN_INFO
++                  "klips_info: ipsec_alg_test_encrypt: "
++                  "cbc_encrypt=1 ret=%d\n", 
++                      ret);
++      ret=memcmp(test_enc, test_tmp, BUFSZ);
++      printk(KERN_INFO
++                  "klips_info: ipsec_alg_test_encrypt: "
++                  "memcmp(enc, tmp) ret=%d: %s\n", ret,
++                      ret!=0? "OK. (encr->DIFFers)" : "FAIL! (encr->SAME)" );
++      memcpy(test_dec, test_enc, BUFSZ);
++      ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_dec, BUFSZ, test_iv, 0);
++      printk(KERN_INFO
++                  "klips_info: ipsec_alg_test_encrypt: "
++                  "cbc_encrypt=0 ret=%d\n", ret);
++      ret=memcmp(test_dec, test_tmp, BUFSZ);
++      printk(KERN_INFO
++                  "klips_info: ipsec_alg_test_encrypt: "
++                  "memcmp(dec,tmp) ret=%d: %s\n", ret,
++                      ret==0? "OK. (encr->decr->SAME)" : "FAIL! (encr->decr->DIFFers)" );
++      {
++              /*      Shamelessly taken from drivers/md sources  O:)  */
++              unsigned long now;
++              int i, count, max=0;
++              int encrypt, speed;
++              for (encrypt=0; encrypt <2;encrypt ++) {
++                      for (i = 0; i < 5; i++) {
++                              now = jiffies;
++                              count = 0;
++                              while (jiffies == now) {
++                                      mb();
++                                      ixt_e->ixt_e_cbc_encrypt(ixt_e, 
++                                                      tmp_key_e, test_tmp, 
++                                                      BUFSZ, test_iv, encrypt);
++                                      mb();
++                                      count++;
++                                      mb();
++                              }
++                              if (count > max)
++                                      max = count;
++                      }
++                      speed = max * (HZ * BUFSZ / 1024);
++                      printk(KERN_INFO
++                                  "klips_info: ipsec_alg_test_encrypt: "
++                                  "%s %s speed=%d KB/s\n", 
++                                  ixt_e->ixt_common.ixt_name,
++                                  encrypt? "encrypt": "decrypt", speed);
++              }
++      }
++out:
++      if (tmp_key_e && ixt_e->ixt_e_destroy_key) ixt_e->ixt_e_destroy_key(ixt_e, tmp_key_e);
++      if (buf) kfree(buf);
++      if (ixt_e) ipsec_alg_put((struct ipsec_alg *)ixt_e);
++      return ret;
++      #undef test_enc  
++      #undef test_dec  
++      #undef test_tmp  
++      #undef test_key_e
++      #undef test_iv   
++      #undef test_key  
++      #undef test_size 
++}
++
++/*
++ *    Must be called from user context
++ *    used at module load type for testing algo implementation
++ */
++static int ipsec_alg_test_auth(int auth_alg, int test) {
++      int ret;
++      caddr_t buf = NULL;
++      int blocksize, keysize, key_a_size;
++      struct ipsec_alg_auth *ixt_a;
++      #define BUFSZ   1024
++      #define MARGIN  0
++      #define test_auth  (buf+MARGIN)
++      #define test_key_a (test_auth+BUFSZ+MARGIN)
++      #define test_key   (test_key_a+key_a_size+MARGIN)
++      #define test_hash  (test_key+keysize+MARGIN)
++      #define test_size  (BUFSZ+key_a_size+keysize+AHHMAC_HASHLEN+MARGIN*4)
++      ixt_a=(struct ipsec_alg_auth *)ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, auth_alg);
++      if (ixt_a==NULL) {
++              KLIPS_PRINT(1, 
++                          "klips_debug: ipsec_alg_test_auth: "
++                          "encalg=%d object not found\n",
++                          auth_alg);
++              ret=-EINVAL;
++              goto out;
++      }
++      blocksize=ixt_a->ixt_common.ixt_blocksize;
++      key_a_size=ixt_a->ixt_a_ctx_size;
++      keysize=ixt_a->ixt_a_keylen;
++      KLIPS_PRINT(1, 
++                  "klips_debug: ipsec_alg_test_auth: "
++                  "auth_alg=%d blocksize=%d key_a_size=%d keysize=%d\n",
++                  auth_alg, blocksize, key_a_size, keysize);
++      if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
++              ret= -ENOMEM;
++              goto out;
++      }
++      get_random_bytes(test_key, keysize);
++      ret = ixt_a->ixt_a_hmac_set_key(ixt_a, test_key_a, test_key, keysize);
++      if (ret < 0 )
++              goto out;
++      get_random_bytes(test_auth, BUFSZ);
++      ret=ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
++      printk(KERN_INFO
++                  "klips_info: ipsec_alg_test_auth: "
++                  "ret=%d\n", ret);
++      {
++              /*      Shamelessly taken from drivers/md sources  O:)  */
++              unsigned long now;
++              int i, count, max=0;
++              int speed;
++              for (i = 0; i < 5; i++) {
++                      now = jiffies;
++                      count = 0;
++                      while (jiffies == now) {
++                              mb();
++                              ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
++                              mb();
++                              count++;
++                              mb();
++                      }
++                      if (count > max)
++                              max = count;
++              }
++              speed = max * (HZ * BUFSZ / 1024);
++              printk(KERN_INFO
++                              "klips_info: ipsec_alg_test_auth: "
++                              "%s hash speed=%d KB/s\n", 
++                              ixt_a->ixt_common.ixt_name,
++                              speed);
++      }
++out:
++      if (buf) kfree(buf);
++      if (ixt_a) ipsec_alg_put((struct ipsec_alg *)ixt_a);
++      return ret;
++      #undef test_auth 
++      #undef test_key_a
++      #undef test_key  
++      #undef test_hash 
++      #undef test_size 
++}
++
++int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int test) {
++      switch(alg_type) {
++              case IPSEC_ALG_TYPE_ENCRYPT:
++                      return ipsec_alg_test_encrypt(alg_id, test);
++                      break;
++              case IPSEC_ALG_TYPE_AUTH:
++                      return ipsec_alg_test_auth(alg_id, test);
++                      break;
++      }
++      printk(KERN_ERR "klips_info: ipsec_alg_test() called incorrectly: "
++                      "alg_type=%d alg_id=%d\n",
++                      alg_type, alg_id);
++      return -EINVAL;
++}
++
++int ipsec_alg_init(void) {
++      KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
++                      "KLIPS alg v=%d.%d.%d-%d (EALG_MAX=%d, AALG_MAX=%d)\n",
++                      IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION),
++                      K_SADB_EALG_MAX, K_SADB_AALG_MAX);
++      /*      Initialize tables */
++      write_lock_bh(&ipsec_alg_lock);
++      ipsec_alg_hash_init();
++      write_unlock_bh(&ipsec_alg_lock);
++
++      /*      Initialize static algos         */
++      KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
++              "calling ipsec_alg_static_init()\n");
++
++      /* If we are suppose to use our AES, and don't have
++       * CryptoAPI enabled...
++       */
++#if defined(CONFIG_KLIPS_ENC_AES) && CONFIG_KLIPS_ENC_AES && !defined(CONFIG_KLIPS_ENC_AES_MODULE) 
++#if defined(CONFIG_KLIPS_ENC_CRYPTOAPI) && CONFIG_KLIPS_ENC_CRYPTOAPI
++#warning "Using built-in AES rather than CryptoAPI AES"
++#endif        
++      {
++              extern int ipsec_aes_init(void);
++              ipsec_aes_init();
++      }
++#endif
++
++#if defined(CONFIG_KLIPS_ENC_3DES) && !defined(CONFIG_KLIPS_ENC_3DES_MODULE) 
++#if defined(CONFIG_KLIPS_ENC_CRYPTOAPI) && CONFIG_KLIPS_ENC_CRYPTOAPI
++#warning "Using built-in 3des rather than CryptoAPI 3des"
++#endif        
++      {
++              extern int ipsec_3des_init(void);
++              ipsec_3des_init();
++      }
++#endif
++
++      /* If we are doing CryptoAPI, then init */
++#if defined(CONFIG_KLIPS_ENC_CRYPTOAPI) && CONFIG_KLIPS_ENC_CRYPTOAPI && !defined(CONFIG_KLIPS_ENC_CRYPTOAPI_MODULE)
++      {
++                extern int ipsec_cryptoapi_init(void);
++                ipsec_cryptoapi_init();
++        }
++#endif
++
++
++      return 0;
++}
++
++/**********************************************
++ *
++ *    INTERFACE for ipsec_sa init and wipe
++ *
++ **********************************************/
++
++/*    
++ *    Called from pluto -> pfkey_v2_parser.c:pfkey_ipsec_sa_init()    
++ */
++int ipsec_alg_sa_init(struct ipsec_sa *sa_p) {
++      struct ipsec_alg_enc *ixt_e;
++      struct ipsec_alg_auth *ixt_a;
++
++      /*      Only ESP for now ... */
++      if (sa_p->ips_said.proto != IPPROTO_ESP)
++              return -EPROTONOSUPPORT;
++
++      KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_init() :"
++                      "entering for encalg=%d, authalg=%d\n",
++                          sa_p->ips_encalg, sa_p->ips_authalg);
++
++      if ((ixt_e=(struct ipsec_alg_enc *)
++              ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, sa_p->ips_encalg))) {
++              KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: ipsec_alg_sa_init() :"
++                  "found ipsec_alg (ixt_e=%p) for encalg=%d\n",
++                  ixt_e, sa_p->ips_encalg);
++              sa_p->ips_alg_enc=ixt_e;
++      }
++
++      if ((ixt_a=(struct ipsec_alg_auth *)
++              ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, sa_p->ips_authalg))) {
++              KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: ipsec_alg_sa_init() :"
++                  "found ipsec_alg (ixt_a=%p) for auth=%d\n",
++                  ixt_a, sa_p->ips_authalg);
++              sa_p->ips_alg_auth=ixt_a;
++      }
++      return 0;
++}
++
++/*    
++ *    Called from pluto -> ipsec_sa.c:ipsec_sa_delchain()
++ */
++int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p) {
++      struct ipsec_alg *ixt;
++      if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_enc)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
++                              "unlinking for encalg=%d\n",
++                              ixt->ixt_support.ias_id);
++              ipsec_alg_put(ixt);
++      }
++      if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_auth)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
++                              "unlinking for authalg=%d\n",
++                              ixt->ixt_support.ias_id);
++              ipsec_alg_put(ixt);
++      }
++      return 0;
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_xform_get_info(char *buffer,
++                   char **start,
++                   off_t offset,
++                   int length     IPSEC_PROC_LAST_ARG)
++{
++      int len = 0;
++      off_t begin = 0;
++      int i;
++      struct list_head *head;
++      struct ipsec_alg *ixt;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_tncfg_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      for(i = 0, head = ipsec_alg_hash_table;
++          i<IPSEC_ALG_HASHSZ;
++          i++, head++)
++      {
++              struct list_head *p;
++              for (p=head->next; p!=head; p=p->next)
++              {
++                      ixt = list_entry(p, struct ipsec_alg, ixt_list);
++                      len += ipsec_snprintf(buffer+len, length-len,
++                                            "VERSION=%d TYPE=%d ID=%d NAME=%s REFCNT=%d ",
++                                            ixt->ixt_version, ixt->ixt_alg_type, ixt->ixt_support.ias_id,
++                                            ixt->ixt_name, ixt->ixt_refcnt);
++
++                      len += ipsec_snprintf(buffer+len, length-len,
++                                            "STATE=%08x BLOCKSIZE=%d IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
++                                            ixt->ixt_state, ixt->ixt_blocksize,
++                                            ixt->ixt_support.ias_ivlen, ixt->ixt_support.ias_keyminbits, ixt->ixt_support.ias_keymaxbits);
++
++                      len += ipsec_snprintf(buffer+len, length-len,
++                                            "IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
++                                            ixt->ixt_support.ias_ivlen, ixt->ixt_support.ias_keyminbits, ixt->ixt_support.ias_keymaxbits);
++
++                      switch(ixt->ixt_alg_type)
++                      {
++                      case IPSEC_ALG_TYPE_AUTH:
++                      {
++                              struct ipsec_alg_auth *auth = (struct ipsec_alg_auth *)ixt;
++
++                              len += ipsec_snprintf(buffer+len, length-len,
++                                                    "KEYLEN=%d CTXSIZE=%d AUTHLEN=%d ",
++                                                    auth->ixt_a_keylen, auth->ixt_a_ctx_size,
++                                                    auth->ixt_a_authlen);
++                              break;
++                      }
++                      case IPSEC_ALG_TYPE_ENCRYPT:
++                      {
++                              struct ipsec_alg_enc *enc = (struct ipsec_alg_enc *)ixt;
++                              len += ipsec_snprintf(buffer+len, length-len,
++                                                    "KEYLEN=%d CTXSIZE=%d ",
++                                                    enc->ixt_e_keylen, enc->ixt_e_ctx_size);
++
++                              break;
++                      }
++                      }
++
++                      len += ipsec_snprintf(buffer+len, length-len, "\n");
++              }
++      } 
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++
++/*
++ *    As the author of this module, I ONLY ALLOW using it from
++ *    GPL (or same LICENSE TERMS as kernel source) modules.
++ *
++ *    In respect to hardware crypto engines this means:
++ *    * Closed-source device drivers ARE NOT ALLOWED to use 
++ *      this interface.
++ *    * Closed-source VHDL/Verilog firmware running on 
++ *      the crypto hardware device IS ALLOWED to use this interface
++ *      via a GPL (or same LICENSE TERMS as kernel source) device driver.
++ *    --Juan Jose Ciarlante 20/03/2002 (thanks RGB for the correct wording)
++ */
++
++/*    
++ *    These symbols can only be used from GPL modules 
++ *    for now, I'm disabling this because it creates false
++ *    symbol problems for old modutils.
++ */
++
++#ifdef CONFIG_MODULES
++#ifndef NET_26
++#if 0
++#ifndef EXPORT_SYMBOL_GPL 
++#undef EXPORT_SYMBOL_GPL
++#define EXPORT_SYMBOL_GPL EXPORT_SYMBOL
++#endif 
++#endif
++EXPORT_SYMBOL(register_ipsec_alg);
++EXPORT_SYMBOL(unregister_ipsec_alg);
++EXPORT_SYMBOL(ipsec_alg_test);
++#endif
++#endif
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_alg_cryptoapi.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,515 @@
++/*
++ * ipsec_alg to linux cryptoapi GLUE
++ *
++ * Authors: CODE.ar TEAM
++ *    Harpo MAxx <harpo@linuxmendoza.org.ar>
++ *    JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
++ *    Luciano Ruete <docemeses@softhome.net>
++ * 
++ * ipsec_alg_cryptoapi.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * Example usage:
++ *   modinfo -p ipsec_cryptoapi   (quite useful info, including supported algos)
++ *   modprobe ipsec_cryptoapi
++ *   modprobe ipsec_cryptoapi test=1
++ *   modprobe ipsec_cryptoapi excl=1                     (exclusive cipher/algo)
++ *   modprobe ipsec_cryptoapi noauto=1  aes=1 twofish=1  (only these ciphers)
++ *   modprobe ipsec_cryptoapi aes=128,128                (force these keylens)
++ *   modprobe ipsec_cryptoapi des_ede3=0                 (everything but 3DES)
++ */
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++/*    
++ *    special case: ipsec core modular with this static algo inside:
++ *    must avoid MODULE magic for this file
++ */
++#if CONFIG_KLIPS_MODULE && CONFIG_KLIPS_ENC_CRYPTOAPI
++#undef MODULE
++#endif
++
++#include <linux/module.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++# include <linux/moduleparam.h>
++#endif
++#include <linux/init.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/string.h>
++
++/* Check if __exit is defined, if not null it */
++#ifndef __exit
++#define __exit
++#endif
++
++/* warn the innocent */
++#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
++#warning "No linux CryptoAPI configured, install 2.4.22+ or 2.6.x or enable CryptoAPI"
++#define NO_CRYPTOAPI_SUPPORT
++#endif
++
++#include "openswan.h"
++#include "openswan/ipsec_alg.h"
++#include "openswan/ipsec_policy.h"
++
++#include <linux/crypto.h>
++#ifdef CRYPTO_API_VERSION_CODE
++#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
++#define NO_CRYPTOAPI_SUPPORT
++#endif
++
++#ifdef NO_CRYPTOAPI_SUPPORT
++#warning "Building an unusable module :P"
++/* Catch old CryptoAPI by not allowing module to load */
++IPSEC_ALG_MODULE_INIT_STATIC( ipsec_cryptoapi_init )
++{
++      printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
++      return -EINVAL;
++}
++#else
++#include <asm/scatterlist.h>
++#include <asm/pgtable.h>
++#include <linux/mm.h>
++
++/*
++ * CryptoAPI compat code - we use the current API and macro back to
++ * the older ones.
++ */
++
++#ifndef CRYPTO_TFM_MODE_CBC
++/*
++ * As of linux-2.6.21 this is no longer defined, and presumably no longer
++ * needed to be passed into the crypto core code.
++ */
++#define       CRYPTO_TFM_MODE_CBC     0
++#define       CRYPTO_TFM_MODE_ECB     0
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++      /*
++       * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
++       * API into old API.
++       */
++
++      /* Symmetric/Block Cipher */
++      struct blkcipher_desc
++      {
++              struct crypto_tfm *tfm;
++              void *info;
++      };
++      #define ecb(X)                                                          #X
++      #define cbc(X)                                                          #X
++      #define crypto_has_blkcipher(X, Y, Z)           crypto_alg_available(X, 0)
++      #define crypto_blkcipher_cast(X)                        X
++      #define crypto_blkcipher_tfm(X)                         X
++      #define crypto_alloc_blkcipher(X, Y, Z)         crypto_alloc_tfm(X, CRYPTO_TFM_MODE_CBC)
++      #define crypto_blkcipher_ivsize(X)                      crypto_tfm_alg_ivsize(X)
++      #define crypto_blkcipher_blocksize(X)           crypto_tfm_alg_blocksize(X)
++      #define crypto_blkcipher_setkey(X, Y, Z)        crypto_cipher_setkey(X, Y, Z)
++      #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++      #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++
++      /* Hash/HMAC/Digest */
++      struct hash_desc
++      {
++              struct crypto_tfm *tfm;
++      };
++      #define hmac(X)                                                 #X
++      #define crypto_has_hash(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_hash_cast(X)                             X
++      #define crypto_hash_tfm(X)                              X
++      #define crypto_alloc_hash(X, Y, Z)              crypto_alloc_tfm(X, 0)
++      #define crypto_hash_digestsize(X)               crypto_tfm_alg_digestsize(X)
++      #define crypto_hash_digest(W, X, Y, Z)  \
++                              crypto_digest_digest((W)->tfm, X, sg_num, Z)
++
++      /* Asymmetric Cipher */
++      #define crypto_has_cipher(X, Y, Z)              crypto_alg_available(X, 0)
++
++      /* Compression */
++      #define crypto_has_comp(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_comp_tfm(X)                              X
++      #define crypto_comp_cast(X)                             X
++      #define crypto_alloc_comp(X, Y, Z)              crypto_alloc_tfm(X, 0)
++#else
++      #define ecb(X)  "ecb(" #X ")"
++      #define cbc(X)  "cbc(" #X ")"
++      #define hmac(X) "hmac(" #X ")"
++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++#define CIPHERNAME_AES                cbc(aes)
++#define CIPHERNAME_1DES               cbc(des)
++#define CIPHERNAME_3DES               cbc(des3_ede)
++#define CIPHERNAME_BLOWFISH   cbc(blowfish)
++#define CIPHERNAME_CAST               cbc(cast5)
++#define CIPHERNAME_SERPENT    cbc(serpent)
++#define CIPHERNAME_TWOFISH    cbc(twofish)
++
++#define DIGESTNAME_MD5                "md5"
++#define DIGESTNAME_SHA1               "sha1"
++
++#define ESP_SERPENT           252     /* from ipsec drafts */
++#define ESP_TWOFISH           253     /* from ipsec drafts */
++
++MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
++static int debug_crypto=0;
++static int test_crypto=0;
++static int excl_crypto=0;
++static int noauto = 0;
++module_param(debug_crypto,int,0644);
++module_param(test_crypto,int,0644);
++module_param(excl_crypto,int,0644);
++module_param(noauto,int,0644);
++
++MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
++
++#ifdef CONFIG_KLIPS_ENC_1DES
++static int des_ede1[] = {-1, -1};
++#endif
++static int des_ede3[] = {-1, -1};
++static int aes[] = {-1, -1};
++static int blowfish[] = {-1, -1};
++static int cast[] = {-1, -1};
++static int serpent[] = {-1, -1};
++static int twofish[] = {-1, -1};
++
++#ifdef CONFIG_KLIPS_ENC_1DES
++module_param_array(des_ede1,int,NULL,0444);
++#endif
++module_param_array(des_ede3,int,NULL,0444);
++module_param_array(aes,int,NULL,0444);
++module_param_array(blowfish,int,NULL,0444);
++module_param_array(cast,int,NULL,0444);
++module_param_array(serpent,int,NULL,0444);
++module_param_array(twofish,int,NULL,0444);
++
++MODULE_PARM_DESC(des_ede1, "0: disable | 1: force_enable | min,max: dontuse");
++MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
++MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
++MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
++
++struct ipsec_alg_capi_cipher {
++      const char *ciphername; /* cryptoapi's ciphername */
++      unsigned blocksize;
++      unsigned short minbits;
++      unsigned short maxbits;
++      int *parm;              /* lkm param for this cipher */
++      struct ipsec_alg_enc alg;       /* note it's not a pointer */
++};
++
++static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
++  { CIPHERNAME_AES,     16, 128, 256, aes,      { ixt_common:{ ixt_support:{ ias_id: ESP_AES}}}},
++  { CIPHERNAME_TWOFISH, 16, 128, 256, twofish,  { ixt_common:{ ixt_support:{ ias_id: ESP_TWOFISH,}}}},
++  { CIPHERNAME_SERPENT, 16, 128, 256, serpent,  { ixt_common:{ ixt_support:{ ias_id: ESP_SERPENT,}}}},
++  { CIPHERNAME_CAST,     8, 128, 128, cast   ,  { ixt_common:{ ixt_support:{ ias_id: ESP_CAST,}}}},
++  { CIPHERNAME_BLOWFISH, 8,  96, 448, blowfish, { ixt_common:{ ixt_support:{ ias_id: ESP_BLOWFISH,}}}},
++  { CIPHERNAME_3DES,     8, 192, 192, des_ede3, { ixt_common:{ ixt_support:{ ias_id: ESP_3DES,}}}},
++#ifdef CONFIG_KLIPS_ENC_1DES
++  { CIPHERNAME_1DES,     8,  64,  64, des_ede1, { ixt_common:{ ixt_support:{ ias_id: ESP_DES,}}}},
++#endif
++  { NULL, 0, 0, 0, NULL, {} }
++};
++
++#ifdef NOT_YET
++struct ipsec_alg_capi_digest {
++      const char *digestname; /* cryptoapi's digestname */
++      struct digest_implementation *di;
++      struct ipsec_alg_auth alg;      /* note it's not a pointer */
++};
++static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
++      { DIGESTNAME_MD5,     NULL, { ixt_alg_id: AH_MD5, }},
++      { DIGESTNAME_SHA1,    NULL, { ixt_alg_id: AH_SHA, }},
++      { NULL, NULL, {} }
++};
++#endif
++/*
++ *    "generic" linux cryptoapi setup_cipher() function
++ */
++int setup_cipher(const char *ciphername)
++{
++      return crypto_has_blkcipher(ciphername, 0, CRYPTO_ALG_ASYNC);
++}
++
++/*
++ *    setups ipsec_alg_capi_cipher "hyper" struct components, calling
++ *    register_ipsec_alg for cointaned ipsec_alg object
++ */
++static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
++static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
++static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, __u8 * iv, int encrypt);
++
++static int
++setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
++{
++      int ret;
++      cptr->alg.ixt_common.ixt_version = IPSEC_ALG_VERSION;
++      cptr->alg.ixt_common.ixt_module  = THIS_MODULE;
++      atomic_set (& cptr->alg.ixt_common.ixt_refcnt, 0);
++      strncpy (cptr->alg.ixt_common.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_common.ixt_name));
++
++      cptr->alg.ixt_common.ixt_blocksize=cptr->blocksize;
++      cptr->alg.ixt_common.ixt_support.ias_keyminbits=cptr->minbits;
++      cptr->alg.ixt_common.ixt_support.ias_keymaxbits=cptr->maxbits;
++      cptr->alg.ixt_common.ixt_state = 0;
++      if (excl_crypto) cptr->alg.ixt_common.ixt_state |= IPSEC_ALG_ST_EXCL;
++      cptr->alg.ixt_e_keylen=cptr->alg.ixt_common.ixt_support.ias_keymaxbits/8;
++      cptr->alg.ixt_e_ctx_size = 0;
++      cptr->alg.ixt_common.ixt_support.ias_exttype = IPSEC_ALG_TYPE_ENCRYPT;
++      cptr->alg.ixt_e_new_key = _capi_new_key;
++      cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
++      cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
++      cptr->alg.ixt_common.ixt_data = cptr;
++
++      ret=register_ipsec_alg_enc(&cptr->alg);
++      printk(KERN_INFO "KLIPS cryptoapi interface: " 
++                      "alg_type=%d alg_id=%d name=%s "
++                      "keyminbits=%d keymaxbits=%d, %s(%d)\n", 
++                              cptr->alg.ixt_common.ixt_support.ias_exttype, 
++                              cptr->alg.ixt_common.ixt_support.ias_id, 
++                              cptr->alg.ixt_common.ixt_name, 
++                              cptr->alg.ixt_common.ixt_support.ias_keyminbits,
++                              cptr->alg.ixt_common.ixt_support.ias_keymaxbits,
++             ret ? "not found" : "found", ret);
++      return ret;
++}
++/*
++ *    called in ipsec_sa_wipe() time, will destroy key contexts
++ *    and do 1 unbind()
++ */
++static void 
++_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
++{
++      struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
++      
++      if (debug_crypto > 0)
++              printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
++                              "name=%s key_e=%p \n",
++                              alg->ixt_common.ixt_name, key_e);
++      if (!key_e) {
++              printk(KERN_ERR "klips_debug: _capi_destroy_key:"
++                              "name=%s NULL key_e!\n",
++                              alg->ixt_common.ixt_name);
++              return;
++      }
++      crypto_free_tfm(tfm);
++}
++      
++/*
++ *    create new key context, need alg->ixt_data to know which
++ *    (of many) cipher inside this module is the target
++ */
++static __u8 *
++_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      struct crypto_tfm *tfm=NULL;
++
++      cptr = alg->ixt_common.ixt_data;
++      if (!cptr) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "NULL ixt_data (?!) for \"%s\" algo\n" 
++                              , alg->ixt_common.ixt_name);
++              goto err;
++      }
++      if (debug_crypto > 0)
++              printk(KERN_DEBUG "klips_debug:_capi_new_key:"
++                              "name=%s cptr=%p key=%p keysize=%d\n",
++                              alg->ixt_common.ixt_name, cptr, key, keylen);
++      
++      /*      
++       *      alloc tfm
++       */
++      tfm = crypto_blkcipher_tfm(crypto_alloc_blkcipher(cptr->ciphername, 0, CRYPTO_ALG_ASYNC));
++      if (!tfm) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n" 
++                      , alg->ixt_common.ixt_name, cptr->ciphername);
++              goto err;
++      }
++      if (crypto_blkcipher_setkey(crypto_blkcipher_cast(tfm), key, keylen) < 0) {
++              printk(KERN_ERR "_capi_new_key(): "
++                              "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n" 
++                      , alg->ixt_common.ixt_name, keylen);
++              crypto_free_tfm(tfm);
++              tfm=NULL;
++      }
++err:
++      if (debug_crypto > 0)
++              printk(KERN_DEBUG "klips_debug:_capi_new_key:"
++                              "name=%s key=%p keylen=%d tfm=%p\n",
++                              alg->ixt_common.ixt_name, key, keylen, tfm);
++      return (__u8 *) tfm;
++}
++/*
++ *    core encryption function: will use cx->ci to call actual cipher's
++ *    cbc function
++ */
++static int 
++_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, __u8 * iv, int encrypt) {
++      int error =0;
++      struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
++      struct scatterlist sg;
++      struct blkcipher_desc desc;
++      if (debug_crypto > 1)
++              printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
++                              "key_e=%p "
++                              "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
++                              , key_e
++                              , in, in, ilen, iv, encrypt);
++
++      memset(&sg, 0, sizeof(sg));
++      sg_set_page(&sg, virt_to_page(in), ilen, offset_in_page(in));
++
++      memset(&desc, 0, sizeof(desc));
++      desc.tfm = crypto_blkcipher_cast(tfm);
++      desc.info = (void *) iv;
++
++      if (encrypt)
++              error = crypto_blkcipher_encrypt_iv (&desc, &sg, &sg, ilen);
++      else
++              error = crypto_blkcipher_decrypt_iv (&desc, &sg, &sg, ilen);
++      if (debug_crypto > 1)
++              printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
++                              "error=%d\n"
++                              , error);
++      return (error<0)? error : ilen;
++}
++/*
++ *    main initialization loop: for each cipher in list, do
++ *    1) setup cryptoapi cipher else continue
++ *    2) register ipsec_alg object
++ */
++static int
++setup_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              /* 
++               * see if cipher has been disabled (0) or
++               * if noauto set and not enabled (1)
++               */
++              if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
++                      if (debug_crypto>0)
++                              printk(KERN_INFO "setup_cipher_list(): "
++                                      "ciphername=%s skipped at user request: "
++                                      "noauto=%d parm[0]=%d parm[1]=%d\n"
++                                      , cptr->ciphername
++                                      , noauto
++                                      , cptr->parm[0]
++                                      , cptr->parm[1]);
++                      continue;
++              } else {
++                      if (debug_crypto>0)
++                              printk(KERN_INFO "setup_cipher_list(): going to init ciphername=%s: noauto=%d parm[0]=%d parm[1]=%d\n",
++                              , cptr->ciphername
++                              , noauto
++                              , cptr->parm[0]
++                              , cptr->parm[1]);
++                      }
++              /* 
++               *      use a local ci to avoid touching cptr->ci,
++               *      if register ipsec_alg success then bind cipher
++               */
++              if(cptr->alg.ixt_common.ixt_support.ias_name == NULL) {
++                cptr->alg.ixt_common.ixt_support.ias_name = cptr->ciphername;
++              }
++
++              if( setup_cipher(cptr->ciphername) ) {
++                      if (debug_crypto > 0)
++                              printk(KERN_DEBUG "klips_debug:"
++                                              "setup_cipher_list():"
++                                              "ciphername=%s found\n"
++                              , cptr->ciphername);
++
++                      if (setup_ipsec_alg_capi_cipher(cptr) != 0) {
++                              printk(KERN_ERR "klips_debug:"
++                                     "setup_cipher_list():"
++                                     "ciphername=%s failed ipsec_alg_register\n"
++                                     , cptr->ciphername);
++                      }
++              } else {
++                      printk(KERN_INFO "KLIPS: lookup for ciphername=%s: not found \n",
++                             cptr->ciphername);
++              }
++      }
++      return 0;
++}
++/*
++ *    deregister ipsec_alg objects and unbind ciphers
++ */
++static int
++unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              if (cptr->alg.ixt_common.ixt_state & IPSEC_ALG_ST_REGISTERED) {
++                      unregister_ipsec_alg_enc(&cptr->alg);
++              }
++      }
++      return 0;
++}
++/*
++ *    test loop for registered algos
++ */
++static int
++test_cipher_list (struct ipsec_alg_capi_cipher* clist) 
++{
++      int test_ret;
++      struct ipsec_alg_capi_cipher *cptr;
++      /* foreach cipher in list ... */
++      for (cptr=clist;cptr->ciphername;cptr++) {
++              if (cptr->alg.ixt_common.ixt_state & IPSEC_ALG_ST_REGISTERED) {
++                      test_ret=ipsec_alg_test(
++                                      cptr->alg.ixt_common.ixt_support.ias_exttype,
++                                      cptr->alg.ixt_common.ixt_support.ias_id, 
++                                      test_crypto);
++                      printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n", 
++                             cptr->alg.ixt_common.ixt_support.ias_exttype, 
++                             cptr->alg.ixt_common.ixt_support.ias_id,
++                             test_ret);
++              }
++      }
++      return 0;
++}
++
++IPSEC_ALG_MODULE_INIT_STATIC( ipsec_cryptoapi_init )
++{
++      int ret, test_ret;
++      if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
++              return  -EPROTONOSUPPORT;
++      if (ret==0 && test_crypto) {
++              test_ret=test_cipher_list(alg_capi_carray);
++      }
++      return ret;
++}
++IPSEC_ALG_MODULE_EXIT_STATIC( ipsec_cryptoapi_fini )
++{
++      unsetup_cipher_list(alg_capi_carray);
++      return;
++}
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++
++#endif /* NO_CRYPTOAPI_SUPPORT */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_esp.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,584 @@
++/*
++ * processing code for ESP
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>  /* struct device, and other headers */
++#include <linux/etherdevice.h>        /* eth_type_trans */
++#include <linux/ip.h>         /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++#include <net/protocol.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_auth.h"
++
++#ifdef CONFIG_KLIPS_ESP
++#include "openswan/ipsec_esp.h"
++#endif /* CONFIG_KLIPS_ESP */
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++#include "ipsec_ocf.h"
++
++#ifdef CONFIG_KLIPS_DEBUG
++#define ESP_DMP(_x,_y,_z) if(debug_rcv && sysctl_ipsec_debug_verbose) ipsec_dmp_block(_x,_y,_z)
++#else
++#define ESP_DMP(_x,_y,_z)
++#endif
++
++#ifdef CONFIG_KLIPS_ESP
++enum ipsec_rcv_value
++ipsec_rcv_esp_checks(struct ipsec_rcv_state *irs,
++                   struct sk_buff *skb)
++{
++      __u8 proto;
++      int len;        /* packet length */
++
++      len = skb->len;
++      proto = irs->ipp->protocol;
++
++      /* XXX this will need to be 8 for IPv6 */
++      if ((proto == IPPROTO_ESP) && ((len - irs->iphlen) % 4)) {
++              printk("klips_error:ipsec_rcv: "
++                     "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n",
++                     len - irs->iphlen,
++                     irs->ipsaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADLEN;
++      }
++
++      if(skb->len < (irs->hard_header_len + sizeof(struct iphdr) + sizeof(struct esphdr))) {
++              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                          "klips_debug:ipsec_rcv: "
++                          "runt esp packet of skb->len=%d received from %s, dropped.\n",
++                          skb->len,
++                          irs->ipsaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADLEN;
++      }
++
++      irs->protostuff.espstuff.espp = (struct esphdr *)skb_transport_header(skb);
++      irs->said.spi = irs->protostuff.espstuff.espp->esp_spi;
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_rcv_value
++ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs,
++                          struct sk_buff *skb,
++                          __u32          *replay,
++                          unsigned char **authenticator)
++{
++      struct esphdr *espp = irs->protostuff.espstuff.espp;
++      //unsigned char *idat = (unsigned char *)espp;
++
++      KLIPS_PRINT(debug_rcv,
++                  "klips_debug:ipsec_rcv: "
++                  "packet from %s received with seq=%d (iv)=0x%08x%08x iplen=%d esplen=%d sa=%s\n",
++                  irs->ipsaddr_txt,
++                  (__u32)ntohl(espp->esp_rpl),
++                  (__u32)ntohl(*((__u32 *)(espp->esp_iv)    )),
++                  (__u32)ntohl(*((__u32 *)(espp->esp_iv) + 1)),
++                  irs->len,
++                  irs->ilen,
++                  irs->sa_len ? irs->sa : " (error)");
++
++      *replay = ntohl(espp->esp_rpl);
++      *authenticator = &(skb_transport_header(skb)[irs->ilen]);
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_rcv_value
++ipsec_rcv_esp_authcalc(struct ipsec_rcv_state *irs,
++                     struct sk_buff *skb)
++{
++      struct auth_alg *aa;
++      struct esphdr *espp = irs->protostuff.espstuff.espp;
++      union {
++              MD5_CTX         md5;
++              SHA1_CTX        sha1;
++      } tctx;
++
++#ifdef CONFIG_KLIPS_OCF
++      if (irs->ipsp->ocf_in_use)
++              return(ipsec_ocf_rcv(irs));
++#endif
++
++#ifdef CONFIG_KLIPS_ALG
++      if (irs->ipsp->ips_alg_auth) {
++              KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: "
++                              "ipsec_alg hashing proto=%d... ",
++                              irs->said.proto);
++              if(irs->said.proto == IPPROTO_ESP) {
++                      ipsec_alg_sa_esp_hash(irs->ipsp,
++                                      (caddr_t)espp, irs->ilen,
++                                      irs->hash, AHHMAC_HASHLEN);
++                      return IPSEC_RCV_OK;
++              }
++              return IPSEC_RCV_BADPROTO;
++      }
++#endif
++      aa = irs->authfuncs;
++
++      /* copy the initialized keying material */
++      memcpy(&tctx, irs->ictx, irs->ictx_len);
++
++#ifdef HASH_DEBUG
++      ESP_DMP("ictx", irs->ictx, irs->ictx_len);
++
++      ESP_DMP("mac_esp", (caddr_t)espp, irs->ilen);
++#endif
++      (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
++
++      (*aa->final)(irs->hash, (void *)&tctx);
++
++#ifdef HASH_DEBUG
++      ESP_DMP("hash1", irs->hash, aa->hashlen);
++#endif
++
++      memcpy(&tctx, irs->octx, irs->octx_len);
++
++#ifdef HASH_DEBUG
++      ESP_DMP("octx", irs->octx, irs->octx_len);
++#endif
++
++      (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
++      (*aa->final)(irs->hash, (void *)&tctx);
++
++      return IPSEC_RCV_OK;
++}
++
++
++enum ipsec_rcv_value
++ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs)
++{
++      struct ipsec_sa *ipsp = irs->ipsp;
++#ifdef CONFIG_KLIPS_ALG
++      struct esphdr *espp = irs->protostuff.espstuff.espp;
++      __u8 *idat;     /* pointer to content to be decrypted/authenticated */
++      int encaplen = 0;
++      struct sk_buff *skb;
++      struct ipsec_alg_enc *ixt_e=NULL;
++#endif
++
++#ifdef CONFIG_KLIPS_OCF
++      if (ipsp->ocf_in_use)
++              return(ipsec_ocf_rcv(irs));
++#endif
++
++#ifdef CONFIG_KLIPS_ALG
++      skb=irs->skb;
++
++      idat = skb_transport_header(skb);
++
++      /* encaplen is the distance between the end of the IP
++       * header and the beginning of the ESP header.
++       * on ESP headers it is zero, but on UDP-encap ESP
++       * it includes the space for the UDP header.
++       *
++       * Note: UDP-encap code has already moved the
++       *       skb->data forward to accomodate this.
++       */
++      encaplen = skb_transport_header(skb) - (skb_network_header(skb) + irs->iphlen);
++
++      ixt_e=ipsp->ips_alg_enc;
++      irs->esphlen = ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;
++      KLIPS_PRINT(debug_rcv,
++                  "klips_debug:ipsec_rcv: "
++                  "encalg=%d esphlen=%d\n",
++                  ipsp->ips_encalg, irs->esphlen);
++
++      idat += irs->esphlen;
++      irs->ilen -= irs->esphlen;
++
++      if (ipsec_alg_esp_encrypt(ipsp, 
++                                idat, irs->ilen, espp->esp_iv, 
++                                IPSEC_ALG_DECRYPT) <= 0) {
++#ifdef CONFIG_KLIPS_DEBUG
++              KLIPS_ERROR(debug_rcv, "klips_error:ipsec_rcv: "
++                          "got packet with esplen = %d "
++                          "from %s -- should be on "
++                          "ENC(%d) octet boundary, "
++                          "packet dropped\n",
++                          irs->ilen,
++                          irs->ipsaddr_txt,
++                          ipsp->ips_encalg);
++#endif
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BAD_DECRYPT;
++      } 
++
++      return ipsec_rcv_esp_post_decrypt(irs);
++#else
++      return IPSEC_RCV_BAD_DECRYPT;
++#endif /* CONFIG_KLIPS_ALG */
++}
++
++
++enum ipsec_rcv_value
++ipsec_rcv_esp_post_decrypt(struct ipsec_rcv_state *irs)
++{
++      struct sk_buff *skb;
++      __u8 *idat;     /* pointer to content to be decrypted/authenticated */
++      struct ipsec_sa *ipsp = irs->ipsp;
++      int pad = 0, padlen;
++      int badpad = 0;
++      int i;
++
++      skb = irs->skb;
++
++      idat = skb_transport_header(skb) + irs->esphlen;
++
++      ESP_DMP("postdecrypt", idat, irs->ilen);
++
++      irs->next_header = idat[irs->ilen - 1];
++      padlen = idat[irs->ilen - 2];
++      pad = padlen + 2 + irs->authlen;
++
++      KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
++                  "klips_debug:ipsec_rcv_esp_post_decrypt: "
++                  "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n",
++                  padlen);
++
++      for (i = 1; i <= padlen; i++) {
++              if((i % 16) == 1) {
++                      KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
++                                  "klips_debug:           %02x:",
++                                  i - 1);
++              }
++              KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
++                              " %02x",
++                              idat[irs->ilen - 2 - padlen + i - 1]);
++              if(i != idat[irs->ilen - 2 - padlen + i - 1]) {
++                      badpad = 1;
++              }
++              if((i % 16) == 0) {
++                      KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
++                                      "\n");
++              }
++      }
++      if((i % 16) != 1) {
++              KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
++                                              "\n");
++      }
++      if(badpad) {
++              KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
++                          "klips_debug:ipsec_rcv_esp_post_decrypt: "
++                          "warning, decrypted packet from %s has bad padding\n",
++                          irs->ipsaddr_txt);
++              KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
++                          "klips_debug:ipsec_rcv_esp_post_decrypt: "
++                          "...may be bad decryption -- not dropped\n");
++              ipsp->ips_errs.ips_encpad_errs += 1;
++      }
++
++      KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
++                  "klips_debug:ipsec_rcv_esp_post_decrypt: "
++                  "packet decrypted from %s: next_header = %d, padding = %d\n",
++                  irs->ipsaddr_txt,
++                  irs->next_header,
++                  pad - 2 - irs->authlen);
++
++      irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (irs->esphlen + pad));
++
++      /*
++       * move the IP header forward by the size of the ESP header, which
++       * will remove the the ESP header from the packet.
++       *
++       * XXX this is really unnecessary, since odds we are in tunnel
++       *     mode, and we will be *removing* this IP header.
++       *
++       */
++      memmove((void *)(idat - irs->iphlen),
++              (void *)(skb_network_header(skb)), irs->iphlen);
++
++      ESP_DMP("esp postmove", (idat - irs->iphlen),
++              irs->iphlen + irs->ilen);
++
++      /* skb_pull below, will move up by esphlen */
++
++      /* XXX not clear how this can happen, as the message indicates */
++      if(skb->len < irs->esphlen) {
++              printk(KERN_WARNING
++                     "klips_error:ipsec_rcv_esp_post_decrypt: "
++                     "tried to skb_pull esphlen=%d, %d available.  This should never happen, please report.\n",
++                     irs->esphlen, (int)(skb->len));
++              return IPSEC_RCV_ESP_DECAPFAIL;
++      }
++      skb_pull(skb, irs->esphlen);
++      skb_set_network_header(skb, ipsec_skb_offset(skb, idat - irs->iphlen));
++      irs->ipp = ip_hdr(skb);
++
++      ESP_DMP("esp postpull", skb->data, skb->len);
++
++      /* now, trip off the padding from the end */
++      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                  "klips_debug:ipsec_rcv: "
++                  "trimming to %d.\n",
++                  irs->len - irs->esphlen - pad);
++      if(pad + irs->esphlen <= irs->len) {
++              skb_trim(skb, irs->len - irs->esphlen - pad);
++      } else {
++              KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                          "klips_debug:ipsec_rcv: "
++                          "bogus packet, size is zero or negative, dropping.\n");
++              return IPSEC_RCV_DECAPFAIL;
++      }
++
++      return IPSEC_RCV_OK;
++}
++
++/*
++ *
++ */
++enum ipsec_xmit_value
++ipsec_xmit_esp_setup(struct ipsec_xmit_state *ixs)
++{
++#ifdef CONFIG_KLIPS_ENC_3DES
++  __u32 iv[2];
++#endif
++  struct esphdr *espp;
++  int ilen = 0;
++  int padlen = 0, i;
++  unsigned char *dat;
++  unsigned char *idat, *pad;
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++  __u8 hash[AH_AMAX];
++  union {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++    MD5_CTX md5;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++    SHA1_CTX sha1;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++  } tctx;
++#endif
++
++  dat = (unsigned char *)ixs->iph;
++
++  espp = (struct esphdr *)(dat + ixs->iphlen);
++  espp->esp_spi = ixs->ipsp->ips_said.spi;
++  espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
++  
++  switch(ixs->ipsp->ips_encalg) {
++#if defined(CONFIG_KLIPS_ENC_3DES)
++#ifdef CONFIG_KLIPS_ENC_3DES
++  case ESP_3DES:
++#endif /* CONFIG_KLIPS_ENC_3DES */
++    iv[0] = *((__u32*)&(espp->esp_iv)    ) =
++      ((__u32*)(ixs->ipsp->ips_iv))[0];
++    iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
++      ((__u32*)(ixs->ipsp->ips_iv))[1];
++    break;
++#endif /* defined(CONFIG_KLIPS_ENC_3DES) */
++  default:
++    ixs->stats->tx_errors++;
++    return IPSEC_XMIT_ESP_BADALG;
++  }
++              
++  idat = dat + ixs->iphlen + sizeof(struct esphdr);
++  ilen = ixs->skb->len - (ixs->iphlen + sizeof(struct esphdr) + ixs->authlen);
++  
++  /* Self-describing padding */
++  pad = &dat[ixs->skb->len - ixs->tailroom];
++  padlen = ixs->tailroom - 2 - ixs->authlen;
++  for (i = 0; i < padlen; i++) {
++    pad[i] = i + 1; 
++  }
++  dat[ixs->skb->len - ixs->authlen - 2] = padlen;
++  
++  dat[ixs->skb->len - ixs->authlen - 1] = ixs->iph->protocol;
++  ixs->iph->protocol = IPPROTO_ESP;
++  
++  switch(ixs->ipsp->ips_encalg) {
++#ifdef CONFIG_KLIPS_ENC_3DES
++  case ESP_3DES:
++    des_ede3_cbc_encrypt((des_cblock *)idat,
++                       (des_cblock *)idat,
++                       ilen,
++                       ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
++                       ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
++                       ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
++                       (des_cblock *)iv, 1);
++    break;
++#endif /* CONFIG_KLIPS_ENC_3DES */
++  default:
++    ixs->stats->tx_errors++;
++    return IPSEC_XMIT_ESP_BADALG;
++  }
++  
++  switch(ixs->ipsp->ips_encalg) {
++#if defined(CONFIG_KLIPS_ENC_3DES)
++#ifdef CONFIG_KLIPS_ENC_3DES
++  case ESP_3DES:
++#endif /* CONFIG_KLIPS_ENC_3DES */
++    /* XXX update IV with the last 8 octets of the encryption */
++#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
++    ((__u32*)(ixs->ipsp->ips_iv))[0] =
++      ((__u32 *)(idat))[(ilen >> 2) - 2];
++    ((__u32*)(ixs->ipsp->ips_iv))[1] =
++      ((__u32 *)(idat))[(ilen >> 2) - 1];
++#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
++    prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ); 
++#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
++    break;
++#endif /* defined(CONFIG_KLIPS_ENC_3DES) */
++  default:
++    ixs->stats->tx_errors++;
++    return IPSEC_XMIT_ESP_BADALG;
++  }
++  
++  switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++  case AH_MD5:
++    ipsec_xmit_dmp("espp", (char*)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
++    tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++    ipsec_xmit_dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, (caddr_t)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
++    ipsec_xmit_dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Final(hash, &tctx.md5);
++    ipsec_xmit_dmp("ictx hash", (char*)&hash, sizeof(hash));
++    tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
++    ipsec_xmit_dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
++    ipsec_xmit_dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++    osMD5Final(hash, &tctx.md5);
++    ipsec_xmit_dmp("octx hash", (char*)&hash, sizeof(hash));
++    memcpy(&(dat[ixs->skb->len - ixs->authlen]), hash, ixs->authlen);
++    
++    /* paranoid */
++    memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
++    memset((caddr_t)hash, 0, sizeof(*hash));
++    break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++  case AH_SHA:
++    tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++    SHA1Update(&tctx.sha1, (caddr_t)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
++    SHA1Final(hash, &tctx.sha1);
++    tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
++    SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++    SHA1Final(hash, &tctx.sha1);
++    memcpy(&(dat[ixs->skb->len - ixs->authlen]), hash, ixs->authlen);
++    
++    /* paranoid */
++    memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
++    memset((caddr_t)hash, 0, sizeof(*hash));
++    break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++  case AH_NONE:
++    break;
++  default:
++    ixs->stats->tx_errors++;
++    return IPSEC_XMIT_AH_BADALG;
++  }
++
++  skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, espp));
++
++  return IPSEC_XMIT_OK;
++}
++
++
++struct xform_functions esp_xform_funcs[]={
++      {
++              protocol:           IPPROTO_ESP,
++              rcv_checks:         ipsec_rcv_esp_checks,
++              rcv_setup_auth:     ipsec_rcv_esp_decrypt_setup,
++              rcv_calc_auth:      ipsec_rcv_esp_authcalc,
++              rcv_decrypt:        ipsec_rcv_esp_decrypt,
++
++              xmit_setup:         ipsec_xmit_esp_setup,
++              xmit_headroom:      sizeof(struct esphdr),
++              xmit_needtailroom:  1,
++      },
++};
++
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++#ifdef NET_26
++struct inet_protocol esp_protocol = {
++  .handler = ipsec_rcv,
++  .no_policy = 1,
++};
++#else
++struct inet_protocol esp_protocol =
++{
++      ipsec_rcv,                      /* ESP handler          */
++      NULL,                           /* TUNNEL error control */
++#ifdef NETDEV_25
++      1,                              /* no policy */
++#else
++      0,                              /* next */
++      IPPROTO_ESP,                    /* protocol ID */
++      0,                              /* copy */
++      NULL,                           /* data */
++      "ESP"                           /* name */
++#endif
++};
++#endif /* NET_26 */
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++
++#endif /* !CONFIG_KLIPS_ESP */
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_init.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,460 @@
++/*
++ * @(#) Initialization code.
++ * Copyright (C) 1996, 1997   John Ioannidis.
++ * Copyright (C) 1998 - 2002  Richard Guy Briggs <rgb@freeswan.org>
++ *               2001 - 2004  Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * /proc system code was split out into ipsec_proc.c after rev. 1.70.
++ *
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/in.h>          /* struct sockaddr_in */
++#include <linux/skbuff.h>
++#include <linux/random.h>       /* get_random_bytes() */
++#include <net/protocol.h>
++
++#include <openswan.h>
++
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* 23_SPINLOCK */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* 23_SPINLOCK */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#ifdef CONFIG_PROC_FS
++# include <linux/proc_fs.h>
++#endif /* CONFIG_PROC_FS */
++
++#ifdef NETLINK_SOCK
++# include <linux/netlink.h>
++#else
++# include <net/netlink.h>
++#endif
++
++#include "openswan/radij.h"
++
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_stats.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_mast.h"
++
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++# include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++
++#ifdef CONFIG_KLIPS_OCF
++#include "ipsec_ocf.h"
++#endif
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#if defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++#include <net/xfrmudp.h>
++#endif
++
++#ifndef HAVE_UDP_ENCAP_CONVERT
++# if defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(HAVE_XFRM4_UDP_REGISTER)
++# warning "You are trying to build KLIPS2.6 with NAT-T support, but you did not"
++# error   "properly apply the NAT-T patch to your 2.6 kernel source tree."
++# endif
++#endif
++
++#if !defined(CONFIG_KLIPS_ESP) && !defined(CONFIG_KLIPS_AH)
++#error "kernel configuration must include ESP or AH"
++#endif
++
++/*
++ * seems to be present in 2.4.10 (Linus), but also in some RH and other
++ * distro kernels of a lower number.
++ */
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++
++struct prng ipsec_prng;
++
++#if defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++xfrm4_rcv_encap_t klips_old_encap = NULL;
++#endif
++
++extern int ipsec_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
++/*
++ * the following structure is required so that we receive
++ * event notifications when network devices are enabled and
++ * disabled (ifconfig up and down).
++ */
++static struct notifier_block ipsec_dev_notifier={
++      .notifier_call = ipsec_device_event
++};
++
++#ifdef CONFIG_SYSCTL
++extern int ipsec_sysctl_register(void);
++extern void ipsec_sysctl_unregister(void);
++#endif
++
++/*
++ * inet_*_protocol returns void on 2.4.x, int on 2.6.x
++ * So we need our own wrapper
++*/
++#ifdef NET_26
++static inline int
++openswan_inet_add_protocol(struct inet_protocol *prot, unsigned protocol, char *protstr)
++{
++      int err = inet_add_protocol(prot, protocol);
++      if (err)
++              printk(KERN_ERR "KLIPS: can not register %s protocol - recompile with CONFIG_INET_%s disabled or as module\n", protstr,protstr);
++      return err;
++}
++
++static inline int
++openswan_inet_del_protocol(struct inet_protocol *prot, unsigned protocol)
++{
++      return inet_del_protocol(prot, protocol);
++}
++
++#else
++static inline int
++openswan_inet_add_protocol(struct inet_protocol *prot, unsigned protocol)
++{
++#ifdef IPSKB_XFRM_TUNNEL_SIZE
++      inet_add_protocol(prot, protocol);
++#else
++      inet_add_protocol(prot);
++#endif
++      return 0;
++}
++
++static inline int
++openswan_inet_del_protocol(struct inet_protocol *prot, unsigned protocol)
++{
++#ifdef IPSKB_XFRM_TUNNEL_SIZE
++      inet_del_protocol(prot, protocol);
++#else
++      inet_del_protocol(prot);
++#endif
++      return 0;
++}
++
++#endif
++
++/* void */
++int
++ipsec_klips_init(void)
++{
++      int error = 0;
++      unsigned char seed[256];
++#ifdef CONFIG_KLIPS_ENC_3DES
++      extern int des_check_key;
++
++      /* turn off checking of keys */
++      des_check_key=0;
++#endif /* CONFIG_KLIPS_ENC_3DES */
++
++      KLIPS_PRINT(1, "klips_info:ipsec_init: "
++                  "KLIPS startup, Openswan KLIPS IPsec stack version: %s\n",
++                  ipsec_version_code());
++
++        error = ipsec_xmit_state_cache_init ();
++        if (error)
++                goto error_xmit_state_cache;
++
++        error = ipsec_rcv_state_cache_init ();
++        if (error)
++                goto error_rcv_state_cache;
++
++      error |= ipsec_proc_init();
++        if (error)
++                goto error_proc_init;
++
++#ifdef SPINLOCK
++      ipsec_sadb.sadb_lock = SPIN_LOCK_UNLOCKED;
++#else /* SPINLOCK */
++      ipsec_sadb.sadb_lock = 0;
++#endif /* SPINLOCK */
++
++#ifndef SPINLOCK
++      tdb_lock.lock = 0;
++      eroute_lock.lock = 0;
++#endif /* !SPINLOCK */
++
++      error |= ipsec_sadb_init();
++        if (error)
++                goto error_sadb_init;
++
++      error |= ipsec_radijinit();
++        if (error)
++                goto error_radijinit;
++
++      error |= pfkey_init();
++        if (error)
++                goto error_pfkey_init;
++
++      error |= register_netdevice_notifier(&ipsec_dev_notifier);
++        if (error)
++                goto error_netdev_notifier;
++
++#ifdef CONFIG_XFRM_ALTERNATE_STACK
++        error = xfrm_register_alternate_rcv (ipsec_rcv);
++        if (error)
++                goto error_xfrm_register;
++
++#else // CONFIG_XFRM_ALTERNATE_STACK
++
++#ifdef CONFIG_KLIPS_ESP
++      error |= openswan_inet_add_protocol(&esp_protocol, IPPROTO_ESP,"ESP");
++      if (error)
++              goto error_openswan_inet_add_protocol_esp;
++
++#endif /* CONFIG_KLIPS_ESP */
++
++#ifdef CONFIG_KLIPS_AH
++      error |= openswan_inet_add_protocol(&ah_protocol, IPPROTO_AH,"AH");
++      if (error)
++              goto error_openswan_inet_add_protocol_ah;
++#endif /* CONFIG_KLIPS_AH */
++
++/* we never actually link IPCOMP to the stack */
++#ifdef IPCOMP_USED_ALONE
++#ifdef CONFIG_KLIPS_IPCOMP
++      error |= openswan_inet_add_protocol(&comp_protocol, IPPROTO_COMP,"IPCOMP");
++      if (error)
++              goto error_openswan_inet_add_protocol_comp;
++#endif /* CONFIG_KLIPS_IPCOMP */
++#endif
++
++#endif // CONFIG_XFRM_ALTERNATE_STACK
++
++      error |= ipsec_tunnel_init_devices();
++        if (error)
++                goto error_tunnel_init_devices;
++
++      error |= ipsec_mast_init_devices();
++
++#if defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++      /* register our ESP-UDP handler */
++      if(udp4_register_esp_rcvencap(klips26_rcv_encap
++                                    , &klips_old_encap)!=0) {
++         printk(KERN_ERR "KLIPS: can not register klips_rcv_encap function\n");
++      }
++#endif        
++
++#ifdef CONFIG_SYSCTL
++        error |= ipsec_sysctl_register();
++        if (error)
++                goto error_sysctl_register;
++#endif                                                                          
++
++#ifdef CONFIG_KLIPS_ALG
++      ipsec_alg_init();
++#endif
++
++#ifdef CONFIG_KLIPS_OCF
++      ipsec_ocf_init();
++#endif
++
++      get_random_bytes((void *)seed, sizeof(seed));
++      prng_init(&ipsec_prng, seed, sizeof(seed));
++      return error;
++
++        // undo ipsec_sysctl_register
++error_sysctl_register:
++      ipsec_tunnel_cleanup_devices();
++error_tunnel_init_devices:
++#ifdef CONFIG_XFRM_ALTERNATE_STACK
++        xfrm_deregister_alternate_rcv(ipsec_rcv);
++error_xfrm_register:
++#else // CONFIG_XFRM_ALTERNATE_STACK
++#ifdef IPCOMP_USED_ALONE
++#ifdef CONFIG_KLIPS_IPCOMP
++error_openswan_inet_add_protocol_comp:
++      openswan_inet_del_protocol(&comp_protocol, IPPROTO_COMP);
++#endif /* CONFIG_KLIPS_IPCOMP */
++#endif
++error_openswan_inet_add_protocol_ah:
++      openswan_inet_del_protocol(&ah_protocol, IPPROTO_AH);
++error_openswan_inet_add_protocol_esp:
++      openswan_inet_del_protocol(&esp_protocol, IPPROTO_ESP);
++#endif
++      unregister_netdevice_notifier(&ipsec_dev_notifier);
++error_netdev_notifier:
++      pfkey_cleanup();
++error_pfkey_init:
++      ipsec_radijcleanup();
++error_radijinit:
++      ipsec_sadb_cleanup(0);
++      ipsec_sadb_free();
++error_sadb_init:
++error_proc_init:
++        // ipsec_proc_init() does not cleanup after itself, so we have to do it here
++        // TODO: ipsec_proc_init() should roll back what it chaned on failure
++      ipsec_proc_cleanup();
++        ipsec_rcv_state_cache_cleanup ();
++error_rcv_state_cache:
++        ipsec_xmit_state_cache_cleanup ();
++error_xmit_state_cache:
++        return error;
++}     
++
++
++/* void */
++int
++ipsec_cleanup(void)
++{
++      int error = 0;
++
++#ifdef CONFIG_SYSCTL
++        ipsec_sysctl_unregister();
++#endif                                                                          
++#if defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++      if(udp4_unregister_esp_rcvencap(klips_old_encap) < 0) {
++              printk(KERN_ERR "KLIPS: can not unregister klips_rcv_encap function\n");
++      }
++#endif
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: "
++                  "calling ipsec_tunnel_cleanup_devices.\n");
++      error |= ipsec_tunnel_cleanup_devices();
++
++      KLIPS_PRINT(debug_netlink, "called ipsec_tunnel_cleanup_devices");
++
++#ifdef CONFIG_XFRM_ALTERNATE_STACK
++
++        xfrm_deregister_alternate_rcv(ipsec_rcv);
++
++#else // CONFIG_XFRM_ALTERNATE_STACK
++
++/* we never actually link IPCOMP to the stack */
++#ifdef IPCOMP_USED_ALONE
++#ifdef CONFIG_KLIPS_IPCOMP
++      if (openswan_inet_del_protocol(&comp_protocol, IPPROTO_COMP) < 0)
++              printk(KERN_INFO "klips_debug:ipsec_cleanup: "
++                     "comp close: can't remove protocol\n");
++#endif /* CONFIG_KLIPS_IPCOMP */
++#endif /* IPCOMP_USED_ALONE */
++
++#ifdef CONFIG_KLIPS_AH
++      if (openswan_inet_del_protocol(&ah_protocol, IPPROTO_AH) < 0)
++              printk(KERN_INFO "klips_debug:ipsec_cleanup: "
++                     "ah close: can't remove protocol\n");
++#endif /* CONFIG_KLIPS_AH */
++
++#ifdef CONFIG_KLIPS_ESP
++      if (openswan_inet_del_protocol(&esp_protocol, IPPROTO_ESP) < 0)
++              printk(KERN_INFO "klips_debug:ipsec_cleanup: "
++                     "esp close: can't remove protocol\n");
++#endif /* CONFIG_KLIPS_ESP */
++
++#endif // CONFIG_XFRM_ALTERNATE_STACK
++
++      error |= unregister_netdevice_notifier(&ipsec_dev_notifier);
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: "
++                  "calling ipsec_sadb_cleanup.\n");
++      error |= ipsec_sadb_cleanup(0);
++      error |= ipsec_sadb_free();
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: "
++                  "calling ipsec_radijcleanup.\n");
++      error |= ipsec_radijcleanup();
++      
++      KLIPS_PRINT(debug_pfkey, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: "
++                  "calling pfkey_cleanup.\n");
++      error |= pfkey_cleanup();
++
++      ipsec_rcv_state_cache_cleanup ();
++      ipsec_xmit_state_cache_cleanup ();
++
++      ipsec_proc_cleanup();
++
++      prng_final(&ipsec_prng);
++
++      return error;
++}
++
++#ifdef MODULE
++int
++init_module(void)
++{
++      int error = 0;
++
++      error |= ipsec_klips_init();
++
++      return error;
++}
++
++#ifndef NET_26
++void
++cleanup_module(void)
++{
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:cleanup_module: "
++                  "calling ipsec_cleanup.\n");
++
++      ipsec_cleanup();
++
++      KLIPS_PRINT(1, "klips_info:cleanup_module: "
++                  "ipsec module unloaded.\n");
++}
++#endif
++#endif /* MODULE */
++
++/*
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_ipcomp.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,253 @@
++/*
++ * processing code for IPCOMP
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>  /* struct device, and other headers */
++#include <linux/etherdevice.h>        /* eth_type_trans */
++#include <linux/ip.h>         /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_auth.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipsec_ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include "openswan/ipsec_proto.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++enum ipsec_rcv_value
++ipsec_rcv_ipcomp_checks(struct ipsec_rcv_state *irs,
++                      struct sk_buff *skb)
++{
++      int ipcompminlen;
++
++      ipcompminlen = sizeof(struct iphdr);
++
++      if(skb->len < (ipcompminlen + sizeof(struct ipcomphdr))) {
++              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                          "klips_debug:ipsec_rcv: "
++                          "runt comp packet of skb->len=%d received from %s, dropped.\n",
++                          skb->len,
++                          irs->ipsaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADLEN;
++      }
++
++      irs->protostuff.ipcompstuff.compp = (struct ipcomphdr *)skb_transport_header(skb);
++      irs->said.spi = htonl((__u32)ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi));
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_rcv_value
++ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs)
++{
++      unsigned int flags = 0;
++      struct ipsec_sa *ipsp = irs->ipsp;
++      struct sk_buff *skb;
++
++      skb=irs->skb;
++
++      ipsec_xmit_dmp("ipcomp", skb_transport_header(skb), skb->len);
++
++      if(ipsp == NULL) {
++              return IPSEC_RCV_SAIDNOTFOUND;
++      }
++
++      if(sysctl_ipsec_inbound_policy_check &&
++         ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) != (ntohl(irs->said.spi) & 0x0000ffff)) &&
++           (ipsp->ips_encalg != ntohl(irs->said.spi))   /* this is a workaround for peer non-compliance with rfc2393 */
++                  ))) {
++              char sa2[SATOT_BUF];
++              size_t sa_len2 = 0;
++
++              sa_len2 = KLIPS_SATOT(debug_rcv, &ipsp->ips_said, 0, sa2, sizeof(sa2));
++
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",
++                          irs->sa_len ? irs->sa : " (error)",
++                          ipsp != NULL ? (sa_len2 ? sa2 : " (error)") : "NULL",
++                          ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi),
++                          (__u32)ntohl(irs->said.spi),
++                          ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
++                          ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0);
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              return IPSEC_RCV_SAIDNOTFOUND;
++      }
++
++      ipsp->ips_comp_ratio_cbytes += ntohs(irs->ipp->tot_len);
++      irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh;
++
++      skb = skb_decompress(skb, ipsp, &flags);
++      if (!skb || flags) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "skb_decompress() returned error flags=%x, dropped.\n",
++                          flags);
++              if (irs->stats) {
++                      if (flags)
++                              irs->stats->rx_errors++;
++                      else
++                              irs->stats->rx_dropped++;
++              }
++              return IPSEC_RCV_IPCOMPFAILED;
++      }
++
++      /* make sure we update the pointer */
++      irs->skb = skb;
++      
++#ifdef NET_21
++      irs->ipp = ip_hdr(skb);
++#else /* NET_21 */
++      irs->ipp = skb->ip_hdr;
++#endif /* NET_21 */
++
++      ipsp->ips_comp_ratio_dbytes += ntohs(irs->ipp->tot_len);
++
++      KLIPS_PRINT(debug_rcv,
++                  "klips_debug:ipsec_rcv: "
++                  "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",
++                  irs->sa_len ? irs->sa : " (error)",
++                  (__u32)ntohl(irs->said.spi),
++                  ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
++                  ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0,
++                  irs->next_header);
++      KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->ipp);
++
++      return IPSEC_RCV_OK;
++}
++
++enum ipsec_xmit_value
++ipsec_xmit_ipcomp_setup(struct ipsec_xmit_state *ixs)
++{
++  unsigned int flags = 0;
++#ifdef CONFIG_KLIPS_DEBUG
++  unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
++#endif /* CONFIG_KLIPS_DEBUG */
++
++  ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
++
++  ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
++
++#ifdef NET_21
++  ixs->iph = ip_hdr(ixs->skb);
++#else /* NET_21 */
++  ixs->iph = ixs->skb->ip_hdr;
++#endif /* NET_21 */
++  
++  ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
++  
++#ifdef CONFIG_KLIPS_DEBUG
++  if (debug_tunnel & DB_TN_CROUT)
++    {
++      if (old_tot_len > ntohs(ixs->iph->tot_len))
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
++                  old_tot_len, ntohs(ixs->iph->tot_len),
++                  ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
++                  ntohl(ixs->ipsp->ips_said.spi),
++                  (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
++      else
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "packet did not compress (flags = %d).\n",
++                  flags);
++    }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++  return IPSEC_XMIT_OK;
++}
++
++struct xform_functions ipcomp_xform_funcs[]={
++      {
++              protocol:           IPPROTO_COMP,
++              rcv_checks:  ipsec_rcv_ipcomp_checks,
++              rcv_decrypt: ipsec_rcv_ipcomp_decomp,
++              xmit_setup:  ipsec_xmit_ipcomp_setup,
++              xmit_headroom: 0,
++              xmit_needtailroom: 0,
++      },
++};
++
++#if 0
++/* We probably don't want to install a pure IPCOMP protocol handler, but
++   only want to handle IPCOMP if it is encapsulated inside an ESP payload
++   (which is already handled) */
++#ifndef CONFIG_XFRM_ALTERNATE_STACK
++#ifdef CONFIG_KLIPS_IPCOMP
++struct inet_protocol comp_protocol =
++{
++      ipsec_rcv,                      /* COMP handler         */
++      NULL,                           /* COMP error control   */
++#ifdef NETDEV_25
++      1,                              /* no policy */
++#else
++      0,                              /* next */
++      IPPROTO_COMP,                   /* protocol ID */
++      0,                              /* copy */
++      NULL,                           /* data */
++      "COMP"                          /* name */
++#endif
++};
++#endif /* CONFIG_KLIPS_IPCOMP */
++#endif /* CONFIG_XFRM_ALTERNATE_STACK */
++#endif
++
++#endif /* CONFIG_KLIPS_IPCOMP */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_ipip.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,123 @@
++/*
++ * processing code for IPIP
++ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>  /* struct device, and other headers */
++#include <linux/etherdevice.h>        /* eth_type_trans */
++#include <linux/ip.h>         /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_auth.h"
++#include "openswan/ipsec_ipip.h"
++#include "openswan/ipsec_param.h"
++
++#include "openswan/ipsec_proto.h"
++
++enum ipsec_xmit_value
++ipsec_xmit_ipip_setup(struct ipsec_xmit_state *ixs)
++{
++  ixs->iph->version  = 4;
++
++  switch(sysctl_ipsec_tos) {
++  case 0:
++#ifdef NET_21
++    ixs->iph->tos = ip_hdr(ixs->skb)->tos;
++#else /* NET_21 */
++    ixs->iph->tos = ixs->skb->ip_hdr->tos;
++#endif /* NET_21 */
++    break;
++  case 1:
++    ixs->iph->tos = 0;
++    break;
++  default:
++    break;
++  }
++  ixs->iph->ttl      = SYSCTL_IPSEC_DEFAULT_TTL;
++  ixs->iph->frag_off = 0;
++  ixs->iph->saddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
++  ixs->iph->daddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
++  ixs->iph->protocol = IPPROTO_IPIP;
++  ixs->iph->ihl      = sizeof(struct iphdr) >> 2;
++  
++  KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
++  
++  ixs->newdst = (__u32)ixs->iph->daddr;
++  ixs->newsrc = (__u32)ixs->iph->saddr;
++  
++#ifdef NET_21
++  skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ip_hdr(ixs->skb)));
++#endif /* NET_21 */
++  return IPSEC_XMIT_OK;
++}
++
++struct xform_functions ipip_xform_funcs[]={
++  {
++        protocol:           IPPROTO_IPIP,
++        rcv_checks:         NULL,
++        rcv_setup_auth:     NULL,
++        rcv_calc_auth:      NULL,
++        rcv_decrypt:        NULL,
++        
++        xmit_setup:         ipsec_xmit_ipip_setup,
++        xmit_headroom:      sizeof(struct iphdr),
++        xmit_needtailroom:  0,
++  },
++};
++
++
++
++
++
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_kern24.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 2005 (C) Michael Richardson <mcr@xelerance.com>
++ *
++ * This is a file of functions which are present in 2.6 kernels,
++ * but are not available by default in the 2.4 series.
++ *
++ * As such this code is usually from the Linux kernel, and is covered by
++ * GPL.
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * $Id: ipsec_kern24.c,v 1.2 2005/05/20 03:19:18 mcr Exp $
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/spinlock.h>
++
++/*
++ * printk rate limiting, lifted from the networking subsystem.
++ *
++ * This enforces a rate limit: not more than one kernel message
++ * every printk_ratelimit_jiffies to make a denial-of-service
++ * attack impossible.
++ */
++static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
++
++int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
++{
++      static unsigned long toks = 10*5*HZ;
++      static unsigned long last_msg;
++      static int missed;
++      unsigned long flags;
++      unsigned long now = jiffies;
++
++      spin_lock_irqsave(&ratelimit_lock, flags);
++      toks += now - last_msg;
++      last_msg = now;
++      if (toks > (ratelimit_burst * ratelimit_jiffies))
++              toks = ratelimit_burst * ratelimit_jiffies;
++      if (toks >= ratelimit_jiffies) {
++              int lost = missed;
++              missed = 0;
++              toks -= ratelimit_jiffies;
++              spin_unlock_irqrestore(&ratelimit_lock, flags);
++              if (lost)
++                      printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
++              return 1;
++      }
++      missed++;
++      spin_unlock_irqrestore(&ratelimit_lock, flags);
++      return 0;
++}
++
++/* minimum time in jiffies between messages */
++int printk_ratelimit_jiffies = 5*HZ;
++
++/* number of messages we send before ratelimiting */
++int printk_ratelimit_burst = 10;
++
++int printk_ratelimit(void)
++{
++      return __printk_ratelimit(printk_ratelimit_jiffies,
++                              printk_ratelimit_burst);
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_life.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,221 @@
++/*
++ * @(#) lifetime structure utilities
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@freeswan.org>
++ *                 and Michael Richardson  <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ *
++ */
++
++/* 
++ * This provides series of utility functions for dealing with lifetime
++ * structures.
++ *
++ * ipsec_check_lifetime - returns -1    hard lifetime exceeded
++ *                                 0    soft lifetime exceeded
++ *                                 1    everything is okay
++ *                        based upon whether or not the count exceeds hard/soft
++ *
++ */
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif        /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#include <linux/netdevice.h>   /* struct device, struct net_device_stats and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <openswan.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_eroute.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_ipe4.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++
++
++enum ipsec_life_alive
++ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
++                   const char *lifename,
++                   const char *saname,
++                   enum ipsec_life_type ilt,
++                   enum ipsec_direction idir,
++                   struct ipsec_sa *ips)
++{
++      __u64 count;
++      const char *dir;
++
++      if(saname == NULL) {
++              saname = "unknown-SA";
++      }
++
++      if(idir == ipsec_incoming) {
++              dir = "incoming";
++      } else {
++              dir = "outgoing";
++      }
++              
++
++      if(ilt == ipsec_life_timebased) {
++              count = jiffies/HZ - il64->ipl_count;
++      } else {
++              count = il64->ipl_count;
++      }
++
++      if(il64->ipl_hard &&
++         (count > il64->ipl_hard)) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_lifetime_check: "
++                          "hard %s lifetime of SA:<%s%s%s> %s has been reached, SA expired, "
++                          "%s packet dropped.\n",
++                          lifename,
++                          IPS_XFORM_NAME(ips),
++                          saname,
++                          dir);
++
++              pfkey_expire(ips, 1);
++              return ipsec_life_harddied;
++      }
++
++      if(il64->ipl_soft &&
++         (count > il64->ipl_soft)) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_lifetime_check: "
++                          "soft %s lifetime of SA:<%s%s%s> %s has been reached, SA expiring, "
++                          "soft expire message sent up, %s packet still processed.\n",
++                          lifename,
++                          IPS_XFORM_NAME(ips),
++                          saname,
++                          dir);
++
++              if(ips->ips_state != K_SADB_SASTATE_DYING) {
++                      pfkey_expire(ips, 0);
++              }
++              ips->ips_state = K_SADB_SASTATE_DYING;
++
++              return ipsec_life_softdied;
++      }
++      return ipsec_life_okay;
++}
++
++
++/*
++ * This function takes a buffer (with length), a lifetime name and type,
++ * and formats a string to represent the current values of the lifetime.
++ * 
++ * It returns the number of bytes that the format took (or would take,
++ * if the buffer were large enough: snprintf semantics).
++ * This is used in /proc routines and in debug output.
++ */
++int
++ipsec_lifetime_format(char *buffer,
++                    int   buflen,
++                    char *lifename,
++                    enum ipsec_life_type timebaselife,
++                    struct ipsec_lifetime64 *lifetime)
++{
++      int len = 0;
++      __u64 count;
++
++      if(timebaselife == ipsec_life_timebased) {
++              count = jiffies/HZ - lifetime->ipl_count;
++      } else {
++              count = lifetime->ipl_count;
++      }
++
++      if(lifetime->ipl_count > 1 || 
++         lifetime->ipl_soft      ||
++         lifetime->ipl_hard) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) 
++              len = ipsec_snprintf(buffer, buflen,
++                             "%s(%Lu,%Lu,%Lu)",
++                             lifename,
++                             count,
++                             lifetime->ipl_soft,
++                             lifetime->ipl_hard);
++#else /* XXX high 32 bits are not displayed */
++              len = ipsec_snprintf(buffer, buflen,
++                              "%s(%lu,%lu,%lu)",
++                              lifename,
++                              (unsigned long)count,
++                              (unsigned long)lifetime->ipl_soft,
++                              (unsigned long)lifetime->ipl_hard);
++#endif
++      }
++
++      return len;
++}
++
++void
++ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
++                        __u64 newvalue)
++{
++      if(newvalue &&
++         (!lifetime->ipl_hard ||
++          (newvalue < lifetime->ipl_hard))) {
++              lifetime->ipl_hard = newvalue;
++
++              if(!lifetime->ipl_soft &&
++                 (lifetime->ipl_hard < lifetime->ipl_soft)) {
++                      lifetime->ipl_soft = lifetime->ipl_hard;
++              }
++      }
++}     
++
++void
++ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
++                        __u64 newvalue)
++{
++      if(newvalue &&
++         (!lifetime->ipl_soft ||
++          (newvalue < lifetime->ipl_soft))) {
++              lifetime->ipl_soft = newvalue;
++
++              if(lifetime->ipl_hard &&
++                 (lifetime->ipl_hard < lifetime->ipl_soft)) {
++                      lifetime->ipl_soft = lifetime->ipl_hard;
++              }
++      }
++}
++
++      
++/*
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_mast.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,869 @@
++/*
++ * IPSEC MAST code.
++ * Copyright (C) 2005 Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++char ipsec_mast_c_version[] = "RCSID $Id: ipsec_mast.c,v 1.7 2005/04/29 05:10:22 mcr Exp $";
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif        /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <net/arp.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++#include <linux/skbuff.h>
++
++#include <linux/netdevice.h>   /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <net/xfrm.h>
++
++#include <openswan.h>
++
++#include <net/icmp.h>         /* icmp_send() */
++#include <net/ip.h>
++#ifdef NETDEV_23
++# include <linux/netfilter_ipv4.h>
++#endif /* NETDEV_23 */
++
++#include <linux/if_arp.h>
++
++#include "openswan/ipsec_kversion.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_eroute.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_xmit.h"
++#include "openswan/ipsec_mast.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_ipe4.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_kern24.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#include <linux/udp.h>
++#endif
++
++int ipsec_mastdevice_count = -1;
++int debug_mast;
++
++static __u32 zeroes[64];
++
++DEBUG_NO_STATIC int
++ipsec_mast_open(struct net_device *dev)
++{
++        struct mastpriv *prv = dev->priv; 
++
++      prv = prv;
++
++      /*
++       * Can't open until attached.
++       */
++
++      KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                  "klips_debug:ipsec_mast_open: "
++                  "dev = %s\n",
++                  dev->name);
++
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_mast_close(struct net_device *dev)
++{
++      return 0;
++}
++
++static inline int ipsec_mast_xmit2(struct sk_buff *skb)
++{
++      return dst_output(skb);
++}
++
++#ifdef HAVE_IPSEC_SAREF
++int ip_cmsg_send_ipsec(struct cmsghdr *cmsg, struct ipcm_cookie *ipc)
++{
++      struct ipsec_sa *sa1;
++      xfrm_sec_unique_t *ref;
++      struct sec_path *sp;
++
++      if(cmsg->cmsg_len != CMSG_LEN(sizeof(xfrm_sec_unique_t))) {
++              return -EINVAL;
++      }
++
++      ref = (xfrm_sec_unique_t *)CMSG_DATA(cmsg);
++
++      sp = secpath_dup(NULL);
++      if(!sp) {
++              return -EINVAL;
++      }
++
++      sp->ref = *ref;
++      KLIPS_PRINT(debug_mast, "sending with saref=%u\n", sp->ref);
++              
++      sa1 = ipsec_sa_getbyref(sp->ref);
++      if(sa1 && sa1->ips_out) {
++              ipc->oif = sa1->ips_out->ifindex;
++              KLIPS_PRINT(debug_mast, "setting oif: %d\n", ipc->oif);
++      }
++      ipsec_sa_put(sa1);
++      
++      ipc->sp  = sp;
++
++      return 0;
++}
++#endif
++
++#if 0
++/* Paul: This seems to be unused dead code */
++enum ipsec_xmit_value
++ipsec_mast_send(struct ipsec_xmit_state*ixs)
++{
++      /* new route/dst cache code from James Morris */
++      ixs->skb->dev = ixs->physdev;
++      /*skb_orphan(ixs->skb);*/
++      if((ixs->error = ip_route_output(&ixs->route,
++                                  ixs->skb->nh.iph->daddr,
++                                  ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
++                                  RT_TOS(ixs->skb->nh.iph->tos),
++                                  ixs->physdev->ifindex /* rgb: should this be 0? */))) {
++              ixs->stats->tx_errors++;
++              KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
++                          "klips_debug:ipsec_xmit_send: "
++                          "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
++                          ixs->error,
++                          ixs->route->u.dst.dev->name);
++              return IPSEC_XMIT_ROUTEERR;
++      }
++      if(ixs->dev == ixs->route->u.dst.dev) {
++              ip_rt_put(ixs->route);
++              /* This is recursion, drop it. */
++              ixs->stats->tx_errors++;
++              KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
++                          "klips_debug:ipsec_xmit_send: "
++                          "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
++                          ixs->dev->name);
++              return IPSEC_XMIT_RECURSDETECT;
++      }
++      dst_release(ixs->skb->dst);
++      ixs->skb->dst = &ixs->route->u.dst;
++      ixs->stats->tx_bytes += ixs->skb->len;
++      if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
++              ixs->stats->tx_errors++;
++              printk(KERN_WARNING
++                     "klips_error:ipsec_xmit_send: "
++                     "tried to __skb_pull nh-data=%ld, %d available.  This should never happen, please report.\n",
++                     (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
++                     ixs->skb->len);
++              return IPSEC_XMIT_PUSHPULLERR;
++      }
++      __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
++
++      ipsec_nf_reset(ixs->skb);
++
++      KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
++                  "klips_debug:ipsec_xmit_send: "
++                  "...done, calling ip_send() on device:%s\n",
++                  ixs->skb->dev ? ixs->skb->dev->name : "NULL");
++      KLIPS_IP_PRINT(debug_mast & DB_MAST_XMIT, ixs->skb->nh.iph);
++      {
++              int err;
++
++              err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
++                            ipsec_mast_xmit2);
++              if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
++                      if(net_ratelimit())
++                              printk(KERN_ERR
++                                     "klips_error:ipsec_xmit_send: "
++                                     "ip_send() failed, err=%d\n", 
++                                     -err);
++                      ixs->stats->tx_errors++;
++                      ixs->stats->tx_aborted_errors++;
++                      ixs->skb = NULL;
++                      return IPSEC_XMIT_IPSENDFAILURE;
++              }
++      }
++      ixs->stats->tx_packets++;
++        ixs->skb = NULL;
++
++        return IPSEC_XMIT_OK;
++}
++#endif
++
++static void
++ipsec_mast_xsm_complete(
++      struct ipsec_xmit_state *ixs,
++      enum ipsec_xmit_value stat)
++{
++      if (stat != IPSEC_XMIT_OK) {
++              KLIPS_PRINT(debug_mast,
++                              "klips_debug:ipsec_mast_xsm_complete: ipsec_xsm failed: %d\n",
++                              stat);
++              goto cleanup;
++      }
++
++      /* do any final NAT-encapsulation */
++      stat = ipsec_nat_encap(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++      /* now send the packet again */
++      {
++              struct flowi fl;
++              
++              memset(&fl, 0, sizeof(fl));
++              ipsec_xmit_send(ixs, &fl);
++      }
++
++cleanup:
++      ipsec_xmit_cleanup(ixs);
++
++      if(ixs->ipsp) {
++              ipsec_sa_put(ixs->ipsp);
++              ixs->ipsp=NULL;
++      }
++      if(ixs->skb) {
++              ipsec_kfree_skb(ixs->skb);
++              ixs->skb=NULL;
++      }
++      ipsec_xmit_state_delete(ixs);
++}
++
++/*
++ *    This function assumes it is being called from dev_queue_xmit()
++ *    and that skb is filled properly by that function.
++ */
++int
++ipsec_mast_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct ipsec_xmit_state *ixs;
++      IPsecSAref_t SAref;
++
++      if(skb == NULL) {
++              printk("mast start_xmit passed NULL\n");
++              return 0;
++      }
++              
++      ixs = ipsec_xmit_state_new();
++      if(ixs == NULL) {
++              printk("mast failed to allocate IXS\n");
++              return 0;
++      }
++
++      ixs->skb = skb;
++      SAref = 0;
++      if(skb->nfmark & 0x80000000) {
++              SAref = NFmark2IPsecSAref(skb->nfmark);
++              KLIPS_PRINT(debug_mast, "getting SAref=%d from nfmark\n",
++                          SAref);
++      }
++
++#ifdef HAVE_IPSEC_SAREF
++      if(skb->sp && skb->sp->ref != IPSEC_SAREF_NULL) {
++              SAref = skb->sp->ref;
++              KLIPS_PRINT(debug_mast, "getting SAref=%d from sec_path\n",
++                          SAref);
++      }
++#endif
++      KLIPS_PRINT(debug_mast, "skb=%p\n", skb);
++
++      ipsec_xmit_sanity_check_skb(ixs);
++
++      ixs->ipsp = ipsec_sa_getbyref(SAref);
++      if(ixs->ipsp == NULL) {
++              KLIPS_ERROR(debug_mast, "%s: no SA for saref=%d (sp=%p)\n",
++                          dev->name, SAref, skb->sp);
++              ipsec_kfree_skb(skb);
++              return 0;
++      }
++
++      /*
++       * we should be calculating the MTU by looking up a route
++       * based upon the destination in the SA, and then cache
++       * it into the SA, but we don't do that right now.
++       */
++      ixs->cur_mtu = 1460;
++      ixs->physmtu = 1460;
++
++      ixs->xsm_complete = ipsec_mast_xsm_complete;
++      ixs->state = IPSEC_XSM_INIT2;   /* we start later in the process */
++
++      ipsec_xsm(ixs);
++      return 0;
++
++}
++
++DEBUG_NO_STATIC struct net_device_stats *
++ipsec_mast_get_stats(struct net_device *dev)
++{
++      return &(((struct mastpriv *)(dev->priv))->mystats);
++}
++
++#if 0
++/*
++ * Revectored calls.
++ * For each of these calls, a field exists in our private structure.
++ */
++DEBUG_NO_STATIC int
++ipsec_mast_hard_header(struct sk_buff *skb, struct net_device *dev,
++      unsigned short type, void *daddr, void *saddr, unsigned len)
++{
++      struct mastpriv *prv = dev->priv;
++      struct net_device_stats *stats; /* This device's statistics */
++      int ret = 0;
++      
++      if(skb == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                          "klips_debug:ipsec_mast_hard_header: "
++                          "no skb...\n");
++              return -ENODATA;
++      }
++
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                          "klips_debug:ipsec_mast_hard_header: "
++                          "no device...\n");
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                  "klips_debug:ipsec_mast_hard_header: "
++                  "skb->dev=%s\n",
++                  dev->name);
++      
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                          "klips_debug:ipsec_mast_hard_header: "
++                          "no private space associated with dev=%s\n",
++                          dev->name ? dev->name : "NULL");
++              return -ENODEV;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      /* check if we have to send a IPv6 packet. It might be a Router
++         Solicitation, where the building of the packet happens in
++         reverse order:
++         1. ll hdr,
++         2. IPv6 hdr,
++         3. ICMPv6 hdr
++         -> skb->nh.raw is still uninitialized when this function is
++         called!!  If this is no IPv6 packet, we can print debugging
++         messages, otherwise we skip all debugging messages and just
++         build the ll header */
++      if(type != ETH_P_IPV6) {
++              /* execute this only, if we don't have to build the
++                 header for a IPv6 packet */
++              if(!prv->hard_header) {
++                      KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                                  "klips_debug:ipsec_mast_hard_header: "
++                                  "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
++                                  saddr,
++                                  daddr,
++                                  len,
++                                  type,
++                                  dev->name);
++                      KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
++                                      "ip=%08x->%08x\n",
++                                      (__u32)ntohl(skb->nh.iph->saddr),
++                                      (__u32)ntohl(skb->nh.iph->daddr) );
++                      stats->tx_dropped++;
++                      return -ENODEV;
++              }
++      } else {
++              KLIPS_PRINT(debug_mast,
++                          "klips_debug:ipsec_mast_hard_header: "
++                          "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
++      }                                                                      
++
++      return ret;
++}
++
++DEBUG_NO_STATIC int
++ipsec_mast_rebuild_header(struct sk_buff *skb)
++{
++      struct mastpriv *prv = skb->dev->priv;
++
++      prv = prv;
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_mast_set_mac_address(struct net_device *dev, void *addr)
++{
++      struct mastpriv *prv = dev->priv;
++      
++      prv = prv;
++      return 0;
++
++}
++
++DEBUG_NO_STATIC void
++ipsec_mast_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char *  haddr)
++{
++      struct mastpriv *prv = dev->priv;
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                          "klips_debug:ipsec_mast_cache_update: "
++                          "no device...");
++              return;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                          "klips_debug:ipsec_mast_cache_update: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return;
++      }
++
++      KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                  "klips_debug:ipsec_mast: "
++                  "Revectored cache_update\n");
++      return;
++}
++#endif
++
++DEBUG_NO_STATIC int
++ipsec_mast_neigh_setup(struct neighbour *n)
++{
++      KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                  "klips_debug:ipsec_mast_neigh_setup:\n");
++
++        if (n->nud_state == NUD_NONE) {
++                n->ops = &arp_broken_ops;
++                n->output = n->ops->output;
++        }
++        return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_mast_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
++{
++      KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
++                  "klips_debug:ipsec_mast_neigh_setup_dev: "
++                  "setting up %s\n",
++                  dev ? dev->name : "NULL");
++
++        if (p->tbl->family == AF_INET) {
++                p->neigh_setup = ipsec_mast_neigh_setup;
++                p->ucast_probes = 0;
++                p->mcast_probes = 0;
++        }
++        return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_mast_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      struct ipsecmastconf *cf = (struct ipsecmastconf *)&ifr->ifr_data;
++      struct ipsecpriv *prv = dev->priv;
++
++      cf = cf;
++      prv=prv;
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_ioctl: "
++                          "device not supplied.\n");
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                  "klips_debug:ipsec_mast_ioctl: "
++                  "tncfg service call #%d for dev=%s\n",
++                  cmd,
++                  dev->name ? dev->name : "NULL");
++
++      switch (cmd) {
++      default:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_ioctl: "
++                          "unknown command %d.\n",
++                          cmd);
++              return -EOPNOTSUPP;
++        
++      }
++}
++
++int
++ipsec_mast_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
++{
++      struct net_device *dev = ptr;
++      struct mastpriv *priv = dev->priv;
++
++      priv = priv;
++
++      if (dev == NULL) {
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "dev=NULL for event type %ld.\n",
++                          event);
++              return(NOTIFY_DONE);
++      }
++
++      /* check for loopback devices */
++      if (dev && (dev->flags & IFF_LOOPBACK)) {
++              return(NOTIFY_DONE);
++      }
++
++      switch (event) {
++      case NETDEV_DOWN:
++              /* look very carefully at the scope of these compiler
++                 directives before changing anything... -- RGB */
++
++      case NETDEV_UNREGISTER:
++              switch (event) {
++              case NETDEV_DOWN:
++                      KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                                  "klips_debug:ipsec_mast_device_event: "
++                                  "NETDEV_DOWN dev=%s flags=%x\n",
++                                  dev->name,
++                                  dev->flags);
++                      if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
++                              printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
++                                     dev->name);
++                      }
++                      break;
++              case NETDEV_UNREGISTER:
++                      KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                                  "klips_debug:ipsec_mast_device_event: "
++                                  "NETDEV_UNREGISTER dev=%s flags=%x\n",
++                                  dev->name,
++                                  dev->flags);
++                      break;
++              }
++              break;
++
++      case NETDEV_UP:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_UP dev=%s\n",
++                          dev->name);
++              break;
++
++      case NETDEV_REBOOT:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_REBOOT dev=%s\n",
++                          dev->name);
++              break;
++
++      case NETDEV_CHANGE:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_CHANGE dev=%s flags=%x\n",
++                          dev->name,
++                          dev->flags);
++              break;
++
++      case NETDEV_REGISTER:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_REGISTER dev=%s\n",
++                          dev->name);
++              break;
++
++      case NETDEV_CHANGEMTU:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
++                          dev->name,
++                          dev->mtu);
++              break;
++
++      case NETDEV_CHANGEADDR:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_CHANGEADDR dev=%s\n",
++                          dev->name);
++              break;
++
++      case NETDEV_GOING_DOWN:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_GOING_DOWN dev=%s\n",
++                          dev->name);
++              break;
++
++      case NETDEV_CHANGENAME:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "NETDEV_CHANGENAME dev=%s\n",
++                          dev->name);
++              break;
++
++      default:
++              KLIPS_PRINT(debug_mast & DB_MAST_INIT,
++                          "klips_debug:ipsec_mast_device_event: "
++                          "event type %ld unrecognised for dev=%s\n",
++                          event,
++                          dev->name);
++              break;
++      }
++      return NOTIFY_DONE;
++}
++
++/*
++ *    Called when an ipsec mast device is initialized.
++ *    The ipsec mast device structure is passed to us.
++ */
++int
++ipsec_mast_probe(struct net_device *dev)
++{
++      int i;
++
++      KLIPS_PRINT(debug_mast,
++                  "klips_debug:ipsec_mast_init: "
++                  "allocating %lu bytes initialising device: %s\n",
++                  (unsigned long) sizeof(struct mastpriv),
++                  dev->name ? dev->name : "NULL");
++
++      /* Add our mast functions to the device */
++      dev->open               = ipsec_mast_open;
++      dev->stop               = ipsec_mast_close;
++      dev->hard_start_xmit    = ipsec_mast_start_xmit;
++      dev->get_stats          = ipsec_mast_get_stats;
++
++      dev->priv = kmalloc(sizeof(struct mastpriv), GFP_KERNEL);
++      if (dev->priv == NULL)
++              return -ENOMEM;
++      memset((caddr_t)(dev->priv), 0, sizeof(struct mastpriv));
++
++      for(i = 0; i < sizeof(zeroes); i++) {
++              ((__u8*)(zeroes))[i] = 0;
++      }
++      
++      dev->set_multicast_list = NULL;
++      dev->do_ioctl           = ipsec_mast_ioctl;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      dev->header_ops = NULL;
++#else
++      dev->hard_header        = NULL;
++      dev->rebuild_header     = NULL;
++      dev->header_cache_update= NULL;
++#endif
++      dev->set_mac_address    = NULL;
++      dev->neigh_setup        = ipsec_mast_neigh_setup_dev;
++      dev->hard_header_len    = 8+20+20+8;
++      dev->mtu                = 0;
++      dev->addr_len           = 0;
++      dev->type               = ARPHRD_NONE;
++      dev->tx_queue_len       = 10;           
++      memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN);       /* what if this is not attached to ethernet? */
++
++      /* New-style flags. */
++      dev->flags              = IFF_NOARP;
++
++      /* We're done.  Have I forgotten anything? */
++      return 0;
++}
++
++#ifdef alloc_netdev
++static void ipsec_mast_netdev_setup(struct net_device *dev)
++{
++}
++#endif
++struct net_device *mastdevices[IPSEC_NUM_IFMAX];
++int mastdevices_max=-1;
++
++int ipsec_mast_createnum(int vifnum) 
++{
++      struct net_device *im;
++      int vifentry;
++      char name[IFNAMSIZ];
++
++      if(vifnum > IPSEC_NUM_IFMAX) {
++              return -ENOENT;
++      }
++
++      if(mastdevices[vifnum]!=NULL) {
++              return -EEXIST;
++      }
++      
++      /* no identical device */
++      if(vifnum > mastdevices_max) {
++              mastdevices_max=vifnum;
++      }
++      vifentry = vifnum;
++
++      snprintf(name, IFNAMSIZ, MAST_DEV_FORMAT, vifnum);
++      
++#ifdef alloc_netdev
++      im = alloc_netdev(0, name, ipsec_mast_netdev_setup);
++#else
++      im = (struct net_device *)kmalloc(sizeof(struct net_device),GFP_KERNEL);
++#endif
++      if(im == NULL) {
++              printk(KERN_ERR "failed to allocate space for mast%d device\n", vifnum);
++              return -ENOMEM;
++      }
++
++#ifndef alloc_netdev
++      memset((caddr_t)im, 0, sizeof(struct net_device));
++      memcpy(im->name, name, IFNAMSIZ);
++#endif
++              
++      im->init = ipsec_mast_probe;
++
++      if(register_netdev(im) != 0) {
++              printk(KERN_ERR "ipsec_mast: failed to register %s\n",
++                     im->name);
++              return -EIO;
++      }
++
++      dev_hold(im);
++      mastdevices[vifentry]=im;
++
++      return 0;
++}
++
++
++int
++ipsec_mast_deletenum(int vifnum)
++{
++      struct net_device *dev_ipsec;
++      
++      if(vifnum > IPSEC_NUM_IFMAX) {
++              return -ENOENT;
++      }
++
++      dev_ipsec = mastdevices[vifnum];
++      if(dev_ipsec == NULL) {
++              return -ENOENT;
++      }
++
++      /* release reference */
++      mastdevices[vifnum]=NULL;
++      ipsec_dev_put(dev_ipsec);
++      
++      KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
++                  dev_ipsec->name,
++                  atomic_read(&dev_ipsec->refcnt));
++      unregister_netdev(dev_ipsec);
++      KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", dev_ipsec->name);
++#ifndef NETDEV_23
++      kfree(dev_ipsec->name);
++      dev_ipsec->name=NULL;
++#endif /* !NETDEV_23 */
++      kfree(dev_ipsec->priv);
++      dev_ipsec->priv=NULL;
++
++      return 0;
++}
++
++
++struct net_device *
++ipsec_mast_get_device(int vifnum)
++{
++      int ovifnum = vifnum;
++
++      if(vifnum > IPSECDEV_OFFSET) {
++              return ipsec_tunnel_get_device(vifnum-IPSECDEV_OFFSET);
++      } else {
++              struct net_device *nd;
++              
++              if(vifnum >= MASTTRANSPORT_OFFSET) {
++                      vifnum -= MASTTRANSPORT_OFFSET;
++              }
++
++              if(vifnum <= mastdevices_max) {
++                      nd = mastdevices[vifnum];
++
++                      if(nd) dev_hold(nd);
++                      return nd;
++              } else {
++                      KLIPS_ERROR(debug_tunnel,
++                                  "no such vif %d (ovif=%d)\n", vifnum, ovifnum);
++                      return NULL;
++              }
++      }
++}
++
++unsigned int
++ipsec_mast_is_transport(int vifnum)
++{
++      if(vifnum > MASTTRANSPORT_OFFSET && vifnum <IPSECDEV_OFFSET) {
++              return 1;
++      }
++      return 0;
++}
++
++int 
++ipsec_mast_init_devices(void)
++{
++      /*
++       * mast0 is used for transport mode stuff, and generally is
++       * the default unless the user decides to create more.
++       */
++      ipsec_mast_createnum(0);
++  
++      return 0;
++}
++
++/* void */
++int
++ipsec_mast_cleanup_devices(void)
++{
++      int error = 0;
++      int i;
++      struct net_device *dev_mast;
++      
++      for(i = 0; i <= mastdevices_max; i++) {
++              if(mastdevices[i]!=NULL) {
++                      dev_mast = mastdevices[i];
++                      unregister_netdev(dev_mast);
++                      kfree(dev_mast->priv);
++                      dev_mast->priv=NULL;
++                      dev_put(mastdevices[i]);
++                      mastdevices[i]=NULL;
++              }
++      }
++      return error;
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
++
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_md5c.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,406 @@
++/*
++ * RCSID $Id: ipsec_md5c.c,v 1.10 2005/04/15 01:25:57 mcr Exp $
++ */
++
++/*
++ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
++ * changes to accomodate it in the kernel by ji.
++ */
++
++#include <asm/byteorder.h>
++#include <linux/string.h>
++
++#include "openswan/ipsec_md5h.h"
++
++/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
++ */
++
++/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
++rights reserved.
++
++License to copy and use this software is granted provided that it
++is identified as the "RSA Data Security, Inc. MD5 Message-Digest
++Algorithm" in all material mentioning or referencing this software
++or this function.
++
++License is also granted to make and use derivative works provided
++that such works are identified as "derived from the RSA Data
++Security, Inc. MD5 Message-Digest Algorithm" in all material
++mentioning or referencing the derived work.
++
++RSA Data Security, Inc. makes no representations concerning either
++the merchantability of this software or the suitability of this
++software for any particular purpose. It is provided "as is"
++without express or implied warranty of any kind.
++
++These notices must be retained in any copies of any part of this
++documentation and/or software.
++ */
++
++/*
++ * Additions by JI
++ * 
++ * HAVEMEMCOPY is defined if mem* routines are available
++ *
++ * HAVEHTON is defined if htons() and htonl() can be used
++ * for big/little endian conversions
++ *
++ */
++
++#define HAVEMEMCOPY
++#ifdef __LITTLE_ENDIAN
++#define LITTLENDIAN
++#endif
++#ifdef __BIG_ENDIAN
++#define BIGENDIAN
++#endif
++
++/* Constants for MD5Transform routine.
++ */
++
++#define S11 7
++#define S12 12
++#define S13 17
++#define S14 22
++#define S21 5
++#define S22 9
++#define S23 14
++#define S24 20
++#define S31 4
++#define S32 11
++#define S33 16
++#define S34 23
++#define S41 6
++#define S42 10
++#define S43 15
++#define S44 21
++
++static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
++
++#ifdef LITTLEENDIAN
++#define Encode MD5_memcpy
++#define Decode MD5_memcpy
++#else
++static void Encode PROTO_LIST
++  ((unsigned char *, UINT4 *, unsigned int));
++static void Decode PROTO_LIST
++  ((UINT4 *, unsigned char *, unsigned int));
++#endif
++
++#ifdef HAVEMEMCOPY
++/* no need to include <memory.h> here; <linux/string.h> defines these */
++#define MD5_memcpy    memcpy
++#define MD5_memset    memset
++#else
++#ifdef HAVEBCOPY
++#define MD5_memcpy(_a,_b,_c) bcopy((_b),(_a),(_c))
++#define MD5_memset(_a,_b,_c) bzero((_a),(_c))
++#else
++static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
++static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
++#endif
++#endif
++static unsigned char PADDING[64] = {
++  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/* F, G, H and I are basic MD5 functions.
++ */
++#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
++#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++#define I(x, y, z) ((y) ^ ((x) | (~z)))
++
++/* ROTATE_LEFT rotates x left n bits.
++ */
++#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
++
++/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
++Rotation is separate from addition to prevent recomputation.
++ */
++#define FF(a, b, c, d, x, s, ac) { \
++ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++  }
++#define GG(a, b, c, d, x, s, ac) { \
++ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++  }
++#define HH(a, b, c, d, x, s, ac) { \
++ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++  }
++#define II(a, b, c, d, x, s, ac) { \
++ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
++ (a) = ROTATE_LEFT ((a), (s)); \
++ (a) += (b); \
++  }
++
++/*
++ * MD5 initialization. Begins an MD5 operation, writing a new context.
++ */
++void osMD5Init(void *vcontext)
++{
++  MD5_CTX *context = vcontext;                                     
++
++  context->count[0] = context->count[1] = 0;
++  /* Load magic initialization constants.*/
++  context->state[0] = 0x67452301;
++  context->state[1] = 0xefcdab89;
++  context->state[2] = 0x98badcfe;
++  context->state[3] = 0x10325476;
++}
++
++/* MD5 block update operation. Continues an MD5 message-digest
++  operation, processing another message block, and updating the
++  context.
++ */
++void osMD5Update (vcontext, input, inputLen)
++     void *vcontext;
++     unsigned char *input;                                /* input block */
++     __u32 inputLen;                     /* length of input block */
++{
++  MD5_CTX *context = vcontext;                                     
++  __u32 i;
++  unsigned int index, partLen;
++
++  /* Compute number of bytes mod 64 */
++  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
++
++  /* Update number of bits */
++  if ((context->count[0] += ((UINT4)inputLen << 3))
++   < ((UINT4)inputLen << 3))
++ context->count[1]++;
++  context->count[1] += ((UINT4)inputLen >> 29);
++
++  partLen = 64 - index;
++
++  /* Transform as many times as possible.
++*/
++  if (inputLen >= partLen) {
++ MD5_memcpy
++   ((POINTER)&context->buffer[index], (POINTER)input, partLen);
++ MD5Transform (context->state, context->buffer);
++
++ for (i = partLen; i + 63 < inputLen; i += 64)
++   MD5Transform (context->state, &input[i]);
++
++ index = 0;
++  }
++  else
++ i = 0;
++
++  /* Buffer remaining input */
++  MD5_memcpy
++ ((POINTER)&context->buffer[index], (POINTER)&input[i],
++  inputLen-i);
++}
++
++/* MD5 finalization. Ends an MD5 message-digest operation, writing the
++  the message digest and zeroizing the context.
++ */
++void osMD5Final (digest, vcontext)
++unsigned char digest[16];                         /* message digest */
++void *vcontext;                                       /* context */
++{
++  MD5_CTX *context = vcontext;                                     
++  unsigned char bits[8];
++  unsigned int index, padLen;
++
++  /* Save number of bits */
++  Encode (bits, context->count, 8);
++
++  /* Pad out to 56 mod 64.
++*/
++  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
++  padLen = (index < 56) ? (56 - index) : (120 - index);
++  osMD5Update (context, PADDING, padLen);
++
++  /* Append length (before padding) */
++  osMD5Update (context, bits, 8);
++
++  if (digest != NULL)                 /* Bill Simpson's padding */
++  {
++        /* store state in digest */
++        Encode (digest, context->state, 16);
++
++        /* Zeroize sensitive information.
++         */
++        MD5_memset ((POINTER)context, 0, sizeof (*context));
++  }
++}
++
++/* MD5 basic transformation. Transforms state based on block.
++ */
++static void MD5Transform (state, block)
++UINT4 state[4];
++unsigned char block[64];
++{
++  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
++
++  Decode (x, block, 64);
++
++  /* Round 1 */
++  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
++  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
++  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
++  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
++  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
++  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
++  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
++  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
++  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
++  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
++  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
++  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
++  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
++  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
++  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
++  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
++
++ /* Round 2 */
++  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
++  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
++  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
++  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
++  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
++  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
++  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
++  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
++  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
++  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
++  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
++  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
++  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
++  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
++  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
++  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
++
++  /* Round 3 */
++  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
++  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
++  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
++  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
++  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
++  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
++  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
++  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
++  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
++  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
++  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
++  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
++  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
++  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
++  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
++  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
++
++  /* Round 4 */
++  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
++  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
++  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
++  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
++  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
++  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
++  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
++  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
++  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
++  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
++  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
++  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
++  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
++  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
++  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
++  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
++
++  state[0] += a;
++  state[1] += b;
++  state[2] += c;
++  state[3] += d;
++
++  /* Zeroize sensitive information.
++*/
++  MD5_memset ((POINTER)x, 0, sizeof (x));
++}
++
++#ifndef LITTLEENDIAN
++
++/* Encodes input (UINT4) into output (unsigned char). Assumes len is
++  a multiple of 4.
++ */
++static void Encode (output, input, len)
++unsigned char *output;
++UINT4 *input;
++unsigned int len;
++{
++  unsigned int i, j;
++
++  for (i = 0, j = 0; j < len; i++, j += 4) {
++ output[j] = (unsigned char)(input[i] & 0xff);
++ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
++ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
++ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
++  }
++}
++
++/* Decodes input (unsigned char) into output (UINT4). Assumes len is
++  a multiple of 4.
++ */
++static void Decode (output, input, len)
++UINT4 *output;
++unsigned char *input;
++unsigned int len;
++{
++  unsigned int i, j;
++
++  for (i = 0, j = 0; j < len; i++, j += 4)
++ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
++   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
++}
++
++#endif
++
++#ifndef HAVEMEMCOPY
++#ifndef HAVEBCOPY
++/* Note: Replace "for loop" with standard memcpy if possible.
++ */
++
++static void MD5_memcpy (output, input, len)
++POINTER output;
++POINTER input;
++unsigned int len;
++{
++  unsigned int i;
++
++  for (i = 0; i < len; i++)
++
++ output[i] = input[i];
++}
++
++/* Note: Replace "for loop" with standard memset if possible.
++ */
++
++static void MD5_memset (output, value, len)
++POINTER output;
++int value;
++unsigned int len;
++{
++  unsigned int i;
++
++  for (i = 0; i < len; i++)
++ ((char *)output)[i] = (char)value;
++}
++#endif
++#endif
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_ocf.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,739 @@
++/*
++ * IPSEC OCF support
++ *
++ * This code written by David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2005 Intel Corporation.  All Rights Reserved.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++
++#include <linux/interrupt.h>
++
++#include <net/ip.h>
++
++#include <openswan.h>
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_xmit.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_auth.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_ah.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "ipsec_ocf.h"
++
++extern int debug_pfkey;
++extern int debug_rcv;
++
++int ipsec_ocf_crid = (CRYPTOCAP_F_HARDWARE|CRYPTOCAP_F_SOFTWARE);
++#if 0 /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
++/*
++ * allow users to force us to a particular OCF driver
++ */
++char *ipsec_ocf_driver = NULL;
++module_parm(ipsec_ocf_driver, charp, 0644);
++MODULE_PARM_DESC(ipsec_ocf_driver,
++      "Driver name (ie., cryptosoft), hw, sw, both (default both)");
++#endif
++
++/*
++ * Tuning parameters,  the settings below appear best for
++ * the IXP
++ */
++#define USE_BATCH 1   /* enable batch mode */
++#define USE_CBIMM 1   /* enable immediate callbacks */
++#define FORCE_QS  0   /* force use of queues for continuation of state machine */
++#ifdef DECLARE_TASKLET
++#define USE_TASKLET 1  /* use tasklet for continuation of state machine */
++#else
++#define USE_TASKLET 0  /* don't use tasklet for continuation of state machine */
++#endif
++/*
++ * Because some OCF operations are synchronous (ie., software encryption)
++ * we need to protect ourselves from distructive re-entry.  All we do
++ * is track where we are at and either callback  immediately or Q the
++ * callback to avoid conflicts.  This allows us to deal with the fact that
++ * OCF doesn't tell us if our crypto operations will be async or sync.
++ */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++#define       _INIT_WORK(wq, fn, arg) INIT_WORK(&(wq), (void (*)(struct work_struct *))(fn))
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++#define       _INIT_WORK(wq, fn, arg) INIT_WORK(&(wq), (void (*)(struct work_queue *))(fn))
++#else
++#define       _INIT_WORK(wq, fn, arg) INIT_WORK(&(wq), (void (*)(void *))(fn), (void *)(arg))
++#endif
++
++#define PROCESS_LATER(wq, sm, arg) \
++      ({ \
++              _INIT_WORK(wq, sm, arg); \
++              schedule_work(&(wq)); \
++      })
++
++#define PROCESS_NOW(sm, arg) \
++      ({ \
++              (*sm)(arg); \
++      })
++
++#if USE_TASKLET == 1
++      #define PROCESS_NEXT(this, wqsm, sm) ({ \
++              tasklet_init(&this->tasklet, \
++                      (void (*)(unsigned long)) sm, (unsigned long)this); \
++              tasklet_schedule(&this->tasklet); \
++              })
++#elif FORCE_QS == 0
++      #define PROCESS_NEXT(this, wqsm, sm) \
++              if (in_interrupt()) { \
++                      PROCESS_LATER(this->workq, wqsm, this); \
++              } else { \
++                      PROCESS_NOW(sm, this); \
++              }
++#else
++      #define PROCESS_NEXT(this, wqsm, sm) PROCESS_LATER(this->workq, wqsm, this)
++#endif
++
++/*
++ * convert openswan values to OCF values
++ */
++
++static int
++ipsec_ocf_authalg(int authalg)
++{
++      switch (authalg) {
++      case AH_SHA:  return CRYPTO_SHA1_HMAC;
++      case AH_MD5:  return CRYPTO_MD5_HMAC;
++      }
++      return 0;
++}
++
++
++static int
++ipsec_ocf_encalg(int encalg)
++{
++      switch (encalg) {
++      case ESP_NULL:      return CRYPTO_NULL_CBC;
++      case ESP_DES:       return CRYPTO_DES_CBC;
++      case ESP_3DES:      return CRYPTO_3DES_CBC;
++      case ESP_AES:       return CRYPTO_AES_CBC;
++      case ESP_CAST:      return CRYPTO_CAST_CBC;
++      case ESP_BLOWFISH:  return CRYPTO_BLF_CBC;
++      }
++      return 0;
++}
++
++/*
++ * if we can do the request ops, setup the sessions and return true
++ * otherwise return false with ipsp unchanged
++ */
++
++int
++ipsec_ocf_sa_init(struct ipsec_sa *ipsp, int authalg, int encalg)
++{
++      struct cryptoini crie, cria;
++      int error;
++
++      KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x)\n",
++                      authalg, encalg);
++
++      if (authalg && ipsp->ips_key_bits_a == 0) {
++              KLIPS_PRINT(debug_pfkey,
++                              "klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x) a-key-bits=0\n",
++                              authalg, encalg);
++              /* pretend we are happy with this */
++              return 1;
++      }
++
++      if (encalg && ipsp->ips_key_bits_e == 0) {
++              KLIPS_PRINT(debug_pfkey,
++                              "klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x) e-key-bits=0\n",
++                              authalg, encalg);
++              /* pretend we are happy with this */
++              return 1;
++      }
++
++      memset(&crie, 0, sizeof(crie));
++      memset(&cria, 0, sizeof(cria));
++
++      cria.cri_alg = ipsec_ocf_authalg(authalg);
++      cria.cri_klen = ipsp->ips_key_bits_a;
++      cria.cri_key  = ipsp->ips_key_a;
++      cria.cri_mlen = 12;
++
++      crie.cri_alg = ipsec_ocf_encalg(encalg);
++      crie.cri_klen = ipsp->ips_key_bits_e;
++      crie.cri_key  = ipsp->ips_key_e;
++      switch (crie.cri_alg) {
++      case CRYPTO_AES_CBC:
++              ipsp->ips_iv_size = 16;
++              break;
++      case CRYPTO_DES_CBC:
++      case CRYPTO_3DES_CBC:
++              ipsp->ips_iv_size = 8;
++              break;
++      default:
++              ipsp->ips_iv_size = 0;
++              break;
++      }
++      ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
++      ipsp->ips_auth_bits = ipsp->ips_key_bits_a;
++
++      if (authalg && encalg) {
++              crie.cri_next = &cria;
++              error = crypto_newsession(&ipsp->ocf_cryptoid, &crie, ipsec_ocf_crid);
++      } else if (encalg) {
++              error = crypto_newsession(&ipsp->ocf_cryptoid, &crie, ipsec_ocf_crid);
++      } else if (authalg) {
++              error = crypto_newsession(&ipsp->ocf_cryptoid, &cria, ipsec_ocf_crid);
++      } else {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init: "
++                              "no authalg or encalg\n");
++              return 0;
++      }
++
++      if (error) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init: "
++                              "crypto_newsession failed 0x%x\n", error);
++              return 0;
++      }
++
++      /* make sure no ALG stuff bites us */
++      if (ipsp->ips_alg_enc)
++              printk("We received an ALG initted SA\n");
++      ipsp->ips_alg_enc = NULL;
++
++      ipsp->ocf_in_use = 1;
++      return 1;
++}
++
++
++int
++ipsec_ocf_sa_free(struct ipsec_sa *ipsp)
++{
++      KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_free()\n");
++      crypto_freesession(ipsp->ocf_cryptoid);
++      ipsp->ocf_cryptoid = -1;
++      ipsp->ocf_in_use = 0;
++      return 1;
++}
++
++#if USE_TASKLET == 0
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ipsec_rsm_wq(struct work_struct *work)
++{
++      struct ipsec_rcv_state *irs = container_of(work, struct ipsec_rcv_state, workq);
++      ipsec_rsm(irs);
++}
++#else
++#define       ipsec_rsm_wq    ipsec_rsm
++#endif
++#endif /* USE_TASKLET */
++
++static int
++ipsec_ocf_rcv_cb(struct cryptop *crp)
++{
++      struct ipsec_rcv_state *irs = (struct ipsec_rcv_state *)crp->crp_opaque;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb\n");
++      if (irs == NULL) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb: "
++                              "NULL irs in callback\n");
++              return 0;
++      }
++
++      /*
++       * we must update the state before returning to the state machine.
++       * if we have an error,  terminate the processing by moving to the DONE
++       * state
++       */
++
++      irs->state = IPSEC_RSM_DONE; /* assume it went badly */
++      if (crp->crp_etype) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb: "
++                              "error in processing 0x%x\n", crp->crp_etype);
++      } else {
++              if (!irs->ipsp->ips_encalg) {
++                      /* AH post processing, put back fields we had to zero */
++                      irs->ipp->ttl      = irs->ttl;
++                      irs->ipp->check    = irs->check;
++                      irs->ipp->frag_off = irs->frag_off;
++                      irs->ipp->tos      = irs->tos;
++                      irs->state         = IPSEC_RSM_AUTH_CHK;
++                      /* pull up the IP header again after processing */
++                      skb_pull(irs->skb, ((unsigned char *)irs->protostuff.ahstuff.ahp) -
++                                                              ((unsigned char *)irs->ipp));
++              } else if (ipsec_rcv_esp_post_decrypt(irs) == IPSEC_RCV_OK) {
++                      /* this one came up good, set next state */
++                      irs->state         = IPSEC_RSM_DECAP_CONT;
++              }
++      }
++
++      crypto_freereq(crp);
++      crp = NULL;
++
++      /* setup the rest of the processing now */
++      PROCESS_NEXT(irs, ipsec_rsm_wq, ipsec_rsm);
++      return 0;
++}
++
++enum ipsec_rcv_value
++ipsec_ocf_rcv(struct ipsec_rcv_state *irs)
++{
++      struct cryptop *crp;
++      struct cryptodesc *crde, *crda = NULL;
++      struct ipsec_sa *ipsp;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv\n");
++
++      ipsp = irs->ipsp;
++      if (!ipsp) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
++                              "no SA for rcv processing\n");
++              return IPSEC_RCV_SAIDNOTFOUND;
++      }
++
++      if (!irs->skb) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: no skb\n");
++              return IPSEC_RCV_SAIDNOTFOUND;
++      }
++
++      crp = crypto_getreq((ipsp->ips_authalg && ipsp->ips_encalg) ? 2 : 1);
++      if (!crp) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
++                              "crypto_getreq returned NULL\n");
++              return IPSEC_RCV_REALLYBAD;
++      }
++
++      if (ipsp->ips_authalg) {
++              crda = crp->crp_desc;
++              crde = crda->crd_next;
++      } else {
++              crde = crp->crp_desc;
++              crda = crde->crd_next;
++      }
++
++      if (crda) {
++              /* Authentication descriptor */
++              crda->crd_alg = ipsec_ocf_authalg(ipsp->ips_authalg);
++              if (!crda->crd_alg) {
++                      KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
++                                      "bad auth alg 0x%x\n", ipsp->ips_authalg);
++                      crypto_freereq(crp);
++                      return IPSEC_RCV_BADPROTO;
++              }
++
++              if (!crde) { /* assuming AH processing */
++                      /* push the IP header so we can authenticate it */
++                      skb_push(irs->skb, ((unsigned char *)irs->protostuff.ahstuff.ahp) -
++                                                              ((unsigned char *)irs->ipp));
++              }
++
++              crda->crd_key          = ipsp->ips_key_a;
++              crda->crd_klen         = ipsp->ips_key_bits_a;
++              crda->crd_inject       = irs->authenticator - irs->skb->data;
++              /* Copy the authenticator to check aganinst later */
++              memcpy(irs->hash, irs->authenticator, 12);
++
++              if (!crde) { /* assume AH processing */
++                      /* AH processing, save fields we have to zero */
++                      irs->ttl           = irs->ipp->ttl;
++                      irs->check         = irs->ipp->check;
++                      irs->frag_off      = irs->ipp->frag_off;
++                      irs->tos           = irs->ipp->tos;
++                      irs->ipp->ttl      = 0;
++                      irs->ipp->check    = 0;
++                      irs->ipp->frag_off = 0;
++                      irs->ipp->tos      = 0;
++                      crda->crd_len      = irs->skb->len;
++                      crda->crd_skip     = ((unsigned char *)irs->ipp) - irs->skb->data;
++                      memset(irs->authenticator, 0, 12);
++              } else {
++                      crda->crd_len      = irs->ilen;
++                      crda->crd_skip     =
++                              ((unsigned char *) irs->protostuff.espstuff.espp) -
++                                                      irs->skb->data;
++                      /*
++                       * It would be nice to clear the authenticator here
++                       * to be sure we do not see it again later when checking.
++                       * We cannot.  Some HW actually expects to check the in-data
++                       * hash and and flag an error if it is incorrect.
++                       *
++                       * What we do to allow this is to pass in the current in-data
++                       * value.  Your OCF driver must ensure that it fails a request
++                       * for hash+decrypt with an invalid hash value, or returns the
++                       * computed in-data hash as requested.
++                       *
++                       * If your driver does not check the in-data hash but just
++                       * computes it value,  you must ensure that it does not return
++                       * the original in-data hash by accident.  It must invalidate the
++                       * in-data hash itself to force an auth check error.
++                       *
++                       * All existing drivers that do not care about the current
++                       * in-data hash do this by clearing the in-data hash before
++                       * processing, either directly or via their implementation.
++                       */
++#if 0
++                      memset(irs->authenticator, 0, 12);
++#endif
++              }
++      }
++
++      if (crde) {
++              crde->crd_alg = ipsec_ocf_encalg(ipsp->ips_encalg);
++              if (!crde->crd_alg) {
++                      KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
++                                      "bad enc alg 0x%x\n", ipsp->ips_encalg);
++                      crypto_freereq(crp);
++                      return IPSEC_RCV_BADPROTO;
++              }
++
++              irs->esphlen     = ESP_HEADER_LEN + ipsp->ips_iv_size;
++              irs->ilen       -= irs->esphlen;
++              crde->crd_skip   = (skb_transport_header(irs->skb) - irs->skb->data) + irs->esphlen;
++              crde->crd_len    = irs->ilen;
++              crde->crd_inject = crde->crd_skip - ipsp->ips_iv_size;
++              crde->crd_klen   = ipsp->ips_key_bits_e;
++              crde->crd_key    = ipsp->ips_key_e;
++      }
++
++      crp->crp_ilen = irs->skb->len; /* Total input length */
++      crp->crp_flags =
++                      CRYPTO_F_SKBUF |
++#if USE_CBIMM == 1
++                      CRYPTO_F_CBIMM |
++#endif
++#if USE_BATCH == 1
++                      CRYPTO_F_BATCH |
++#endif
++                      0;
++      crp->crp_buf = (caddr_t) irs->skb;
++      crp->crp_callback = ipsec_ocf_rcv_cb;
++      crp->crp_sid = ipsp->ocf_cryptoid;
++      crp->crp_opaque = (caddr_t) irs;
++      if (crypto_dispatch(crp)){
++              crypto_freereq(crp);
++              return IPSEC_RCV_REALLYBAD;
++      }
++      return(IPSEC_RCV_PENDING);
++}
++
++#if USE_TASKLET == 0
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++ipsec_xsm_wq(struct work_struct *work)
++{
++      struct ipsec_xmit_state *ixs = container_of(work, struct ipsec_xmit_state, workq);
++      ipsec_xsm(ixs);
++}
++#else
++#define       ipsec_xsm_wq    ipsec_xsm
++#endif
++#endif /* USE_TASKLET */
++
++static int
++ipsec_ocf_xmit_cb(struct cryptop *crp)
++{
++      struct ipsec_xmit_state *ixs = (struct ipsec_xmit_state *)crp->crp_opaque;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb\n");
++
++      if (ixs == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb: "
++                              "NULL ixs in callback\n");
++              return 0;
++      }
++
++      /*
++       * we must update the state before returning to the state machine.
++       * if we have an error,  terminate the processing by moving to the DONE
++       * state
++       */
++
++      ixs->state = IPSEC_XSM_DONE; /* assume bad xmit */
++      if (crp->crp_etype) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb: "
++                              "error in processing 0x%x\n", crp->crp_etype);
++      } else {
++              if (!ixs->ipsp->ips_encalg) {
++                      /* AH post processing, put back fields we had to zero */
++                      ixs->iph->ttl      = ixs->ttl;
++                      ixs->iph->check    = ixs->check;
++                      ixs->iph->frag_off = ixs->frag_off;
++                      ixs->iph->tos      = ixs->tos;
++              }
++              ixs->state = IPSEC_XSM_CONT; /* ESP was all good */
++      }
++
++      crypto_freereq(crp);
++      crp = NULL;
++
++      /* setup the rest of the processing now */
++      PROCESS_NEXT(ixs, ipsec_xsm_wq, ipsec_xsm);
++      return 0;
++}
++
++
++enum ipsec_xmit_value
++ipsec_ocf_xmit(struct ipsec_xmit_state *ixs)
++{
++      struct cryptop *crp;
++      struct cryptodesc *crde, *crda;
++      struct ipsec_sa *ipsp;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit\n");
++
++      ipsp = ixs->ipsp;
++      if (!ipsp) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
++                              "no SA for rcv processing\n");
++              return IPSEC_XMIT_SAIDNOTFOUND;
++      }
++
++      if (!ixs->skb) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                              "klips_debug:ipsec_ocf_xmit: no skb\n");
++              return IPSEC_XMIT_SAIDNOTFOUND;
++      }
++
++      crp = crypto_getreq((ipsp->ips_authalg && ipsp->ips_encalg) ? 2 : 1);
++      if (!crp) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
++                              "crypto_getreq returned NULL\n");
++              return IPSEC_XMIT_ERRMEMALLOC;
++      }
++
++      if (ipsp->ips_encalg) {
++              crde = crp->crp_desc;
++              crda = crde->crd_next;
++      } else {
++              crda = crp->crp_desc;
++              crde = crda->crd_next;
++      }
++
++      if (crda) {
++              /* Authentication descriptor */
++              crda->crd_alg = ipsec_ocf_authalg(ipsp->ips_authalg);
++              if (!crda->crd_alg) {
++                      KLIPS_PRINT(debug_tunnel&DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
++                                      "bad auth alg 0x%x\n", ipsp->ips_authalg);
++                      crypto_freereq(crp);
++                      return IPSEC_RCV_BADPROTO;
++              }
++              if (!crde) { /* assume AH processing */
++                      /* AH processing, save fields we have to zero */
++                      crda->crd_skip     = ((unsigned char *) ixs->iph) - ixs->skb->data;
++                      ixs->ttl           = ixs->iph->ttl;
++                      ixs->check         = ixs->iph->check;
++                      ixs->frag_off      = ixs->iph->frag_off;
++                      ixs->tos           = ixs->iph->tos;
++                      ixs->iph->ttl      = 0;
++                      ixs->iph->check    = 0;
++                      ixs->iph->frag_off = 0;
++                      ixs->iph->tos      = 0;
++                      crda->crd_inject   =
++                              (((struct ahhdr *)(ixs->dat + ixs->iphlen))->ah_data) -
++                                      ixs->skb->data;
++                      crda->crd_len      = ixs->len - ixs->authlen;
++                      memset(ixs->skb->data + crda->crd_inject, 0, 12); // DM
++              } else {
++                      crda->crd_skip     = ((unsigned char *) ixs->espp) - ixs->skb->data;
++                      crda->crd_inject   = ixs->len - ixs->authlen;
++                      crda->crd_len      = ixs->len - ixs->iphlen - ixs->authlen;
++              }
++              crda->crd_key    = ipsp->ips_key_a;
++              crda->crd_klen   = ipsp->ips_key_bits_a;
++      }
++
++      if (crde) {
++              /* Encryption descriptor */
++              crde->crd_alg = ipsec_ocf_encalg(ipsp->ips_encalg);
++              if (!crde->crd_alg) {
++                      KLIPS_PRINT(debug_tunnel&DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
++                                      "bad enc alg 0x%x\n", ipsp->ips_encalg);
++                      crypto_freereq(crp);
++                      return IPSEC_RCV_BADPROTO;
++              }
++              crde->crd_flags  = CRD_F_ENCRYPT;
++              crde->crd_skip   = ixs->idat - ixs->dat;
++              crde->crd_len    = ixs->ilen;
++              crde->crd_inject = ((unsigned char *) ixs->espp->esp_iv) - ixs->dat;
++              crde->crd_klen   = ipsp->ips_key_bits_e;
++              crde->crd_key    = ipsp->ips_key_e;
++      }
++
++      crp->crp_ilen = ixs->skb->len; /* Total input length */
++      crp->crp_flags =
++                      CRYPTO_F_SKBUF |
++#if USE_CBIMM == 1
++                      CRYPTO_F_CBIMM |
++#endif
++#if USE_BATCH == 1
++                      CRYPTO_F_BATCH |
++#endif
++                      0;
++      crp->crp_buf = (caddr_t) ixs->skb;
++      crp->crp_callback = ipsec_ocf_xmit_cb;
++      crp->crp_sid = ipsp->ocf_cryptoid;
++      crp->crp_opaque = (caddr_t) ixs;
++      if (crypto_dispatch(crp)){
++              crypto_freereq(crp);
++              return IPSEC_XMIT_ERRMEMALLOC;
++      }
++      return(IPSEC_XMIT_PENDING);
++}
++
++
++
++
++#ifdef CONFIG_KLIPS_AH
++static struct ipsec_alg_supported ocf_ah_algs[] = {
++  {
++        .ias_name       = "ocf-md5hmac",
++        .ias_id         = AH_MD5,
++        .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 128,
++        .ias_keymaxbits = 128,
++  },
++  {
++        .ias_name       = "ocf-sha1hmac",
++        .ias_id         = AH_SHA,
++        .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 160,
++        .ias_keymaxbits = 160,
++  },
++  {
++        .ias_name       = NULL,
++        .ias_id         = 0,
++        .ias_exttype    = 0,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 0,
++        .ias_keymaxbits = 0,
++  }
++};
++#endif /* CONFIG_KLIPS_AH */
++
++static struct ipsec_alg_supported ocf_esp_algs[] = {
++  {
++        .ias_name       = "ocf-md5hmac",
++        .ias_id         = AH_MD5,
++        .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 128,
++        .ias_keymaxbits = 128,
++  },
++  {
++        .ias_name       = "ocf-sha1hmac",
++        .ias_id         = AH_SHA,
++        .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 160,
++        .ias_keymaxbits = 160,
++  },
++  {
++        .ias_name       = "ocf-aes",
++        .ias_id         = ESP_AES,
++        .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
++        .ias_ivlen      = 16,
++        .ias_keyminbits = 128,
++        .ias_keymaxbits = 256,
++  },
++  {
++        .ias_name       = "ocf-3des",
++        .ias_id         = ESP_3DES,
++        .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
++        .ias_ivlen      = 8,
++        .ias_keyminbits = 192,
++        .ias_keymaxbits = 192,
++  },
++  {
++        .ias_name       = "ocf-des",
++        .ias_id         = ESP_DES,
++        .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
++        .ias_ivlen      = 8,
++        .ias_keyminbits = 64,
++        .ias_keymaxbits = 64,
++  },
++  {
++        .ias_name       = NULL,
++        .ias_id         = 0,
++        .ias_exttype    = 0,
++        .ias_ivlen      = 0,
++        .ias_keyminbits = 0,
++        .ias_keymaxbits = 0,
++  }
++};
++
++static int
++ipsec_ocf_check_alg(struct ipsec_alg_supported *s)
++{
++      struct cryptoini cri;
++      int64_t cryptoid;
++
++      memset(&cri, 0, sizeof(cri));
++      if (s->ias_exttype == SADB_EXT_SUPPORTED_ENCRYPT)
++              cri.cri_alg  = ipsec_ocf_encalg(s->ias_id);
++      else
++              cri.cri_alg  = ipsec_ocf_authalg(s->ias_id);
++      cri.cri_klen     = s->ias_keyminbits;
++      cri.cri_key      = "0123456789abcdefghijklmnopqrstuvwxyz";
++
++      if (crypto_newsession(&cryptoid, &cri, ipsec_ocf_crid)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf:%s not supported\n",
++                              s->ias_name);
++              return 0;
++      }
++      crypto_freesession(cryptoid);
++      KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf:%s supported\n",
++                      s->ias_name);
++      return 1;
++}
++
++void
++ipsec_ocf_init(void)
++{
++      struct ipsec_alg_supported *s;
++
++      for (s = ocf_esp_algs; s->ias_name; s++) {
++              if (ipsec_ocf_check_alg(s))
++                      (void)pfkey_list_insert_supported(s,
++                                      &(pfkey_supported_list[SADB_SATYPE_ESP]));
++      }
++
++#ifdef CONFIG_KLIPS_AH
++      for (s = ocf_ah_algs; s->ias_name; s++) {
++              if (ipsec_ocf_check_alg(s))
++                      (void)pfkey_list_insert_supported(s,
++                                      &(pfkey_supported_list[SADB_SATYPE_AH]));
++      }
++#endif
++
++      /* send register event to userspace     */
++      pfkey_register_reply(SADB_SATYPE_ESP, NULL);
++      pfkey_register_reply(SADB_SATYPE_AH, NULL);
++}
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_ocf.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,41 @@
++#ifndef _IPSEC_OCF_H_
++#define _IPSEC_OCF_H_
++/****************************************************************************/
++/*
++ * IPSEC OCF support
++ *
++ * This code written by David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2005 Intel Corporation.  All Rights Reserved.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h>
++
++#ifdef CONFIG_KLIPS_OCF
++
++#include <cryptodev.h>
++
++extern int  ipsec_ocf_sa_init(struct ipsec_sa *ipsp, int authalg, int encalg);
++extern int  ipsec_ocf_sa_free(struct ipsec_sa *ipsp);
++extern enum ipsec_rcv_value ipsec_ocf_rcv(struct ipsec_rcv_state *irs);
++extern enum ipsec_xmit_value ipsec_ocf_xmit(struct ipsec_xmit_state *ixs);
++extern void   ipsec_ocf_init(void);
++
++#endif
++
++/****************************************************************************/
++#endif /* _IPSEC_OCF_H_ */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_proc.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1056 @@
++/*
++ * @(#) /proc file system interface code.
++ *
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs <rgb@freeswan.org>
++ *                                 2001  Michael Richardson <mcr@freeswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * Split out from ipsec_init.c version 1.70.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#define __NO_VERSION__
++#include <linux/module.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) 
++#include <linux/moduleparam.h> 
++#endif 
++#include <linux/kernel.h> /* printk() */
++#include <linux/ip.h>          /* struct iphdr */
++
++#include "openswan/ipsec_kversion.h"
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/in.h>          /* struct sockaddr_in */
++#include <linux/skbuff.h>
++#include <asm/uaccess.h>       /* copy_from_user */
++#include <openswan.h>
++#ifdef SPINLOCK
++#ifdef SPINLOCK_23
++#include <linux/spinlock.h> /* *lock* */
++#else /* SPINLOCK_23 */
++#include <asm/spinlock.h> /* *lock* */
++#endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++#ifdef CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif /* CONFIG_PROC_FS */
++#ifdef NETLINK_SOCK
++#include <linux/netlink.h>
++#else
++#include <net/netlink.h>
++#endif
++
++#include "openswan/radij.h"
++
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_stats.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_kern24.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include "openswan/ipsec_proto.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#ifdef CONFIG_PROC_FS
++
++#ifdef IPSEC_PROC_SUBDIRS
++static struct proc_dir_entry *proc_net_ipsec_dir = NULL;
++static struct proc_dir_entry *proc_eroute_dir    = NULL;
++static struct proc_dir_entry *proc_spi_dir       = NULL;
++static struct proc_dir_entry *proc_spigrp_dir    = NULL;
++static struct proc_dir_entry *proc_birth_dir     = NULL;
++static struct proc_dir_entry *proc_stats_dir     = NULL;
++#endif
++
++struct ipsec_birth_reply ipsec_ipv4_birth_packet;
++struct ipsec_birth_reply ipsec_ipv6_birth_packet;
++
++#ifdef CONFIG_KLIPS_DEBUG
++int debug_esp = 0;
++int debug_ah = 0;
++int sysctl_ipsec_inbound_policy_check = 1;
++int debug_tunnel = 0;
++int debug_xmit = 0;
++int debug_xform = 0;
++int debug_eroute = 0;
++int debug_spi = 0;
++int debug_radij = 0;
++int debug_pfkey = 0;
++int debug_rcv = 0;
++int debug_netlink = 0;
++int sysctl_ipsec_debug_verbose = 0;
++int sysctl_ipsec_debug_ipcomp =0;
++int sysctl_ipsec_icmp = 0;
++int sysctl_ipsec_tos = 0;
++#endif /* CONFIG_KLIPS_DEBUG */
++
++#define DECREMENT_UNSIGNED(X, amount) ((amount < (X)) ? (X)-amount : 0)
++
++#ifdef CONFIG_KLIPS_ALG
++extern int ipsec_xform_get_info(char *buffer, char **start,
++                              off_t offset, int length IPSEC_PROC_LAST_ARG);
++#endif
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_eroute_get_info(char *buffer, 
++                    char **start, 
++                    off_t offset, 
++                    int length        IPSEC_PROC_LAST_ARG)
++{
++      struct wsbuf w = {buffer, length, offset, 0, 0};
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_radij & DB_RJ_DUMPTREES)
++        rj_dumptrees();                       /* XXXXXXXXX */
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_eroute_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      spin_lock_bh(&eroute_lock);
++
++      rj_walktree(rnh, ipsec_rj_walker_procprint, &w);
++/*    rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */
++
++      spin_unlock_bh(&eroute_lock);
++
++      *start = buffer + (offset - w.begin);   /* Start of wanted data */
++      return w.len - (offset - w.begin);
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_spi_get_info(char *buffer,
++                 char **start,
++                 off_t offset,
++                 int length    IPSEC_PROC_LAST_ARG)
++{
++      const int max_content = length > 0? length-1 : 0;
++      int len = 0;
++      off_t begin = 0;
++      int i;
++      struct ipsec_sa *sa_p;
++      char sa[SATOT_BUF];
++      char buf_s[SUBNETTOA_BUF];
++      char buf_d[SUBNETTOA_BUF];
++      size_t sa_len;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_spi_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++      
++      spin_lock_bh(&tdb_lock);
++
++      for (i = 0; i < SADB_HASHMOD; i++) {
++              for (sa_p = ipsec_sadb_hash[i];
++                   sa_p;
++                   sa_p = sa_p->ips_hnext) {
++                      ipsec_sa_get(sa_p);
++                      sa_len = satot(&sa_p->ips_said, 'x', sa, sizeof(sa));
++                      len += ipsec_snprintf(buffer+len, length-len, "%s ",
++                                     sa_len ? sa : " (error)");
++
++                      len += ipsec_snprintf(buffer+len, length-len, "%s%s%s",
++                                     IPS_XFORM_NAME(sa_p));
++
++                      len += ipsec_snprintf(buffer+len, length-len, ": dir=%s",
++                                     (sa_p->ips_flags & EMT_INBOUND) ?
++                                     "in " : "out");
++
++                      if(sa_p->ips_addr_s) {
++                              addrtoa(((struct sockaddr_in*)(sa_p->ips_addr_s))->sin_addr,
++                                      0, buf_s, sizeof(buf_s));
++                              len += ipsec_snprintf(buffer+len, length-len, " src=%s",
++                                             buf_s);
++                      }
++
++                      if((sa_p->ips_said.proto == IPPROTO_IPIP)
++                         && (sa_p->ips_flags & SADB_X_SAFLAGS_INFLOW)) {
++                              subnettoa(sa_p->ips_flow_s.u.v4.sin_addr,
++                                        sa_p->ips_mask_s.u.v4.sin_addr,
++                                        0,
++                                        buf_s,
++                                        sizeof(buf_s));
++
++                              subnettoa(sa_p->ips_flow_d.u.v4.sin_addr,
++                                        sa_p->ips_mask_d.u.v4.sin_addr,
++                                        0,
++                                        buf_d,
++                                        sizeof(buf_d));
++
++                              len += ipsec_snprintf(buffer+len, length-len, " policy=%s->%s",
++                                             buf_s, buf_d);
++                      }
++                      
++                      if(sa_p->ips_iv_bits) {
++                              int j;
++                              len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x",
++                                             sa_p->ips_iv_bits);
++
++#ifdef CONFIG_KLIPS_OCF
++                              if (!sa_p->ips_iv) {
++                                      /* ocf doesn't set the IV, fake it for the UML tests */
++                                      len += ipsec_snprintf(buffer+len, length-len, "0cf0");
++                                      for (j = 0; j < (sa_p->ips_iv_bits / 8) - 2; j++) {
++                                              len += ipsec_snprintf(buffer+len, length-len, "%02x",
++                                                                 (int) ((((long)sa_p) >> j) & 0xff));
++                                      }
++                              } else
++#endif
++                              for(j = 0; j < sa_p->ips_iv_bits / 8; j++) {
++                                      len += ipsec_snprintf(buffer+len, length-len, "%02x",
++                                                     (__u32)((__u8*)(sa_p->ips_iv))[j]);
++                              }
++                      }
++
++                      if(sa_p->ips_encalg || sa_p->ips_authalg) {
++                              if(sa_p->ips_replaywin) {
++                                      len += ipsec_snprintf(buffer+len, length-len, " ooowin=%d",
++                                                     sa_p->ips_replaywin);
++                              }
++                              if(sa_p->ips_errs.ips_replaywin_errs) {
++                                      len += ipsec_snprintf(buffer+len, length-len, " ooo_errs=%d",
++                                                     sa_p->ips_errs.ips_replaywin_errs);
++                              }
++                              if(sa_p->ips_replaywin_lastseq) {
++                                       len += ipsec_snprintf(buffer+len, length-len, " seq=%d",
++                                                    sa_p->ips_replaywin_lastseq);
++                              }
++                              if(sa_p->ips_replaywin_bitmap) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++                                      len += ipsec_snprintf(buffer+len, length-len, " bit=0x%Lx",
++                                                     sa_p->ips_replaywin_bitmap);
++#else
++                                      len += ipsec_snprintf(buffer+len, length-len, " bit=0x%x%08x",
++                                                     (__u32)(sa_p->ips_replaywin_bitmap >> 32),
++                                                     (__u32)sa_p->ips_replaywin_bitmap);
++#endif
++                              }
++                              if(sa_p->ips_replaywin_maxdiff) {
++                                      len += ipsec_snprintf(buffer+len, length-len, " max_seq_diff=%d",
++                                                     sa_p->ips_replaywin_maxdiff);
++                              }
++                      }
++                      if(sa_p->ips_flags & ~EMT_INBOUND) {
++                              len += ipsec_snprintf(buffer+len, length-len, " flags=0x%x",
++                                             sa_p->ips_flags & ~EMT_INBOUND);
++                              len += ipsec_snprintf(buffer+len, length-len, "<");
++                              /* flag printing goes here */
++                              len += ipsec_snprintf(buffer+len, length-len, ">");
++                      }
++                      if(sa_p->ips_auth_bits) {
++                              len += ipsec_snprintf(buffer+len, length-len, " alen=%d",
++                                             sa_p->ips_auth_bits);
++                      }
++                      if(sa_p->ips_key_bits_a) {
++                              len += ipsec_snprintf(buffer+len, length-len, " aklen=%d",
++                                             sa_p->ips_key_bits_a);
++                      }
++                      if(sa_p->ips_errs.ips_auth_errs) {
++                              len += ipsec_snprintf(buffer+len, length-len, " auth_errs=%d",
++                                             sa_p->ips_errs.ips_auth_errs);
++                      }
++                      if(sa_p->ips_key_bits_e) {
++                              len += ipsec_snprintf(buffer+len, length-len, " eklen=%d",
++                                             sa_p->ips_key_bits_e);
++                      }
++                      if(sa_p->ips_errs.ips_encsize_errs) {
++                              len += ipsec_snprintf(buffer+len, length-len, " encr_size_errs=%d",
++                                             sa_p->ips_errs.ips_encsize_errs);
++                      }
++                      if(sa_p->ips_errs.ips_encpad_errs) {
++                              len += ipsec_snprintf(buffer+len, length-len, " encr_pad_errs=%d",
++                                             sa_p->ips_errs.ips_encpad_errs);
++                      }
++                      
++                      len += ipsec_snprintf(buffer+len, length-len, " life(c,s,h)=");
++
++                      len += ipsec_lifetime_format(buffer + len,
++                                                   length - len,
++                                                   "alloc", 
++                                                   ipsec_life_countbased,
++                                                   &sa_p->ips_life.ipl_allocations);
++
++                      len += ipsec_lifetime_format(buffer + len,
++                                                   length - len,
++                                                   "bytes",
++                                                   ipsec_life_countbased,
++                                                   &sa_p->ips_life.ipl_bytes);
++
++                      len += ipsec_lifetime_format(buffer + len,
++                                                   length - len,
++                                                   "addtime",
++                                                   ipsec_life_timebased,
++                                                   &sa_p->ips_life.ipl_addtime);
++
++                      len += ipsec_lifetime_format(buffer + len,
++                                                   length - len,
++                                                   "usetime",
++                                                   ipsec_life_timebased,
++                                                   &sa_p->ips_life.ipl_usetime);
++                      
++                      len += ipsec_lifetime_format(buffer + len,
++                                                   length - len,
++                                                   "packets",
++                                                   ipsec_life_countbased,
++                                                   &sa_p->ips_life.ipl_packets);
++                      
++                      if(sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++                              len += ipsec_snprintf(buffer+len, length-len, " idle=%Ld",
++                                             jiffies / HZ - sa_p->ips_life.ipl_usetime.ipl_last);
++#else
++                              len += ipsec_snprintf(buffer+len, length-len, " idle=%lu",
++                                             jiffies / HZ - (unsigned long)sa_p->ips_life.ipl_usetime.ipl_last);
++#endif
++                      }
++
++#ifdef CONFIG_KLIPS_IPCOMP
++                      if(sa_p->ips_said.proto == IPPROTO_COMP &&
++                         (sa_p->ips_comp_ratio_dbytes ||
++                          sa_p->ips_comp_ratio_cbytes)) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++                              len += ipsec_snprintf(buffer+len, length-len, " ratio=%Ld:%Ld",
++                                             sa_p->ips_comp_ratio_dbytes,
++                                             sa_p->ips_comp_ratio_cbytes);
++#else
++                              len += ipsec_snprintf(buffer+len, length-len, " ratio=%lu:%lu",
++                                             (unsigned long)sa_p->ips_comp_ratio_dbytes,
++                                             (unsigned long)sa_p->ips_comp_ratio_cbytes);
++#endif
++                      }
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++                      {
++                              char *natttype_name;
++
++                              switch(sa_p->ips_natt_type)
++                              {
++                              case 0:
++                                      natttype_name="none";
++                                      break;
++                              case ESPINUDP_WITH_NON_IKE:
++                                      natttype_name="nonike";
++                                      break;
++                              case ESPINUDP_WITH_NON_ESP:
++                                      natttype_name="nonesp";
++                                      break;
++                              default:
++                                      natttype_name = "unknown";
++                                      break;
++                              }
++
++                              len += ipsec_snprintf(buffer + len, length-len, " natencap=%s",
++                                             natttype_name);
++                              
++                              len += ipsec_snprintf(buffer + len, length-len, " natsport=%d",
++                                             sa_p->ips_natt_sport);
++                              
++                              len += ipsec_snprintf(buffer + len,length-len, " natdport=%d",
++                                             sa_p->ips_natt_dport);
++                      }
++#else
++                      len += ipsec_snprintf(buffer + len, length-len, " natencap=na");
++#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
++                              
++                      /* we decrement by one, because this SA has been referenced in order to dump this info */
++                      len += ipsec_snprintf(buffer + len,length-len, " refcount=%d",
++                                     atomic_read(&sa_p->ips_refcount)-1);
++
++                      len += ipsec_snprintf(buffer+len, length-len, " ref=%d",
++                                     sa_p->ips_ref);
++                      len += ipsec_snprintf(buffer+len, length-len, " refhim=%d",
++                                     sa_p->ips_refhim);
++
++                      if(sa_p->ips_out) {
++                              len += ipsec_snprintf(buffer+len, length-len, " outif=%s:%d",
++                                                    sa_p->ips_out->name,
++                                                    sa_p->ips_transport_direct);
++                      }
++#ifdef CONFIG_KLIPS_DEBUG
++                      if(debug_xform) {
++                      len += ipsec_snprintf(buffer+len, length-len, " reftable=%lu refentry=%lu",
++                                     (unsigned long)IPsecSAref2table(sa_p->ips_ref),
++                                     (unsigned long)IPsecSAref2entry(sa_p->ips_ref));
++                      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++                      len += ipsec_snprintf(buffer+len, length-len, "\n");
++
++                        ipsec_sa_put(sa_p);   
++                       
++                        if (len >= max_content) {
++                               /* we've done all that can fit -- stop loops */
++                               len = max_content;      /* truncate crap */
++                                goto done_spi_i;
++                        } else {
++                               const off_t pos = begin + len;  /* file position of end of what we've generated */
++
++                               if (pos <= offset) {
++                                       /* all is before first interesting character:
++                                        * discard, but note where we are.
++                                        */
++                                       len = 0;
++                                       begin = pos;
++                               }
++                        }
++                }
++        }
++
++done_spi_i:   
++      spin_unlock_bh(&tdb_lock);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      return len - (offset - begin);
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_spigrp_get_info(char *buffer,
++                    char **start,
++                    off_t offset,
++                    int length     IPSEC_PROC_LAST_ARG)
++{
++      /* Limit of useful snprintf output */
++      const int max_content = length > 0? length-1 : 0; 
++
++      int len = 0;
++      off_t begin = 0;
++      int i;
++      struct ipsec_sa *sa_p, *sa_p2;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_spigrp_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      spin_lock_bh(&tdb_lock);
++      
++      for (i = 0; i < SADB_HASHMOD; i++) {
++              for (sa_p = ipsec_sadb_hash[i];
++                   sa_p != NULL;
++                   sa_p = sa_p->ips_hnext)
++              {
++                      sa_p2 = sa_p;
++                      while(sa_p2 != NULL) {
++                              struct ipsec_sa *sa2n;
++                              sa_len = satot(&sa_p2->ips_said,
++                                             'x', sa, sizeof(sa));
++                              
++                              len += ipsec_snprintf(buffer+len, length-len, "%s ",
++                                                    sa_len ? sa : " (error)");
++                              
++                              sa2n = sa_p2->ips_next;
++                              sa_p2 = sa2n;
++                      }
++                      len += ipsec_snprintf(buffer+len, length-len, "\n");
++                      
++                      if (len >= max_content) {
++                              /* we've done all that can fit -- stop loops */
++                              len = max_content;      /* truncate crap */
++                              goto done_spigrp_i;
++                      } else {
++                              const off_t pos = begin + len;
++                              
++                              if (pos <= offset) {
++                                      /* all is before first interesting character:
++                                       * discard, but note where we are.
++                                       */
++                                        len = 0;
++                                        begin = pos;
++                              }
++                      }
++              }
++      }
++
++done_spigrp_i:        
++      spin_unlock_bh(&tdb_lock);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      return len - (offset - begin);
++}
++
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_tncfg_get_info(char *buffer,
++                   char **start,
++                   off_t offset,
++                   int length     IPSEC_PROC_LAST_ARG)
++{
++      /* limit of useful snprintf output */ 
++      const int max_content = length > 0? length-1 : 0;
++      int len = 0;
++      off_t begin = 0;
++      int i;
++      char name[9];
++      struct net_device *dev, *privdev;
++      struct ipsecpriv *priv;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_tncfg_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              ipsec_snprintf(name, (ssize_t) sizeof(name), IPSEC_DEV_FORMAT, i);
++              dev = __ipsec_dev_get(name);
++              if(dev) {
++                      priv = (struct ipsecpriv *)(dev->priv);
++                      len += ipsec_snprintf(buffer+len, length-len, "%s",
++                                     dev->name);
++                      if(priv) {
++                              privdev = (struct net_device *)(priv->dev);
++                              len += ipsec_snprintf(buffer+len, length-len, " -> %s",
++                                             privdev ? privdev->name : "NULL");
++                              len += ipsec_snprintf(buffer+len, length-len, " mtu=%d(%d) -> %d",
++                                             dev->mtu,
++                                             priv->mtu,
++                                             privdev ? privdev->mtu : 0);
++                      } else {
++                              KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                                          "klips_debug:ipsec_tncfg_get_info: device '%s' has no private data space!\n",
++                                          dev->name);
++                      }
++                      len += ipsec_snprintf(buffer+len, length-len, "\n");
++
++                        if (len >= max_content) {
++                                /* we've done all that can fit -- stop loop */
++                                len = max_content;      /* truncate crap */
++                                 break;
++                        } else {
++                                const off_t pos = begin + len;
++                                if (pos <= offset) {
++                                        len = 0;
++                                        begin = pos;
++                                }
++                      }
++              }
++      }
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_version_get_info(char *buffer,
++                     char **start,
++                     off_t offset,
++                     int length  IPSEC_PROC_LAST_ARG)
++{
++      int len = 0;
++      off_t begin = 0;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      len += ipsec_snprintf(buffer + len,length-len, "Openswan version: %s\n",
++                     ipsec_version_code());
++#if 0
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: "
++                  "ipsec_init version: %s\n",
++                  ipsec_init_c_version);
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: "
++                  "ipsec_tunnel version: %s\n",
++                  ipsec_tunnel_c_version);
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: "
++                  "ipsec_netlink version: %s\n",
++                  ipsec_netlink_c_version);
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: "
++                  "radij_c_version: %s\n",
++                  radij_c_version);
++#endif
++
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++unsigned int natt_available = 1;
++#else
++unsigned int natt_available = 0;
++#endif
++module_param(natt_available,int,0644);
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_natt_get_info(char *buffer,
++                  char **start,
++                  off_t offset,
++                  int length  IPSEC_PROC_LAST_ARG)
++{
++      int len = 0;
++      off_t begin = 0;
++
++      len += ipsec_snprintf(buffer + len,
++                            length-len, "%d\n",
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++                            1
++#else
++                            0
++#endif
++              );
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_birth_info(char *page,
++               char **start,
++               off_t offset,
++               int count,
++               int *eof,
++               void *data)
++{
++      struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
++      int len;
++
++      if(offset >= ibr->packet_template_len) {
++              if(eof) {
++                      *eof=1;
++              }
++              return 0;
++      }
++
++      len = ibr->packet_template_len;
++      len -= offset;
++      if (len > count)
++              len = count;
++
++      memcpy(page + offset, ibr->packet_template+offset, len);
++
++      return len;
++}
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_birth_set(struct file *file, const char *buffer,
++              unsigned long count, void *data)
++{
++      struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
++      int len;
++
++      KLIPS_INC_USE;
++        if(count > IPSEC_BIRTH_TEMPLATE_MAXLEN) {
++                len = IPSEC_BIRTH_TEMPLATE_MAXLEN;
++      } else {
++                len = count;
++      }
++
++        if(copy_from_user(ibr->packet_template, buffer, len)) {
++                KLIPS_DEC_USE;
++                return -EFAULT;
++        }
++      ibr->packet_template_len = len;
++
++        KLIPS_DEC_USE;
++
++        return len;
++}
++
++
++#ifdef CONFIG_KLIPS_DEBUG
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_klipsdebug_get_info(char *buffer,
++                        char **start,
++                        off_t offset,
++                        int length      IPSEC_PROC_LAST_ARG)
++{
++      int len = 0;
++      off_t begin = 0;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_klipsdebug_get_info: "
++                  "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
++                  buffer,
++                  *start,
++                  (int)offset,
++                  length);
++
++      len += ipsec_snprintf(buffer+len, length-len, "debug_tunnel=%08x.\n", debug_tunnel);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_xform=%08x.\n", debug_xform);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_eroute=%08x.\n", debug_eroute);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_spi=%08x.\n", debug_spi);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_radij=%08x.\n", debug_radij);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_esp=%08x.\n", debug_esp);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_ah=%08x.\n", debug_ah);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_rcv=%08x.\n", debug_rcv);
++      len += ipsec_snprintf(buffer+len, length-len, "debug_pfkey=%08x.\n", debug_pfkey);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++#endif /* CONFIG_KLIPS_DEBUG */
++
++IPSEC_PROCFS_DEBUG_NO_STATIC
++int
++ipsec_stats_get_int_info(char *buffer,
++                       char **start,
++                       off_t offset,
++                       int   length,
++                       int   *eof,
++                       void  *data)
++{
++
++      const int max_content = length > 0? length-1 : 0;
++      int len = 0;
++      int *thing;
++
++      thing = (int *)data;
++      
++      len = ipsec_snprintf(buffer+len, length-len, "%08x\n", *thing);
++
++      if (len >= max_content)
++               len = max_content;      /* truncate crap */
++
++        *start = buffer + offset;       /* Start of wanted data */
++        return len > offset? len - offset : 0;
++
++}
++
++#ifndef PROC_FS_2325
++struct proc_dir_entry ipsec_eroute =
++{
++      0,
++      12, "ipsec_eroute",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_eroute_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++
++struct proc_dir_entry ipsec_spi =
++{
++      0,
++      9, "ipsec_spi",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_spi_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++
++struct proc_dir_entry ipsec_spigrp =
++{
++      0,
++      12, "ipsec_spigrp",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_spigrp_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++
++struct proc_dir_entry ipsec_tncfg =
++{
++      0,
++      11, "ipsec_tncfg",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_tncfg_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++
++struct proc_dir_entry ipsec_version =
++{
++      0,
++      13, "ipsec_version",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_version_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++
++#ifdef CONFIG_KLIPS_DEBUG
++struct proc_dir_entry ipsec_klipsdebug =
++{
++      0,
++      16, "ipsec_klipsdebug",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_klipsdebug_get_info,
++      NULL, NULL, NULL, NULL, NULL
++};
++#endif /* CONFIG_KLIPS_DEBUG */
++#endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++#if defined(PROC_FS_2325) 
++struct ipsec_proc_list {
++      char                   *name;
++      struct proc_dir_entry **parent;
++      struct proc_dir_entry **dir;
++      read_proc_t            *readthing;
++      write_proc_t           *writething;
++      void                   *data;
++};
++static struct ipsec_proc_list proc_items[]={
++#ifdef CONFIG_KLIPS_DEBUG
++      {"klipsdebug", &proc_net_ipsec_dir, NULL,             ipsec_klipsdebug_get_info, NULL, NULL},
++#endif
++      {"eroute",     &proc_net_ipsec_dir, &proc_eroute_dir, NULL, NULL, NULL},
++      {"all",        &proc_eroute_dir,    NULL,             ipsec_eroute_get_info,     NULL, NULL},
++      {"spi",        &proc_net_ipsec_dir, &proc_spi_dir,    NULL, NULL, NULL},
++      {"all",        &proc_spi_dir,       NULL,             ipsec_spi_get_info,        NULL, NULL},
++      {"spigrp",     &proc_net_ipsec_dir, &proc_spigrp_dir, NULL, NULL, NULL},
++      {"all",        &proc_spigrp_dir,    NULL,             ipsec_spigrp_get_info,     NULL, NULL},
++      {"birth",      &proc_net_ipsec_dir, &proc_birth_dir,  NULL,      NULL, NULL},
++      {"ipv4",       &proc_birth_dir,     NULL,             ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv4_birth_packet},
++      {"ipv6",       &proc_birth_dir,     NULL,             ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv6_birth_packet},
++      {"tncfg",      &proc_net_ipsec_dir, NULL,             ipsec_tncfg_get_info,      NULL, NULL},
++#ifdef CONFIG_KLIPS_ALG
++
++      {"xforms",     &proc_net_ipsec_dir, NULL,             ipsec_xform_get_info,      NULL, NULL},
++#endif
++      {"stats",      &proc_net_ipsec_dir, &proc_stats_dir,  NULL,      NULL, NULL},
++      {"trap_count", &proc_stats_dir,     NULL,             ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_count},
++      {"trap_sendcount", &proc_stats_dir, NULL,             ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_sendcount},
++      {"natt",       &proc_net_ipsec_dir, NULL,             ipsec_natt_get_info,    NULL, NULL},
++      {"version",    &proc_net_ipsec_dir, NULL,             ipsec_version_get_info,    NULL, NULL},
++      {NULL,         NULL,                NULL,             NULL,      NULL, NULL}
++};
++#endif
++              
++int
++ipsec_proc_init()
++{
++      int error = 0;
++#ifdef IPSEC_PROC_SUBDIRS
++      struct proc_dir_entry *item;
++#endif
++
++      /*
++       * just complain because pluto won't run without /proc!
++       */
++#ifndef CONFIG_PROC_FS 
++#error You must have PROC_FS built in to use KLIPS
++#endif
++
++        /* for 2.0 kernels */
++#if !defined(PROC_FS_2325) && !defined(PROC_FS_21)
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_eroute);
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_spi);
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_spigrp);
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_tncfg);
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_version);
++#ifdef CONFIG_KLIPS_DEBUG
++      error |= proc_register_dynamic(&PROC_NET, &ipsec_klipsdebug);
++#endif /* CONFIG_KLIPS_DEBUG */
++#endif
++
++      /* for 2.2 kernels */
++#if !defined(PROC_FS_2325) && defined(PROC_FS_21)
++      error |= proc_register(PROC_NET, &ipsec_eroute);
++      error |= proc_register(PROC_NET, &ipsec_spi);
++      error |= proc_register(PROC_NET, &ipsec_spigrp);
++      error |= proc_register(PROC_NET, &ipsec_tncfg);
++      error |= proc_register(PROC_NET, &ipsec_version);
++#ifdef CONFIG_KLIPS_DEBUG
++      error |= proc_register(PROC_NET, &ipsec_klipsdebug);
++#endif /* CONFIG_KLIPS_DEBUG */
++#endif
++
++      /* for 2.4 kernels */
++#if defined(PROC_FS_2325)
++      /* create /proc/net/ipsec */
++
++      /* zero these out before we initialize /proc/net/ipsec/birth/stuff */
++      memset(&ipsec_ipv4_birth_packet, 0, sizeof(struct ipsec_birth_reply));
++      memset(&ipsec_ipv6_birth_packet, 0, sizeof(struct ipsec_birth_reply));
++
++      proc_net_ipsec_dir = proc_mkdir("ipsec", PROC_NET);
++      if(proc_net_ipsec_dir == NULL) {
++              /* no point in continuing */
++              return 1;
++      }       
++
++      {
++              struct ipsec_proc_list *it;
++
++              it=proc_items;
++              while(it->name!=NULL) {
++                      if(it->dir) {
++                              /* make a dir instead */
++                              item = proc_mkdir(it->name, *it->parent);
++                              *it->dir = item;
++                      } else {
++                              item = create_proc_entry(it->name, 0400, *it->parent);
++                      }
++                      if(item) {
++                              item->read_proc  = it->readthing;
++                              item->write_proc = it->writething;
++                              item->data       = it->data;
++#ifdef MODULE
++                              item->owner = THIS_MODULE;
++#endif
++                      } else {
++                              error |= 1;
++                      }
++                      it++;
++              }
++      }
++      
++      /* now create some symlinks to provide compatibility */
++      proc_symlink("ipsec_eroute", PROC_NET, "ipsec/eroute/all");
++      proc_symlink("ipsec_spi",    PROC_NET, "ipsec/spi/all");
++      proc_symlink("ipsec_spigrp", PROC_NET, "ipsec/spigrp/all");
++      proc_symlink("ipsec_tncfg",  PROC_NET, "ipsec/tncfg");
++      proc_symlink("ipsec_version",PROC_NET, "ipsec/version");
++      proc_symlink("ipsec_klipsdebug",PROC_NET,"ipsec/klipsdebug");
++
++#endif /* !PROC_FS_2325 */
++
++      return error;
++}
++
++void
++ipsec_proc_cleanup()
++{
++
++      /* for 2.0 and 2.2 kernels */
++#if !defined(PROC_FS_2325) 
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_klipsdebug\n");
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      if (proc_net_unregister(ipsec_version.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_version\n");
++      if (proc_net_unregister(ipsec_eroute.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_eroute\n");
++      if (proc_net_unregister(ipsec_spi.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_spi\n");
++      if (proc_net_unregister(ipsec_spigrp.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_spigrp\n");
++      if (proc_net_unregister(ipsec_tncfg.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: "
++                     "cannot unregister /proc/net/ipsec_tncfg\n");
++#endif
++
++      /* for 2.4 kernels */
++#if defined(PROC_FS_2325)
++      {
++              struct ipsec_proc_list *it;
++
++              /* find end of list */
++              it=proc_items;
++              while(it->name!=NULL) {
++                      it++;
++              }
++              it--;
++
++              do {
++                      remove_proc_entry(it->name, *it->parent);
++                      it--;
++              } while(it >= proc_items);
++      }
++
++
++#ifdef CONFIG_KLIPS_DEBUG
++      remove_proc_entry("ipsec_klipsdebug", PROC_NET);
++#endif /* CONFIG_KLIPS_DEBUG */
++      remove_proc_entry("ipsec_eroute",     PROC_NET);
++      remove_proc_entry("ipsec_spi",        PROC_NET);
++      remove_proc_entry("ipsec_spigrp",     PROC_NET);
++      remove_proc_entry("ipsec_tncfg",      PROC_NET);
++      remove_proc_entry("ipsec_version",    PROC_NET);
++      remove_proc_entry("ipsec",            PROC_NET);
++#endif /* 2.4 kernel */
++}
++
++/*
++ *
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_radij.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,554 @@
++/*
++ * Interface between the IPSEC code and the radix (radij) tree code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, struct net_device_stats and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* 23_SPINLOCK */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* 23_SPINLOCK */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "openswan/ipsec_eroute.h"
++#include "openswan/ipsec_sa.h"
++ 
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_tunnel.h"    /* struct ipsecpriv */
++#include "openswan/ipsec_xform.h"
++ 
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++
++struct radij_node_head *rnh = NULL;
++#ifdef SPINLOCK
++spinlock_t eroute_lock = SPIN_LOCK_UNLOCKED;
++#else /* SPINLOCK */
++spinlock_t eroute_lock;
++#endif /* SPINLOCK */
++
++int
++ipsec_radijinit(void)
++{
++      maj_keylen = sizeof (struct sockaddr_encap);
++
++      rj_init();
++      
++      if (rj_inithead((void **)&rnh, /*16*/offsetof(struct sockaddr_encap, sen_type) * sizeof(__u8)) == 0) /* 16 is bit offset of sen_type */
++              return -1;
++      return 0;
++}
++
++int
++ipsec_radijcleanup(void)
++{
++      int error = 0;
++
++      spin_lock_bh(&eroute_lock);
++
++      error = radijcleanup();
++
++      spin_unlock_bh(&eroute_lock);
++
++      return error;
++}
++
++int
++ipsec_cleareroutes(void)
++{
++      int error;
++
++      spin_lock_bh(&eroute_lock);
++
++      error = radijcleartree();
++
++      spin_unlock_bh(&eroute_lock);
++
++      return error;
++}
++
++int
++ipsec_breakroute(struct sockaddr_encap *eaddr,
++               struct sockaddr_encap *emask,
++               struct sk_buff **first,
++               struct sk_buff **last)
++{
++      struct eroute *ro;
++      struct radij_node *rn;
++      int error;
++#ifdef CONFIG_KLIPS_DEBUG
++      
++      if (debug_eroute) {
++                char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
++              subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
++              KLIPS_PRINT(debug_eroute,
++                          "klips_debug:ipsec_breakroute: "
++                          "attempting to delete eroute for %s:%d->%s:%d %d\n",
++                          buf1, ntohs(eaddr->sen_sport),
++                          buf2, ntohs(eaddr->sen_dport), eaddr->sen_proto);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      spin_lock_bh(&eroute_lock);
++
++      if ((error = rj_delete(eaddr, emask, rnh, &rn)) != 0) {
++              spin_unlock_bh(&eroute_lock);
++              KLIPS_PRINT(debug_eroute, 
++                          "klips_debug:ipsec_breakroute: "
++                          "node not found, eroute delete failed.\n");
++              return error;
++      }
++
++      spin_unlock_bh(&eroute_lock);
++      
++      ro = (struct eroute *)rn;
++      
++      KLIPS_PRINT(debug_eroute, 
++                  "klips_debug:ipsec_breakroute: "
++                  "deleted eroute=0p%p, ident=0p%p->0p%p, first=0p%p, last=0p%p\n",
++                  ro,
++                  ro->er_ident_s.data,
++                  ro->er_ident_d.data,
++                  ro->er_first,
++                  ro->er_last);
++      
++      if (ro->er_ident_s.data != NULL) {
++              kfree(ro->er_ident_s.data);
++      }
++      if (ro->er_ident_d.data != NULL) {
++              kfree(ro->er_ident_d.data);
++      }
++      if (ro->er_first != NULL) {
++#if 0
++              struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_first->dev->priv))->mystats);
++              stats->tx_dropped--;
++#endif
++              *first = ro->er_first;
++      }
++      if (ro->er_last != NULL) {
++#if 0
++              struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_last->dev->priv))->mystats);
++              stats->tx_dropped--;
++#endif
++              *last = ro->er_last;
++      }
++      
++      if (rn->rj_flags & (RJF_ACTIVE | RJF_ROOT))
++              panic ("ipsec_breakroute RMT_DELEROUTE root or active node\n");
++      memset((caddr_t)rn, 0, sizeof (struct eroute));
++      kfree(rn);
++      
++      return 0;
++}
++
++int
++ipsec_makeroute(struct sockaddr_encap *eaddr,
++              struct sockaddr_encap *emask,
++              ip_said said,
++              uint32_t pid,
++              struct sk_buff *skb,
++              struct ident *ident_s,
++              struct ident *ident_d)
++{
++      struct eroute *retrt;
++      int error;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++
++#ifdef CONFIG_KLIPS_DEBUG
++      
++      if (debug_eroute) {
++
++              {
++                       char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
++
++                       subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
++                       subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
++                       sa_len = satot(&said, 0, sa, sizeof(sa));
++                       KLIPS_PRINT(debug_eroute,
++                                   "klips_debug:ipsec_makeroute: "
++                                   "attempting to allocate %lu bytes to insert eroute for %s->%s, SA: %s, PID:%d, skb=0p%p, ident:%s->%s\n",
++                                   (unsigned long) sizeof(struct eroute),
++                                   buf1,
++                                   buf2,
++                                   sa_len ? sa : " (error)",
++                                   pid,
++                                   skb,
++                                   (ident_s ? (ident_s->data ? ident_s->data : "NULL") : "NULL"),
++                                   (ident_d ? (ident_d->data ? ident_d->data : "NULL") : "NULL"));
++               }
++               {
++                       char buf1[sizeof(struct sockaddr_encap)*2 + 1],   
++                               buf2[sizeof(struct sockaddr_encap)*2 + 1];
++                       int i;
++                       unsigned char *b1 = buf1,
++                               *b2 = buf2,
++                               *ea = (unsigned char *)eaddr,
++                               *em = (unsigned char *)emask;
++                                   
++                                   
++                       for (i=0; i<sizeof(struct sockaddr_encap); i++) {
++                               sprintf(b1, "%02x", ea[i]);
++                               sprintf(b2, "%02x", em[i]);
++                               b1+=2;
++                               b2+=2;
++                       }
++                       KLIPS_PRINT(debug_eroute, "klips_debug:ipsec_makeroute: %s / %s \n", buf1, buf2);
++                }
++
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      retrt = (struct eroute *)kmalloc(sizeof (struct eroute), GFP_ATOMIC);
++      if (retrt == NULL) {
++              printk("klips_error:ipsec_makeroute: "
++                     "not able to allocate kernel memory");
++              return -ENOMEM;
++      }
++      memset((caddr_t)retrt, 0, sizeof (struct eroute));
++
++      retrt->er_eaddr = *eaddr;
++      retrt->er_emask = *emask;
++      retrt->er_said = said;
++      retrt->er_pid = pid;
++      retrt->er_count = 0;
++      retrt->er_lasttime = jiffies/HZ;
++
++      {
++        /* this is because gcc 3. doesn't like cast's as lvalues */
++        struct rjtentry *rje = (struct rjtentry *)&(retrt->er_rjt);
++        caddr_t er = (caddr_t)&(retrt->er_eaddr);
++        
++        rje->rd_nodes->rj_key= er;
++      }
++      
++      if (ident_s && ident_s->type != SADB_IDENTTYPE_RESERVED) {
++              int data_len = ident_s->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++              
++              retrt->er_ident_s.type = ident_s->type;
++              retrt->er_ident_s.id = ident_s->id;
++              retrt->er_ident_s.len = ident_s->len;
++              if(data_len) {
++                      KLIPS_PRINT(debug_eroute, 
++                                  "klips_debug:ipsec_makeroute: "
++                                  "attempting to allocate %u bytes for ident_s.\n",
++                                  data_len);
++                      if(!(retrt->er_ident_s.data = kmalloc(data_len, GFP_KERNEL))) {
++                              kfree(retrt);
++                              printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
++                              return ENOMEM;
++                      }
++                      memcpy(retrt->er_ident_s.data, ident_s->data, data_len);
++              } else {
++                      retrt->er_ident_s.data = NULL;
++              }
++      }
++      
++      if (ident_d && ident_d->type != SADB_IDENTTYPE_RESERVED) {
++              int data_len = ident_d->len  * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++              
++              retrt->er_ident_d.type = ident_d->type;
++              retrt->er_ident_d.id = ident_d->id;
++              retrt->er_ident_d.len = ident_d->len;
++              if(data_len) {
++                      KLIPS_PRINT(debug_eroute, 
++                                  "klips_debug:ipsec_makeroute: "
++                                  "attempting to allocate %u bytes for ident_d.\n",
++                                  data_len);
++                      if(!(retrt->er_ident_d.data = kmalloc(data_len, GFP_KERNEL))) {
++                              if (retrt->er_ident_s.data)
++                                      kfree(retrt->er_ident_s.data);
++                              kfree(retrt);
++                              printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
++                              return ENOMEM;
++                      }
++                      memcpy(retrt->er_ident_d.data, ident_d->data, data_len);
++              } else {
++                      retrt->er_ident_d.data = NULL;
++              }
++      }
++      retrt->er_first = skb;
++      retrt->er_last = NULL;
++      
++      KLIPS_PRINT(debug_eroute, 
++                  "klips_debug:ipsec_makeroute: "
++                  "calling rj_addroute now\n");
++
++      spin_lock_bh(&eroute_lock);
++      
++      error = rj_addroute(&(retrt->er_eaddr), &(retrt->er_emask), 
++                       rnh, retrt->er_rjt.rd_nodes);
++
++      spin_unlock_bh(&eroute_lock);
++      
++      if(error) {
++              sa_len = KLIPS_SATOT(debug_eroute, &said, 0, sa, sizeof(sa));
++              KLIPS_PRINT(debug_eroute, 
++                          "klips_debug:ipsec_makeroute: "
++                          "rj_addroute not able to insert eroute for SA:%s (error:%d)\n",
++                          sa_len ? sa : " (error)", error);
++              if (retrt->er_ident_s.data)
++                      kfree(retrt->er_ident_s.data);
++              if (retrt->er_ident_d.data)
++                      kfree(retrt->er_ident_d.data);
++              
++              kfree(retrt);
++              
++              return error;
++      }
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_eroute) {
++              char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
++/*
++              subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
++*/
++              subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_src, rd_mask((&(retrt->er_rjt)))->sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_dst, rd_mask((&(retrt->er_rjt)))->sen_ip_dst, 0, buf2, sizeof(buf2));
++              sa_len = satot(&retrt->er_said, 0, sa, sizeof(sa));
++              
++              KLIPS_PRINT(debug_eroute,
++                          "klips_debug:ipsec_makeroute: "
++                          "pid=%05d "
++                          "count=%10d "
++                          "lasttime=%6d "
++                          "%-18s -> %-18s => %s\n",
++                          retrt->er_pid,
++                          retrt->er_count,
++                          (int)(jiffies/HZ - retrt->er_lasttime),
++                          buf1,
++                          buf2,
++                          sa_len ? sa : " (error)");
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      KLIPS_PRINT(debug_eroute,
++                  "klips_debug:ipsec_makeroute: "
++                  "succeeded.\n");
++      return 0;
++}
++
++struct eroute *
++ipsec_findroute(struct sockaddr_encap *eaddr)
++{
++      struct radij_node *rn;
++#ifdef CONFIG_KLIPS_DEBUG
++      char buf1[ADDRTOA_BUF], buf2[ADDRTOA_BUF];
++      
++      if (debug_radij & DB_RJ_FINDROUTE) {
++              addrtoa(eaddr->sen_ip_src, 0, buf1, sizeof(buf1));
++              addrtoa(eaddr->sen_ip_dst, 0, buf2, sizeof(buf2));
++              KLIPS_PRINT(debug_eroute,
++                          "klips_debug:ipsec_findroute: "
++                          "%s:%d->%s:%d %d\n",
++                          buf1, ntohs(eaddr->sen_sport),
++                          buf2, ntohs(eaddr->sen_dport),
++                          eaddr->sen_proto);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      rn = rj_match((caddr_t)eaddr, rnh);
++      if(rn) {
++              KLIPS_PRINT(debug_eroute && sysctl_ipsec_debug_verbose,
++                          "klips_debug:ipsec_findroute: "
++                          "found, points to proto=%d, spi=%x, dst=%x.\n",
++                          ((struct eroute*)rn)->er_said.proto,
++                          ntohl(((struct eroute*)rn)->er_said.spi),
++                          ntohl(((struct eroute*)rn)->er_said.dst.u.v4.sin_addr.s_addr));
++      }
++      return (struct eroute *)rn;
++}
++              
++#ifdef CONFIG_PROC_FS
++/** ipsec_rj_walker_procprint: print one line of eroute table output.
++ *
++ * Theoretical BUG: if w->length is less than the length
++ * of some line we should produce, that line will never
++ * be finished.  In effect, the "file" will stop part way 
++ * through that line.
++ */
++int
++ipsec_rj_walker_procprint(struct radij_node *rn, void *w0)
++{
++      struct eroute *ro = (struct eroute *)rn;
++      struct rjtentry *rd = (struct rjtentry *)rn;
++      struct wsbuf *w = (struct wsbuf *)w0;
++      char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
++      char buf3[16];
++      char sa[SATOT_BUF];
++      size_t sa_len, buf_len;
++      struct sockaddr_encap *key, *mask;
++      
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:ipsec_rj_walker_procprint: "
++                  "rn=0p%p, w0=0p%p\n",
++                  rn,
++                  w0);
++      if (rn->rj_b >= 0) {
++              return 0;
++      }
++      
++      key = rd_key(rd);
++      mask = rd_mask(rd);
++
++      if (key == NULL || mask == NULL) {
++                return 0;
++        }
++
++      buf_len = subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
++      if(key->sen_sport != 0) {
++        sprintf(buf1+buf_len-1, ":%d", ntohs(key->sen_sport));
++      }
++
++      buf_len = subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
++      if(key->sen_dport != 0) {
++        sprintf(buf2+buf_len-1, ":%d", ntohs(key->sen_dport));
++      }
++
++      buf3[0]='\0';
++      if(key->sen_proto != 0) {
++        sprintf(buf3, ":%d", key->sen_proto);
++      }
++
++      sa_len = satot(&ro->er_said, 'x', sa, sizeof(sa));
++      w->len += ipsec_snprintf(w->buffer + w->len,
++                               w->length - w->len,
++                               "%-10d "
++                               "%-18s -> %-18s => %s%s\n",
++                               ro->er_count,
++                               buf1,
++                               buf2,
++                               sa_len ? sa : " (error)",
++                               buf3);
++      
++       {
++               /* snprintf can only fill the last character with NUL
++                * so the maximum useful character is w->length-1.
++                * However, if w->length == 0, we cannot go back.
++                * (w->length surely cannot be negative.)
++                */
++               int max_content = w->length > 0? w->length-1 : 0;
++
++               if (w->len >= max_content) {
++                       /* we've done all that can fit -- stop treewalking */
++                       w->len = max_content;   /* truncate crap */
++                       return -ENOBUFS;
++               } else {
++                       const off_t pos = w->begin + w->len;    /* file position of end of what we've generated */
++                
++                       if (pos <= w->offset) {
++                               /* all is before first interesting character:
++                                * discard, but note where we are.
++                                */
++                               w->len = 0;
++                               w->begin = pos;
++                       }
++                       return 0;
++               }
++        }        
++}
++#endif          /* CONFIG_PROC_FS */
++
++int
++ipsec_rj_walker_delete(struct radij_node *rn, void *w0)
++{
++      struct eroute *ro;
++      struct rjtentry *rd = (struct rjtentry *)rn;
++      struct radij_node *rn2;
++      int error;
++      struct sockaddr_encap *key, *mask;
++      
++      key = rd_key(rd);
++      mask = rd_mask(rd);
++      
++      if(!key || !mask) {
++              return -ENODATA;
++      }
++#ifdef CONFIG_KLIPS_DEBUG
++      if(debug_radij) {
++              char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
++              subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
++              KLIPS_PRINT(debug_radij, 
++                          "klips_debug:ipsec_rj_walker_delete: "
++                          "deleting: %s -> %s\n",
++                          buf1,
++                          buf2);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      if((error = rj_delete(key, mask, rnh, &rn2))) {
++              KLIPS_PRINT(debug_radij,
++                          "klips_debug:ipsec_rj_walker_delete: "
++                          "rj_delete failed with error=%d.\n", error);
++              return error;
++      }
++
++      if(rn2 != rn) {
++              printk("klips_debug:ipsec_rj_walker_delete: "
++                     "tried to delete a different node?!?  This should never happen!\n");
++      }
++ 
++      ro = (struct eroute *)rn;
++      
++      if (ro->er_ident_s.data)
++              kfree(ro->er_ident_s.data);
++      if (ro->er_ident_d.data)
++              kfree(ro->er_ident_d.data);
++      
++      memset((caddr_t)rn, 0, sizeof (struct eroute));
++      kfree(rn);
++      
++      return 0;
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_rcv.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,2124 @@
++/*
++ * receive code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998-2003   Richard Guy Briggs.
++ * Copyright (C) 2004-2007   Michael Richardson <mcr@xelerance.com>
++ * Copyright (C) 2007-2008   Paul Wouters <paul@xelerance.com>
++ *
++ * OCF/receive state machine written by
++ * David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>  /* struct device, and other headers */
++#include <linux/etherdevice.h>        /* eth_type_trans */
++#include <linux/ip.h>         /* struct iphdr */
++
++#include <net/tcp.h>
++#include <net/udp.h>
++#include <net/xfrm.h>
++#include <linux/skbuff.h>
++#include <openswan.h>
++
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++#  ifdef NEED_SPINLOCK_TYPES
++#   include <linux/spinlock_types.h> 
++#  endif
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "openswan/ipsec_kern24.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_mast.h"
++#include "openswan/ipsec_rcv.h"
++
++#include "openswan/ipsec_auth.h"
++
++#include "openswan/ipsec_esp.h"
++
++#ifdef CONFIG_KLIPS_AH
++#include "openswan/ipsec_ah.h"
++#endif /* CONFIG_KLIPS_AH */
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipsec_ipcomp.h"
++#endif /* CONFIG_KLIPS_COMP */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++#include "openswan/ipsec_kern24.h"
++
++#ifdef CONFIG_KLIPS_OCF
++#include "ipsec_ocf.h"
++#endif
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#include <linux/udp.h>
++#endif
++
++/* This is a private use protocol, and AT&T should be ashamed. They should have
++ * used protocol # 59, which is "no next header" instead of 0xFE.
++ */
++#ifndef IPPROTO_ATT_HEARTBEAT
++#define IPPROTO_ATT_HEARTBEAT 0xFE
++#endif
++
++/* management of buffers */
++static struct ipsec_rcv_state *ipsec_rcv_state_new (void);
++static void ipsec_rcv_state_delete (struct ipsec_rcv_state *irs);
++
++/*
++ * Check-replay-window routine, adapted from the original
++ * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt
++ *
++ *  This is a routine that implements a 64 packet window. This is intend-
++ *  ed on being an implementation sample.
++ */
++
++DEBUG_NO_STATIC int
++ipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq)
++{
++      __u32 diff;
++
++      if (ipsp->ips_replaywin == 0)   /* replay shut off */
++              return 1;
++      if (seq == 0)
++              return 0;               /* first == 0 or wrapped */
++
++      /* new larger sequence number */
++      if (seq > ipsp->ips_replaywin_lastseq) {
++              return 1;               /* larger is good */
++      }
++      diff = ipsp->ips_replaywin_lastseq - seq;
++
++      /* too old or wrapped */ /* if wrapped, kill off SA? */
++      if (diff >= ipsp->ips_replaywin) {
++              return 0;
++      }
++      /* this packet already seen */
++      if (ipsp->ips_replaywin_bitmap & (1 << diff))
++              return 0;
++      return 1;                       /* out of order but good */
++}
++
++DEBUG_NO_STATIC int
++ipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq)
++{
++      __u32 diff;
++
++      if (ipsp->ips_replaywin == 0)   /* replay shut off */
++              return 1;
++      if (seq == 0)
++              return 0;               /* first == 0 or wrapped */
++
++      /* new larger sequence number */
++      if (seq > ipsp->ips_replaywin_lastseq) {
++              diff = seq - ipsp->ips_replaywin_lastseq;
++
++              /* In win, set bit for this pkt */
++              if (diff < ipsp->ips_replaywin)
++                      ipsp->ips_replaywin_bitmap =
++                              (ipsp->ips_replaywin_bitmap << diff) | 1;
++              else
++                      /* This packet has way larger seq num */
++                      ipsp->ips_replaywin_bitmap = 1;
++
++              if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) {
++                      ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1;
++              }
++              ipsp->ips_replaywin_lastseq = seq;
++              return 1;               /* larger is good */
++      }
++      diff = ipsp->ips_replaywin_lastseq - seq;
++
++      /* too old or wrapped */ /* if wrapped, kill off SA? */
++      if (diff >= ipsp->ips_replaywin) {
++/*
++              if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) {
++                      ipsec_sa_delchain(ipsp);
++              }
++*/
++              return 0;
++      }
++      /* this packet already seen */
++      if (ipsp->ips_replaywin_bitmap & (1 << diff))
++              return 0;
++      ipsp->ips_replaywin_bitmap |= (1 << diff);      /* mark as seen */
++      return 1;                       /* out of order but good */
++}
++
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++struct auth_alg ipsec_rcv_md5[]={
++      {osMD5Init, osMD5Update, osMD5Final, AHMD596_ALEN}
++};
++
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++struct auth_alg ipsec_rcv_sha1[]={
++      {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}
++};
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++
++
++static inline void ipsec_rcv_redodebug(struct ipsec_rcv_state *irs)
++{
++      struct iphdr * ipp = irs->ipp;
++      struct in_addr ipsaddr, ipdaddr;
++
++      ipsaddr.s_addr = ipp->saddr;
++      addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
++      ipdaddr.s_addr = ipp->daddr;
++      addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
++}
++
++
++#ifdef CONFIG_KLIPS_DEBUG
++DEBUG_NO_STATIC char *
++ipsec_rcv_err(int err)
++{
++      static char tmp[32];
++      switch ((int) err) {
++      case IPSEC_RCV_PENDING:                 return("IPSEC_RCV_PENDING");
++      case IPSEC_RCV_LASTPROTO:               return("IPSEC_RCV_LASTPROTO");
++      case IPSEC_RCV_OK:                              return("IPSEC_RCV_OK");
++      case IPSEC_RCV_BADPROTO:                return("IPSEC_RCV_BADPROTO");
++      case IPSEC_RCV_BADLEN:                  return("IPSEC_RCV_BADLEN");
++      case IPSEC_RCV_ESP_BADALG:              return("IPSEC_RCV_ESP_BADALG");
++      case IPSEC_RCV_3DES_BADBLOCKING:return("IPSEC_RCV_3DES_BADBLOCKING");
++      case IPSEC_RCV_ESP_DECAPFAIL:   return("IPSEC_RCV_ESP_DECAPFAIL");
++      case IPSEC_RCV_DECAPFAIL:               return("IPSEC_RCV_DECAPFAIL");
++      case IPSEC_RCV_SAIDNOTFOUND:    return("IPSEC_RCV_SAIDNOTFOUND");
++      case IPSEC_RCV_IPCOMPALONE:             return("IPSEC_RCV_IPCOMPALONE");
++      case IPSEC_RCV_IPCOMPFAILED:    return("IPSEC_RCV_IPCOMPFAILED");
++      case IPSEC_RCV_SAIDNOTLIVE:             return("IPSEC_RCV_SAIDNOTLIVE");
++      case IPSEC_RCV_FAILEDINBOUND:   return("IPSEC_RCV_FAILEDINBOUND");
++      case IPSEC_RCV_LIFETIMEFAILED:  return("IPSEC_RCV_LIFETIMEFAILED");
++      case IPSEC_RCV_BADAUTH:                 return("IPSEC_RCV_BADAUTH");
++      case IPSEC_RCV_REPLAYFAILED:    return("IPSEC_RCV_REPLAYFAILED");
++      case IPSEC_RCV_AUTHFAILED:              return("IPSEC_RCV_AUTHFAILED");
++      case IPSEC_RCV_REPLAYROLLED:    return("IPSEC_RCV_REPLAYROLLED");
++      case IPSEC_RCV_BAD_DECRYPT:             return("IPSEC_RCV_BAD_DECRYPT");
++      case IPSEC_RCV_REALLYBAD:               return("IPSEC_RCV_REALLYBAD");
++      }
++      snprintf(tmp, sizeof(tmp), "%d", err);
++      return tmp;
++}
++#endif
++
++/*
++ * here is a state machine to handle receiving ipsec packets.
++ * basically we keep getting re-entered until processing is
++ * complete.  For the simple case we step down the states and finish.
++ * each state is ideally some logical part of the process.  If a state
++ * can pend (ie., require async processing to complete),  then this
++ * should be the part of last action before it returns IPSEC_RCV_PENDING
++ *
++ * Any particular action may alter the next_state in irs to move us to
++ * a state other than the preferred "next_state",  but this is the
++ * exception and is highlighted when it is done.
++ *
++ * prototypes for state action
++ */
++
++static enum ipsec_rcv_value ipsec_rcv_init(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_decap_init(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_decap_lookup(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_auth_init(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_auth_decap(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_auth_calc(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_auth_chk(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_decrypt(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_decap_cont(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_cleanup(struct ipsec_rcv_state *irs);
++static enum ipsec_rcv_value ipsec_rcv_complete(struct ipsec_rcv_state *irs);
++
++/*
++ * the state table and each action
++ */
++
++struct {
++      enum ipsec_rcv_value (*action)(struct ipsec_rcv_state *irs);
++      int next_state;
++} rcv_state_table[] = {
++      [IPSEC_RSM_INIT]         = {ipsec_rcv_init,        IPSEC_RSM_DECAP_INIT },
++      [IPSEC_RSM_DECAP_INIT]   = {ipsec_rcv_decap_init,  IPSEC_RSM_DECAP_LOOKUP },
++      [IPSEC_RSM_DECAP_LOOKUP] = {ipsec_rcv_decap_lookup,IPSEC_RSM_AUTH_INIT },
++      [IPSEC_RSM_AUTH_INIT]    = {ipsec_rcv_auth_init,   IPSEC_RSM_AUTH_DECAP },
++      [IPSEC_RSM_AUTH_DECAP]   = {ipsec_rcv_auth_decap,  IPSEC_RSM_AUTH_CALC },
++      [IPSEC_RSM_AUTH_CALC]    = {ipsec_rcv_auth_calc,   IPSEC_RSM_AUTH_CHK },
++      [IPSEC_RSM_AUTH_CHK]     = {ipsec_rcv_auth_chk,    IPSEC_RSM_DECRYPT },
++      [IPSEC_RSM_DECRYPT]      = {ipsec_rcv_decrypt,     IPSEC_RSM_DECAP_CONT },
++      [IPSEC_RSM_DECAP_CONT]   = {ipsec_rcv_decap_cont,  IPSEC_RSM_CLEANUP },
++      [IPSEC_RSM_CLEANUP]      = {ipsec_rcv_cleanup,     IPSEC_RSM_COMPLETE },
++      [IPSEC_RSM_COMPLETE]     = {ipsec_rcv_complete,    IPSEC_RSM_DONE },
++
++      [IPSEC_RSM_DONE]         = {NULL,                  IPSEC_RSM_DONE},
++};
++
++
++
++struct sk_buff *ipsec_rcv_unclone(struct sk_buff *skb,
++                                struct ipsec_rcv_state *irs)
++{
++      /* if skb was cloned (most likely due to a packet sniffer such as
++         tcpdump being momentarily attached to the interface), make
++         a copy of our own to modify */
++      if(skb_cloned(skb)) {
++              /* include any mac header while copying.. */
++              if(skb_headroom(skb) < irs->hard_header_len) {
++                      printk(KERN_WARNING "klips_error:ipsec_rcv: "
++                             "tried to skb_push hhlen=%d, %d available.  This should never happen, please report.\n",
++                             irs->hard_header_len,
++                             skb_headroom(skb));
++                      goto rcvleave;
++              }
++              skb_push(skb, irs->hard_header_len);
++              if
++#ifdef SKB_COW_NEW
++                (skb_cow(skb, skb_headroom(skb)) != 0)
++#else /* SKB_COW_NEW */
++                ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
++#endif /* SKB_COW_NEW */
++              {
++                      goto rcvleave;
++              }
++              if(skb->len < irs->hard_header_len) {
++                      printk(KERN_WARNING "klips_error:ipsec_rcv: "
++                             "tried to skb_pull hhlen=%d, %d available.  This should never happen, please report.\n",
++                             irs->hard_header_len,
++                             skb->len);
++                      goto rcvleave;
++              }
++              skb_pull(skb, irs->hard_header_len);
++      }
++      return skb;
++
++rcvleave:
++      ipsec_kfree_skb(skb);
++      return NULL;
++}
++
++
++
++
++#if !defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++/*
++ * decapsulate a UDP encapsulated ESP packet
++ */
++struct sk_buff *ipsec_rcv_natt_decap(struct sk_buff *skb
++                                   , struct ipsec_rcv_state *irs
++                                   , int *udp_decap_ret_p)
++{
++      *udp_decap_ret_p = 0;
++      if (skb->sk && ip_hdr(skb) && ip_hdr(skb)->protocol==IPPROTO_UDP) {
++              /**
++               * Packet comes from udp_queue_rcv_skb so it is already defrag,
++               * checksum verified, ... (ie safe to use)
++               *
++               * If the packet is not for us, return -1 and udp_queue_rcv_skb
++               * will continue to handle it (do not kfree skb !!).
++               */
++
++#ifndef UDP_OPT_IN_SOCK
++              struct udp_opt {
++                      __u32 esp_in_udp;
++              };
++              struct udp_opt *tp =  (struct udp_opt *)&(skb->sk->tp_pinfo.af_tcp);
++#else
++              struct udp_opt *tp =  &(skb->sk->tp_pinfo.af_udp);
++#endif
++
++              struct iphdr *ip = ip_hdr(skb);
++              struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
++              __u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
++              __u32 *udpdata32 = (__u32 *)udpdata;
++              
++              irs->natt_sport = ntohs(udp->source);
++              irs->natt_dport = ntohs(udp->dest);
++        
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
++                          tp->esp_in_udp);
++              KLIPS_IP_PRINT(debug_rcv, ip);
++        
++              if (udpdata < skb->tail) {
++                      unsigned int len = skb->tail - udpdata;
++                      if ((len==1) && (udpdata[0]==0xff)) {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          /* not IPv6 compliant message */
++                                          "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
++                              *udp_decap_ret_p = 0;
++                              return NULL;
++                      }
++                      else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
++                                (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
++                                (udpdata32[0]==0) && (udpdata32[1]==0) ) {
++                              /* ESP Packet with Non-IKE header */
++                              KLIPS_PRINT(debug_rcv, 
++                                          "klips_debug:ipsec_rcv: "
++                                          "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
++                                          ntohl(udpdata32[2]));
++                              irs->natt_type = ESPINUDP_WITH_NON_IKE;
++                              irs->natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
++                      }
++                      else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
++                                (len > sizeof(struct esphdr)) &&
++                                (udpdata32[0]!=0) ) {
++                              /* ESP Packet without Non-ESP header */
++                              irs->natt_type = ESPINUDP_WITH_NON_ESP;
++                              irs->natt_len = sizeof(struct udphdr);
++                              KLIPS_PRINT(debug_rcv, 
++                                          "klips_debug:ipsec_rcv: "
++                                          "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
++                                          ntohl(udpdata32[0]));
++                      }
++                      else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "IKE packet - not handled here\n");
++                              *udp_decap_ret_p = -1;
++                              return NULL;
++                      }
++              }
++              else {
++                      return NULL;
++              }
++      }
++      return skb;
++}
++#endif
++
++#ifdef HAVE_IPSEC_SAREF
++void ip_cmsg_recv_ipsec(struct msghdr *msg, struct sk_buff *skb)
++{
++      struct ipsec_sa *sa1;
++      struct sec_path *sp;
++      xfrm_sec_unique_t refs[2];
++
++      sp = skb->sp;
++
++      if(sp==NULL) return;
++
++      KLIPS_PRINT(debug_rcv, "retrieving saref=%u from skb=%p\n",
++                  sp->ref, skb);
++
++      sa1 = ipsec_sa_getbyref(sp->ref);
++      if(sa1) {
++              refs[1]= sa1->ips_refhim;
++      }
++      refs[0]=sp->ref;
++
++      put_cmsg(msg, SOL_IP, IP_IPSEC_REFINFO,
++               sizeof(xfrm_sec_unique_t)*2, &refs);
++}
++#endif
++
++
++void ipsec_rcv_setoutif(struct ipsec_rcv_state *irs)
++{
++      struct sk_buff *skb = irs->skb;
++
++      if(skb!=NULL && irs->ipsp->ips_out) {
++              if(skb->dev != irs->ipsp->ips_out) {
++                      KLIPS_PRINT(debug_rcv,
++                                  "changing originating interface from %s to %s\n",
++                                  skb->dev->name,
++                                  irs->ipsp->ips_out->name);
++              }
++              skb->dev = irs->ipsp->ips_out;
++              
++              if(skb->dev && skb->dev->get_stats) {
++                      struct net_device_stats *stats = skb->dev->get_stats(skb->dev);
++                      irs->stats = stats;
++              }
++      } 
++}
++
++static enum ipsec_rcv_value
++ipsec_rcv_decap_ipip(struct ipsec_rcv_state *irs)
++{
++      struct ipsec_sa *ipsp = NULL;
++      struct ipsec_sa* ipsnext = NULL;
++      struct iphdr *ipp;
++      struct sk_buff *skb;
++      enum ipsec_rcv_value result = IPSEC_RCV_DECAPFAIL;
++
++      ipp  = irs->ipp;
++      ipsp = irs->ipsp;
++      skb  = irs->skb;
++      irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));
++      if((ipp->protocol != IPPROTO_IPIP) && 
++         (ipp->protocol != IPPROTO_ATT_HEARTBEAT)) {  /* AT&T heartbeats to SIG/GIG */
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "SA:%s, Hey!  How did this get through?  Dropped.\n",
++                          irs->sa_len ? irs->sa : " (error)");
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              goto rcvleave;
++      }
++      if(sysctl_ipsec_inbound_policy_check) {
++              struct sockaddr_in *psin = (struct sockaddr_in*)(ipsp->ips_addr_s);
++              if((ipsnext = ipsp->ips_next)) {
++                      char sa2[SATOT_BUF];
++                      size_t sa_len2;
++                      sa_len2 = satot(&ipsnext->ips_said, 0, sa2, sizeof(sa2));
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "unexpected SA:%s after IPIP SA:%s\n",
++                                  sa_len2 ? sa2 : " (error)",
++                                  irs->sa_len ? irs->sa : " (error)");
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              if(ipp->saddr != psin->sin_addr.s_addr) {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, src=%s(%08x) does match expected 0x%08x.\n",
++                                  irs->sa_len ? irs->sa : " (error)",
++                                  irs->ipsaddr_txt, 
++                                  ipp->saddr, psin->sin_addr.s_addr);
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++      }
++      
++      ipsec_rcv_setoutif(irs);
++
++      if(ipp->protocol == IPPROTO_IPIP)  /* added to support AT&T heartbeats to SIG/GIG */
++      {  
++              /*
++               * XXX this needs to be locked from when it was first looked
++               * up in the decapsulation loop.  Perhaps it is better to put
++               * the IPIP decap inside the loop.
++               */
++              ipsp->ips_life.ipl_bytes.ipl_count += skb->len;
++              ipsp->ips_life.ipl_bytes.ipl_last   = skb->len;
++              
++              if(!ipsp->ips_life.ipl_usetime.ipl_count) {
++                      ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
++              }
++              ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
++              ipsp->ips_life.ipl_packets.ipl_count += 1;
++              
++              if(skb->len < irs->iphlen) {
++                      printk(KERN_WARNING "klips_debug:ipsec_rcv: "
++                             "tried to skb_pull iphlen=%d, %d available.  This should never happen, please report.\n",
++                             irs->iphlen,
++                             (int)(skb->len));
++                      
++                      goto rcvleave;
++              }
++              
++              /*
++               * we need to pull up by size of IP header,
++               * options, but also by any UDP/ESP encap there might
++               * have been, and this deals with all cases.
++               */
++              skb_pull(skb, (skb_transport_header(skb) - skb_network_header(skb)));
++              
++              /* new L3 header is where L4 payload was */
++              skb_set_network_header(skb, ipsec_skb_offset(skb, skb_transport_header(skb)));
++              
++              /* now setup new L4 payload location */
++              ipp = (struct iphdr *)skb_network_header(skb);
++              skb_set_transport_header(skb, ipsec_skb_offset(skb, skb_network_header(skb) + (ipp->ihl << 2)));
++
++              
++              /* remove any saved options that we might have,
++               * since we have a new IP header.
++               */
++              memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++              
++#if 0
++              KLIPS_PRINT(debug_rcv, "csum: %d\n", ip_fast_csum((u8 *)ipp, ipp->ihl));
++#endif
++              
++              /* re-do any strings for debugging */
++              irs->ipp = ipp;
++              ipsec_rcv_redodebug(irs);
++
++              skb->protocol = htons(ETH_P_IP);
++              skb->ip_summed = 0;
++              KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                          "klips_debug:ipsec_rcv: "
++                          "IPIP tunnel stripped.\n");
++              KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
++      }
++      
++      if(sysctl_ipsec_inbound_policy_check
++         /*
++           Note: "xor" (^) logically replaces "not equal"
++           (!=) and "bitwise or" (|) logically replaces
++           "boolean or" (||).  This is done to speed up
++           execution by doing only bitwise operations and
++           no branch operations
++         */
++         && (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr)
++              ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr)
++             | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr)
++                ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) )
++      {
++              char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];
++              
++              subnettoa(ipsp->ips_flow_s.u.v4.sin_addr,
++                        ipsp->ips_mask_s.u.v4.sin_addr,
++                        0, sflow_txt, sizeof(sflow_txt));
++              subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
++                        ipsp->ips_mask_d.u.v4.sin_addr,
++                        0, dflow_txt, sizeof(dflow_txt));
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
++                          irs->sa_len ? irs->sa : " (error)",
++                          sflow_txt,
++                          dflow_txt,
++                          irs->ipsaddr_txt,
++                          irs->ipdaddr_txt);
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              goto rcvleave;
++      }
++#ifdef CONFIG_NETFILTER
++      skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK))))
++              | IPsecSAref2NFmark(IPsecSA2SAref(ipsp));
++      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                  "klips_debug:ipsec_rcv: "
++                  "IPIP SA sets skb->nfmark=0x%x.\n",
++                  (unsigned)skb->nfmark);
++#endif /* CONFIG_NETFILTER */
++
++      result = IPSEC_RCV_OK;
++
++rcvleave:
++      return result;
++}
++
++/*
++ * get all the initial checking and setup done.  Not of this can be off
++ * loaded by any currently support hardware
++ *
++ * the following things should be setup when we exit this function.
++ *
++ * irs->stats  == stats structure (or NULL)
++ * irs->ipp    = IP header.
++ * irs->len    = total length of packet
++ * skb->nh.iph = ipp;
++ * skb->h.raw  = start of payload
++ * irs->ipsp   = NULL.
++ * irs->iphlen = N/A = is recalculated.
++ * irs->ilen   = 0;
++ * irs->authlen = 0;
++ * irs->authfuncs = NULL;
++ * irs->skb    = the skb;
++ *
++ * proto_funcs should be from ipsec_esp.c, ipsec_ah.c or ipsec_ipcomp.c.
++ *
++ */
++
++static enum ipsec_rcv_value
++ipsec_rcv_init(struct ipsec_rcv_state *irs)
++{
++#ifdef CONFIG_KLIPS_DEBUG
++      struct net_device *dev;
++#endif /* CONFIG_KLIPS_DEBUG */
++      unsigned char protoc;
++      struct iphdr *ipp;
++      struct net_device_stats *stats = NULL;          /* This device's statistics */
++      int i;
++      struct sk_buff *skb;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      if (irs == NULL) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_init: NULL irs.");
++              return IPSEC_RCV_REALLYBAD;
++      }
++
++      skb = irs->skb;
++      if (!skb) {
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_init: NULL skb.");
++              return IPSEC_RCV_REALLYBAD;
++      }
++      dev = skb->dev;
++
++      if (skb->data == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "NULL skb->data passed in, packet is bogus, dropping.\n");
++              return IPSEC_RCV_REALLYBAD;
++      }
++
++      /* dev->hard_header_len is unreliable and should not be used */
++      /* klips26_rcv_encap will have already set hard_header_len for us */
++      if (irs->hard_header_len == 0) {
++              irs->hard_header_len = skb_mac_header(skb) ? (skb_network_header(skb) - skb_mac_header(skb)) : 0;
++              if((irs->hard_header_len < 0) || (irs->hard_header_len > skb_headroom(skb)))
++                      irs->hard_header_len = 0;
++      }
++
++      skb = ipsec_rcv_unclone(skb, irs);
++      if(skb == NULL) {
++              return IPSEC_RCV_REALLYBAD;
++      }
++
++#if IP_FRAGMENT_LINEARIZE
++      /* In Linux 2.4.4, we may have to reassemble fragments. They are
++         not assembled automatically to save TCP from having to copy
++         twice.
++      */
++      if (skb_is_nonlinear(skb)) {
++#ifdef HAVE_NEW_SKB_LINEARIZE
++              if (skb_linearize_cow(skb) != 0)
++#else
++              if (skb_linearize(skb, GFP_ATOMIC) != 0) 
++#endif
++              {
++                      return IPSEC_RCV_REALLYBAD;
++              }
++      }
++#endif /* IP_FRAGMENT_LINEARIZE */
++
++      ipp = ip_hdr(skb);
++      irs->ipp = ipp;
++
++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
++      if (irs->natt_len) {
++              /**
++               * Now, we are sure packet is ESPinUDP, and we have a private
++               * copy that has been linearized, remove natt_len bytes
++               * from packet and modify protocol to ESP.
++               */
++              if (((unsigned char *)skb->data > (unsigned char *)ip_hdr(skb))
++                  && ((unsigned char *)ip_hdr(skb) > (unsigned char *)skb->head))
++              {
++                      unsigned int _len = (unsigned char *)skb->data -
++                              (unsigned char *)ip_hdr(skb);
++                      KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
++                              _len);
++                      skb_push(skb, _len);
++              }
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "removing %d bytes from ESPinUDP packet\n"
++                          , irs->natt_len);
++
++              ipp = (struct iphdr *)skb->data;
++              irs->iphlen = ipp->ihl << 2;
++              ipp->tot_len = htons(ntohs(ipp->tot_len) - irs->natt_len);
++              if (skb->len < irs->iphlen + irs->natt_len) {
++                      printk(KERN_WARNING
++                             "klips_error:ipsec_rcv: "
++                             "ESPinUDP packet is too small (%d < %d+%d). "
++                             "This should never happen, please report.\n",
++                             (int)(skb->len), irs->iphlen, irs->natt_len);
++                      return IPSEC_RCV_REALLYBAD;
++              }
++
++              /* advance payload pointer to point past the UDP header */
++              skb->h.raw = skb->h.raw + irs->natt_len;
++
++              /* modify protocol */
++              ipp->protocol = IPPROTO_ESP;
++
++              skb->sk = NULL;
++
++              KLIPS_IP_PRINT(debug_rcv, ip_hdr(skb));
++      }
++#endif
++
++      if (debug_rcv)
++              ipsec_rcv_redodebug(irs);
++
++      irs->iphlen = ipp->ihl << 2;
++
++      KLIPS_PRINT(debug_rcv,
++                  "klips_debug:ipsec_rcv: "
++                  "<<< Info -- ");
++      KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
++                      skb->dev->name ? skb->dev->name : "NULL");
++      KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
++                      dev->name ? dev->name : "NULL");
++      KLIPS_PRINTMORE(debug_rcv, "\n");
++
++      KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),
++                  "klips_debug:ipsec_rcv: "
++                  "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",
++                  skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",
++                  dev ? (dev->name ? dev->name : "NULL") : "NULL");
++
++      protoc = ipp->protocol;
++#ifndef NET_21
++      if((!protocol) || (protocol->protocol != protoc)) {
++              KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
++                          "klips_debug:ipsec_rcv: "
++                          "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
++      }
++#endif /* !NET_21 */
++
++      if( (protoc != IPPROTO_AH) &&
++#ifdef CONFIG_KLIPS_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
++          (protoc != IPPROTO_COMP) &&
++#endif /* CONFIG_KLIPS_IPCOMP */
++          (protoc != IPPROTO_ESP) ) {
++              KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
++                          "klips_debug:ipsec_rcv: Why the hell is someone "
++                          "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
++                          protoc);
++              return IPSEC_RCV_REALLYBAD;
++      }
++
++      /*
++       * if there is an attached ipsec device, then use that device for
++       * stats until we know better.
++       */
++      if(skb->dev) {
++              struct ipsecpriv  *prvdev = NULL;
++              struct net_device *ipsecdev = NULL;
++
++              for(i = 0; i <= ipsecdevices_max; i++) {
++                      if(ipsecdevices[i] == NULL) continue;
++                      prvdev = ipsecdevices[i]->priv;
++                      
++                      if(prvdev == NULL) continue;
++
++                      if(prvdev->dev == skb->dev) {
++                              ipsecdev = ipsecdevices[i];
++                              break;
++                      }
++              }
++
++              if(ipsecdev) {
++                      skb->dev = ipsecdev;
++              } else {
++                      skb->dev = ipsec_mast_get_device(0);
++                      
++                      /* ipsec_mast_get takes the device */
++                      if(skb->dev) dev_put(skb->dev);
++              }
++
++              if(prvdev) {
++                      stats = (struct net_device_stats *) &(prvdev->mystats);
++              }
++      } 
++
++      if(stats) {
++              stats->rx_packets++;
++      }
++
++      KLIPS_IP_PRINT(debug_rcv, ipp);
++
++      /* set up for decap */
++      irs->stats= stats;
++      irs->ipp  = ipp;
++      irs->ipsp = NULL;
++      irs->ilen = 0;
++      irs->authlen=0;
++      irs->authfuncs=NULL;
++      irs->skb = skb;
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_decap_init(struct ipsec_rcv_state *irs)
++{
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      switch (irs->ipp->protocol) {
++      case IPPROTO_ESP:
++              irs->proto_funcs = esp_xform_funcs;
++              break;
++
++#ifdef CONFIG_KLIPS_AH
++      case IPPROTO_AH:
++              irs->proto_funcs = ah_xform_funcs;
++              break;
++#endif /* !CONFIG_KLIPS_AH */
++
++#ifdef CONFIG_KLIPS_IPCOMP
++      case IPPROTO_COMP:
++              irs->proto_funcs = ipcomp_xform_funcs;
++              break;
++#endif /* !CONFIG_KLIPS_IPCOMP */
++
++      default:
++              if (irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADPROTO;
++      }
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_decap_lookup(struct ipsec_rcv_state *irs)
++{
++      struct iphdr *ipp;
++      struct sk_buff *skb;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      irs->replay = 0;
++#ifdef CONFIG_KLIPS_ALG
++      irs->ixt_a = NULL;
++#endif /* CONFIG_KLIPS_ALG */
++
++      skb = irs->skb;
++      irs->len = skb->len;
++      ipp = irs->ipp;
++      irs->proto = ipp->protocol;
++      if (debug_rcv)
++              ipsec_rcv_redodebug(irs);
++
++      irs->iphlen = ipp->ihl << 2;
++      ipp->check = 0;                 /* we know the sum is good */
++
++      irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr;
++      irs->said.dst.u.v4.sin_family = AF_INET;
++      
++      /* note: rcv_checks set up the said.spi value, if appropriate */
++      if (irs->proto_funcs->rcv_checks)
++              return (*irs->proto_funcs->rcv_checks)(irs, irs->skb);
++
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_auth_init(struct ipsec_rcv_state *irs)
++{
++      struct ipsec_sa *newipsp;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      irs->said.proto = irs->proto;
++      if (debug_rcv) {
++              irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));
++              if(irs->sa_len == 0) {
++                      strcpy(irs->sa, "(error)");
++              }
++      } else
++              irs->sa_len = 0;
++
++      newipsp = ipsec_sa_getbyid(&irs->said);
++      if (newipsp == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
++                          irs->sa_len ? irs->sa : " (error)");
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              return IPSEC_RCV_SAIDNOTFOUND;
++      }
++
++      /* If it is in larval state, drop the packet, we cannot process yet. */
++      if(newipsp->ips_state == K_SADB_SASTATE_LARVAL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              ipsec_sa_put(newipsp);
++              return IPSEC_RCV_SAIDNOTLIVE;
++      }
++
++      if(newipsp->ips_state == K_SADB_SASTATE_DEAD) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              ipsec_sa_put(newipsp);
++              return IPSEC_RCV_SAIDNOTLIVE;
++      }
++
++      if(sysctl_ipsec_inbound_policy_check) {
++              if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
++                      KLIPS_ERROR(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
++                                  irs->sa_len ? irs->sa : " (error)",
++                                  irs->ipsaddr_txt);
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      ipsec_sa_put(newipsp);
++                      return IPSEC_RCV_FAILEDINBOUND;
++              }
++
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",
++                          irs->sa_len ? irs->sa : " (error)",
++                          irs->ipsaddr_txt);
++
++              /*
++               * at this point, we have looked up a new SA, and we want to
++               * make sure that if this isn't the first SA in the list,
++               * that the previous SA actually points at this one.
++               */
++              if(irs->ipsp) {
++                      if(irs->ipsp->ips_next != newipsp) {
++                              KLIPS_ERROR(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "unexpected SA:%s: does not agree with ips->inext policy, dropped\n",
++                                          irs->sa_len ? irs->sa : " (error)");
++                              if(irs->stats) {
++                                      irs->stats->rx_dropped++;
++                              }
++                              ipsec_sa_put(newipsp);
++                              return IPSEC_RCV_FAILEDINBOUND;
++                      }
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s grouping from previous SA is OK.\n",
++                                  irs->sa_len ? irs->sa : " (error)");
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s First SA in group.\n",
++                                  irs->sa_len ? irs->sa : " (error)");
++              }
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++                if (irs->proto == IPPROTO_ESP) {
++                        KLIPS_PRINT(debug_rcv,
++                                "klips_debug:ipsec_rcv: "
++                                "natt_type=%u tdbp->ips_natt_type=%u : %s\n",
++                                irs->natt_type, newipsp->ips_natt_type,
++                                (irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
++                        if (irs->natt_type != newipsp->ips_natt_type) {
++                                KLIPS_PRINT(debug_rcv,
++                                            "klips_debug:ipsec_rcv: "
++                                            "SA:%s does not agree with expected NAT-T policy.\n",
++                                            irs->sa_len ? irs->sa : " (error)");
++                                if(irs->stats) {
++                                        irs->stats->rx_dropped++;
++                                }
++                                ipsec_sa_put(newipsp);
++                                return IPSEC_RCV_FAILEDINBOUND;
++                        }
++                }
++#endif                 
++      }
++
++      irs->ipsp=newipsp;
++
++      return IPSEC_RCV_OK;
++}
++
++static enum ipsec_rcv_value
++ipsec_rcv_auth_decap(struct ipsec_rcv_state *irs)
++{
++      ipsec_rcv_setoutif(irs);
++
++      irs->proto_funcs = irs->ipsp->ips_xformfuncs;
++      if (irs->proto_funcs == NULL)
++              return IPSEC_RCV_BADPROTO;
++
++      if (irs->proto_funcs->protocol != irs->ipp->protocol) {
++              if(irs->proto_funcs->protocol == IPPROTO_COMP) {
++                      /* looks like an IPCOMP that we can skip */
++                      struct ipsec_sa *newipsp = NULL;
++
++                      newipsp = irs->ipsp->ips_next;
++                      if(newipsp) {
++                              ipsec_sa_get(newipsp);
++                      }
++                      if(irs->lastipsp) {
++                              ipsec_sa_put(irs->lastipsp);
++                      }
++                      irs->lastipsp = irs->ipsp;
++                      irs->ipsp=newipsp;
++
++                      /* come back into here with the next transform */
++                      irs->next_state = IPSEC_RSM_AUTH_DECAP;
++                      return IPSEC_RCV_OK;
++              }
++
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_FAILEDINBOUND;
++      }
++
++      if (debug_rcv)
++              ipsec_rcv_redodebug(irs);
++
++      /* now check the lifetimes */
++      if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes,   "bytes",
++                              irs->sa, ipsec_life_countbased, ipsec_incoming,
++                              irs->ipsp) == ipsec_life_harddied ||
++         ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime",
++                              irs->sa, ipsec_life_timebased,  ipsec_incoming,
++                              irs->ipsp) == ipsec_life_harddied ||
++         ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime",
++                              irs->sa, ipsec_life_timebased,  ipsec_incoming,
++                              irs->ipsp) == ipsec_life_harddied ||
++         ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets",
++                              irs->sa, ipsec_life_countbased, ipsec_incoming,
++                              irs->ipsp) == ipsec_life_harddied) {
++              
++              /*
++               * disconnect SA from the hash table, so it can not be
++               * found again.
++               */
++              ipsec_sa_rm(irs->ipsp);
++              if(irs->stats) {
++                      irs->stats->rx_dropped++;
++              }
++              
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv_decap_once: "
++                          "decap (%d) failed lifetime check\n",
++                          irs->proto);
++
++              return IPSEC_RCV_LIFETIMEFAILED;
++      }
++
++#if 0
++      /*
++       * This is removed for some reasons:
++       *   1) it needs to happen *after* authentication.
++       *   2) do we really care, if it authenticates, if it came
++       *      from the wrong location?
++         *   3) the NAT_KA messages in IKE will also get to pluto
++       *      and it will figure out that stuff has moved.
++       *   4) the 2.6 udp-esp encap function does not pass us
++       *      the originating port number, and I can't tell
++       *      if skb->sk is guaranteed to be valid here.
++       *  2005-04-16: mcr@xelerance.com
++       */
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      /*
++       *
++       * XXX we should ONLY update pluto if the SA passes all checks,
++       *     which we clearly do not now.
++       */
++      if ((irs->natt_type) &&
++              ( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) ||
++                (irs->natt_sport != newipsp->ips_natt_sport)
++              )) {
++              struct sockaddr sipaddr;
++              struct sockaddr_in *psin = (struct sockaddr_in*)(newipsp->ips_addr_s);
++
++              /** Advertise NAT-T addr change to pluto **/
++              sipaddr.sa_family = AF_INET;
++              ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr;
++              ((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport);
++              pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->natt_sport);
++
++              /**
++               * Then allow or block packet depending on
++               * sysctl_ipsec_inbound_policy_check.
++               *
++               * In all cases, pluto will update SA if new mapping is
++               * accepted.
++               */
++              if (sysctl_ipsec_inbound_policy_check) {
++                      KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: "
++                              "SA:%s, src=%s:%u of pkt does not agree with expected "
++                              "SA source address [%08x:%u] (notifying pluto of change).\n",
++                              irs->sa_len ? irs->sa : " (error)",
++                                  irs->ipsaddr_txt, irs->natt_sport,
++                                  psin->sin_addr.s_addr,
++                                  newipsp->ips_natt_sport);
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      ipsec_sa_put(newipsp);
++                      return IPSEC_RCV_FAILEDINBOUND;
++              }
++      }
++#endif
++#endif
++
++      irs->authfuncs=NULL;
++
++      /* authenticate, if required */
++#ifdef CONFIG_KLIPS_OCF
++      if (irs->ipsp->ocf_in_use) {
++              irs->authlen = AHHMAC_HASHLEN;
++              irs->authfuncs = NULL;
++              irs->ictx = NULL;
++              irs->octx = NULL;
++              irs->ictx_len = 0;
++              irs->octx_len = 0;
++      } else
++#endif /* CONFIG_KLIPS_OCF */
++#ifdef CONFIG_KLIPS_ALG
++      /* authenticate, if required */
++      if ((irs->ixt_a=irs->ipsp->ips_alg_auth)) {
++              irs->authlen = AHHMAC_HASHLEN;
++              irs->authfuncs = NULL;
++              irs->ictx = NULL;
++              irs->octx = NULL;
++              irs->ictx_len = 0;
++              irs->octx_len = 0;
++              KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: "
++                              "authalg=%d authlen=%d\n",
++                              irs->ipsp->ips_authalg, 
++                              irs->authlen);
++      } else
++#endif /* CONFIG_KLIPS_ALG */
++      switch(irs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++      case AH_MD5:
++              irs->authlen = AHHMAC_HASHLEN;
++              irs->authfuncs = ipsec_rcv_md5;
++              irs->ictx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx;
++              irs->octx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx;
++              irs->ictx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx);
++              irs->octx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx);
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++      case AH_SHA:
++              irs->authlen = AHHMAC_HASHLEN;
++              irs->authfuncs = ipsec_rcv_sha1;
++              irs->ictx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx;
++              irs->octx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx;
++              irs->ictx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx);
++              irs->octx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx);
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      case AH_NONE:
++              irs->authlen = 0;
++              irs->authfuncs = NULL;
++              irs->ictx = NULL;
++              irs->octx = NULL;
++              irs->ictx_len = 0;
++              irs->octx_len = 0;
++              break;
++      default:
++              irs->ipsp->ips_errs.ips_alg_errs += 1;
++              if(irs->stats) {
++                      irs->stats->rx_errors++;
++              }
++              return IPSEC_RCV_BADAUTH;
++      }
++
++      /* ilen counts number of bytes in ESP portion */
++      irs->ilen = ((irs->skb->data + irs->skb->len) - skb_transport_header(irs->skb)) - irs->authlen;
++      if(irs->ilen <= 0) {
++        KLIPS_PRINT(debug_rcv,
++                    "klips_debug:ipsec_rcv: "
++                    "runt %s packet with no data, dropping.\n",
++                    (irs->proto == IPPROTO_ESP ? "esp" : "ah"));
++        if(irs->stats) {
++          irs->stats->rx_dropped++;
++        }
++        return IPSEC_RCV_BADLEN;
++      }
++
++      if(irs->authfuncs ||
++#ifdef CONFIG_KLIPS_OCF
++                      irs->ipsp->ocf_in_use ||
++#endif
++#ifdef CONFIG_KLIPS_ALG
++                      irs->ixt_a ||
++#endif
++                      0) {
++        if(irs->proto_funcs->rcv_setup_auth)
++          return (*irs->proto_funcs->rcv_setup_auth)(irs, irs->skb,
++                              &irs->replay, &irs->authenticator);
++      }
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_auth_calc(struct ipsec_rcv_state *irs)
++{
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      if(irs->authfuncs ||
++#ifdef CONFIG_KLIPS_OCF
++                      irs->ipsp->ocf_in_use ||
++#endif
++#ifdef CONFIG_KLIPS_ALG
++                      irs->ixt_a ||
++#endif
++                      0) {
++              if(!irs->authenticator) {
++                      irs->ipsp->ips_errs.ips_auth_errs += 1;
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      return IPSEC_RCV_BADAUTH;
++              }
++
++              if(!ipsec_checkreplaywindow(irs->ipsp, irs->replay)) {
++                      irs->ipsp->ips_errs.ips_replaywin_errs += 1;
++                      KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
++                                  "klips_debug:ipsec_rcv: "
++                                  "duplicate frame from %s, packet dropped\n",
++                                  irs->ipsaddr_txt);
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      return IPSEC_RCV_REPLAYFAILED;
++              }
++
++              /*
++               * verify authenticator
++               */
++
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "encalg = %d, authalg = %d.\n",
++                          irs->ipsp->ips_encalg,
++                          irs->ipsp->ips_authalg);
++
++              /* calculate authenticator */
++              if(irs->proto_funcs->rcv_calc_auth == NULL) {
++                      return IPSEC_RCV_BADAUTH;
++              }
++              return (*irs->proto_funcs->rcv_calc_auth)(irs, irs->skb);
++      }
++      return IPSEC_RCV_OK;
++}
++
++static enum ipsec_rcv_value
++ipsec_rcv_auth_chk(struct ipsec_rcv_state *irs)
++{
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d) - %s\n", __FUNCTION__,
++                      irs->state, irs->next_state,
++                      irs->auth_checked ? "already checked" : "will check");
++
++      if (irs->auth_checked)
++              return IPSEC_RCV_OK;
++
++      if(irs->authfuncs ||
++#ifdef CONFIG_KLIPS_OCF
++                      irs->ipsp->ocf_in_use ||
++#endif
++#ifdef CONFIG_KLIPS_ALG
++                      irs->ixt_a ||
++#endif
++                      0) {
++              if (memcmp(irs->hash, irs->authenticator, irs->authlen)) {
++                      irs->ipsp->ips_errs.ips_auth_errs += 1;
++                      KLIPS_ERROR(debug_rcv & DB_RX_INAU,
++                                  "klips_debug:ipsec_rcv: "
++                                  "auth failed on incoming packet from %s (replay=%d): calculated hash=%08x%08x%08x received hash=%08x%08x%08x, dropped\n",
++                                  irs->ipsaddr_txt,
++                                  irs->replay,
++                                  ntohl(*(__u32*)&irs->hash[0]),
++                                  ntohl(*(__u32*)&irs->hash[4]),
++                                  ntohl(*(__u32*)&irs->hash[8]),
++                                  ntohl(*(__u32*)irs->authenticator),
++                                  ntohl(*((__u32*)irs->authenticator + 1)),
++                                  ntohl(*((__u32*)irs->authenticator + 2)));
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      return IPSEC_RCV_AUTHFAILED;
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "authentication successful.\n");
++              }
++
++              /* Crypto hygiene: clear memory used to calculate autheticator.
++               * The length varies with the algorithm.
++               */
++              memset(irs->hash, 0, irs->authlen);
++
++              /* If the sequence number == 0, expire SA, it had rolled */
++              if(irs->ipsp->ips_replaywin && !irs->replay /* !irs->ipsp->ips_replaywin_lastseq */) {
++                      /* we need to remove it from the sadb hash, so that it can't be found again */
++                      ipsec_sa_rm(irs->ipsp);
++
++                      KLIPS_ERROR(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "replay window counter rolled, expiring SA.\n");
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      return IPSEC_RCV_REPLAYROLLED;
++              }
++
++              /* now update the replay counter */
++              if (!ipsec_updatereplaywindow(irs->ipsp, irs->replay)) {
++                      irs->ipsp->ips_errs.ips_replaywin_errs += 1;
++                      KLIPS_ERROR(debug_rcv & DB_RX_REPLAY,
++                                  "klips_debug:ipsec_rcv: "
++                                  "duplicate frame from %s, packet dropped\n",
++                                  irs->ipsaddr_txt);
++                      if(irs->stats) {
++                              irs->stats->rx_dropped++;
++                      }
++                      return IPSEC_RCV_REPLAYROLLED;
++              }
++              irs->auth_checked = 1;
++      }
++      return IPSEC_RCV_OK;
++}
++
++static enum ipsec_rcv_value
++ipsec_rcv_decrypt(struct ipsec_rcv_state *irs)
++{
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      if (irs->proto_funcs->rcv_decrypt) {
++              return (*irs->proto_funcs->rcv_decrypt)(irs);
++      }
++      return IPSEC_RCV_OK;
++}
++
++/*
++ * here we decide if there is more decapsulating required and
++ * change the next state appropriately
++ */
++static enum ipsec_rcv_value
++ipsec_rcv_decap_cont(struct ipsec_rcv_state *irs)
++{
++      struct sk_buff *skb;
++      struct iphdr *ipp;
++      struct ipsec_sa *ipsnext = NULL; /* next SA towards inside of packet */
++      enum ipsec_rcv_value rv;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      /*
++       * if we haven't checked the auth values yet, do it now.
++       * This is needed for the case where drivers do crypt+hash
++       * in one operation.
++       */
++      rv = ipsec_rcv_auth_chk(irs);
++      if (rv != IPSEC_RCV_OK)
++              return rv;
++
++      /*
++       *      Adjust pointers after decrypt
++       */
++      skb = irs->skb;
++      irs->len = skb->len;
++      ipp = irs->ipp = ip_hdr(skb);
++      irs->iphlen = ipp->ihl<<2;
++      skb_set_transport_header(skb, ipsec_skb_offset(skb, skb_network_header(skb) + irs->iphlen));
++      
++      /* zero any options that there might be */
++      memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++
++      if (debug_rcv)
++              ipsec_rcv_redodebug(irs);
++
++      /*
++       *      Discard the original ESP/AH header
++       */
++      ipp->protocol = irs->next_header;
++
++      ipp->check = 0; /* NOTE: this will be included in checksum */
++      ipp->check = ip_fast_csum((unsigned char *)ip_hdr(skb), irs->iphlen >> 2);
++
++      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                  "klips_debug:ipsec_rcv: "
++                  "after <%s%s%s>, SA:%s:\n",
++                  IPS_XFORM_NAME(irs->ipsp),
++                  irs->sa_len ? irs->sa : " (error)");
++      KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
++
++      skb->protocol = htons(ETH_P_IP);
++      skb->ip_summed = 0;
++
++      ipsnext = irs->ipsp->ips_next;
++      if(sysctl_ipsec_inbound_policy_check) {
++              if(ipsnext) {
++                      if(
++                              ipp->protocol != IPPROTO_AH
++                              && ipp->protocol != IPPROTO_ESP
++#ifdef CONFIG_KLIPS_IPCOMP
++                              && ipp->protocol != IPPROTO_COMP
++                              && (ipsnext->ips_said.proto != IPPROTO_COMP
++                                  || ipsnext->ips_next)
++#endif /* CONFIG_KLIPS_IPCOMP */
++                              && ipp->protocol != IPPROTO_IPIP
++                              && ipp->protocol != IPPROTO_ATT_HEARTBEAT  /* heartbeats to AT&T SIG/GIG */
++                              ) {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "packet with incomplete policy dropped, last successful SA:%s.\n",
++                                          irs->sa_len ? irs->sa : " (error)");
++                              if(irs->stats) {
++                                      irs->stats->rx_dropped++;
++                              }
++                              return IPSEC_RCV_FAILEDINBOUND;
++                      }
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, Another IPSEC header to process.\n",
++                                  irs->sa_len ? irs->sa : " (error)");
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "No ips_inext from this SA:%s.\n",
++                                  irs->sa_len ? irs->sa : " (error)");
++              }
++      }
++
++#ifdef CONFIG_KLIPS_IPCOMP
++      /* update ipcomp ratio counters, even if no ipcomp packet is present */
++      if (ipsnext
++          && ipsnext->ips_said.proto == IPPROTO_COMP
++          && ipp->protocol != IPPROTO_COMP) {
++              ipsnext->ips_comp_ratio_cbytes += ntohs(ipp->tot_len);
++              ipsnext->ips_comp_ratio_dbytes += ntohs(ipp->tot_len);
++      }
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++      irs->ipsp->ips_life.ipl_bytes.ipl_count += irs->len;
++      irs->ipsp->ips_life.ipl_bytes.ipl_last   = irs->len;
++
++      if(!irs->ipsp->ips_life.ipl_usetime.ipl_count) {
++              irs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
++      }
++      irs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
++      irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
++
++#ifdef CONFIG_NETFILTER
++      if(irs->proto == IPPROTO_ESP || irs->proto == IPPROTO_AH) {
++              skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
++                      | IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
++              KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                          "klips_debug:ipsec_rcv: "
++                          "%s SA sets skb->nfmark=0x%x.\n",
++                          irs->proto == IPPROTO_ESP ? "ESP" : "AH",
++                          (unsigned)skb->nfmark);
++      }
++#endif /* CONFIG_NETFILTER */
++
++      /* okay, acted on this SA, so free any previous SA, and record a new one */
++      if(irs->ipsp) {
++              struct ipsec_sa *newipsp = NULL;
++              newipsp = irs->ipsp->ips_next;
++              if(newipsp) {
++                      ipsec_sa_get(newipsp);
++              }
++              if(irs->lastipsp) {
++                      ipsec_sa_put(irs->lastipsp);
++              }
++              irs->lastipsp = irs->ipsp;
++              irs->ipsp=newipsp;
++      }
++
++      /* do we need to do more decapsulation */
++      if ((irs->ipp->protocol == IPPROTO_ESP ||
++                      irs->ipp->protocol == IPPROTO_AH ||
++#ifdef CONFIG_KLIPS_IPCOMP
++                      irs->ipp->protocol == IPPROTO_COMP ||
++#endif /* CONFIG_KLIPS_IPCOMP */
++                      0) && irs->ipsp != NULL) {
++              irs->next_state = IPSEC_RSM_AUTH_DECAP;
++      }
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_cleanup(struct ipsec_rcv_state *irs)
++{
++      struct sk_buff *skb;
++      struct iphdr *ipp;
++      struct ipsec_sa *ipsp = NULL;
++
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      /* set up for decap loop */
++      ipp  = irs->ipp;
++      ipsp = irs->ipsp;
++      skb = irs->skb;
++
++      /* if there is an IPCOMP, but we don't have an IPPROTO_COMP,
++       * then we can just skip it
++       */
++#ifdef CONFIG_KLIPS_IPCOMP
++      if(irs->ipsp && irs->ipsp->ips_said.proto == IPPROTO_COMP) {
++              struct ipsec_sa *newipsp = NULL;
++              newipsp = irs->ipsp->ips_next;
++              if(newipsp) {
++                      ipsec_sa_get(newipsp);
++              }
++              if(irs->lastipsp) {
++                      ipsec_sa_put(irs->lastipsp);
++              }
++              irs->lastipsp = irs->ipsp;
++              irs->ipsp=newipsp;
++      }
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      if ((irs->natt_type) && (ipp->protocol != IPPROTO_IPIP)) {
++        /**
++         * NAT-Traversal and Transport Mode:
++         *   we need to correct TCP/UDP checksum
++         *
++         * If we've got NAT-OA, we can fix checksum without recalculation.
++         */
++              __u32 natt_oa = ipsp->ips_natt_oa ?
++                      ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
++
++              if(natt_oa != 0) {
++                      /* reset source address to what it was before NAT */
++                      ipp->saddr = natt_oa;
++                      ipp->check = 0;
++                      ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
++                      KLIPS_PRINT(debug_rcv, "csum: %04x\n", ipp->check);
++              }
++      }
++#endif
++
++      /*
++       * the SA is still locked from the loop
++       */
++      if(irs->ipsp && irs->ipsp->ips_xformfuncs->protocol == IPPROTO_IPIP) {
++              enum ipsec_rcv_value decap_stat;
++
++              decap_stat = ipsec_rcv_decap_ipip(irs);
++              if(decap_stat != IPSEC_RCV_OK) {
++                      return decap_stat;
++              }
++      }
++  
++      if(irs->stats) {
++              irs->stats->rx_bytes += skb->len;
++      }
++
++      /*
++       * if we are supposed to return the packet directly to the transport
++       * layer, then dump it out correctly.
++       */
++      if(unlikely(!irs->lastipsp))
++              printk("%s,%d: %s lastipsp should never be NULL\n",
++                      __FILE__, __LINE__, __FUNCTION__);
++      if(irs->lastipsp->ips_transport_direct) {
++              KLIPS_PRINT(debug_rcv, "receiving packet as transport direct\n");
++              skb->ip_summed=CHECKSUM_UNNECESSARY;
++              /* STUFF */
++      }
++
++#ifdef HAVE_IPSEC_SAREF       
++      if(skb->sp) {
++              secpath_put(skb->sp);
++      }
++      skb->sp = secpath_dup(NULL);
++      skb->sp->ref = irs->lastipsp->ips_ref;
++#endif
++
++      /* release the dst that was attached, since we have likely
++       * changed the actual destination of the packet.
++       */
++      if(skb->dst) {
++              dst_release(skb->dst);
++              skb->dst = NULL;
++      }
++      skb->pkt_type = PACKET_HOST;
++      if(irs->hard_header_len &&
++         (skb_mac_header(skb) != (skb_network_header(skb) - irs->hard_header_len)) &&
++         (irs->hard_header_len <= skb_headroom(skb))) {
++              /* copy back original MAC header */
++              memmove(skb_network_header(skb) - irs->hard_header_len,
++                      skb_mac_header(skb), irs->hard_header_len);
++              skb_set_mac_header(skb, ipsec_skb_offset(skb, skb_network_header(skb) - irs->hard_header_len));
++      }
++      return IPSEC_RCV_OK;
++}
++
++
++static enum ipsec_rcv_value
++ipsec_rcv_complete(struct ipsec_rcv_state *irs)
++{
++      KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
++                      irs->state, irs->next_state);
++
++      /*
++       * make sure that data now starts at IP header, since we are going
++       * to pass this back to ip_input (aka netif_rx). Rules for what the
++       * pointers wind up a different for 2.6 vs 2.4, so we just fudge it here.
++       */
++#ifdef NET_26
++      irs->skb->data = skb_push(irs->skb, skb_transport_header(irs->skb) - skb_network_header(irs->skb));
++#else
++      irs->skb->data = skb_network_header(irs->skb);
++      {
++        struct iphdr *iph = ip_hdr(irs->skb);
++        int len = ntohs(iph->tot_len);
++        irs->skb->len  = len;
++      }
++#endif
++
++      ipsec_nf_reset(irs->skb);
++
++      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                  "klips_debug:ipsec_rcv: "
++                  "netif_rx(%s) called.\n", irs->skb->dev->name);
++      netif_rx(irs->skb);
++      irs->skb = NULL;
++      return IPSEC_RCV_OK;
++}
++
++
++
++/*
++ * ipsec_rsm is responsible for walking us through the state machine
++ * it is the only entry point into the receive processing and does
++ * appropriate checks and state changes for us.
++ */
++
++void
++ipsec_rsm(struct ipsec_rcv_state *irs)
++{
++      if (irs == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rsm: "
++                          "irs == NULL.\n");
++              return;
++      }
++
++      /*
++       * make sure nothing is removed from underneath us
++       */
++      spin_lock_bh(&tdb_lock);
++
++      /*
++       * if we have a valid said,  then we must check it here to ensure it
++       * hasn't gone away while we were waiting for a task to complete
++       */
++
++      if (irs->said.proto && ipsec_sa_getbyid(&irs->said) == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
++                          irs->sa_len ? irs->sa : " (error)");
++              if (irs->stats)
++                      irs->stats->rx_dropped++;
++
++              /* drop through and cleanup */
++              irs->state = IPSEC_RSM_DONE;
++      }
++
++      while (irs->state != IPSEC_RSM_DONE) {
++              int rc;
++
++              irs->next_state = rcv_state_table[irs->state].next_state;
++
++              rc = rcv_state_table[irs->state].action(irs);
++
++              if (rc == IPSEC_RCV_OK) {
++                      /* some functions change the next state, see the state table */
++                      irs->state = irs->next_state;
++              } else if (rc == IPSEC_RCV_PENDING) {
++                      /*
++                       * things are on hold until we return here in the next/new state
++                       * we check our SA is valid when we return
++                       */
++                      spin_unlock_bh(&tdb_lock);
++                      return;
++              } else {
++                      /* bad result, force state change to done */
++                      KLIPS_PRINT(debug_rcv,
++                                      "klips_debug:ipsec_rsm: "
++                                      "processing completed due to %s.\n",
++                                      ipsec_rcv_err(rc));
++                      irs->state = IPSEC_RSM_DONE;
++              }
++      }
++
++      /*
++       * all done with anything needing locks
++       */
++      spin_unlock_bh(&tdb_lock);
++
++      if (irs->lastipsp) {
++              ipsec_sa_put(irs->lastipsp);
++              irs->lastipsp=NULL;
++      }
++
++      if (irs->ipsp) {
++              ipsec_sa_put(irs->ipsp);
++              irs->ipsp=NULL;
++      }
++
++      if (irs->skb) {
++              ipsec_kfree_skb(irs->skb);
++              irs->skb = NULL;
++      }
++
++      ipsec_rcv_state_delete(irs);
++
++      KLIPS_DEC_USE; /* once less packet using the driver */
++}
++
++
++int
++ipsec_rcv(struct sk_buff *skb
++#ifndef PROTO_HANDLER_SINGLE_PARM
++        unsigned short xlen
++#endif /* PROTO_HANDLER_SINGLE_PARM */
++        )
++{
++      struct ipsec_rcv_state *irs = NULL;
++
++      /* Don't unlink in the middle of a turnaround */
++      KLIPS_INC_USE;
++
++      if (skb == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "NULL skb passed in.\n");
++              goto rcvleave;
++      }
++
++      if (skb->data == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "NULL skb->data passed in, packet is bogus, dropping.\n");
++              goto rcvleave;
++      }
++
++      irs = ipsec_rcv_state_new();
++      if (unlikely (! irs)) {
++              KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: "
++                              "failled to allocate a rcv state object\n");
++              goto rcvleave;
++      }
++
++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
++      {
++              /* NET_26 NAT-T is handled by seperate function */
++              struct sk_buff *nskb;
++              int udp_decap_ret = 0;
++  
++              nskb = ipsec_rcv_natt_decap(skb, irs, &udp_decap_ret);
++              if(nskb == NULL) {
++                      /* return with non-zero, because UDP.c code
++                       * need to send it upstream.
++                       */
++                      if(skb && udp_decap_ret == 0) {
++                              ipsec_kfree_skb(skb);
++                      }
++                      if (irs) {
++                              ipsec_rcv_state_delete(irs);
++                      }
++                      KLIPS_DEC_USE;
++                      return(udp_decap_ret);
++              }
++              skb = nskb;
++      }
++#endif /* NAT_T */
++
++      irs->skb = skb;
++
++      /*
++       * we hand off real early to the state machine because we just cannot
++       * know how much processing it is off-loading
++       */
++      ipsec_rsm(irs);
++
++      return(0);
++
++ rcvleave:
++      if (irs) {
++              ipsec_rcv_state_delete(irs);
++      }
++      if (skb) {
++              ipsec_kfree_skb(skb);
++      }
++      KLIPS_DEC_USE;
++      return(0);
++}
++
++
++#ifdef NET_26
++/*
++ * this entry point is not a protocol entry point, so the entry
++ * is a bit different.
++ *
++ * skb->iph->tot_len has been byte-swapped, and reduced by the size of
++ *              the IP header (and options).
++ * 
++ * skb->h.raw has been pulled up the ESP header.
++ *
++ * skb->iph->protocol = 50 IPPROTO_ESP;
++ *
++ */
++int klips26_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
++{
++      return klips26_rcv_encap(skb, udp_sk(sk)->encap_type);
++}
++
++int klips26_rcv_encap(struct sk_buff *skb, __u16 encap_type)
++{
++      struct ipsec_rcv_state *irs = NULL;
++
++      /* Don't unlink in the middle of a turnaround */
++      KLIPS_INC_USE;
++
++      if (skb == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "NULL skb passed in.\n");
++              goto rcvleave;
++      }
++
++      if (skb->data == NULL) {
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "NULL skb->data passed in, packet is bogus, dropping.\n");
++              goto rcvleave;
++      }
++
++      irs = ipsec_rcv_state_new();
++      if (unlikely (! irs)) {
++              KLIPS_PRINT(debug_rcv,
++                              "klips_debug:ipsec_rcv: "
++                              "failled to allocate a rcv state object\n");
++              goto rcvleave;
++      }
++
++      /* XXX fudge it so that all nat-t stuff comes from ipsec0    */
++      /*     eventually, the SA itself will determine which device
++       *     it comes from
++       */ 
++      {
++        skb->dev = ipsec_get_device(0);
++      }
++      irs->hard_header_len = skb->dev->hard_header_len;
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      switch(encap_type) {
++      case UDP_ENCAP_ESPINUDP:
++        irs->natt_type = ESPINUDP_WITH_NON_ESP;
++        break;
++        
++      case UDP_ENCAP_ESPINUDP_NON_IKE:
++        irs->natt_type = ESPINUDP_WITH_NON_IKE;
++        break;
++        
++      default:
++        if(printk_ratelimit()) {
++          printk(KERN_INFO "KLIPS received unknown UDP-ESP encap type %u\n",
++                 encap_type);
++        }
++        goto rcvleave;
++      }
++#endif /* NAT_T */
++
++      irs->skb = skb;
++
++      /*
++       * we hand off real early to the state machine because we just cannot
++       * know how much processing it is off-loading
++       */
++      ipsec_rsm(irs);
++
++      return(0);
++
++ rcvleave:
++      if (irs) {
++              ipsec_rcv_state_delete(irs);
++      }
++      if (skb) {
++              ipsec_kfree_skb(skb);
++      }
++      KLIPS_DEC_USE;
++      return(0);
++}
++#endif
++
++// ------------------------------------------------------------------------
++// this handles creating and managing state for recv path
++
++static spinlock_t irs_cache_lock = SPIN_LOCK_UNLOCKED;
++#ifdef HAVE_KMEM_CACHE_MACRO
++static struct kmem_cache *irs_cache_allocator = NULL;
++#else
++static kmem_cache_t *irs_cache_allocator = NULL;
++#endif
++static unsigned  irs_cache_allocated_count = 0;
++
++int ipsec_irs_cache_allocated_max = 1000;
++module_param(ipsec_irs_cache_allocated_max,int,0644);
++MODULE_PARM_DESC(ipsec_irs_cache_allocated_max,
++              "Maximum outstanding receive packets (before they are dropped)");
++
++int
++ipsec_rcv_state_cache_init (void)
++{
++        if (irs_cache_allocator)
++                return -EBUSY;
++
++        spin_lock_init(&irs_cache_lock);
++#ifdef HAVE_KMEM_CACHE_MACRO
++        /* irs_cache_allocator = KMEM_CACHE(ipsec_irs,0); */
++        irs_cache_allocator = kmem_cache_create ("ipsec_irs",
++                sizeof (struct ipsec_rcv_state), 0,
++                0, NULL);
++#else
++        irs_cache_allocator = kmem_cache_create ("ipsec_irs",
++                sizeof (struct ipsec_rcv_state), 0,
++                0, NULL, NULL);
++#endif
++        if (! irs_cache_allocator)
++                return -ENOMEM;
++
++        return 0;
++}
++
++void
++ipsec_rcv_state_cache_cleanup (void)
++{
++        if (unlikely (irs_cache_allocated_count))
++                printk ("ipsec: deleting ipsec_irs kmem_cache while in use\n");
++
++        if (irs_cache_allocator) {
++                kmem_cache_destroy (irs_cache_allocator);
++                irs_cache_allocator = NULL;
++        }
++        irs_cache_allocated_count = 0;
++}
++
++static struct ipsec_rcv_state *
++ipsec_rcv_state_new (void)
++{
++      struct ipsec_rcv_state *irs;
++
++        spin_lock_bh (&irs_cache_lock);
++
++      if (irs_cache_allocated_count >= ipsec_irs_cache_allocated_max) {
++              spin_unlock_bh (&irs_cache_lock);
++              KLIPS_PRINT(debug_rcv,
++                      "klips_debug:ipsec_rcv_state_new: "
++                      "exceeded maximum outstanding RX packet cnt %d\n",
++                      irs_cache_allocated_count);
++              return NULL;
++      }
++
++        irs = kmem_cache_alloc (irs_cache_allocator, GFP_ATOMIC);
++
++        if (likely (irs != NULL))
++                irs_cache_allocated_count++;
++
++        spin_unlock_bh (&irs_cache_lock);
++
++        if (unlikely (NULL == irs))
++                goto bail;
++
++        // initialize the object
++#if 1
++        memset((caddr_t)irs, 0, sizeof(*irs));
++#else
++        /* optimised to only clear the essentials */
++        irs->state = 0;
++        irs->next_state = 0;
++        irs->auth_checked = 0;
++        irs->stats = NULL;
++        irs->authenticator = NULL;
++        irs->said.proto = 0;
++
++        irs->hard_header_len = 0;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++        irs->natt_type = 0;
++        irs->natt_len = 0;
++#endif
++
++              irs->lastipsp = NULL;
++#endif
++
++bail:
++        return irs;
++}
++
++static void
++ipsec_rcv_state_delete (struct ipsec_rcv_state *irs)
++{
++        if (unlikely (! irs))
++                return;
++
++        spin_lock_bh (&irs_cache_lock);
++
++        irs_cache_allocated_count--;
++        kmem_cache_free (irs_cache_allocator, irs);
++
++        spin_unlock_bh (&irs_cache_lock);
++}
++
++/*
++ *
++ * Local Variables:
++ * c-set-style: linux
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_sa.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1575 @@
++/*
++ * Common routines for IPsec SA maintenance routines.
++ *
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001, 2002  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_sa.c,v 1.31 2005/11/11 04:38:56 paul Exp $
++ *
++ * This is the file formerly known as "ipsec_xform.h"
++ *
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/vmalloc.h> /* vmalloc() */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <openswan.h>
++#ifdef SPINLOCK
++#ifdef SPINLOCK_23
++#include <linux/spinlock.h> /* *lock* */
++#else /* SPINLOCK_23 */
++#include <asm/spinlock.h> /* *lock* */
++#endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "openswan/radij.h"
++
++#include "openswan/ipsec_stats.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_xform.h"
++
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_ipe4.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_ipip.h"
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipsec_ipcomp.h"
++#endif /* CONFIG_KLIPS_COMP */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++
++#include "ipsec_ocf.h"
++
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
++#ifdef SPINLOCK
++spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
++#else /* SPINLOCK */
++spinlock_t tdb_lock;
++#endif /* SPINLOCK */
++
++struct ipsec_sadb ipsec_sadb;
++
++/* the sub table must be narrower (or equal) in bits than the variable type
++   in the main table to count the number of unused entries in it. */
++typedef struct {
++      int testSizeOf_refSubTable :
++              ((sizeof(IPsecRefTableUnusedCount) * 8) < IPSEC_SA_REF_SUBTABLE_IDX_WIDTH ? -1 : 1);
++} dummy;
++
++
++/* The field where the saref will be hosted in the skb must be wide enough to
++   accomodate the information it needs to store. */
++typedef struct {
++      int testSizeOf_refField : 
++              (IPSEC_SA_REF_HOST_FIELD_WIDTH < IPSEC_SA_REF_TABLE_IDX_WIDTH ? -1 : 1 );
++} dummy2;
++
++
++#define IPS_HASH(said) (((said)->spi + (said)->dst.u.v4.sin_addr.s_addr + (said)->proto) % SADB_HASHMOD)
++
++int
++ipsec_SAref_recycle(void)
++{
++      int table, i;
++      int error = 0;
++      int entry;
++      int addone;
++
++      ipsec_sadb.refFreeListHead = IPSEC_SAREF_NULL;
++      ipsec_sadb.refFreeListTail = IPSEC_SAREF_NULL;
++
++      if(ipsec_sadb.refFreeListCont == IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_SAref_recycle: "
++                          "end of table reached, continuing at start..\n");
++              ipsec_sadb.refFreeListCont = IPSEC_SAREF_FIRST;
++      }
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_SAref_recycle: "
++                  "recycling, continuing from SAref=%d (0p%p), table=%d, entry=%d.\n",
++                  ipsec_sadb.refFreeListCont,
++                  (ipsec_sadb.refTable[IPsecSAref2table(ipsec_sadb.refFreeListCont)] != NULL) ? IPsecSAref2SA(ipsec_sadb.refFreeListCont) : NULL,
++                  IPsecSAref2table(ipsec_sadb.refFreeListCont),
++                  IPsecSAref2entry(ipsec_sadb.refFreeListCont));
++
++      /* add one additional table entry */
++      addone = 0;
++
++      ipsec_sadb.refFreeListHead = IPSEC_SAREF_FIRST;
++      for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
++              table = IPsecSAref2table(ipsec_sadb.refFreeListCont);
++              if(addone == 0 && ipsec_sadb.refTable[table] == NULL) {
++                      addone = 1;
++                      error = ipsec_SArefSubTable_alloc(table);
++                      if(error) {
++                              return error;
++                      }
++              }
++              for(entry = IPsecSAref2entry(ipsec_sadb.refFreeListCont);
++                  entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES;
++                  entry++) {
++                      if(ipsec_sadb.refTable[table]->entry[entry] == NULL) {
++                              ipsec_sadb.refFreeList[++ipsec_sadb.refFreeListTail] = IPsecSArefBuild(table, entry);
++                              if(ipsec_sadb.refFreeListTail == (IPSEC_SA_REF_FREELIST_NUM_ENTRIES - 1)) {
++                                      ipsec_sadb.refFreeListHead = IPSEC_SAREF_FIRST;
++                                      ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
++                                      KLIPS_PRINT(debug_xform,
++                                                  "klips_debug:ipsec_SAref_recycle: "
++                                                  "SArefFreeList refilled.\n");
++                                      return 0;
++                              }
++                      }
++              }
++              ipsec_sadb.refFreeListCont++;
++              ipsec_sadb.refFreeListTail=i;
++      }
++
++      if(ipsec_sadb.refFreeListTail == IPSEC_SAREF_NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_SAref_recycle: "
++                          "out of room in the SArefTable.\n");
++
++              return(-ENOSPC);
++      }
++
++      ipsec_sadb.refFreeListHead = IPSEC_SAREF_FIRST;
++      ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_SAref_recycle: "
++                  "SArefFreeList partly refilled to %d of %d.\n",
++                  ipsec_sadb.refFreeListTail,
++                  IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
++      return 0;
++}
++
++int
++ipsec_SArefSubTable_alloc(unsigned table)
++{
++      unsigned entry;
++      struct IPsecSArefSubTable* SArefsub;
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_SArefSubTable_alloc: "
++                  "allocating %lu bytes for table %u of %u.\n",
++                  (unsigned long) (IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *)),
++                  table,
++                  IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
++
++      /* allocate another sub-table */
++      SArefsub = vmalloc(IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *));
++      if(SArefsub == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_SArefSubTable_alloc: "
++                          "error allocating memory for table %u of %u!\n",
++                          table,
++                          IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
++              return -ENOMEM;
++      }
++
++      /* add this sub-table to the main table */
++      ipsec_sadb.refTable[table] = SArefsub;
++
++      /* initialise each element to NULL */
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_SArefSubTable_alloc: "
++                  "initialising %u elements (2 ^ %u) of table %u.\n",
++                  IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
++                  IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
++                  table);
++      for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
++              SArefsub->entry[entry] = NULL;
++      }
++
++      return 0;
++}
++
++int
++ipsec_saref_verify_slot(IPsecSAref_t ref)
++{
++      int ref_table=IPsecSAref2table(ref);
++      
++      if(ipsec_sadb.refTable[ref_table] == NULL) {
++              return ipsec_SArefSubTable_alloc(ref_table);
++      }
++      return 0;
++}
++
++int
++ipsec_saref_freelist_init(void)
++{
++      int i;
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_saref_freelist_init: "
++                  "initialising %u elements of FreeList.\n",
++                  IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
++
++      for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
++              ipsec_sadb.refFreeList[i] = IPSEC_SAREF_NULL;
++      }
++      ipsec_sadb.refFreeListHead = IPSEC_SAREF_NULL;
++      ipsec_sadb.refFreeListCont = IPSEC_SAREF_FIRST;
++      ipsec_sadb.refFreeListTail = IPSEC_SAREF_NULL;
++       
++      return 0;
++}
++
++int
++ipsec_sadb_init(void)
++{
++      int error = 0;
++      unsigned i;
++
++      for(i = 0; i < SADB_HASHMOD; i++) {
++              ipsec_sadb_hash[i] = NULL;
++      }
++      /* parts above are for the old style SADB hash table */
++      
++
++      /* initialise SA reference table */
++
++      /* initialise the main table */
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sadb_init: "
++                  "initialising main table of size %u (2 ^ %u).\n",
++                  IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
++                  IPSEC_SA_REF_MAINTABLE_IDX_WIDTH);
++      {
++              unsigned table;
++              for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
++                      ipsec_sadb.refTable[table] = NULL;
++              }
++      }
++
++      /* allocate the first sub-table */
++      error = ipsec_SArefSubTable_alloc(0);
++      if(error) {
++              return error;
++      }
++
++      error = ipsec_saref_freelist_init();
++      return error;
++}
++
++IPsecSAref_t
++ipsec_SAref_alloc(int*error) /* pass in error var by pointer */
++{
++      IPsecSAref_t SAref;
++
++      KLIPS_PRINT(debug_xform,
++                  "ipsec_SAref_alloc: "
++                  "SAref requested... head=%d, cont=%d, tail=%d, listsize=%d.\n",
++                  ipsec_sadb.refFreeListHead,
++                  ipsec_sadb.refFreeListCont,
++                  ipsec_sadb.refFreeListTail,
++                  IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
++
++      if(ipsec_sadb.refFreeListHead == IPSEC_SAREF_NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_SAref_alloc: "
++                          "FreeList empty, recycling...\n");
++              *error = ipsec_SAref_recycle();
++              if(*error) {
++                      return IPSEC_SAREF_NULL;
++              }
++      }
++
++      SAref = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead];
++      if(SAref == IPSEC_SAREF_NULL) {
++              KLIPS_ERROR(debug_xform,
++                          "ipsec_SAref_alloc: "
++                          "unexpected error, refFreeListHead = %d points to invalid entry.\n",
++                          ipsec_sadb.refFreeListHead);
++              *error = -ESPIPE;
++              return IPSEC_SAREF_NULL;
++      }
++
++      KLIPS_PRINT(debug_xform,
++                  "ipsec_SAref_alloc: "
++                  "allocating SAref=%d, table=%u, entry=%u of %u.\n",
++                  SAref,
++                  IPsecSAref2table(SAref),
++                  IPsecSAref2entry(SAref),
++                  IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES);
++      
++      ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead] = IPSEC_SAREF_NULL;
++      ipsec_sadb.refFreeListHead++;
++      if(ipsec_sadb.refFreeListHead > ipsec_sadb.refFreeListTail) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_SAref_alloc: "
++                          "last FreeList entry allocated, resetting list head to empty.\n");
++              ipsec_sadb.refFreeListHead = IPSEC_SAREF_NULL;
++      }
++
++      return SAref;
++}
++
++int
++ipsec_sa_print(struct ipsec_sa *ips)
++{
++        char sa[SATOT_BUF];
++      size_t sa_len;
++
++      printk(KERN_INFO "klips_debug:   SA:");
++      if(ips == NULL) {
++              printk("NULL\n");
++              return -ENOENT;
++      }
++      printk(" ref=%d", ips->ips_ref);
++      printk(" refcount=%d", atomic_read(&ips->ips_refcount));
++      if(ips->ips_hnext != NULL) {
++              printk(" hnext=0p%p", ips->ips_hnext);
++      }
++      if(ips->ips_next != NULL) {
++              printk(" next=0p%p", ips->ips_next);
++      }
++      sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
++      printk(" said=%s", sa_len ? sa : " (error)");
++      if(ips->ips_seq) {
++              printk(" seq=%u", ips->ips_seq);
++      }
++      if(ips->ips_pid) {
++              printk(" pid=%u", ips->ips_pid);
++      }
++      if(ips->ips_authalg) {
++              printk(" authalg=%u", ips->ips_authalg);
++      }
++      if(ips->ips_encalg) {
++              printk(" encalg=%u", ips->ips_encalg);
++      }
++      printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
++      if(ips->ips_replaywin) {
++              printk(" ooowin=%u", ips->ips_replaywin);
++      }
++      if(ips->ips_flags) {
++              printk(" flags=%u", ips->ips_flags);
++      }
++      if(ips->ips_addr_s) {
++              char buf[SUBNETTOA_BUF];
++              addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
++                      0, buf, sizeof(buf));
++              printk(" src=%s", buf);
++      }
++      if(ips->ips_addr_d) {
++              char buf[SUBNETTOA_BUF];
++              addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
++                      0, buf, sizeof(buf));
++              printk(" dst=%s", buf);
++      }
++      if(ips->ips_addr_p) {
++              char buf[SUBNETTOA_BUF];
++              addrtoa(((struct sockaddr_in*)(ips->ips_addr_p))->sin_addr,
++                      0, buf, sizeof(buf));
++              printk(" proxy=%s", buf);
++      }
++      if(ips->ips_key_bits_a) {
++              printk(" key_bits_a=%u", ips->ips_key_bits_a);
++      }
++      if(ips->ips_key_bits_e) {
++              printk(" key_bits_e=%u", ips->ips_key_bits_e);
++      }
++
++      printk("\n");
++      return 0;
++}
++
++struct ipsec_sa*
++ipsec_sa_alloc(int*error) /* pass in error var by pointer */
++{
++      struct ipsec_sa* ips;
++
++      if((ips = kmalloc(sizeof(*ips), GFP_ATOMIC) ) == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_alloc: "
++                          "memory allocation error\n");
++              *error = -ENOMEM;
++              return NULL;
++      }
++      memset((caddr_t)ips, 0, sizeof(*ips));
++
++      /* return with at least counter = 1 */
++      ipsec_sa_get(ips);
++
++      *error = 0;
++      return(ips);
++}
++
++void
++ipsec_sa_untern(struct ipsec_sa *ips)
++{
++      IPsecSAref_t ref = ips->ips_ref;
++      int error;
++
++      /* verify that we are removing correct item! */
++      error = ipsec_saref_verify_slot(ref);
++      if(error) {
++              return;
++      }
++
++      if(IPsecSAref2SA(ref) == ips) {
++              IPsecSAref2SA(ref) = NULL;
++              ipsec_sa_put(ips);
++      } else {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_untern: "
++                          "ref=%u -> %p but untern'ing %p\n", ref,
++                          IPsecSAref2SA(ref), ips);
++      }
++              
++}
++
++int
++ipsec_sa_intern(struct ipsec_sa *ips)
++{
++      int error;
++      IPsecSAref_t ref = ips->ips_ref;
++
++      if(ref == IPSEC_SAREF_NULL) {
++              ref = ipsec_SAref_alloc(&error); /* pass in error return by pointer */
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_intern: "
++                          "allocated ref=%u for sa %p\n", ref, ips);
++
++              if(ref == IPSEC_SAREF_NULL) {
++                      KLIPS_PRINT(debug_xform,
++                                  "ipsec_sa_intern: "
++                                  "SAref allocation error\n");
++                      return error;
++              }
++
++              ips->ips_ref = ref;
++      }
++
++      error = ipsec_saref_verify_slot(ref);
++      if(error) {
++              return error;
++      }
++
++      ipsec_sa_get(ips);
++      /*
++       * if there is an existing SA at this reference, then free it
++       * note, that nsa might == ips!. That's okay, we just incremented
++       * the reference count above.
++       */
++      {
++              struct ipsec_sa *nsa = IPsecSAref2SA(ref);
++              if(nsa) {
++                      ipsec_sa_put(nsa);
++              }
++      }
++
++      KLIPS_PRINT(debug_xform,
++                  "ipsec_sa_alloc: "
++                  "SAref[%d]=%p\n",
++                  ips->ips_ref, ips);
++      IPsecSAref2SA(ips->ips_ref) = ips;
++
++      /* return OK */
++      return 0;
++}
++
++
++struct ipsec_sa *
++ipsec_sa_getbyid(ip_said *said)
++{
++      int hashval;
++      struct ipsec_sa *ips;
++        char sa[SATOT_BUF];
++      size_t sa_len;
++
++      if(said == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_getbyid: "
++                          "null pointer passed in!\n");
++              return NULL;
++      }
++
++      hashval = IPS_HASH(said);
++      
++      sa_len = KLIPS_SATOT(debug_xform, said, 0, sa, sizeof(sa));
++      KLIPS_PRINT(debug_xform,
++                  "ipsec_sa_getbyid: "
++                  "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
++                  hashval,
++                  sa_len ? sa : " (error)");
++
++      if((ips = ipsec_sadb_hash[hashval]) == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_getbyid: "
++                          "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
++                          hashval,
++                          sa_len ? sa : " (error)");
++              return NULL;
++      }
++
++      for (; ips; ips = ips->ips_hnext) {
++              if ((ips->ips_said.spi == said->spi) &&
++                  (ips->ips_said.dst.u.v4.sin_addr.s_addr == said->dst.u.v4.sin_addr.s_addr) &&
++                  (ips->ips_said.proto == said->proto)) {
++                      ipsec_sa_get(ips);
++                      return ips;
++              }
++      }
++      
++      KLIPS_PRINT(debug_xform,
++                  "ipsec_sa_getbyid: "
++                  "no entry in linked list for hash=%d of SA:%s.\n",
++                  hashval,
++                  sa_len ? sa : " (error)");
++      return NULL;
++}
++
++struct ipsec_sa *
++ipsec_sa_getbyref(IPsecSAref_t ref)
++{
++      struct ipsec_sa *ips;
++      struct IPsecSArefSubTable *st = ipsec_sadb.refTable[IPsecSAref2table(ref)];
++
++      if(st == NULL) {
++              return NULL;
++      }
++
++      ips = st->entry[IPsecSAref2entry(ref)];
++      if(ips) {
++              ipsec_sa_get(ips);
++      }
++      return ips;
++}
++
++
++void
++__ipsec_sa_put(struct ipsec_sa *ips, const char *func, int line)
++{
++      if(ips == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_put: "
++                          "null pointer passed in!\n");
++              return;
++      }
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if(debug_xform) {
++              char sa[SATOT_BUF];
++              size_t sa_len;
++              sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
++
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_put: "
++                          "ipsec_sa %p SA:%s, ref:%d reference count (%d--) decremented by %s:%d.\n",
++                          ips,
++                          sa_len ? sa : " (error)",
++                          ips->ips_ref,
++                          atomic_read(&ips->ips_refcount),
++                          func, line);
++      }
++#endif
++
++      if(atomic_dec_and_test(&ips->ips_refcount)) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_put: freeing %p\n",
++                          ips);
++              /* it was zero */
++              ipsec_sa_wipe(ips);
++      }
++
++      return;
++}
++
++struct ipsec_sa *
++__ipsec_sa_get(struct ipsec_sa *ips, const char *func, int line)
++{
++        if (ips == NULL)
++                return NULL;
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if(debug_xform) {
++              char sa[SATOT_BUF];
++              size_t sa_len;
++        sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
++
++        KLIPS_PRINT(debug_xform,
++                    "ipsec_sa_get: "
++                    "ipsec_sa %p SA:%s, ref:%d reference count (%d++) incremented by %s:%d.\n",
++                    ips,
++                    sa_len ? sa : " (error)",
++                    ips->ips_ref,
++                    atomic_read(&ips->ips_refcount),
++                    func, line);
++      }
++#endif
++
++      atomic_inc(&ips->ips_refcount);
++
++#if 0
++      /*
++       * DAVIDM: if we include this code it means the SA is freed immediately
++       * on creation and then reused ! Not sure why it is here.
++      */
++
++      if(atomic_dec_and_test(&ips->ips_refcount)) {
++              KLIPS_PRINT(debug_xform,
++                          "ipsec_sa_get: freeing %p\n",
++                          ips);
++              /* it was zero */
++              ipsec_sa_wipe(ips);
++      }
++#endif
++
++        return ips;
++}
++
++/*
++  The ipsec_sa table better *NOT* be locked before it is handed in, or SMP locks will happen
++*/
++int
++ipsec_sa_add(struct ipsec_sa *ips)
++{
++      int error = 0;
++      unsigned int hashval;
++
++      ips = ipsec_sa_get(ips);
++
++      if(ips == NULL) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:ipsec_sa_add: "
++                          "null pointer passed in!\n");
++              return -ENODATA;
++      }
++      hashval = IPS_HASH(&ips->ips_said);
++
++      ipsec_sa_get(ips);
++      spin_lock_bh(&tdb_lock);
++      
++      ips->ips_hnext = ipsec_sadb_hash[hashval];
++      ipsec_sadb_hash[hashval] = ips;
++      
++      spin_unlock_bh(&tdb_lock);
++
++      return error;
++}
++
++/*
++ * remove it from the hash chain, decrementing hash count
++ */
++void ipsec_sa_rm(struct ipsec_sa *ips)
++{
++      unsigned int hashval;
++        char sa[SATOT_BUF];
++      size_t sa_len;
++
++
++      if(ips == NULL) return;
++
++
++      hashval = IPS_HASH(&ips->ips_said);
++
++      sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa, sizeof(sa));
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sa_del: "
++                  "unhashing SA:%s (ref=%u), hashval=%d.\n",
++                  sa_len ? sa : " (error)",
++                  ips->ips_ref,
++                  hashval);
++
++      if(ipsec_sadb_hash[hashval] == NULL) {
++              return;
++      }
++      
++      if (ips == ipsec_sadb_hash[hashval]) {
++              ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
++              ips->ips_hnext = NULL;
++              ipsec_sa_put(ips);
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_sa_del: "
++                          "successfully unhashed first ipsec_sa in chain.\n");
++              return;
++      } else {
++              struct ipsec_sa *ipstp;
++
++              for (ipstp = ipsec_sadb_hash[hashval];
++                   ipstp;
++                   ipstp = ipstp->ips_hnext) {
++                      if (ipstp->ips_hnext == ips) {
++                              ipstp->ips_hnext = ips->ips_hnext;
++                              ips->ips_hnext = NULL;
++                              ipsec_sa_put(ips);
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_sa_del: "
++                                          "successfully unhashed link in ipsec_sa chain.\n");
++                              return;
++                      }
++              }
++      }
++}
++      
++      
++#if 0
++/*
++ * The ipsec_sa table better be locked before it is handed in,
++ * or races might happen. 
++ *
++ * this routine assumes the SA has a refcount==0, and we free it.
++ * we also assume that the pointers are already cleaned up.
++ */
++static int
++ipsec_sa_del(struct ipsec_sa *ips)
++{
++      unsigned int hashval;
++      struct ipsec_sa *ipstp;
++        char sa[SATOT_BUF];
++      size_t sa_len;
++
++      if(ips == NULL) {
++              KLIPS_ERROR(debug_xform,
++                          "klips_error:ipsec_sa_del: "
++                          "null pointer passed in!\n");
++              return -ENODATA;
++      }
++
++      if(ips->ips_next) {
++              struct ipsec_sa *in = ips->ips_next;
++
++              ips->ips_next=NULL;
++              ipsec_sa_put(in);
++      }
++      
++      sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa, sizeof(sa));
++      hashval = IPS_HASH(&ips->ips_said);
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sa_del: "
++                  "deleting SA:%s (ref=%u), hashval=%d.\n",
++                  sa_len ? sa : " (error)",
++                  ips->ips_ref,
++                  hashval);
++
++      if(ipsec_sadb_hash[hashval] == NULL) {
++        /* if this is NULL, then we can be sure that the SA was never
++         * added to the SADB, so we just free it.
++         */
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_sa_del: "
++                          "no entries in ipsec_sa table for hash=%d (ref=%u) of SA:%s.\n",
++                          hashval,
++                          ips->ips_ref,
++                          sa_len ? sa : " (error)");
++              return -ENOENT;
++      }
++      
++      if (ips == ipsec_sadb_hash[hashval]) {
++              ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
++              ips->ips_hnext = NULL;
++
++              ipsec_sa_put(ips);
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_sa_del: "
++                          "successfully deleted first ipsec_sa in chain.\n");
++              return 0;
++      } else {
++              for (ipstp = ipsec_sadb_hash[hashval];
++                   ipstp;
++                   ipstp = ipstp->ips_hnext) {
++                      if (ipstp->ips_hnext == ips) {
++                              ipstp->ips_hnext = ips->ips_hnext;
++                              ips->ips_hnext = NULL;
++                              ipsec_sa_put(ips);
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_sa_del: "
++                                          "successfully deleted link in ipsec_sa chain.\n");
++                              return 0;
++                      }
++              }
++      }
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sa_del: "
++                  "no entries in linked list for hash=%d of SA:%s.\n",
++                  hashval,
++                  sa_len ? sa : " (error)");
++      return -ENOENT;
++}
++#endif
++
++int 
++ipsec_sadb_cleanup(__u8 proto)
++{
++      unsigned i;
++      int error = 0;
++      struct ipsec_sa *ips;
++      //struct ipsec_sa *ipsnext, **ipsprev;
++        //char sa[SATOT_BUF];
++      //size_t sa_len;
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sadb_cleanup: "
++                  "cleaning up proto=%d.\n",
++                  proto);
++
++      spin_lock_bh(&tdb_lock);
++
++      for (i = 0; i < SADB_HASHMOD; i++) {
++              ips = ipsec_sadb_hash[i];
++              
++              while(ips) {
++                      ipsec_sadb_hash[i]=ips->ips_hnext;
++                      ips->ips_hnext=NULL;
++                      ipsec_sa_put(ips);
++
++                      ips = ipsec_sadb_hash[i];
++              }
++      }
++
++//errlab:
++
++      spin_unlock_bh(&tdb_lock);
++
++
++#if IPSEC_SA_REF_CODE
++      /* clean up SA reference table */
++
++      /* go through the ref table and clean out all the SAs */
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sadb_cleanup: "
++                  "removing SAref entries and tables.");
++      {
++              unsigned table, entry;
++              for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
++                      KLIPS_PRINT(debug_xform,
++                                  "klips_debug:ipsec_sadb_cleanup: "
++                                  "cleaning SAref table=%u.\n",
++                                  table);
++                      if(ipsec_sadb.refTable[table] == NULL) {
++                              printk("\n");
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_sadb_cleanup: "
++                                          "cleaned %u used refTables.\n",
++                                          table);
++                              break;
++                      }
++                      for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
++                              if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
++                                      struct ipsec_sa *sa1 = ipsec_sadb.refTable[table]->entry[entry];
++                                      ipsec_sa_put(sa1);
++                                      ipsec_sadb.refTable[table]->entry[entry] = NULL;
++                              }
++                      }
++              }
++      }
++#endif /* IPSEC_SA_REF_CODE */
++
++      return(error);
++}
++
++int 
++ipsec_sadb_free(void)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sadb_free: "
++                  "freeing SArefTable memory.\n");
++
++      /* clean up SA reference table */
++
++      /* go through the ref table and clean out all the SAs if any are
++         left and free table memory */
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_sadb_free: "
++                  "removing SAref entries and tables.\n");
++      {
++              unsigned table, entry;
++              for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
++                      KLIPS_PRINT(debug_xform,
++                                  "klips_debug:ipsec_sadb_free: "
++                                  "removing SAref table=%u.\n",
++                                  table);
++                      if(ipsec_sadb.refTable[table] == NULL) {
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_sadb_free: "
++                                          "removed %u used refTables.\n",
++                                          table);
++                              break;
++                      }
++                      for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
++                              if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
++                                      struct ipsec_sa *sa1 = ipsec_sadb.refTable[table]->entry[entry];
++
++                                      BUG_ON(atomic_read(&sa1->ips_refcount) == 1);
++                                      ipsec_sa_put(sa1);
++                                      ipsec_sadb.refTable[table]->entry[entry] = NULL;
++                              }
++                      }
++                      vfree(ipsec_sadb.refTable[table]);
++                      ipsec_sadb.refTable[table] = NULL;
++              }
++      }
++
++      return(error);
++}
++
++int
++ipsec_sa_wipe(struct ipsec_sa *ips)
++{
++      if(ips == NULL) {
++              return -ENODATA;
++      }
++
++#if IPSEC_SA_REF_CODE
++      /* remove me from the SArefTable */
++      if(debug_xform) 
++      {
++              char sa[SATOT_BUF];
++              size_t sa_len;
++              struct IPsecSArefSubTable *subtable = NULL;
++
++              if(IPsecSAref2table(IPsecSA2SAref(ips))<IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES
++                 && ipsec_sadb.refTable != NULL) {
++                      subtable = ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))];
++              }
++
++              sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:ipsec_sa_wipe: "
++                          "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
++                          sa_len ? sa : " (error)",
++                          ips,
++                          ips->ips_ref,
++                          IPsecSAref2table(IPsecSA2SAref(ips)),
++                          subtable,
++                          subtable ? IPsecSAref2entry(IPsecSA2SAref(ips)) : 0);
++      }
++
++      if(ips->ips_ref != IPSEC_SAREF_NULL) {
++              struct IPsecSArefSubTable *subtable = NULL;
++              int ref_table=IPsecSAref2table(IPsecSA2SAref(ips));
++              int ref_entry=IPsecSAref2entry(IPsecSA2SAref(ips));
++
++              if(ref_table < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
++                      subtable = ipsec_sadb.refTable[ref_table];
++                      if(subtable!=NULL && subtable->entry[ref_entry] == ips) {
++                      
++                              subtable->entry[ref_entry] = NULL;
++                      }
++              }
++              ips->ips_ref = IPSEC_SAREF_NULL;
++      }
++#endif /* IPSEC_SA_REF_CODE */
++
++      /* paranoid clean up */
++      if(ips->ips_addr_s != NULL) {
++              memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
++              kfree(ips->ips_addr_s);
++      }
++      ips->ips_addr_s = NULL;
++
++      if(ips->ips_addr_d != NULL) {
++              memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
++              kfree(ips->ips_addr_d);
++      }
++      ips->ips_addr_d = NULL;
++
++      if(ips->ips_addr_p != NULL) {
++              memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
++              kfree(ips->ips_addr_p);
++      }
++      ips->ips_addr_p = NULL;
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      if(ips->ips_natt_oa) {
++              memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
++              kfree(ips->ips_natt_oa);
++      }
++      ips->ips_natt_oa = NULL;
++#endif
++
++      if(ips->ips_key_a != NULL) {
++              memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
++              kfree(ips->ips_key_a);
++      }
++      ips->ips_key_a = NULL;
++
++      if(ips->ips_key_e != NULL) {
++#ifdef CONFIG_KLIPS_ALG
++              if (ips->ips_alg_enc &&
++                  ips->ips_alg_enc->ixt_e_destroy_key)
++              {
++                      ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc, 
++                                                          ips->ips_key_e);
++              } else
++#endif
++              {
++                      memset((caddr_t)(ips->ips_key_e), 0, ips->ips_key_e_size);
++                      kfree(ips->ips_key_e);
++              }
++      }
++      ips->ips_key_e = NULL;
++
++      if(ips->ips_iv != NULL) {
++              memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
++              kfree(ips->ips_iv);
++      }
++      ips->ips_iv = NULL;
++
++#ifdef CONFIG_KLIPS_OCF
++      if (ips->ocf_in_use)
++              ipsec_ocf_sa_free(ips);
++#endif
++
++      if(ips->ips_ident_s.data != NULL) {
++              memset((caddr_t)(ips->ips_ident_s.data),
++                       0,
++                     ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
++              kfree(ips->ips_ident_s.data);
++        }
++      ips->ips_ident_s.data = NULL;
++      
++      if(ips->ips_ident_d.data != NULL) {
++              memset((caddr_t)(ips->ips_ident_d.data),
++                       0,
++                     ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
++              kfree(ips->ips_ident_d.data);
++        }
++      ips->ips_ident_d.data = NULL;
++
++#ifdef CONFIG_KLIPS_ALG
++      if (ips->ips_alg_enc||ips->ips_alg_auth) {
++              ipsec_alg_sa_wipe(ips);
++      }
++#endif
++      
++      BUG_ON(atomic_read(&ips->ips_refcount) != 0);
++
++      memset((caddr_t)ips, 0, sizeof(*ips));
++      kfree(ips);
++      ips = NULL;
++
++      return 0;
++}
++
++extern int sysctl_ipsec_debug_verbose;
++
++int ipsec_sa_init(struct ipsec_sa *ipsp)
++{
++        int error = 0;
++        char sa[SATOT_BUF];
++      size_t sa_len;
++      char ipaddr_txt[ADDRTOA_BUF];
++      char ipaddr2_txt[ADDRTOA_BUF];
++#if defined (CONFIG_KLIPS_AUTH_HMAC_MD5) || defined (CONFIG_KLIPS_AUTH_HMAC_SHA1)
++      unsigned char kb[AHMD596_BLKLEN];
++#endif
++#ifdef CONFIG_KLIPS_ALG
++      struct ipsec_alg_enc *ixt_e = NULL;
++      struct ipsec_alg_auth *ixt_a = NULL;
++        int i;
++#endif
++
++      if(ipsp == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "ipsec_sa_init: "
++                          "ipsp is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &ipsp->ips_said, 0, sa, sizeof(sa));
++
++        KLIPS_PRINT(debug_pfkey,
++                  "ipsec_sa_init: "
++                  "(pfkey defined) called for SA:%s\n",
++                  sa_len ? sa : " (error)");
++
++      KLIPS_PRINT(debug_pfkey,
++                  "ipsec_sa_init: "
++                  "calling init routine of %s%s%s\n",
++                  IPS_XFORM_NAME(ipsp));
++      
++      switch(ipsp->ips_said.proto) {
++#ifdef CONFIG_KLIPS_IPIP
++      case IPPROTO_IPIP: {
++              ipsp->ips_xformfuncs = ipip_xform_funcs;
++              addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr,
++                      0,
++                      ipaddr_txt, sizeof(ipaddr_txt));
++              addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
++                      0,
++                      ipaddr2_txt, sizeof(ipaddr_txt));
++              KLIPS_PRINT(debug_pfkey,
++                          "ipsec_sa_init: "
++                          "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n",
++                          ipaddr_txt,
++                          ipaddr2_txt);
++      }
++      break;
++#endif /* !CONFIG_KLIPS_IPIP */
++
++#ifdef CONFIG_KLIPS_AH
++      case IPPROTO_AH:
++
++#ifdef CONFIG_KLIPS_OCF
++              if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, 0))
++                  break;
++#endif
++
++              ipsp->ips_xformfuncs = ah_xform_funcs;
++              switch(ipsp->ips_authalg) {
++# ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              case AH_MD5: {
++                      unsigned char *akp;
++                      unsigned int aks;
++                      MD5_CTX *ictx;
++                      MD5_CTX *octx;
++                      
++                      if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "ipsec_sa_init: "
++                                          "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          ipsp->ips_key_bits_a, AHMD596_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      
++                      ipsp->ips_auth_bits = AHMD596_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = ipsp->ips_key_a;
++                      aks = ipsp->ips_key_a_size;
++                      
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                 "ipsec_sa_init: "
++                                 "allocating %lu bytes for md5_ctx.\n",
++                                 (unsigned long) sizeof(struct md5_ctx));
++                      if((ipsp->ips_key_a = (caddr_t)
++                          kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
++                              ipsp->ips_key_a = akp;
++                              SENDERR(ENOMEM);
++                      }
++                      ipsp->ips_key_a_size = sizeof(struct md5_ctx);
++
++                      for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
++                      osMD5Init(ictx);
++                      osMD5Update(ictx, kb, AHMD596_BLKLEN);
++
++                      for (i = 0; i < AHMD596_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
++                      osMD5Init(octx);
++                      osMD5Update(octx, kb, AHMD596_BLKLEN);
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
++                                  ((__u32*)ictx)[0],
++                                  ((__u32*)ictx)[1],
++                                  ((__u32*)ictx)[2],
++                                  ((__u32*)ictx)[3],
++                                  ((__u32*)octx)[0],
++                                  ((__u32*)octx)[1],
++                                  ((__u32*)octx)[2],
++                                  ((__u32*)octx)[3] );
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      
++                      /* zero key buffer -- paranoid */
++                      memset(akp, 0, aks);
++                      kfree(akp);
++              }
++              break;
++# endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++# ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              case AH_SHA: {
++                      unsigned char *akp;
++                      unsigned int aks;
++                      SHA1_CTX *ictx;
++                      SHA1_CTX *octx;
++                      
++                      if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "ipsec_sa_init: "
++                                          "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          ipsp->ips_key_bits_a, AHSHA196_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      
++                      ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = ipsp->ips_key_a;
++                      aks = ipsp->ips_key_a_size;
++                      
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "allocating %lu bytes for sha1_ctx.\n",
++                                  (unsigned long) sizeof(struct sha1_ctx));
++                      if((ipsp->ips_key_a = (caddr_t)
++                          kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
++                              ipsp->ips_key_a = akp;
++                              SENDERR(ENOMEM);
++                      }
++                      ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
++
++                      for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
++                      SHA1Init(ictx);
++                      SHA1Update(ictx, kb, AHSHA196_BLKLEN);
++
++                      for (i = 0; i < AHSHA196_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx);
++                      SHA1Init(octx);
++                      SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n", 
++                                  ((__u32*)ictx)[0],
++                                  ((__u32*)ictx)[1],
++                                  ((__u32*)ictx)[2],
++                                  ((__u32*)ictx)[3],
++                                  ((__u32*)octx)[0],
++                                  ((__u32*)octx)[1],
++                                  ((__u32*)octx)[2],
++                                  ((__u32*)octx)[3] );
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      /* zero key buffer -- paranoid */
++                      memset(akp, 0, aks);
++                      kfree(akp);
++              }
++              break;
++# endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "ipsec_sa_init: "
++                                  "authalg=%d support not available in the kernel",
++                                  ipsp->ips_authalg);
++                      SENDERR(EINVAL);
++              }
++      break;
++#endif /* CONFIG_KLIPS_AH */
++
++#ifdef CONFIG_KLIPS_ESP
++      case IPPROTO_ESP:
++              ipsp->ips_xformfuncs = esp_xform_funcs;
++      {
++#if defined (CONFIG_KLIPS_AUTH_HMAC_MD5) || defined (CONFIG_KLIPS_AUTH_HMAC_SHA1)
++              unsigned char *akp;
++              unsigned int aks;
++#endif
++
++#ifdef CONFIG_KLIPS_OCF
++              if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, ipsp->ips_encalg))
++                  break;
++#endif
++
++#ifdef CONFIG_KLIPS_ALG
++              ipsec_alg_sa_init(ipsp);
++              ixt_e=ipsp->ips_alg_enc;
++
++              if (ixt_e == NULL) {
++                      if(printk_ratelimit()) {
++                              printk(KERN_ERR
++                                     "ipsec_sa_init: "
++                                     "encalg=%d support not available in the kernel",
++                                     ipsp->ips_encalg);
++                      }
++                      SENDERR(ENOENT);
++              }
++
++              ipsp->ips_iv_size = ixt_e->ixt_common.ixt_support.ias_ivlen/8;
++
++              /* Create IV */
++              if (ipsp->ips_iv_size) {
++                      if((ipsp->ips_iv = (caddr_t)
++                          kmalloc(ipsp->ips_iv_size, GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      prng_bytes(&ipsec_prng,
++                                 (char *)ipsp->ips_iv,
++                                 ipsp->ips_iv_size);
++                      ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
++              }
++              
++              if ((error=ipsec_alg_enc_key_create(ipsp)) < 0)
++                      SENDERR(-error);
++
++              if ((ixt_a=ipsp->ips_alg_auth)) {
++                      if ((error=ipsec_alg_auth_key_create(ipsp)) < 0)
++                              SENDERR(-error);
++              } else  
++#endif /* CONFIG_KLIPS_ALG */
++              
++              switch(ipsp->ips_authalg) {
++# ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              case AH_MD5: {
++                      MD5_CTX *ictx;
++                      MD5_CTX *octx;
++
++                      if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "ipsec_sa_init: "
++                                          "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          ipsp->ips_key_bits_a,
++                                          AHMD596_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
++                                  ntohl(*(((__u32 *)(ipsp->ips_key_a))+0)),
++                                  ntohl(*(((__u32 *)(ipsp->ips_key_a))+1)),
++                                  ntohl(*(((__u32 *)(ipsp->ips_key_a))+2)),
++                                  ntohl(*(((__u32 *)(ipsp->ips_key_a))+3)));
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      ipsp->ips_auth_bits = AHMD596_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = ipsp->ips_key_a;
++                      aks = ipsp->ips_key_a_size;
++                      
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "allocating %lu bytes for md5_ctx.\n",
++                                  (unsigned long) sizeof(struct md5_ctx));
++                      if((ipsp->ips_key_a = (caddr_t)
++                          kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
++                              ipsp->ips_key_a = akp;
++                              SENDERR(ENOMEM);
++                      }
++                      ipsp->ips_key_a_size = sizeof(struct md5_ctx);
++
++                      for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
++                      osMD5Init(ictx);
++                      osMD5Update(ictx, kb, AHMD596_BLKLEN);
++
++                      for (i = 0; i < AHMD596_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
++                      osMD5Init(octx);
++                      osMD5Update(octx, kb, AHMD596_BLKLEN);
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
++                                  ((__u32*)ictx)[0],
++                                  ((__u32*)ictx)[1],
++                                  ((__u32*)ictx)[2],
++                                  ((__u32*)ictx)[3],
++                                  ((__u32*)octx)[0],
++                                  ((__u32*)octx)[1],
++                                  ((__u32*)octx)[2],
++                                  ((__u32*)octx)[3] );
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      /* paranoid */
++                      memset(akp, 0, aks);
++                      kfree(akp);
++                      break;
++              }
++# endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++# ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              case AH_SHA: {
++                      SHA1_CTX *ictx;
++                      SHA1_CTX *octx;
++
++                      if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "ipsec_sa_init: "
++                                          "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          ipsp->ips_key_bits_a,
++                                          AHSHA196_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
++                                  ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = ipsp->ips_key_a;
++                      aks = ipsp->ips_key_a_size;
++
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "allocating %lu bytes for sha1_ctx.\n",
++                                  (unsigned long) sizeof(struct sha1_ctx));
++                      if((ipsp->ips_key_a = (caddr_t)
++                          kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
++                              ipsp->ips_key_a = akp;
++                              SENDERR(ENOMEM);
++                      }
++                      ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
++
++                      for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
++                      SHA1Init(ictx);
++                      SHA1Update(ictx, kb, AHSHA196_BLKLEN);
++
++                      for (i = 0; i < AHSHA196_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &((struct sha1_ctx*)(ipsp->ips_key_a))->octx;
++                      SHA1Init(octx);
++                      SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                      
++#  if KLIPS_DIVULGE_HMAC_KEY
++                      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                  "ipsec_sa_init: "
++                                  "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
++                                  ((__u32*)ictx)[0],
++                                  ((__u32*)ictx)[1],
++                                  ((__u32*)ictx)[2],
++                                  ((__u32*)ictx)[3],
++                                  ((__u32*)octx)[0],
++                                  ((__u32*)octx)[1],
++                                  ((__u32*)octx)[2],
++                                  ((__u32*)octx)[3] );
++#  endif /* KLIPS_DIVULGE_HMAC_KEY */
++                      memset(akp, 0, aks);
++                      kfree(akp);
++                      break;
++              }
++# endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++              case AH_NONE:
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "ipsec_sa_init: "
++                                  "authalg=%d support not available in the kernel.\n",
++                                  ipsp->ips_authalg);
++                      SENDERR(EINVAL);
++              }
++      }
++                      break;
++#endif /* !CONFIG_KLIPS_ESP */
++#ifdef CONFIG_KLIPS_IPCOMP
++      case IPPROTO_COMP:
++              ipsp->ips_xformfuncs = ipcomp_xform_funcs;
++              ipsp->ips_comp_adapt_tries = 0;
++              ipsp->ips_comp_adapt_skip = 0;
++              ipsp->ips_comp_ratio_cbytes = 0;
++              ipsp->ips_comp_ratio_dbytes = 0;
++              break;
++#endif /* CONFIG_KLIPS_IPCOMP */
++      default:
++              printk(KERN_ERR "KLIPS sa initialization: "
++                     "proto=%d unknown.\n",
++                     ipsp->ips_said.proto);
++              SENDERR(EINVAL);
++      }
++      
++ errlab:
++      return(error);
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_sha1.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,177 @@
++/*
++ * RCSID $Id: ipsec_sha1.c,v 1.9 2004/04/06 02:49:26 mcr Exp $
++ */
++
++/*
++ * The rest of the code is derived from sha1.c by Steve Reid, which is
++ * public domain.
++ * Minor cosmetic changes to accomodate it in the Linux kernel by ji.
++ */
++
++#include <asm/byteorder.h>
++#include <linux/string.h>
++
++#include "openswan/ipsec_sha1.h"
++
++#if defined(rol)
++#undef rol
++#endif
++
++#define SHA1HANDSOFF
++
++#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
++
++/* blk0() and blk() perform the initial expand. */
++/* I got the idea of expanding during the round function from SSLeay */
++#ifdef __LITTLE_ENDIAN
++#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
++    |(rol(block->l[i],8)&0x00FF00FF))
++#else
++#define blk0(i) block->l[i]
++#endif
++#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
++    ^block->l[(i+2)&15]^block->l[i&15],1))
++
++/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
++#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
++#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
++#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
++#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
++#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
++
++
++/* Hash a single 512-bit block. This is the core of the algorithm. */
++
++void SHA1Transform(__u32 state[5], __u8 buffer[64])
++{
++__u32 a, b, c, d, e;
++typedef union {
++    unsigned char c[64];
++    __u32 l[16];
++} CHAR64LONG16;
++CHAR64LONG16* block;
++#ifdef SHA1HANDSOFF
++static unsigned char workspace[64];
++    block = (CHAR64LONG16*)workspace;
++    memcpy(block, buffer, 64);
++#else
++    block = (CHAR64LONG16*)buffer;
++#endif
++    /* Copy context->state[] to working vars */
++    a = state[0];
++    b = state[1];
++    c = state[2];
++    d = state[3];
++    e = state[4];
++    /* 4 rounds of 20 operations each. Loop unrolled. */
++    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
++    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
++    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
++    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
++    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
++    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
++    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
++    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
++    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
++    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
++    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
++    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
++    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
++    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
++    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
++    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
++    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
++    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
++    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
++    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
++    /* Add the working vars back into context.state[] */
++    state[0] += a;
++    state[1] += b;
++    state[2] += c;
++    state[3] += d;
++    state[4] += e;
++    /* Wipe variables */
++    a = b = c = d = e = 0;
++}
++
++
++/* SHA1Init - Initialize new context */
++
++void SHA1Init(void *vcontext)
++{
++    SHA1_CTX* context = vcontext;
++
++    /* SHA1 initialization constants */
++    context->state[0] = 0x67452301;
++    context->state[1] = 0xEFCDAB89;
++    context->state[2] = 0x98BADCFE;
++    context->state[3] = 0x10325476;
++    context->state[4] = 0xC3D2E1F0;
++    context->count[0] = context->count[1] = 0;
++}
++
++
++/* Run your data through this. */
++
++void SHA1Update(void *vcontext, unsigned char* data, __u32 len)
++{
++    SHA1_CTX* context = vcontext;
++    __u32 i, j;
++
++    j = context->count[0];
++    if ((context->count[0] += len << 3) < j)
++      context->count[1]++;
++    context->count[1] += (len>>29);
++    j = (j >> 3) & 63;
++    if ((j + len) > 63) {
++        memcpy(&context->buffer[j], data, (i = 64-j));
++        SHA1Transform(context->state, context->buffer);
++        for ( ; i + 63 < len; i += 64) {
++            SHA1Transform(context->state, &data[i]);
++        }
++        j = 0;
++    }
++    else i = 0;
++    memcpy(&context->buffer[j], &data[i], len - i);
++}
++
++
++/* Add padding and return the message digest. */
++
++void SHA1Final(unsigned char digest[20], void *vcontext)
++{
++  __u32 i, j;
++  unsigned char finalcount[8];
++  SHA1_CTX* context = vcontext;
++    
++    for (i = 0; i < 8; i++) {
++        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
++         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
++    }
++    SHA1Update(context, (unsigned char *)"\200", 1);
++    while ((context->count[0] & 504) != 448) {
++        SHA1Update(context, (unsigned char *)"\0", 1);
++    }
++    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
++    for (i = 0; i < 20; i++) {
++        digest[i] = (unsigned char)
++         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
++    }
++    /* Wipe variables */
++    i = j = 0;
++    memset(context->buffer, 0, 64);
++    memset(context->state, 0, 20);
++    memset(context->count, 0, 8);
++    memset(&finalcount, 0, 8);
++#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */
++    SHA1Transform(context->state, context->buffer);
++#endif
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_snprintf.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,121 @@
++/*
++ * @(#) ipsec_snprintf() function
++ *
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs <rgb@freeswan.org>
++ *                                 2001  Michael Richardson <mcr@freeswan.org>
++ * Copyright (C) 2005 Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * Split out from ipsec_proc.c.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_kversion.h"
++#include "openswan/ipsec_param.h"
++
++#include <net/ip.h>
++
++#include "openswan/radij.h"
++
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_stats.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_xmit.h"
++
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_kern24.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include "openswan/ipsec_proto.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++/* ipsec_snprintf: like snprintf except
++ * - size is signed and a negative value is treated as if it were 0
++ * - the returned result is never negative --
++ *   an error generates a "?" or null output (depending on space).
++ *   (Our callers are too lazy to check for an error return.)
++ * 
++ * @param buf String buffer
++ * @param size Size of the string
++ * @param fmt printf string
++ * @param ... Variables to be displayed in fmt
++ * @return int Return code
++ */
++int ipsec_snprintf(char *buf, ssize_t size, const char *fmt, ...)
++{
++       va_list args;
++       int i;
++       size_t possize = size < 0? 0 : size;
++       va_start(args, fmt);
++       i = vsnprintf(buf,possize,fmt,args);
++       va_end(args);
++       if (i < 0) {
++           /* create empty output in place of error */
++           i = 0;
++           if (size > 0) {
++               *buf = '\0';
++           }
++       }
++       return i;
++}
++
++
++void ipsec_dmp_block(char *s, caddr_t bb, int len)
++{
++      int i;
++      unsigned char *b = bb;
++  
++      printk(KERN_INFO "klips_dmp: "
++             "at %s, len=%d:\n", s, len);
++      
++      for(i = 0; i < len; i++ /*, c++*/) {
++              if(!(i % 16)) {
++                      printk(KERN_INFO
++                             "klips_debug:   @%03x:",
++                             i);
++              }
++              printk(" %02x", b[i]);
++              if(!((i + 1) % 16)) {
++                      printk("\n");
++              }
++      }
++      if(i % 16) {
++              printk("\n");
++      }
++}
++              
++/*
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_tunnel.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,2004 @@
++/*
++ * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Richard Guy Briggs.
++ * 
++ * OCF/receive state machine written by
++ * David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif        /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <net/tcp.h>
++#include <net/udp.h>
++#include <linux/skbuff.h>
++
++#include <linux/netdevice.h>   /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <net/arp.h>
++#include <linux/skbuff.h>
++
++#include <openswan.h>
++
++#ifdef NET_21
++# include <linux/in6.h>
++# define IS_MYADDR RTN_LOCAL
++# include <net/dst.h>
++# undef dev_kfree_skb
++# define dev_kfree_skb(a,b) kfree_skb(a)
++# define PHYSDEV_TYPE
++#endif /* NET_21 */
++
++#ifndef NETDEV_TX_BUSY
++# ifdef NETDEV_XMIT_CN
++#  define NETDEV_TX_BUSY NETDEV_XMIT_CN
++# else
++#  define NETDEV_TX_BUSY 1
++# endif
++#endif
++
++#include <net/icmp.h>         /* icmp_send() */
++#include <net/ip.h>
++#include <net/arp.h>
++#ifdef NETDEV_23
++# include <linux/netfilter_ipv4.h>
++#endif /* NETDEV_23 */
++
++#include <linux/if_arp.h>
++#include <net/arp.h>
++
++#include "openswan/ipsec_kversion.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_eroute.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_xmit.h"
++#include "openswan/ipsec_ipe4.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_kern24.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#include <linux/udp.h>
++#endif
++
++static __u32 zeroes[64];
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_open(struct net_device *dev)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      /*
++       * Can't open until attached.
++       */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_open: "
++                  "dev = %s, prv->dev = %s\n",
++                  dev->name, prv->dev?prv->dev->name:"NONE");
++
++      if (prv->dev == NULL)
++              return -ENODEV;
++      
++      KLIPS_INC_USE;
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_close(struct net_device *dev)
++{
++      KLIPS_DEC_USE;
++      return 0;
++}
++
++static inline int ipsec_tunnel_xmit2(struct sk_buff *skb)
++{
++
++#ifdef NETDEV_25      /* 2.6 kernels */
++      return dst_output(skb);
++#else
++      return ip_send(skb);
++#endif
++}
++
++enum ipsec_xmit_value
++ipsec_tunnel_strip_hard_header(struct ipsec_xmit_state *ixs)
++{
++      /* ixs->physdev->hard_header_len is unreliable and should not be used */
++        ixs->hard_header_len = (unsigned char *)(ixs->iph) - ixs->skb->data;
++
++      if(ixs->hard_header_len < 0) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_error:ipsec_xmit_strip_hard_header: "
++                          "Negative hard_header_len (%d)?!\n", ixs->hard_header_len);
++              ixs->stats->tx_dropped++;
++              return IPSEC_XMIT_BADHHLEN;
++      }
++
++      /* while ixs->physdev->hard_header_len is unreliable and
++       * should not be trusted, it accurate and required for ATM, GRE and
++       * some other interfaces to work. Thanks to Willy Tarreau 
++       * <willy@w.ods.org>.
++       */
++      if(ixs->hard_header_len == 0) { /* no hard header present */
++              ixs->hard_header_stripped = 1;
++              ixs->hard_header_len = ixs->physdev->hard_header_len;
++      }
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_tunnel & DB_TN_XMIT) {
++              int i;
++              char c;
++              
++              printk(KERN_INFO "klips_debug:ipsec_xmit_strip_hard_header: "
++                     ">>> skb->len=%ld hard_header_len:%d",
++                     (unsigned long int)ixs->skb->len, ixs->hard_header_len);
++              c = ' ';
++              for (i=0; i < ixs->hard_header_len; i++) {
++                      printk("%c%02x", c, ixs->skb->data[i]);
++                      c = ':';
++              }
++              printk(" \n");
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_strip_hard_header: "
++                  "Original head,tailroom: %d,%d\n",
++                  skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
++
++      return IPSEC_XMIT_OK;
++}
++
++enum ipsec_xmit_value
++ipsec_tunnel_SAlookup(struct ipsec_xmit_state *ixs)
++{
++      unsigned int bypass;
++
++      bypass = FALSE;
++
++      /*
++       * First things first -- look us up in the erouting tables.
++       */
++      ixs->matcher.sen_len = sizeof (struct sockaddr_encap);
++      ixs->matcher.sen_family = AF_ENCAP;
++      ixs->matcher.sen_type = SENT_IP4;
++      ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
++      ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
++      ixs->matcher.sen_proto = ixs->iph->protocol;
++      ipsec_extract_ports(ixs->iph, &ixs->matcher);
++
++      /*
++       * The spinlock is to prevent any other process from accessing or deleting
++       * the eroute while we are using and updating it.
++       */
++      spin_lock_bh(&eroute_lock);
++      
++      ixs->eroute = ipsec_findroute(&ixs->matcher);
++
++      if(ixs->iph->protocol == IPPROTO_UDP) {
++              struct udphdr *t = NULL;
++
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:udp port check: "
++                          "fragoff: %d len: %d>%ld \n",
++                          ntohs(ixs->iph->frag_off) & IP_OFFSET,
++                          (ixs->skb->len - ixs->hard_header_len),
++                            (unsigned long int) ((ixs->iph->ihl << 2) + sizeof(struct udphdr)));
++              
++              if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 &&
++                 ((ixs->skb->len - ixs->hard_header_len) >=
++                  ((ixs->iph->ihl << 2) + sizeof(struct udphdr))))
++              {
++                      t =((struct udphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2)));
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:udp port in packet: "
++                                  "port %d -> %d\n",
++                                  ntohs(t->source), ntohs(t->dest));
++              }
++
++              ixs->sport=0; ixs->dport=0;
++
++              if(ixs->skb->sk) {
++#ifdef NET_26
++#ifdef HAVE_INET_SK_SPORT
++                      ixs->sport = ntohs(inet_sk(ixs->skb->sk)->sport);
++                      ixs->dport = ntohs(inet_sk(ixs->skb->sk)->dport);
++#else
++                      struct udp_sock *us;
++                      
++                      us = (struct udp_sock *)ixs->skb->sk;
++
++                      ixs->sport = ntohs(us->inet.sport);
++                      ixs->dport = ntohs(us->inet.dport);
++#endif
++#else
++                      ixs->sport = ntohs(ixs->skb->sk->sport);
++                      ixs->dport = ntohs(ixs->skb->sk->dport);
++#endif
++
++              } 
++
++              if(t != NULL) {
++                      if(ixs->sport == 0) {
++                              ixs->sport = ntohs(t->source);
++                      }
++                      if(ixs->dport == 0) {
++                              ixs->dport = ntohs(t->dest);
++                      }
++              }
++      }
++
++      /*
++       * practically identical to above, but let's be careful about
++       * tcp vs udp headers
++       */
++      if(ixs->iph->protocol == IPPROTO_TCP) {
++              struct tcphdr *t = NULL;
++
++              if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 &&
++                 ((ixs->skb->len - ixs->hard_header_len) >=
++                  ((ixs->iph->ihl << 2) + sizeof(struct tcphdr)))) {
++                      t =((struct tcphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2)));
++              }
++
++              ixs->sport=0; ixs->dport=0;
++
++              if(ixs->skb->sk) {
++#ifdef NET_26
++#ifdef HAVE_INET_SK_SPORT
++                      ixs->sport = ntohs(inet_sk(ixs->skb->sk)->sport);
++                      ixs->dport = ntohs(inet_sk(ixs->skb->sk)->dport);
++#else
++                      struct tcp_tw_bucket *tw;
++                      tw = (struct tcp_tw_bucket *)ixs->skb->sk;
++                      ixs->sport = ntohs(tw->tw_sport);
++                      ixs->dport = ntohs(tw->tw_dport);
++#endif
++#else
++                      ixs->sport = ntohs(ixs->skb->sk->sport);
++                      ixs->dport = ntohs(ixs->skb->sk->dport);
++#endif
++              } 
++
++              if(t != NULL) {
++                      if(ixs->sport == 0) {
++                              ixs->sport = ntohs(t->source);
++                      }
++                      if(ixs->dport == 0) {
++                              ixs->dport = ntohs(t->dest);
++                      }
++              }
++      }
++      
++      /* default to a %drop eroute */
++      ixs->outgoing_said.proto = IPPROTO_INT;
++      ixs->outgoing_said.spi = htonl(SPI_DROP);
++      ixs->outgoing_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY;
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "klips_debug:ipsec_xmit_SAlookup: "
++                  "checking for local udp/500 IKE packet "
++                  "saddr=%x, er=0p%p, daddr=%x, er_dst=%x, proto=%d sport=%d dport=%d\n",
++                  ntohl((unsigned int)ixs->iph->saddr),
++                  ixs->eroute,
++                  ntohl((unsigned int)ixs->iph->daddr),
++                  ixs->eroute ? ntohl((unsigned int)ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr) : 0,
++                  ixs->iph->protocol,
++                  ixs->sport,
++                  ixs->dport); 
++
++      /*
++       * cheat for now...are we udp/500? If so, let it through
++       * without interference since it is most likely an IKE packet.
++       */
++
++      if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR
++          && (ixs->eroute==NULL
++              || ixs->iph->daddr == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr
++              || INADDR_ANY == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr)
++          && (ixs->iph->protocol == IPPROTO_UDP &&
++              (ixs->sport == 500 || ixs->sport == 4500))) {
++              /* Whatever the eroute, this is an IKE message 
++               * from us (i.e. not being forwarded).
++               * Furthermore, if there is a tunnel eroute,
++               * the destination is the peer for this eroute.
++               * So %pass the packet: modify the default %drop.
++               */
++
++              ixs->outgoing_said.spi = htonl(SPI_PASS);
++              if(!(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_SAlookup: "
++                                  "local UDP/500 (probably IKE) passthrough: base fragment, rest of fragments will probably get filtered.\n");
++              }
++              bypass = TRUE;
++      }
++
++#ifdef KLIPS_EXCEPT_DNS53
++      /*
++       *
++       * if we are udp/53 or tcp/53, also let it through a %trap or %hold,
++       * since it is DNS, but *also* follow the %trap.
++       * 
++       * we do not do this for tunnels, only %trap's and %hold's.
++       *
++       */
++
++      if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR
++          && (ixs->eroute==NULL
++              || ixs->iph->daddr == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr
++              || INADDR_ANY == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr)
++          && ((ixs->iph->protocol == IPPROTO_UDP
++               || ixs->iph->protocol == IPPROTO_TCP)
++              && ixs->dport == 53)) {
++              
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_SAlookup: "
++                          "possible DNS packet\n");
++
++              if(ixs->eroute)
++              {
++                      if(ixs->eroute->er_said.spi == htonl(SPI_TRAP)
++                         || ixs->eroute->er_said.spi == htonl(SPI_HOLD))
++                      {
++                              ixs->outgoing_said.spi = htonl(SPI_PASSTRAP);
++                              bypass = TRUE;
++                      }
++              }
++              else
++              {
++                      ixs->outgoing_said.spi = htonl(SPI_PASSTRAP);
++                      bypass = TRUE;
++              }
++                              
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_SAlookup: "
++                          "bypass = %d\n", bypass);
++
++              if(bypass
++                 && !(ixs->skb->sk)
++                 && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0))
++              {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_SAlookup: "
++                                  "local port 53 (probably DNS) passthrough:"
++                                  "base fragment, rest of fragments will "
++                                  "probably get filtered.\n");
++              }
++      }
++#endif
++
++      if (bypass==FALSE && ixs->eroute) {
++              ixs->eroute->er_count++;
++              ixs->eroute->er_lasttime = jiffies/HZ;
++              if(ixs->eroute->er_said.proto==IPPROTO_INT
++                 && ixs->eroute->er_said.spi==htonl(SPI_HOLD))
++              {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_SAlookup: "
++                                  "shunt SA of HOLD: skb stored in HOLD.\n");
++                      if(ixs->eroute->er_last != NULL) {
++                              kfree_skb(ixs->eroute->er_last);
++                      }
++                      ixs->eroute->er_last = ixs->skb;
++                      ixs->skb = NULL;
++                      ixs->stats->tx_dropped++;
++                      spin_unlock_bh(&eroute_lock);
++                      return IPSEC_XMIT_STOLEN;
++              }
++              ixs->outgoing_said = ixs->eroute->er_said;
++              ixs->eroute_pid = ixs->eroute->er_pid;
++
++              /* Copy of the ident for the TRAP/TRAPSUBNET eroutes */
++              if(ixs->outgoing_said.proto==IPPROTO_INT
++                 && (ixs->outgoing_said.spi==htonl(SPI_TRAP)
++                     || (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)))) {
++                      int len;
++                      
++                      ixs->ips.ips_ident_s.type = ixs->eroute->er_ident_s.type;
++                      ixs->ips.ips_ident_s.id = ixs->eroute->er_ident_s.id;
++                      ixs->ips.ips_ident_s.len = ixs->eroute->er_ident_s.len;
++                      if (ixs->ips.ips_ident_s.len)
++                      {
++                              len = ixs->ips.ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_xmit_SAlookup: "
++                                          "allocating %d bytes for ident_s shunt SA of HOLD: skb stored in HOLD.\n",
++                                          len);
++                              if ((ixs->ips.ips_ident_s.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
++                                      printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
++                                             "Failed, tried to allocate %d bytes for source ident.\n", 
++                                             len);
++                                      ixs->stats->tx_dropped++;
++                                      spin_unlock_bh(&eroute_lock);
++                                      return IPSEC_XMIT_ERRMEMALLOC;
++                              }
++                              memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len);
++                      }
++                      ixs->ips.ips_ident_d.type = ixs->eroute->er_ident_d.type;
++                      ixs->ips.ips_ident_d.id = ixs->eroute->er_ident_d.id;
++                      ixs->ips.ips_ident_d.len = ixs->eroute->er_ident_d.len;
++                      if (ixs->ips.ips_ident_d.len)
++                      {
++                              len = ixs->ips.ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_xmit_SAlookup: "
++                                          "allocating %d bytes for ident_d shunt SA of HOLD: skb stored in HOLD.\n",
++                                          len);
++                              if ((ixs->ips.ips_ident_d.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
++                                      printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
++                                             "Failed, tried to allocate %d bytes for dest ident.\n", 
++                                             len);
++                                      ixs->stats->tx_dropped++;
++                                      spin_unlock_bh(&eroute_lock);
++                                      return IPSEC_XMIT_ERRMEMALLOC;
++                              }
++                              memcpy(ixs->ips.ips_ident_d.data, ixs->eroute->er_ident_d.data, len);
++                      }
++              }
++      }
++
++      spin_unlock_bh(&eroute_lock);
++      return IPSEC_XMIT_OK;
++}
++
++
++enum ipsec_xmit_value
++ipsec_tunnel_restore_hard_header(struct ipsec_xmit_state*ixs)
++{
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_restore_hard_header: "
++                  "After recursive xforms -- head,tailroom: %d,%d\n",
++                  skb_headroom(ixs->skb),
++                  skb_tailroom(ixs->skb));
++
++      if(ixs->saved_header) {
++              if(skb_headroom(ixs->skb) < ixs->hard_header_len) {
++                      printk(KERN_WARNING
++                             "klips_error:ipsec_xmit_restore_hard_header: "
++                             "tried to skb_push hhlen=%d, %d available.  This should never happen, please report.\n",
++                             ixs->hard_header_len,
++                             skb_headroom(ixs->skb));
++                      ixs->stats->tx_errors++;
++                      return IPSEC_XMIT_PUSHPULLERR;
++
++              }
++              skb_push(ixs->skb, ixs->hard_header_len);
++              {
++                      int i;
++                      for (i = 0; i < ixs->hard_header_len; i++) {
++                              ixs->skb->data[i] = ixs->saved_header[i];
++                      }
++              }
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_restore_hard_header: "
++                  "With hard_header, final head,tailroom: %d,%d\n",
++                  skb_headroom(ixs->skb),
++                  skb_tailroom(ixs->skb));
++
++      return IPSEC_XMIT_OK;
++}
++
++
++/*
++ * when encap processing is complete it call this for us to continue
++ */
++
++void
++ipsec_tunnel_xsm_complete(
++      struct ipsec_xmit_state *ixs,
++      enum ipsec_xmit_value stat)
++{
++      if(stat != IPSEC_XMIT_OK) {
++              if(stat == IPSEC_XMIT_PASS) {
++                      goto bypass;
++              }
++              
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                              "klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
++                              stat);
++              goto cleanup;
++      }
++
++      ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
++      ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
++      ixs->matcher.sen_proto = ixs->iph->protocol;
++      ipsec_extract_ports(ixs->iph, &ixs->matcher);
++
++      spin_lock_bh(&eroute_lock);
++      ixs->eroute = ipsec_findroute(&ixs->matcher);
++      if(ixs->eroute) {
++              ixs->outgoing_said = ixs->eroute->er_said;
++              ixs->eroute_pid = ixs->eroute->er_pid;
++              ixs->eroute->er_count++;
++              ixs->eroute->er_lasttime = jiffies/HZ;
++      }
++      spin_unlock_bh(&eroute_lock);
++
++      KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
++                      /* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
++                      (ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
++                      ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
++                      ixs->eroute,
++                      "klips_debug:ipsec_tunnel_start_xmit: "
++                      "We are recursing here.\n");
++
++      if (/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
++                      (ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
++                      ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
++                      ixs->eroute) {
++              ipsec_xsm(ixs);
++              return;
++      }
++
++      stat = ipsec_nat_encap(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++      stat = ipsec_tunnel_restore_hard_header(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++bypass:
++      stat = ipsec_tunnel_send(ixs);
++
++cleanup:
++      ipsec_xmit_cleanup(ixs);
++      ipsec_xmit_state_delete(ixs);
++}
++
++
++/*
++ *    This function assumes it is being called from dev_queue_xmit()
++ *    and that skb is filled properly by that function.
++ */
++int
++ipsec_tunnel_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct ipsec_xmit_state *ixs = NULL;
++      enum ipsec_xmit_value stat;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "\n\nipsec_tunnel_start_xmit: STARTING");
++
++      stat = IPSEC_XMIT_ERRMEMALLOC;
++      ixs = ipsec_xmit_state_new();
++      if (! ixs) {
++              goto alloc_error;
++      }
++
++      ixs->dev = dev;
++      ixs->skb = skb;
++
++      stat = ipsec_xmit_sanity_check_dev(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++      stat = ipsec_xmit_sanity_check_skb(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++      stat = ipsec_tunnel_strip_hard_header(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              goto cleanup;
++      }
++
++      stat = ipsec_tunnel_SAlookup(ixs);
++      if(stat != IPSEC_XMIT_OK) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: SAlookup failed: %d\n",
++                          stat);
++              goto cleanup;
++      }
++      
++      ixs->innersrc = ixs->iph->saddr;
++
++      ixs->xsm_complete = ipsec_tunnel_xsm_complete;
++
++      ipsec_xsm(ixs);
++      return 0;
++
++ cleanup:
++      ipsec_xmit_cleanup(ixs);
++      ipsec_xmit_state_delete(ixs);
++alloc_error:
++      return 0;
++}
++
++DEBUG_NO_STATIC struct net_device_stats *
++ipsec_tunnel_get_stats(struct net_device *dev)
++{
++      return &(((struct ipsecpriv *)(dev->priv))->mystats);
++}
++
++/*
++ * Revectored calls.
++ * For each of these calls, a field exists in our private structure.
++ */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_hard_header(struct sk_buff *skb, struct net_device *dev,
++      unsigned short type, const void *daddr, const void *saddr, unsigned len)
++{
++      struct ipsecpriv *prv = dev->priv;
++      struct net_device *tmp;
++      int ret;
++      struct net_device_stats *stats; /* This device's statistics */
++      
++      if(skb == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "no skb...\n");
++              return -ENODATA;
++      }
++
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "no device...\n");
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_hard_header: "
++                  "skb->dev=%s dev=%s.\n",
++                  skb->dev ? skb->dev->name : "NULL",
++                  dev->name);
++      
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "no private space associated with dev=%s\n",
++                          dev->name ? dev->name : "NULL");
++              return -ENODEV;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      if(prv->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "no physical device associated with dev=%s\n",
++                          dev->name ? dev->name : "NULL");
++              stats->tx_dropped++;
++              return -ENODEV;
++      }
++
++      /* check if we have to send a IPv6 packet. It might be a Router
++         Solicitation, where the building of the packet happens in
++         reverse order:
++         1. ll hdr,
++         2. IPv6 hdr,
++         3. ICMPv6 hdr
++         -> skb->nh.raw is still uninitialized when this function is
++         called!!  If this is no IPv6 packet, we can print debugging
++         messages, otherwise we skip all debugging messages and just
++         build the ll header */
++      if(type != ETH_P_IPV6) {
++              /* execute this only, if we don't have to build the
++                 header for a IPv6 packet */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++              if(!prv->header_ops->create)
++#else
++              if(!prv->hard_header)
++#endif
++              {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                                  "klips_debug:ipsec_tunnel_hard_header: "
++                                  "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
++                                  saddr,
++                                  daddr,
++                                  len,
++                                  type,
++                                  dev->name);
++#ifdef NET_21
++                      KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
++                                      "ip=%08x->%08x\n",
++                                      (__u32)ntohl(ip_hdr(skb)->saddr),
++                                      (__u32)ntohl(ip_hdr(skb)->daddr) );
++#else /* NET_21 */
++                      KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
++                                      "ip=%08x->%08x\n",
++                                      (__u32)ntohl(skb->ip_hdr->saddr),
++                                      (__u32)ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++                      stats->tx_dropped++;
++                      return -ENODEV;
++              }
++              
++#define da ((struct net_device *)(prv->dev))->dev_addr
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
++                          saddr,
++                          daddr,
++                          len,
++                          type,
++                          dev->name,
++                          prv->dev->name,
++                          da[0], da[1], da[2], da[3], da[4], da[5]);
++#ifdef NET_21
++              KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08x->%08x\n",
++                          (__u32)ntohl(ip_hdr(skb)->saddr),
++                          (__u32)ntohl(ip_hdr(skb)->daddr) );
++#else /* NET_21 */
++              KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08x->%08x\n",
++                          (__u32)ntohl(skb->ip_hdr->saddr),
++                          (__u32)ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++      } else {
++              KLIPS_PRINT(debug_tunnel,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
++      }                                                                       
++      tmp = skb->dev;
++      skb->dev = prv->dev;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      ret = prv->header_ops->create(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
++#else
++      ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
++#endif
++      skb->dev = tmp;
++      return ret;
++}
++
++DEBUG_NO_STATIC int
++#ifdef NET_21
++ipsec_tunnel_rebuild_header(struct sk_buff *skb)
++#else /* NET_21 */
++ipsec_tunnel_rebuild_header(void *buff, struct net_device *dev,
++                      unsigned long raddr, struct sk_buff *skb)
++#endif /* NET_21 */
++{
++      struct ipsecpriv *prv = skb->dev->priv;
++      struct net_device *tmp;
++      int ret;
++      struct net_device_stats *stats; /* This device's statistics */
++      
++      if(skb->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_rebuild_header: "
++                          "no device...");
++              return -ENODEV;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_rebuild_header: "
++                          "no private space associated with dev=%s",
++                          skb->dev->name ? skb->dev->name : "NULL");
++              return -ENODEV;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      if(prv->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_rebuild_header: "
++                          "no physical device associated with dev=%s",
++                          skb->dev->name ? skb->dev->name : "NULL");
++              stats->tx_dropped++;
++              return -ENODEV;
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      if(!prv->header_ops->rebuild)
++#else
++      if(!prv->rebuild_header)
++#endif
++      {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_rebuild_header: "
++                          "physical device has been detached, packet dropped skb->dev=%s->NULL ",
++                          skb->dev->name);
++#ifdef NET_21
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08x->%08x\n",
++                          (__u32)ntohl(ip_hdr(skb)->saddr),
++                          (__u32)ntohl(ip_hdr(skb)->daddr) );
++#else /* NET_21 */
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08x->%08x\n",
++                          (__u32)ntohl(skb->ip_hdr->saddr),
++                          (__u32)ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++              stats->tx_dropped++;
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel: "
++                  "Revectored rebuild_header dev=%s->%s ",
++                  skb->dev->name, prv->dev->name);
++#ifdef NET_21
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "ip=%08x->%08x\n",
++                  (__u32)ntohl(ip_hdr(skb)->saddr),
++                  (__u32)ntohl(ip_hdr(skb)->daddr) );
++#else /* NET_21 */
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "ip=%08x->%08x\n",
++                  (__u32)ntohl(skb->ip_hdr->saddr),
++                  (__u32)ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++      tmp = skb->dev;
++      skb->dev = prv->dev;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      ret = prv->header_ops->rebuild(skb);
++#else
++#ifdef NET_21
++      ret = prv->rebuild_header(skb);
++#else /* NET_21 */
++      ret = prv->rebuild_header(buff, prv->dev, raddr, skb);
++#endif /* NET_21 */
++#endif
++      skb->dev = tmp;
++      return ret;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_set_mac_address(struct net_device *dev, void *addr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      struct net_device_stats *stats; /* This device's statistics */
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_set_mac_address: "
++                          "no device...");
++              return -ENODEV;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_set_mac_address: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return -ENODEV;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      if(prv->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_set_mac_address: "
++                          "no physical device associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              stats->tx_dropped++;
++              return -ENODEV;
++      }
++
++      if(!prv->set_mac_address) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_set_mac_address: "
++                          "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
++                          dev->name);
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_set_mac_address: "
++                  "Revectored dev=%s->%s addr=0p%p\n",
++                  dev->name, prv->dev->name, addr);
++      return prv->set_mac_address(prv->dev, addr);
++
++}
++
++#ifndef NET_21
++DEBUG_NO_STATIC void
++ipsec_tunnel_cache_bind(struct hh_cache **hhp, struct net_device *dev,
++                               unsigned short htype, __u32 daddr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      struct net_device_stats *stats; /* This device's statistics */
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_bind: "
++                          "no device...");
++              return;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_bind: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      if(prv->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_bind: "
++                          "no physical device associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              stats->tx_dropped++;
++              return;
++      }
++
++      if(!prv->header_cache_bind) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_bind: "
++                          "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
++                          dev->name);
++              stats->tx_dropped++;
++              return;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_cache_bind: "
++                  "Revectored \n");
++      prv->header_cache_bind(hhp, prv->dev, htype, daddr);
++      return;
++}
++#endif /* !NET_21 */
++
++
++DEBUG_NO_STATIC void
++ipsec_tunnel_cache_update(struct hh_cache *hh, const struct net_device *dev,
++                              const unsigned char *  haddr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      struct net_device_stats *stats; /* This device's statistics */
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_update: "
++                          "no device...");
++              return;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_update: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return;
++      }
++
++      stats = (struct net_device_stats *) &(prv->mystats);
++
++      if(prv->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_update: "
++                          "no physical device associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              stats->tx_dropped++;
++              return;
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      if(!prv->header_ops->cache_update)
++#else
++      if(!prv->header_cache_update)
++#endif
++      {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_cache_update: "
++                          "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
++                          dev->name);
++              return;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel: "
++                  "Revectored cache_update\n");
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      prv->header_ops->cache_update(hh, prv->dev, haddr);
++#else
++      prv->header_cache_update(hh, prv->dev, haddr);
++#endif
++      return;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++const struct header_ops ipsec_tunnel_header_ops = {
++      .create         = ipsec_tunnel_hard_header,
++      .rebuild        = ipsec_tunnel_rebuild_header,
++      .cache_update   = ipsec_tunnel_cache_update,
++};
++#endif
++
++#ifdef NET_21
++DEBUG_NO_STATIC int
++ipsec_tunnel_neigh_setup(struct neighbour *n)
++{
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_neigh_setup:\n");
++
++        if (n->nud_state == NUD_NONE) {
++                n->ops = &arp_broken_ops;
++                n->output = n->ops->output;
++        }
++        return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
++{
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_neigh_setup_dev: "
++                  "setting up %s\n",
++                  dev ? dev->name : "NULL");
++
++        if (p->tbl->family == AF_INET) {
++                p->neigh_setup = ipsec_tunnel_neigh_setup;
++                p->ucast_probes = 0;
++                p->mcast_probes = 0;
++        }
++        return 0;
++}
++#endif /* NET_21 */
++
++/*
++ * We call the attach routine to attach another device.
++ */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_attach(struct net_device *dev, struct net_device *physdev)
++{
++        int i;
++      struct ipsecpriv *prv = dev->priv;
++
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_attach: "
++                          "no device...");
++              return -ENODEV;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_attach: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return -ENODATA;
++      }
++
++      prv->dev = physdev;
++      prv->hard_start_xmit = physdev->hard_start_xmit;
++      prv->get_stats = physdev->get_stats;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      if (physdev->header_ops) {
++              prv->header_ops = physdev->header_ops;
++              dev->header_ops = &ipsec_tunnel_header_ops;
++      } else
++              dev->header_ops = NULL;
++#else
++      if (physdev->hard_header) {
++              prv->hard_header = physdev->hard_header;
++              dev->hard_header = &ipsec_tunnel_hard_header;
++      } else
++              dev->hard_header = NULL;
++      
++      if (physdev->rebuild_header) {
++              prv->rebuild_header = physdev->rebuild_header;
++              dev->rebuild_header = ipsec_tunnel_rebuild_header;
++      } else
++              dev->rebuild_header = NULL;
++      
++#ifndef NET_21
++      if (physdev->header_cache_bind) {
++              prv->header_cache_bind = physdev->header_cache_bind;
++              dev->header_cache_bind = ipsec_tunnel_cache_bind;
++      } else
++              dev->header_cache_bind = NULL;
++#endif /* !NET_21 */
++
++      if (physdev->header_cache_update) {
++              prv->header_cache_update = physdev->header_cache_update;
++              dev->header_cache_update = ipsec_tunnel_cache_update;
++      } else
++              dev->header_cache_update = NULL;
++#endif
++      
++      if (physdev->set_mac_address) {
++              prv->set_mac_address = physdev->set_mac_address;
++              dev->set_mac_address = ipsec_tunnel_set_mac_address;
++      } else
++              dev->set_mac_address = NULL;
++
++      dev->hard_header_len = physdev->hard_header_len;
++
++#ifdef NET_21
++/*    prv->neigh_setup        = physdev->neigh_setup; */
++      dev->neigh_setup        = ipsec_tunnel_neigh_setup_dev;
++#endif /* NET_21 */
++      dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
++      prv->mtu = physdev->mtu;
++
++#ifdef PHYSDEV_TYPE
++      dev->type = physdev->type; /* ARPHRD_TUNNEL; */
++#endif /*  PHYSDEV_TYPE */
++
++      dev->addr_len = physdev->addr_len;
++      for (i=0; i<dev->addr_len; i++) {
++              dev->dev_addr[i] = physdev->dev_addr[i];
++      }
++#ifdef CONFIG_KLIPS_DEBUG
++      if(debug_tunnel & DB_TN_INIT) {
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_attach: "
++                     "physical device %s being attached has HW address: %2x",
++                     physdev->name, physdev->dev_addr[0]);
++              for (i=1; i < physdev->addr_len; i++) {
++                      printk(":%02x", physdev->dev_addr[i]);
++              }
++              printk("\n");
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      return 0;
++}
++
++/*
++ * We call the detach routine to detach the ipsec tunnel from another device.
++ */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_detach(struct net_device *dev)
++{
++        int i;
++      struct ipsecpriv *prv = dev->priv;
++
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_detach: "
++                          "no device...");
++              return -ENODEV;
++      }
++
++      if(prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_detach: "
++                          "no private space associated with dev=%s",
++                          dev->name ? dev->name : "NULL");
++              return -ENODATA;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_detach: "
++                  "physical device %s being detached from virtual device %s\n",
++                  prv->dev ? prv->dev->name : "NULL",
++                  dev->name);
++
++      ipsec_dev_put(prv->dev);
++      prv->dev = NULL;
++      prv->hard_start_xmit = NULL;
++      prv->get_stats = NULL;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      prv->header_ops = NULL;
++#else
++      prv->hard_header = NULL;
++      prv->rebuild_header = NULL;
++      prv->header_cache_update = NULL;
++#ifndef NET_21
++      prv->header_cache_bind = NULL;
++#else
++/*    prv->neigh_setup        = NULL; */
++#endif
++#endif
++      prv->set_mac_address = NULL;
++      dev->hard_header_len = 0;
++
++#ifdef DETACH_AND_DOWN
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      dev->header_ops = NULL;
++#else
++      dev->hard_header = NULL;
++      dev->rebuild_header = NULL;
++      dev->header_cache_update = NULL;
++#ifndef NET_21
++      dev->header_cache_bind = NULL;
++#else
++      dev->neigh_setup        = NULL;
++#endif
++#endif
++      dev->set_mac_address = NULL;
++      dev->mtu = 0;
++#endif /* DETACH_AND_DOWN */
++      
++      prv->mtu = 0;
++      for (i=0; i<MAX_ADDR_LEN; i++) {
++              dev->dev_addr[i] = 0;
++      }
++      dev->addr_len = 0;
++#ifdef PHYSDEV_TYPE
++      dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */
++#endif /*  PHYSDEV_TYPE */
++      
++      return 0;
++}
++
++/*
++ * We call the clear routine to detach all ipsec tunnels from other devices.
++ */
++DEBUG_NO_STATIC int
++ipsec_tunnel_clear(void)
++{
++      int i;
++      struct net_device *ipsecdev = NULL, *prvdev;
++      struct ipsecpriv *prv;
++      int ret;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_clear: .\n");
++
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              ipsecdev = ipsecdevices[i];
++              if(ipsecdev != NULL) {
++                      if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
++                              prvdev = (struct net_device *)(prv->dev);
++                              if(prvdev) {
++                                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                                  "klips_debug:ipsec_tunnel_clear: "
++                                                  "physical device for device %s is %s\n",
++                                                  ipsecdev->name, prvdev->name);
++                                      if((ret = ipsec_tunnel_detach(ipsecdev))) {
++                                              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                                          "klips_debug:ipsec_tunnel_clear: "
++                                                          "error %d detatching device %s from device %s.\n",
++                                                          ret, ipsecdev->name, prvdev->name);
++                                              return ret;
++                                      }
++                              }
++                      }
++              }
++      }
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++      struct ipsectunnelconf *cf = (struct ipsectunnelconf *)&ifr->ifr_data;
++      struct ipsecpriv *prv = dev->priv;
++      struct net_device *them; /* physical device */
++#ifdef CONFIG_IP_ALIAS
++      char *colon;
++      char realphysname[IFNAMSIZ];
++#endif /* CONFIG_IP_ALIAS */
++      
++      if(dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_ioctl: "
++                          "device not supplied.\n");
++              return -ENODEV;
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_ioctl: "
++                  "tncfg service call #%d for dev=%s\n",
++                  cmd,
++                  dev->name ? dev->name : "NULL");
++      switch (cmd) {
++      /* attach a virtual ipsec? device to a physical device */
++      case IPSEC_SET_DEV:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_ioctl: "
++                          "calling ipsec_tunnel_attatch...\n");
++#ifdef CONFIG_IP_ALIAS
++              /* If this is an IP alias interface, get its real physical name */
++              strncpy(realphysname, cf->cf_name, IFNAMSIZ);
++              realphysname[IFNAMSIZ-1] = 0;
++              colon = strchr(realphysname, ':');
++              if (colon) *colon = 0;
++              them = ipsec_dev_get(realphysname);
++#else /* CONFIG_IP_ALIAS */
++              them = ipsec_dev_get(cf->cf_name);
++#endif /* CONFIG_IP_ALIAS */
++
++              if (them == NULL) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_tunnel_ioctl: "
++                                  "physical device %s requested is null\n",
++                                  cf->cf_name);
++                      return -ENXIO;
++              }
++              
++#if 0
++              if (them->flags & IFF_UP) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_tunnel_ioctl: "
++                                  "physical device %s requested is not up.\n",
++                                  cf->cf_name);
++                      ipsec_dev_put(them);
++                      return -ENXIO;
++              }
++#endif
++              
++              if (prv && prv->dev) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_tunnel_ioctl: "
++                                  "virtual device is already connected to %s.\n",
++                                  prv->dev->name ? prv->dev->name : "NULL");
++                      ipsec_dev_put(them);
++                      return -EBUSY;
++              }
++              return ipsec_tunnel_attach(dev, them);
++
++      case IPSEC_DEL_DEV:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_ioctl: "
++                          "calling ipsec_tunnel_detatch.\n");
++              if (! prv->dev) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_tunnel_ioctl: "
++                                  "physical device not connected.\n");
++                      return -ENODEV;
++              }
++              return ipsec_tunnel_detach(dev);
++             
++      case IPSEC_CLR_DEV:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_ioctl: "
++                          "calling ipsec_tunnel_clear.\n");
++              return ipsec_tunnel_clear();
++
++#ifdef HAVE_UDP_ENCAP_CONVERT
++      case IPSEC_UDP_ENCAP_CONVERT:
++      {
++              unsigned int *socknum =(unsigned int *)&ifr->ifr_data;
++              struct socket *sock;
++              int err, fput_needed;
++
++              /* that's a static function in socket.c 
++               * sock = sockfd_lookup_light(*socknum, &err, &fput_needed); */
++              sock = sockfd_lookup(*socknum, &err);
++              if (!sock)
++                      goto encap_out;
++
++              /* check that it's a UDP socket */
++              udp_sk(sk)->encap_type = UDP_ENCAP_ESPINUDP_NON_IKE;
++              udp_sk(sk)->encap_rcv  = klips26_udp_encap_rcv;
++
++              KLIPS_PRINT(debug_tunnel
++                          , "UDP socket: %u set to NON-IKE encap mode\n"
++                          , socknum);
++                     
++              err = 0;
++
++      encap_output:
++              fput_light(sock->file, fput_needed);
++      encap_out:
++              return err;
++#endif
++
++      default:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_ioctl: "
++                          "unknown command %d.\n",
++                          cmd);
++              return -EOPNOTSUPP;
++      }
++}
++
++struct net_device *ipsec_get_device(int inst)
++{
++  struct net_device *ipsec_dev;
++
++  ipsec_dev = NULL;
++
++  if(inst < IPSEC_NUM_IF) {
++    ipsec_dev = ipsecdevices[inst];
++  }
++
++  return ipsec_dev;
++}
++
++int
++ipsec_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
++{
++      struct net_device *dev = ptr;
++      struct net_device *ipsec_dev;
++      struct ipsecpriv *priv;
++      int i;
++
++      if (dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "dev=NULL for event type %ld.\n",
++                          event);
++              return(NOTIFY_DONE);
++      }
++
++      /* check for loopback devices */
++      if (dev && (dev->flags & IFF_LOOPBACK)) {
++              return(NOTIFY_DONE);
++      }
++
++      switch (event) {
++      case NETDEV_DOWN:
++              /* look very carefully at the scope of these compiler
++                 directives before changing anything... -- RGB */
++#ifdef NET_21
++      case NETDEV_UNREGISTER:
++              switch (event) {
++              case NETDEV_DOWN:
++#endif /* NET_21 */
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_device_event: "
++                                  "NETDEV_DOWN dev=%s flags=%x\n",
++                                  dev->name,
++                                  dev->flags);
++                      if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
++                              printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
++                                     dev->name);
++                      }
++#ifdef NET_21
++                      break;
++              case NETDEV_UNREGISTER:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "klips_debug:ipsec_device_event: "
++                                  "NETDEV_UNREGISTER dev=%s flags=%x\n",
++                                  dev->name,
++                                  dev->flags);
++                      break;
++              }
++#endif /* NET_21 */
++              
++              /* find the attached physical device and detach it. */
++              for(i = 0; i < IPSEC_NUM_IF; i++) {
++                      ipsec_dev = ipsecdevices[i];
++
++                      if(ipsec_dev) {
++                              priv = (struct ipsecpriv *)(ipsec_dev->priv);
++                              if(priv) {
++                                      ;
++                                      if(((struct net_device *)(priv->dev)) == dev) {
++                                              /* dev_close(ipsec_dev); */
++                                              /* return */ ipsec_tunnel_detach(ipsec_dev);
++                                              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                                          "klips_debug:ipsec_device_event: "
++                                                          "device '%s' has been detached.\n",
++                                                          ipsec_dev->name);
++                                              break;
++                                      }
++                              } else {
++                                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                                  "klips_debug:ipsec_device_event: "
++                                                  "device '%s' has no private data space!\n",
++                                                  ipsec_dev->name);
++                              }
++                      }
++              }
++              break;
++      case NETDEV_UP:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_UP dev=%s\n",
++                          dev->name);
++              break;
++#ifdef NET_21
++      case NETDEV_REBOOT:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_REBOOT dev=%s\n",
++                          dev->name);
++              break;
++      case NETDEV_CHANGE:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_CHANGE dev=%s flags=%x\n",
++                          dev->name,
++                          dev->flags);
++              break;
++      case NETDEV_REGISTER:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_REGISTER dev=%s\n",
++                          dev->name);
++              break;
++      case NETDEV_CHANGEMTU:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
++                          dev->name,
++                          dev->mtu);
++              break;
++      case NETDEV_CHANGEADDR:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_CHANGEADDR dev=%s\n",
++                          dev->name);
++              break;
++      case NETDEV_GOING_DOWN:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_GOING_DOWN dev=%s\n",
++                          dev->name);
++              break;
++      case NETDEV_CHANGENAME:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "NETDEV_CHANGENAME dev=%s\n",
++                          dev->name);
++              break;
++#endif /* NET_21 */
++      default:
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_device_event: "
++                          "event type %ld unrecognised for dev=%s\n",
++                          event,
++                          dev->name);
++              break;
++      }
++      return NOTIFY_DONE;
++}
++
++/*
++ *    Called when an ipsec tunnel device is initialized.
++ *    The ipsec tunnel device structure is passed to us.
++ */
++ 
++int
++ipsec_tunnel_init(struct net_device *dev)
++{
++      int i;
++
++      KLIPS_PRINT(debug_tunnel,
++                  "klips_debug:ipsec_tunnel_init: "
++                  "allocating %lu bytes initialising device: %s\n",
++                  (unsigned long) sizeof(struct ipsecpriv),
++                  dev->name ? dev->name : "NULL");
++
++      /* Add our tunnel functions to the device */
++      dev->open               = ipsec_tunnel_open;
++      dev->stop               = ipsec_tunnel_close;
++      dev->hard_start_xmit    = ipsec_tunnel_start_xmit;
++      dev->get_stats          = ipsec_tunnel_get_stats;
++
++      dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
++      if (dev->priv == NULL)
++              return -ENOMEM;
++      memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
++
++      for(i = 0; i < sizeof(zeroes); i++) {
++              ((__u8*)(zeroes))[i] = 0;
++      }
++      
++#ifndef NET_21
++      /* Initialize the tunnel device structure */
++      for (i = 0; i < DEV_NUMBUFFS; i++)
++              skb_queue_head_init(&dev->buffs[i]);
++#endif /* !NET_21 */
++
++      dev->set_multicast_list = NULL;
++      dev->do_ioctl           = ipsec_tunnel_ioctl;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++      dev->header_ops         = NULL;
++#else
++      dev->hard_header        = NULL;
++      dev->rebuild_header     = NULL;
++      dev->set_mac_address    = NULL;
++#ifndef NET_21
++      dev->header_cache_bind  = NULL;
++#endif /* !NET_21 */
++      dev->header_cache_update= NULL;
++#endif
++
++#ifdef NET_21
++/*    prv->neigh_setup        = NULL; */
++      dev->neigh_setup        = ipsec_tunnel_neigh_setup_dev;
++#endif /* NET_21 */
++      dev->hard_header_len    = 0;
++      dev->mtu                = 0;
++      dev->addr_len           = 0;
++      dev->type               = ARPHRD_VOID; /* ARPHRD_TUNNEL; */ /* ARPHRD_ETHER; */
++      dev->tx_queue_len       = 10;           /* Small queue */
++      memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN);       /* what if this is not attached to ethernet? */
++
++      /* New-style flags. */
++      dev->flags              = IFF_NOARP /* 0 */ /* Petr Novak */;
++
++      /* We're done.  Have I forgotten anything? */
++      return 0;
++}
++
++/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
++/*  Module specific interface (but it links with the rest of IPSEC)  */
++/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
++
++int
++ipsec_tunnel_probe(struct net_device *dev)
++{
++      ipsec_tunnel_init(dev); 
++      return 0;
++}
++
++#ifdef alloc_netdev
++static void ipsec_tunnel_netdev_setup(struct net_device *dev)
++{
++}
++#endif
++
++struct net_device *ipsecdevices[IPSEC_NUM_IFMAX];
++int ipsecdevices_max=-1;
++
++int
++ipsec_tunnel_createnum(int ifnum)
++{
++      char name[IFNAMSIZ];
++      struct net_device *dev_ipsec;
++      int vifentry;
++
++      if(ifnum > IPSEC_NUM_IFMAX) {
++              return -ENOENT;
++      }
++
++      if(ipsecdevices[ifnum]!=NULL) {
++              return -EEXIST;
++      }
++      
++      /* no identical device */
++      if(ifnum > ipsecdevices_max) {
++              ipsecdevices_max=ifnum;
++      }
++      vifentry = ifnum;
++      
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "creating and registering IPSEC_NUM_IF=%u device\n",
++                  ifnum);
++
++      sprintf(name, IPSEC_DEV_FORMAT, ifnum);
++#ifdef alloc_netdev
++      dev_ipsec = alloc_netdev(0, name, ipsec_tunnel_netdev_setup);
++#else
++      dev_ipsec = (struct net_device*)kmalloc(sizeof(struct net_device), GFP_KERNEL);
++#endif
++      if (dev_ipsec == NULL) {
++              printk(KERN_ERR "klips_debug:ipsec_tunnel_init_devices: "
++                     "failed to allocate memory for device %s, quitting device init.\n",
++                     name);
++              return -ENOMEM;
++      }
++#ifndef alloc_netdev
++      memset((caddr_t)dev_ipsec, 0, sizeof(struct net_device));
++#ifdef NETDEV_23
++      strncpy(dev_ipsec->name, name, sizeof(dev_ipsec->name));
++#else /* NETDEV_23 */
++      dev_ipsec->name = (char*)kmalloc(IFNAMSIZ, GFP_KERNEL);
++      if (dev_ipsec->name == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_init_devices: "
++                          "failed to allocate memory for device %s name, quitting device init.\n",
++                          name);
++              return -ENOMEM;
++      }
++      memset((caddr_t)dev_ipsec->name, 0, IFNAMSIZ);
++      strncpy(dev_ipsec->name, name, IFNAMSIZ);
++#endif /* NETDEV_23 */
++#ifdef PAUL_FIXME
++      dev_ipsec->next = NULL;
++#endif
++#endif /* alloc_netdev */
++      dev_ipsec->init = &ipsec_tunnel_probe;
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "registering device %s\n",
++                  dev_ipsec->name);
++      
++      /* reference and hold the device reference */
++      dev_hold(dev_ipsec);
++      ipsecdevices[vifentry]=dev_ipsec;
++      
++      if (register_netdev(dev_ipsec) != 0) {
++              KLIPS_PRINT(1 || debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_init_devices: "
++                          "registering device %s failed, quitting device init.\n",
++                          dev_ipsec->name);
++              return -EIO;
++      } else {
++              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                          "klips_debug:ipsec_tunnel_init_devices: "
++                          "registering device %s succeeded, continuing...\n",
++                          dev_ipsec->name);
++      }
++      return 0;
++}
++      
++
++int 
++ipsec_tunnel_init_devices(void)
++{
++      int i;
++      int error;
++      
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "creating and registering IPSEC_NUM_IF=%u devices, allocating %lu per device, IFNAMSIZ=%u.\n",
++                  IPSEC_NUM_IF,
++                  (unsigned long) (sizeof(struct net_device) + IFNAMSIZ),
++                  IFNAMSIZ);
++
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              error = ipsec_tunnel_createnum(i);
++              
++              if(error) break;
++      }
++      return 0;
++}
++
++int
++ipsec_tunnel_deletenum(int vifnum)
++{
++      struct net_device *dev_ipsec;
++      
++      if(vifnum > IPSEC_NUM_IFMAX) {
++              return -ENOENT;
++      }
++
++      dev_ipsec = ipsecdevices[vifnum];
++      if(dev_ipsec == NULL) {
++              return -ENOENT;
++      }
++
++      /* release reference */
++      ipsecdevices[vifnum]=NULL;
++      ipsec_dev_put(dev_ipsec);
++      
++      KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
++                  dev_ipsec->name,
++                  atomic_read(&dev_ipsec->refcnt));
++      unregister_netdev(dev_ipsec);
++      KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", dev_ipsec->name);
++#ifdef alloc_netdev
++      free_netdev(dev_ipsec);
++#else
++#ifndef NETDEV_23
++      kfree(dev_ipsec->name);
++      dev_ipsec->name=NULL;
++#endif /* !NETDEV_23 */
++      kfree(dev_ipsec->priv);
++#endif /* alloc_netdev */
++      dev_ipsec->priv=NULL;
++
++      return 0;
++}
++
++
++struct net_device *
++ipsec_tunnel_get_device(int vifnum)
++{
++      struct net_device *nd;
++      
++      if(vifnum < ipsecdevices_max) {
++              nd = ipsecdevices[vifnum];
++
++              if(nd) dev_hold(nd);
++              return nd;
++      } else {
++              return NULL;
++      }
++}
++
++/* void */
++int
++ipsec_tunnel_cleanup_devices(void)
++{
++      int error = 0;
++      int i;
++      struct net_device *dev_ipsec;
++      
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              dev_ipsec = ipsecdevices[i];
++              if(dev_ipsec == NULL) {
++                continue;
++              }
++
++              /* release reference */
++              ipsecdevices[i]=NULL;
++              ipsec_dev_put(dev_ipsec);
++
++              KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
++                          dev_ipsec->name,
++                          atomic_read(&dev_ipsec->refcnt));
++              unregister_netdev(dev_ipsec);
++              KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", dev_ipsec->name);
++#ifdef alloc_netdev
++              free_netdev(dev_ipsec);
++#else
++#ifndef NETDEV_23
++              kfree(dev_ipsec->name);
++              dev_ipsec->name=NULL;
++#endif /* !NETDEV_23 */
++              kfree(dev_ipsec->priv);
++#endif /* alloc_netdev */
++              dev_ipsec->priv=NULL;
++      }
++      return error;
++}
++
++// ------------------------------------------------------------------------
++// this handles creating and managing state for xmit path
++
++static spinlock_t ixs_cache_lock = SPIN_LOCK_UNLOCKED;
++#ifdef HAVE_KMEM_CACHE_MACRO
++static struct kmem_cache *ixs_cache_allocator = NULL;
++#else
++static kmem_cache_t *ixs_cache_allocator = NULL;
++#endif
++static unsigned  ixs_cache_allocated_count = 0;
++
++#if !defined(MODULE_PARM) && defined(module_param)
++/*
++ * As of 2.6.17 MODULE_PARM no longer exists, use module_param instead.
++ */
++#define       MODULE_PARM(a,b)        module_param(a,int,0644)
++#endif
++
++int ipsec_ixs_cache_allocated_count_max = 1000;
++MODULE_PARM(ipsec_ixs_cache_allocated_count_max, "i");
++MODULE_PARM_DESC(ipsec_ixs_cache_allocated_count_max,
++      "Maximum outstanding transmit packets");
++
++int
++ipsec_xmit_state_cache_init (void)
++{
++        if (ixs_cache_allocator)
++                return -EBUSY;
++
++        spin_lock_init(&ixs_cache_lock);
++#ifdef HAVE_KMEM_CACHE_MACRO
++      /* ixs_cache_allocator = KMEM_CACHE(ipsec_ixs,0); */
++        ixs_cache_allocator = kmem_cache_create ("ipsec_ixs",
++                sizeof (struct ipsec_xmit_state), 0,
++                0, NULL);
++#else
++        ixs_cache_allocator = kmem_cache_create ("ipsec_ixs",
++                sizeof (struct ipsec_xmit_state), 0,
++                0, NULL, NULL);
++#endif
++        if (! ixs_cache_allocator)
++                return -ENOMEM;
++
++        return 0;
++}
++
++void
++ipsec_xmit_state_cache_cleanup (void)
++{
++        if (unlikely (ixs_cache_allocated_count))
++                printk ("ipsec: deleting ipsec_ixs kmem_cache while in use\n");
++
++        if (ixs_cache_allocator) {
++                kmem_cache_destroy (ixs_cache_allocator);
++                ixs_cache_allocator = NULL;
++        }
++        ixs_cache_allocated_count = 0;
++}
++
++struct ipsec_xmit_state *
++ipsec_xmit_state_new (void)
++{
++      struct ipsec_xmit_state *ixs;
++
++        spin_lock_bh (&ixs_cache_lock);
++
++      if (ixs_cache_allocated_count >= ipsec_ixs_cache_allocated_count_max) {
++              spin_unlock_bh (&ixs_cache_lock);
++              KLIPS_PRINT(debug_tunnel,
++                      "klips_debug:ipsec_xmit_state_new: "
++                      "exceeded maximum outstanding TX packet cnt %d\n",
++                      ixs_cache_allocated_count);
++              return NULL;
++      }
++
++        ixs = kmem_cache_alloc (ixs_cache_allocator, GFP_ATOMIC);
++
++        if (likely (ixs != NULL))
++                ixs_cache_allocated_count++;
++
++        spin_unlock_bh (&ixs_cache_lock);
++
++        if (unlikely (NULL == ixs))
++                goto bail;
++
++        // initialize the object
++#if 1 /* optimised to only clear the required bits */
++              memset((caddr_t)ixs, 0, sizeof(*ixs));
++#else
++              ixs->pass = 0;
++              ixs->state = 0;
++              ixs->next_state = 0;
++              ixs->ipsp = NULL;
++              ixs->sa_len = 0;
++              ixs->stats = NULL;
++              ixs->ips.ips_ident_s.data = NULL;
++              ixs->ips.ips_ident_d.data = NULL;
++              ixs->outgoing_said.proto = 0;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++              ixs->natt_type = 0, ixs->natt_head = 0;
++              ixs->natt_sport = 0, ixs->natt_dport = 0;
++#endif
++              ixs->tot_headroom = 0;
++              ixs->tot_tailroom = 0;
++              ixs->eroute = NULL;
++              ixs->hard_header_stripped = 0;
++              ixs->hard_header_len = 0;
++              ixs->cur_mtu = 0; /* FIXME: can we do something better ? */
++
++              ixs->oskb = NULL;
++              ixs->saved_header = NULL;       /* saved copy of the hard header */
++              ixs->route = NULL;
++#endif /* memset */
++
++bail:
++        return ixs;
++}
++
++void
++ipsec_xmit_state_delete (struct ipsec_xmit_state *ixs)
++{
++        if (unlikely (! ixs))
++                return;
++
++        spin_lock_bh (&ixs_cache_lock);
++
++        ixs_cache_allocated_count--;
++        kmem_cache_free (ixs_cache_allocator, ixs);
++
++        spin_unlock_bh (&ixs_cache_lock);
++}
++
++/*
++ * Local Variables:
++ * c-style: linux
++ * End:
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_xform.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,69 @@
++/*
++ * Common routines for IPSEC transformations.
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: ipsec_xform.c,v 1.65 2005/04/29 05:10:22 mcr Exp $
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "freeswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#include <linux/random.h>     /* get_random_bytes() */
++#include <freeswan.h>
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++
++#include <net/ip.h>
++
++#include "freeswan/radij.h"
++#include "freeswan/ipsec_encap.h"
++#include "freeswan/ipsec_radij.h"
++#include "freeswan/ipsec_xform.h"
++#include "freeswan/ipsec_ipe4.h"
++#include "freeswan/ipsec_ah.h"
++#include "freeswan/ipsec_esp.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ipsec_xmit.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,2273 @@
++/*
++ * IPSEC Transmit code.
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998-2003   Richard Guy Briggs.
++ * Copyright (C) 2004-2005   Michael Richardson <mcr@xelerance.com>
++ * 
++ * OCF/receive state machine written by
++ * David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ */
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif        /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++
++#include <net/tcp.h>
++#include <net/udp.h>
++#include <linux/skbuff.h>
++
++#include <asm/uaccess.h>
++#include <asm/checksum.h>
++#include <openswan.h>
++#ifdef NET_21
++# define MSS_HACK_            /* experimental */
++# include <linux/in6.h>
++# include <net/dst.h>
++# define proto_priv cb
++#endif /* NET_21 */
++
++#include <net/icmp.h>         /* icmp_send() */
++#include <net/ip.h>
++#ifdef NETDEV_23
++# include <linux/netfilter_ipv4.h>
++#endif /* NETDEV_23 */
++
++#include <linux/if_arp.h>
++#ifdef MSS_HACK
++# include <net/tcp.h>         /* TCP options */
++#endif        /* MSS_HACK */
++
++#include "openswan/ipsec_kern24.h"
++#include "openswan/radij.h"
++#include "openswan/ipsec_life.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_eroute.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xmit.h"
++#include "openswan/ipsec_sa.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_ipe4.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#include "openswan/ipcomp.h"
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++#include "ipsec_ocf.h"
++
++
++/* 
++ * Stupid kernel API differences in APIs. Not only do some
++ * kernels not have ip_select_ident, but some have differing APIs,
++ * and SuSE has one with one parameter, but no way of checking to
++ * see what is really what.
++ */
++
++#ifdef SUSE_LINUX_2_4_19_IS_STUPID
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
++#else
++
++/* simplest case, nothing */
++#if !defined(IP_SELECT_IDENT)
++#define KLIPS_IP_SELECT_IDENT(iph, skb)  do { iph->id = htons(ip_id_count++); } while(0)
++#endif
++
++/* kernels > 2.3.37-ish */
++#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
++#endif
++
++/* kernels > 2.4.2 */
++#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
++#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
++#endif
++
++#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
++
++
++
++#if defined(CONFIG_KLIPS_AH)
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++static __u32 zeroes[64];
++#endif
++#endif
++
++int ipsec_xmit_trap_count = 0;
++int ipsec_xmit_trap_sendcount = 0;
++
++#ifdef CONFIG_KLIPS_DEBUG
++#define dmp(_x,_y,_z) if(debug_xmit && sysctl_ipsec_debug_verbose) ipsec_dmp_block(_x,_y,_z)
++#else /* CONFIG_KLIPS_DEBUG */
++#define dmp(_x, _y, _z) 
++#endif /* CONFIG_KLIPS_DEBUG */
++
++
++#if !defined(SKB_COPY_EXPAND) || defined(KLIPS_UNIT_TESTS)
++/*
++ *    This is mostly skbuff.c:skb_copy().
++ */
++struct sk_buff *
++skb_copy_expand(const struct sk_buff *skb, int headroom,
++              int tailroom, int priority)
++{
++      struct sk_buff *n;
++      unsigned long offset;
++
++      /*
++       *      Do sanity checking
++       */
++      if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) {
++              printk(KERN_WARNING
++                     "klips_error:skb_copy_expand: "
++                     "Illegal negative head,tailroom %d,%d\n",
++                     headroom,
++                     tailroom);
++              return NULL;
++      }
++      /*
++       *      Allocate the copy buffer
++       */
++       
++#ifndef NET_21
++      IS_SKB(skb);
++#endif /* !NET_21 */
++
++
++      n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority);
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:skb_copy_expand: "
++                  "allocating %d bytes, head=0p%p data=0p%p tail=0p%p end=0p%p end-head=%d tail-data=%d\n",
++                  skb->end - skb->head + headroom + tailroom,
++                  skb->head,
++                  skb->data,
++                  skb->tail,
++                  skb->end,
++                  skb->end - skb->head,
++                  skb->tail - skb->data);
++
++      if(n==NULL)
++              return NULL;
++
++      /*
++       *      Shift between the two data areas in bytes
++       */
++       
++      /* Set the data pointer */
++      skb_reserve(n,skb->data-skb->head+headroom);
++      /* Set the tail pointer and length */
++      if(skb_tailroom(n) < skb->len) {
++              printk(KERN_WARNING "klips_error:skb_copy_expand: "
++                     "tried to skb_put %ld, %d available.  This should never happen, please report.\n",
++                     (unsigned long int)skb->len,
++                     skb_tailroom(n));
++              ipsec_kfree_skb(n);
++              return NULL;
++      }
++      skb_put(n,skb->len);
++
++      offset=n->head + headroom - skb->head;
++
++      /* Copy the bytes */
++      memcpy(n->head + headroom, skb->head,skb->end-skb->head);
++#ifdef NET_21
++      n->csum=skb->csum;
++      n->priority=skb->priority;
++      n->dst=dst_clone(skb->dst);
++      if(skb->nh.raw)
++              n->nh.raw=skb->nh.raw+offset;
++#ifndef NETDEV_23
++      n->is_clone=0;
++#endif /* NETDEV_23 */
++      atomic_set(&n->users, 1);
++      n->destructor = NULL;
++#ifdef HAVE_SOCK_SECURITY
++      n->security=skb->security;
++#endif
++#else /* NET_21 */
++      n->link3=NULL;
++      n->when=skb->when;
++      if(skb->ip_hdr)
++              n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
++      n->saddr=skb->saddr;
++      n->daddr=skb->daddr;
++      n->raddr=skb->raddr;
++      n->seq=skb->seq;
++      n->end_seq=skb->end_seq;
++      n->ack_seq=skb->ack_seq;
++      n->acked=skb->acked;
++      n->free=1;
++      n->arp=skb->arp;
++      n->tries=0;
++      n->lock=0;
++      n->users=0;
++#endif /* NET_21 */
++      n->protocol=skb->protocol;
++      n->list=NULL;
++      n->sk=NULL;
++      n->dev=skb->dev;
++      if(skb->h.raw)
++              n->h.raw=skb->h.raw+offset;
++      if(skb->mac.raw) 
++              n->mac.raw=skb->mac.raw+offset;
++      memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
++#ifndef NETDEV_23
++      n->used=skb->used;
++#endif /* !NETDEV_23 */
++      n->pkt_type=skb->pkt_type;
++      n->stamp=skb->stamp;
++      
++#ifndef NET_21
++      IS_SKB(n);
++#endif /* !NET_21 */
++      return n;
++}
++#endif /* !SKB_COPY_EXPAND */
++
++#ifdef CONFIG_KLIPS_DEBUG
++void
++ipsec_print_ip(struct iphdr *ip)
++{
++      char buf[ADDRTOA_BUF];
++
++      printk(KERN_INFO "klips_debug:   IP:");
++      printk(" ihl:%d", ip->ihl << 2);
++      printk(" ver:%d", ip->version);
++      printk(" tos:%d", ip->tos);
++      printk(" tlen:%d", ntohs(ip->tot_len));
++      printk(" id:%d", ntohs(ip->id));
++      printk(" %s%s%sfrag_off:%d",
++               ip->frag_off & __constant_htons(IP_CE) ? "CE " : "",
++               ip->frag_off & __constant_htons(IP_DF) ? "DF " : "",
++               ip->frag_off & __constant_htons(IP_MF) ? "MF " : "",
++               (ntohs(ip->frag_off) & IP_OFFSET) << 3);
++      printk(" ttl:%d", ip->ttl);
++      printk(" proto:%d", ip->protocol);
++      if(ip->protocol == IPPROTO_UDP)
++              printk(" (UDP)");
++      if(ip->protocol == IPPROTO_TCP)
++              printk(" (TCP)");
++      if(ip->protocol == IPPROTO_ICMP)
++              printk(" (ICMP)");
++      if(ip->protocol == IPPROTO_ESP)
++              printk(" (ESP)");
++      if(ip->protocol == IPPROTO_AH)
++              printk(" (AH)");
++      if(ip->protocol == IPPROTO_COMP)
++              printk(" (COMP)");
++      printk(" chk:%d", ntohs(ip->check));
++      addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
++      printk(" saddr:%s", buf);
++      if(ip->protocol == IPPROTO_UDP)
++              printk(":%d",
++                     ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
++      if(ip->protocol == IPPROTO_TCP)
++              printk(":%d",
++                     ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
++      addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
++      printk(" daddr:%s", buf);
++      if(ip->protocol == IPPROTO_UDP)
++              printk(":%d",
++                     ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
++      if(ip->protocol == IPPROTO_TCP)
++              printk(":%d",
++                     ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
++      if(ip->protocol == IPPROTO_ICMP)
++              printk(" type:code=%d:%d",
++                     ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type,
++                     ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code);
++      printk("\n");
++
++      if(sysctl_ipsec_debug_verbose) {
++              __u8 *c;
++              int len = ntohs(ip->tot_len) - ip->ihl*4;
++              
++              c = ((__u8*)ip) + ip->ihl*4;
++              ipsec_dmp_block("ip_print", c, len);
++      }
++}
++#endif /* CONFIG_KLIPS_DEBUG */
++
++#ifdef MSS_HACK
++/*
++ * Issues:
++ *  1) Fragments arriving in the tunnel should probably be rejected.
++ *  2) How does this affect syncookies, mss_cache, dst cache ?
++ *  3) Path MTU discovery handling needs to be reviewed.  For example,
++ *     if we receive an ICMP 'packet too big' message from an intermediate 
++ *     router specifying it's next hop MTU, our stack may process this and
++ *     adjust the MSS without taking our AH/ESP overheads into account.
++ */
++
++ 
++/*
++ * Recaclulate checksum using differences between changed datum, 
++ * borrowed from netfilter.
++ */
++DEBUG_NO_STATIC u_int16_t 
++ipsec_fast_csum(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
++{
++      u_int32_t diffs[] = { oldvalinv, newval };
++      return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
++      oldcheck^0xFFFF));
++}
++
++/*
++ * Determine effective MSS.
++ *
++ * Note that we assume that there is always an MSS option for our own
++ * SYN segments, which is mentioned in tcp_syn_build_options(), kernel 2.2.x.
++ * This could change, and we should probably parse TCP options instead.
++ *
++ */
++DEBUG_NO_STATIC u_int8_t
++ipsec_adjust_mss(struct sk_buff *skb, struct tcphdr *tcph, u_int16_t mtu)
++{
++      u_int16_t oldmss, newmss;
++      u_int32_t *mssp;
++      struct sock *sk = skb->sk;
++      
++      newmss = tcp_sync_mss(sk, mtu);
++      printk(KERN_INFO "klips: setting mss to %u\n", newmss);
++      mssp = (u_int32_t *)tcph + sizeof(struct tcphdr) / sizeof(u_int32_t);
++      oldmss = ntohl(*mssp) & 0x0000FFFF;
++      *mssp = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | newmss);
++      tcph->check = ipsec_fast_csum(htons(~oldmss), 
++                                    htons(newmss), tcph->check);
++      return 1;
++}
++#endif        /* MSS_HACK */
++
++#ifdef CONFIG_KLIPS_DEBUG
++DEBUG_NO_STATIC char *
++ipsec_xmit_err(int err)
++{
++      static char tmp[32];
++      switch ((int) err) {
++      case IPSEC_XMIT_STOLEN:                 return("IPSEC_XMIT_STOLEN");
++      case IPSEC_XMIT_PASS:                   return("IPSEC_XMIT_PASS");
++      case IPSEC_XMIT_OK:                             return("IPSEC_XMIT_OK");
++      case IPSEC_XMIT_ERRMEMALLOC:    return("IPSEC_XMIT_ERRMEMALLOC");
++      case IPSEC_XMIT_ESP_BADALG:             return("IPSEC_XMIT_ESP_BADALG");
++      case IPSEC_XMIT_BADPROTO:               return("IPSEC_XMIT_BADPROTO");
++      case IPSEC_XMIT_ESP_PUSHPULLERR:return("IPSEC_XMIT_ESP_PUSHPULLERR");
++      case IPSEC_XMIT_BADLEN:                 return("IPSEC_XMIT_BADLEN");
++      case IPSEC_XMIT_AH_BADALG:              return("IPSEC_XMIT_AH_BADALG");
++      case IPSEC_XMIT_SAIDNOTFOUND:   return("IPSEC_XMIT_SAIDNOTFOUND");
++      case IPSEC_XMIT_SAIDNOTLIVE:    return("IPSEC_XMIT_SAIDNOTLIVE");
++      case IPSEC_XMIT_REPLAYROLLED:   return("IPSEC_XMIT_REPLAYROLLED");
++      case IPSEC_XMIT_LIFETIMEFAILED: return("IPSEC_XMIT_LIFETIMEFAILED");
++      case IPSEC_XMIT_CANNOTFRAG:             return("IPSEC_XMIT_CANNOTFRAG");
++      case IPSEC_XMIT_MSSERR:                 return("IPSEC_XMIT_MSSERR");
++      case IPSEC_XMIT_ERRSKBALLOC:    return("IPSEC_XMIT_ERRSKBALLOC");
++      case IPSEC_XMIT_ENCAPFAIL:              return("IPSEC_XMIT_ENCAPFAIL");
++      case IPSEC_XMIT_NODEV:                  return("IPSEC_XMIT_NODEV");
++      case IPSEC_XMIT_NOPRIVDEV:              return("IPSEC_XMIT_NOPRIVDEV");
++      case IPSEC_XMIT_NOPHYSDEV:              return("IPSEC_XMIT_NOPHYSDEV");
++      case IPSEC_XMIT_NOSKB:                  return("IPSEC_XMIT_NOSKB");
++      case IPSEC_XMIT_NOIPV6:                 return("IPSEC_XMIT_NOIPV6");
++      case IPSEC_XMIT_NOIPOPTIONS:    return("IPSEC_XMIT_NOIPOPTIONS");
++      case IPSEC_XMIT_TTLEXPIRED:             return("IPSEC_XMIT_TTLEXPIRED");
++      case IPSEC_XMIT_BADHHLEN:               return("IPSEC_XMIT_BADHHLEN");
++      case IPSEC_XMIT_PUSHPULLERR:    return("IPSEC_XMIT_PUSHPULLERR");
++      case IPSEC_XMIT_ROUTEERR:               return("IPSEC_XMIT_ROUTEERR");
++      case IPSEC_XMIT_RECURSDETECT:   return("IPSEC_XMIT_RECURSDETECT");
++      case IPSEC_XMIT_IPSENDFAILURE:  return("IPSEC_XMIT_IPSENDFAILURE");
++      case IPSEC_XMIT_ESPUDP:                 return("IPSEC_XMIT_ESPUDP");
++      case IPSEC_XMIT_ESPUDP_BADTYPE: return("IPSEC_XMIT_ESPUDP_BADTYPE");
++      case IPSEC_XMIT_PENDING:                return("IPSEC_XMIT_PENDING");
++      }
++      snprintf(tmp, sizeof(tmp), "%d", err);
++      return tmp;
++}
++#endif
++                                                        
++/*
++ * Sanity checks
++ */
++enum ipsec_xmit_value
++ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs)
++{
++
++      if (ixs->dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_error:ipsec_xmit_sanity_check_dev: "
++                          "No device associated with skb!\n" );
++              return IPSEC_XMIT_NODEV;
++      }
++
++      ixs->prv = ixs->dev->priv;
++      if (ixs->prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_error:ipsec_xmit_sanity_check_dev: "
++                          "Device has no private structure!\n" );
++              return  IPSEC_XMIT_NOPRIVDEV;
++      }
++
++      ixs->physdev = ixs->prv->dev;
++      if (ixs->physdev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_error:ipsec_xmit_sanity_check_dev: "
++                          "Device is not attached to physical device!\n" );
++              return IPSEC_XMIT_NOPHYSDEV;
++      }
++
++      ixs->physmtu = ixs->physdev->mtu;
++        ixs->cur_mtu = ixs->physdev->mtu;
++      ixs->stats = (struct net_device_stats *) &(ixs->prv->mystats);
++
++      return IPSEC_XMIT_OK;
++}
++
++enum ipsec_xmit_value
++ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs)
++{
++      /*
++       *      Return if there is nothing to do.  (Does this ever happen?) XXX
++       */
++      if (ixs->skb == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_error:ipsec_xmit_sanity_check_skb: "
++                          "Nothing to do!\n" );
++              return IPSEC_XMIT_NOSKB;
++      }
++
++      /* if skb was cloned (most likely due to a packet sniffer such as
++         tcpdump being momentarily attached to the interface), make
++         a copy of our own to modify */
++      if(skb_cloned(ixs->skb)) {
++              if
++#ifdef SKB_COW_NEW
++             (skb_cow(ixs->skb, skb_headroom(ixs->skb)) != 0)
++#else /* SKB_COW_NEW */
++             ((ixs->skb = skb_cow(ixs->skb, skb_headroom(ixs->skb))) == NULL)
++#endif /* SKB_COW_NEW */
++              {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_error:ipsec_xmit_sanity_check_skb: "
++                                  "skb_cow failed to allocate buffer, dropping.\n" );
++                      ixs->stats->tx_dropped++;
++                      return IPSEC_XMIT_ERRSKBALLOC;
++              }
++      }
++
++      ixs->iph = ip_hdr(ixs->skb);
++
++      /* sanity check for IP version as we can't handle IPv6 right now */
++      if (ixs->iph->version != 4) {
++              KLIPS_PRINT(debug_tunnel,
++                          "klips_debug:ipsec_xmit_sanity_check_skb: "
++                          "found IP Version %d but cannot process other IP versions than v4.\n",
++                          ixs->iph->version); /* XXX */
++              ixs->stats->tx_dropped++;
++              return IPSEC_XMIT_NOIPV6;
++      }
++      
++#if IPSEC_DISALLOW_IPOPTIONS
++      if ((ixs->iph->ihl << 2) != sizeof (struct iphdr)) {
++              KLIPS_PRINT(debug_tunnel,
++                          "klips_debug:ipsec_xmit_sanity_check_skb: "
++                          "cannot process IP header options yet.  May be mal-formed packet.\n"); /* XXX */
++              ixs->stats->tx_dropped++;
++              return IPSEC_XMIT_NOIPOPTIONS;
++      }
++#endif /* IPSEC_DISALLOW_IPOPTIONS */
++      
++#ifndef NET_21
++      if (ixs->iph->ttl <= 0) {
++              /* Tell the sender its packet died... */
++              ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev);
++
++              KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: "
++                          "TTL=0, too many hops!\n");
++              ixs->stats->tx_dropped++;
++              return IPSEC_XMIT_TTLEXPIRED;
++      }
++#endif /* !NET_21 */
++      
++      return IPSEC_XMIT_OK;
++}
++
++
++enum ipsec_xmit_value
++ipsec_xmit_encap_init(struct ipsec_xmit_state *ixs)
++{
++      ixs->blocksize = 8;
++      ixs->headroom = 0;
++      ixs->tailroom = 0;
++      ixs->authlen = 0;
++
++#ifdef CONFIG_KLIPS_ALG
++      ixs->ixt_e = NULL;
++      ixs->ixt_a = NULL;
++#endif /* CONFIG_KLIPS_ALG */
++
++      ixs->iphlen = ixs->iph->ihl << 2;
++      ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
++      ixs->sa_len = KLIPS_SATOT(debug_tunnel, &ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOT_BUF);
++      KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "calling output for <%s%s%s>, SA:%s\n", 
++                  IPS_XFORM_NAME(ixs->ipsp),
++                  ixs->sa_len ? ixs->sa_txt : " (error)");
++      switch(ixs->ipsp->ips_said.proto) {
++#ifdef CONFIG_KLIPS_AH
++      case IPPROTO_AH:
++              ixs->headroom += sizeof(struct ahhdr);
++              break;
++#endif /* CONFIG_KLIPS_AH */
++#ifdef CONFIG_KLIPS_ESP
++      case IPPROTO_ESP:
++#ifdef CONFIG_KLIPS_OCF
++              /*
++               * this needs cleaning up for sure - DM
++               */
++              if (ixs->ipsp->ocf_in_use) {
++                      switch (ixs->ipsp->ips_encalg) {
++                      case ESP_DES:
++                      case ESP_3DES:
++                              ixs->blocksize = 8;
++                              ixs->headroom += ESP_HEADER_LEN + 8 /* ivsize */;
++                              break;
++                      case ESP_AES:
++                              ixs->blocksize = 16;
++                              ixs->headroom += ESP_HEADER_LEN + 16 /* ivsize */;
++                              break;
++                      default:
++                              ixs->stats->tx_errors++;
++                              return IPSEC_XMIT_ESP_BADALG;
++                      }
++              } else
++#endif
++#ifdef CONFIG_KLIPS_ALG
++              if ((ixs->ixt_e=ixs->ipsp->ips_alg_enc)) {
++                      ixs->blocksize = ixs->ixt_e->ixt_common.ixt_blocksize;
++                      ixs->headroom += ESP_HEADER_LEN + ixs->ixt_e->ixt_common.ixt_support.ias_ivlen/8;
++              } else
++#endif /* CONFIG_KLIPS_ALG */
++              {
++                      ixs->stats->tx_errors++;
++                      return IPSEC_XMIT_ESP_BADALG;
++              }
++#ifdef CONFIG_KLIPS_OCF
++              if (ixs->ipsp->ocf_in_use) {
++                      switch (ixs->ipsp->ips_authalg) {
++                      case AH_MD5:
++                      case AH_SHA:
++                              ixs->authlen = AHHMAC_HASHLEN;
++                              break;
++                      case AH_NONE:
++                              break;
++                      }
++              } else
++#endif /* CONFIG_KLIPS_OCF */
++#ifdef CONFIG_KLIPS_ALG
++
++              ixs->ixt_a=ixs->ipsp->ips_alg_auth;
++              if (ixs->ixt_a) {
++                      ixs->tailroom += AHHMAC_HASHLEN;
++                      ixs->authlen = AHHMAC_HASHLEN;
++              } else 
++#endif /* CONFIG_KLIPS_ALG */
++              switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              case AH_MD5:
++                      ixs->authlen = AHHMAC_HASHLEN;
++                      break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              case AH_SHA:
++                      ixs->authlen = AHHMAC_HASHLEN;
++                      break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++              case AH_NONE:
++                      break;
++              default:
++                      ixs->stats->tx_errors++;
++                      return IPSEC_XMIT_ESP_BADALG;
++              }               
++              ixs->tailroom += ixs->blocksize != 1 ?
++                      ((ixs->blocksize - ((ixs->pyldsz + 2) % ixs->blocksize)) % ixs->blocksize) + 2 :
++                      ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
++              ixs->tailroom += ixs->authlen;
++              break;
++#endif /* !CONFIG_KLIPS_ESP */
++#ifdef CONFIG_KLIPS_IPIP
++      case IPPROTO_IPIP:
++              ixs->headroom += sizeof(struct iphdr);
++              ixs->iphlen = sizeof(struct iphdr);
++              break;
++#endif /* !CONFIG_KLIPS_IPIP */
++#ifdef CONFIG_KLIPS_IPCOMP
++      case IPPROTO_COMP:
++              break;
++#endif /* CONFIG_KLIPS_IPCOMP */
++      default:
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_BADPROTO;
++      }
++      
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "pushing %d bytes, putting %d, proto %d.\n", 
++                  ixs->headroom, ixs->tailroom, ixs->ipsp->ips_said.proto);
++      if(skb_headroom(ixs->skb) < ixs->headroom) {
++              printk(KERN_WARNING
++                     "klips_error:ipsec_xmit_encap_once: "
++                     "tried to skb_push headroom=%d, %d available.  This should never happen, please report.\n",
++                     ixs->headroom, skb_headroom(ixs->skb));
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_ESP_PUSHPULLERR;
++      }
++
++      ixs->dat = skb_push(ixs->skb, ixs->headroom);
++      ixs->ilen = ixs->skb->len - ixs->tailroom;
++      if(skb_tailroom(ixs->skb) < ixs->tailroom) {
++              printk(KERN_WARNING
++                     "klips_error:ipsec_xmit_encap_once: "
++                     "tried to skb_put %d, %d available.  This should never happen, please report.\n",
++                     ixs->tailroom, skb_tailroom(ixs->skb));
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_ESP_PUSHPULLERR;
++      }
++      skb_put(ixs->skb, ixs->tailroom);
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "head,tailroom: %d,%d before xform.\n",
++                  skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
++      ixs->len = ixs->skb->len;
++      if(ixs->len > 0xfff0) {
++              printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
++                     "tot_len (%d) > 65520.  This should never happen, please report.\n",
++                     ixs->len);
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_BADLEN;
++      }
++      memmove((void *)ixs->dat, (void *)(ixs->dat + ixs->headroom), ixs->iphlen);
++      ixs->iph = (struct iphdr *)ixs->dat;
++      ixs->iph->tot_len = htons(ixs->skb->len);
++
++      return IPSEC_XMIT_OK;
++}
++
++
++/*
++ * work out which state to proceed to next
++ */
++
++enum ipsec_xmit_value
++ipsec_xmit_encap_select(struct ipsec_xmit_state *ixs)
++{
++      switch (ixs->ipsp->ips_said.proto) {
++#ifdef CONFIG_KLIPS_ESP
++      case IPPROTO_ESP:
++              ixs->next_state = IPSEC_XSM_ESP;
++              break;
++#endif
++#ifdef CONFIG_KLIPS_AH
++      case IPPROTO_AH:
++              ixs->next_state = IPSEC_XSM_AH;
++              break;
++#endif
++#ifdef CONFIG_KLIPS_IPIP
++      case IPPROTO_IPIP:
++              ixs->next_state = IPSEC_XSM_IPIP;
++              break;
++#endif
++#ifdef CONFIG_KLIPS_IPCOMP
++      case IPPROTO_COMP:
++              ixs->next_state = IPSEC_XSM_IPCOMP;
++              break;
++#endif
++      default:
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_BADPROTO;
++      }
++      return IPSEC_XMIT_OK;
++}
++
++
++#ifdef CONFIG_KLIPS_ESP
++
++enum ipsec_xmit_value
++ipsec_xmit_esp(struct ipsec_xmit_state *ixs)
++{
++      int i;
++      unsigned char *pad;
++      int padlen = 0;
++
++      ixs->espp = (struct esphdr *)(ixs->dat + ixs->iphlen);
++#ifdef NET_21
++      skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->espp));
++#endif /* NET_21 */
++      ixs->espp->esp_spi = ixs->ipsp->ips_said.spi;
++      ixs->espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
++      
++      ixs->idat = ixs->dat + ixs->iphlen + ixs->headroom;
++      ixs->ilen = ixs->len - (ixs->iphlen + ixs->headroom + ixs->authlen);
++
++      /* Self-describing padding */
++      pad = &ixs->dat[ixs->len - ixs->tailroom];
++      padlen = ixs->tailroom - 2 - ixs->authlen;
++      for (i = 0; i < padlen; i++) {
++              pad[i] = i + 1; 
++      }
++      ixs->dat[ixs->len - ixs->authlen - 2] = padlen;
++      
++      ixs->dat[ixs->len - ixs->authlen - 1] = ixs->iph->protocol;
++      ixs->iph->protocol = IPPROTO_ESP;
++      
++#ifdef CONFIG_KLIPS_OCF
++      if (ixs->ipsp->ocf_in_use)
++              return(ipsec_ocf_xmit(ixs));
++#endif
++
++#ifdef CONFIG_KLIPS_ALG
++      if (!ixs->ixt_e) {
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_ESP_BADALG;
++      }
++      
++#ifdef CONFIG_KLIPS_DEBUG             
++      if(debug_tunnel & DB_TN_ENCAP) {
++              dmp("pre-encrypt", ixs->dat, ixs->len);
++      }
++#endif
++
++      /*
++       * Do all operations here:
++       * copy IV->ESP, encrypt, update ips IV
++       *
++       */
++      {
++              int ret;
++              memcpy(ixs->espp->esp_iv, 
++                         ixs->ipsp->ips_iv, 
++                         ixs->ipsp->ips_iv_size);
++              ret=ipsec_alg_esp_encrypt(ixs->ipsp, 
++                                        ixs->idat, ixs->ilen, ixs->espp->esp_iv,
++                                        IPSEC_ALG_ENCRYPT);
++
++              prng_bytes(&ipsec_prng,
++                         (char *)ixs->ipsp->ips_iv,
++                         ixs->ipsp->ips_iv_size);
++      } 
++      return IPSEC_XMIT_OK;
++#else
++      return IPSEC_XMIT_ESP_BADALG;
++#endif /*  CONFIG_KLIPS_ALG */
++}
++
++
++enum ipsec_xmit_value
++ipsec_xmit_esp_ah(struct ipsec_xmit_state *ixs)
++{
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++      __u8 hash[AH_AMAX];
++#endif
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++      union {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              MD5_CTX md5;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              SHA1_CTX sha1;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      } tctx;
++#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1) */
++
++#ifdef CONFIG_KLIPS_OCF
++      if (ixs->ipsp->ocf_in_use) {
++              /* we should never be here using OCF */
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_AH_BADALG;
++      } else
++#endif
++#ifdef CONFIG_KLIPS_ALG
++      if (ixs->ixt_a) {
++              ipsec_alg_sa_esp_hash(ixs->ipsp,
++                              (caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen,
++                              &(ixs->dat[ixs->len - ixs->authlen]), ixs->authlen);
++
++      } else
++#endif /* CONFIG_KLIPS_ALG */
++      switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++      case AH_MD5:
++              dmp("espp", (char*)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
++              tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++              dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, (caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
++              dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Final(hash, &tctx.md5);
++              dmp("ictx hash", (char*)&hash, sizeof(hash));
++              tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
++              dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
++              dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Final(hash, &tctx.md5);
++              dmp("octx hash", (char*)&hash, sizeof(hash));
++              memcpy(&(ixs->dat[ixs->len - ixs->authlen]), hash, ixs->authlen);
++              
++              /* paranoid */
++              memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
++              memset((caddr_t)hash, 0, sizeof(*hash));
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++      case AH_SHA:
++              tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++              SHA1Update(&tctx.sha1, (caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
++              SHA1Final(hash, &tctx.sha1);
++              tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
++              SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++              SHA1Final(hash, &tctx.sha1);
++              memcpy(&(ixs->dat[ixs->len - ixs->authlen]), hash, ixs->authlen);
++              
++              /* paranoid */
++              memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
++              memset((caddr_t)hash, 0, sizeof(*hash));
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      case AH_NONE:
++              break;
++      default:
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_AH_BADALG;
++      }
++      return IPSEC_XMIT_OK;
++}
++
++#endif /* CONFIG_KLIPS_ESP */
++
++
++
++#ifdef CONFIG_KLIPS_AH
++
++enum ipsec_xmit_value
++ipsec_xmit_ah(struct ipsec_xmit_state *ixs)
++{
++      struct iphdr ipo;
++      struct ahhdr *ahp;
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++      __u8 hash[AH_AMAX];
++#endif
++#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
++      union {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              MD5_CTX md5;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              SHA1_CTX sha1;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      } tctx;
++#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1) */
++
++      ahp = (struct ahhdr *)(ixs->dat + ixs->iphlen);
++#ifdef NET_21
++      skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ahp));
++#endif /* NET_21 */
++      ahp->ah_spi = ixs->ipsp->ips_said.spi;
++      ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
++      ahp->ah_rv = 0;
++      ahp->ah_nh = ixs->iph->protocol;
++      ahp->ah_hl = (ixs->headroom >> 2) - sizeof(__u64)/sizeof(__u32);
++      ixs->iph->protocol = IPPROTO_AH;
++      dmp("ahp", (char*)ahp, sizeof(*ahp));
++      
++#ifdef CONFIG_KLIPS_OCF
++      if (ixs->ipsp->ocf_in_use)
++              return(ipsec_ocf_xmit(ixs));
++#endif
++
++      ipo = *ixs->iph;
++      ipo.tos = 0;
++      ipo.frag_off = 0;
++      ipo.ttl = 0;
++      ipo.check = 0;
++      dmp("ipo", (char*)&ipo, sizeof(ipo));
++      
++      switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++      case AH_MD5:
++              tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++              dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
++              dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, (unsigned char *)ahp, ixs->headroom - sizeof(ahp->ah_data));
++              dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++              dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5,  ixs->dat + ixs->iphlen + ixs->headroom, ixs->len - ixs->iphlen - ixs->headroom);
++              dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Final(hash, &tctx.md5);
++              dmp("ictx hash", (char*)&hash, sizeof(hash));
++              tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
++              dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
++              dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++              osMD5Final(hash, &tctx.md5);
++              dmp("octx hash", (char*)&hash, sizeof(hash));
++                              
++              memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
++                              
++              /* paranoid */
++              memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
++              memset((caddr_t)hash, 0, sizeof(*hash));
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++      case AH_SHA:
++              tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
++              SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
++              SHA1Update(&tctx.sha1, (unsigned char *)ahp, ixs->headroom - sizeof(ahp->ah_data));
++              SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++              SHA1Update(&tctx.sha1,  ixs->dat + ixs->iphlen + ixs->headroom, ixs->len - ixs->iphlen - ixs->headroom);
++              SHA1Final(hash, &tctx.sha1);
++              tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
++              SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++              SHA1Final(hash, &tctx.sha1);
++                              
++              memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
++                              
++              /* paranoid */
++              memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
++              memset((caddr_t)hash, 0, sizeof(*hash));
++              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      default:
++              ixs->stats->tx_errors++;
++              return IPSEC_XMIT_AH_BADALG;
++      }
++      return IPSEC_XMIT_OK;
++}
++
++#endif /* CONFIG_KLIPS_AH */
++
++
++#ifdef CONFIG_KLIPS_IPIP
++
++enum ipsec_xmit_value
++ipsec_xmit_ipip(struct ipsec_xmit_state *ixs)
++{
++      ixs->iph->version  = 4;
++      switch(sysctl_ipsec_tos) {
++      case 0:
++#ifdef NET_21
++              ixs->iph->tos = ip_hdr(ixs->skb)->tos;
++#else /* NET_21 */
++              ixs->iph->tos = ixs->skb->ip_hdr->tos;
++#endif /* NET_21 */
++              break;
++      case 1:
++              ixs->iph->tos = 0;
++              break;
++      default:
++              break;
++      }
++      ixs->iph->ttl      = SYSCTL_IPSEC_DEFAULT_TTL;
++      ixs->iph->frag_off = 0;
++      ixs->iph->saddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
++      ixs->iph->daddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
++      ixs->iph->protocol = IPPROTO_IPIP;
++      ixs->iph->ihl      = sizeof(struct iphdr) >> 2;
++
++      KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
++
++      ixs->newdst = (__u32)ixs->iph->daddr;
++      ixs->newsrc = (__u32)ixs->iph->saddr;
++      
++#ifdef NET_21
++      skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ip_hdr(ixs->skb)));
++#endif /* NET_21 */
++      return IPSEC_XMIT_OK;
++}
++
++#endif /* CONFIG_KLIPS_IPIP */
++
++
++#ifdef CONFIG_KLIPS_IPCOMP
++
++enum ipsec_xmit_value
++ipsec_xmit_ipcomp(struct ipsec_xmit_state *ixs)
++{
++#ifdef CONFIG_KLIPS_DEBUG
++      unsigned int old_tot_len;
++#endif
++      int flags = 0;
++
++#ifdef CONFIG_KLIPS_DEBUG
++      old_tot_len = ntohs(ixs->iph->tot_len);
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
++      ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
++
++#ifdef NET_21
++      ixs->iph = ip_hdr(ixs->skb);
++#else /* NET_21 */
++      ixs->iph = ixs->skb->ip_hdr;
++#endif /* NET_21 */
++
++      ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_tunnel & DB_TN_CROUT)
++      {
++              if (old_tot_len > ntohs(ixs->iph->tot_len))
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                      "klips_debug:ipsec_xmit_encap_once: "
++                                      "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
++                                      old_tot_len, ntohs(ixs->iph->tot_len),
++                                      ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
++                                      ntohl(ixs->ipsp->ips_said.spi),
++                                      (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
++              else
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                      "klips_debug:ipsec_xmit_encap_once: "
++                                      "packet did not compress (flags = %d).\n",
++                                      flags);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      return IPSEC_XMIT_OK;
++}
++
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++
++
++/*
++ * upon entry to this function, ixs->skb should be setup
++ * as follows:
++ *
++ *   data   = beginning of IP packet   <- differs from ipsec_rcv().
++ *   nh.raw = beginning of IP packet.
++ *   h.raw  = data after the IP packet.
++ *
++ */
++enum ipsec_xmit_value
++ipsec_xmit_cont(struct ipsec_xmit_state *ixs)
++{
++#ifdef NET_21
++      skb_set_network_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->skb->data));
++#else /* NET_21 */
++      ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
++#endif /* NET_21 */
++      ixs->iph->check = 0;
++      ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl);
++                      
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "klips_debug:ipsec_xmit_encap_once: "
++                  "after <%s%s%s>, SA:%s:\n",
++                  IPS_XFORM_NAME(ixs->ipsp),
++                  ixs->sa_len ? ixs->sa_txt : " (error)");
++      KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
++                      
++      ixs->ipsp->ips_life.ipl_bytes.ipl_count += ixs->len;
++      ixs->ipsp->ips_life.ipl_bytes.ipl_last = ixs->len;
++
++      if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
++              ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
++      }
++      ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
++      ixs->ipsp->ips_life.ipl_packets.ipl_count++; 
++
++      ixs->ipsp = ixs->ipsp->ips_next;
++
++      /*
++       * start again if we have more work to do
++       */
++      if (ixs->ipsp)
++              ixs->next_state = IPSEC_XSM_ENCAP_INIT;
++
++      return IPSEC_XMIT_OK;
++}
++
++
++/*
++ * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
++ * source and destination ports to those from the TCP/UDP header.
++ */
++void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er)
++{
++      struct udphdr *udp;
++
++      switch (iph->protocol) {
++      case IPPROTO_UDP:
++      case IPPROTO_TCP:
++              /*
++               * The ports are at the same offsets in a TCP and UDP
++               * header so hack it ...
++               */
++              udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2));
++              er->sen_sport = udp->source;
++              er->sen_dport = udp->dest;
++              break;
++      default:
++              er->sen_sport = 0;
++              er->sen_dport = 0;
++              break;
++      }
++}
++
++/*
++ * A TRAP eroute is installed and we want to replace it with a HOLD
++ * eroute.
++ */
++static int create_hold_eroute(struct eroute *origtrap,
++                            struct sk_buff * skb, struct iphdr * iph,
++                            uint32_t eroute_pid)
++{
++      struct eroute hold_eroute;
++      ip_said hold_said;
++      struct sk_buff *first, *last;
++      int error;
++
++      first = last = NULL;
++      memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute));
++      memset((caddr_t)&hold_said, 0, sizeof(hold_said));
++      
++      hold_said.proto = IPPROTO_INT;
++      hold_said.spi = htonl(SPI_HOLD);
++      hold_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY;
++      
++      hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap);
++      hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap);
++      hold_eroute.er_eaddr.sen_family = AF_ENCAP;
++      hold_eroute.er_emask.sen_family = AF_ENCAP;
++      hold_eroute.er_eaddr.sen_type = SENT_IP4;
++      hold_eroute.er_emask.sen_type = 255;
++      
++      hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr;
++      hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr;
++      hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST;
++      hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST;
++      hold_eroute.er_emask.sen_sport = 0;
++      hold_eroute.er_emask.sen_dport = 0;
++      hold_eroute.er_pid = eroute_pid;
++      hold_eroute.er_count = 0;
++      hold_eroute.er_lasttime = jiffies/HZ;
++
++      /*
++       * if it wasn't captured by a wildcard, then don't record it as
++       * a wildcard.
++       */
++      if(origtrap->er_eaddr.sen_proto != 0) {
++        hold_eroute.er_eaddr.sen_proto = iph->protocol;
++
++        if((iph->protocol == IPPROTO_TCP ||
++            iph->protocol == IPPROTO_UDP) &&
++           (origtrap->er_eaddr.sen_sport != 0 ||
++            origtrap->er_eaddr.sen_dport != 0)) {
++
++          if(origtrap->er_eaddr.sen_sport != 0)
++            hold_eroute.er_emask.sen_sport = ~0;
++
++          if(origtrap->er_eaddr.sen_dport != 0) 
++            hold_eroute.er_emask.sen_dport = ~0;
++
++          ipsec_extract_ports(iph, &hold_eroute.er_eaddr);
++        }
++      }
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_pfkey) {
++              char buf1[64], buf2[64];
++              subnettoa(hold_eroute.er_eaddr.sen_ip_src,
++                        hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(hold_eroute.er_eaddr.sen_ip_dst,
++                        hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n",
++                          buf1, ntohs(hold_eroute.er_eaddr.sen_sport),
++                          buf2, ntohs(hold_eroute.er_eaddr.sen_dport),
++                          hold_eroute.er_eaddr.sen_proto);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask),
++                           &first, &last)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "HOLD breakeroute found nothing.\n");
++      } else {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n",
++                          NIPQUAD(hold_eroute.er_eaddr.sen_ip_src),
++                          ntohs(hold_eroute.er_eaddr.sen_sport),
++                          NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst),
++                          ntohs(hold_eroute.er_eaddr.sen_dport),
++                          hold_eroute.er_eaddr.sen_proto);
++      }
++      if (first != NULL)
++              kfree_skb(first);
++      if (last != NULL)
++              kfree_skb(last);
++
++      error = ipsec_makeroute(&(hold_eroute.er_eaddr),
++                              &(hold_eroute.er_emask),
++                              hold_said, eroute_pid, skb, NULL, NULL);
++      if (error) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "HOLD makeroute returned %d, failed.\n", error);
++      } else {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "HOLD makeroute call successful.\n");
++      }
++      return (error == 0);
++}
++
++/*
++ * upon entry to this function, ixs->skb should be setup
++ * as follows:
++ *
++ *   data   = beginning of IP packet   <- differs from ipsec_rcv().
++ *   nh.raw = beginning of IP packet.
++ *   h.raw  = data after the IP packet.
++ *
++ */
++enum ipsec_xmit_value
++ipsec_xmit_init1(struct ipsec_xmit_state *ixs)
++{
++      ixs->newdst = ixs->orgdst = ixs->iph->daddr;
++      ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
++      ixs->orgedst = ixs->outgoing_said.dst.u.v4.sin_addr.s_addr;
++      ixs->iphlen = ixs->iph->ihl << 2;
++      ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
++      ixs->max_headroom = ixs->max_tailroom = 0;
++              
++      if (ixs->outgoing_said.proto == IPPROTO_INT) {
++              switch (ntohl(ixs->outgoing_said.spi)) {
++              case SPI_DROP:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle: "
++                                  "shunt SA of DROP or no eroute: dropping.\n");
++                      ixs->stats->tx_dropped++;
++                      break;
++                              
++              case SPI_REJECT:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle: "
++                                  "shunt SA of REJECT: notifying and dropping.\n");
++                      ICMP_SEND(ixs->skb,
++                                ICMP_DEST_UNREACH,
++                                ICMP_PKT_FILTERED,
++                                0,
++                                ixs->physdev);
++                      ixs->stats->tx_dropped++;
++                      break;
++                              
++              case SPI_PASS:
++#ifdef NET_21
++                      ixs->pass = 1;
++#endif /* NET_21 */
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle: "
++                                  "PASS: calling dev_queue_xmit\n");
++                      return IPSEC_XMIT_PASS;
++                              
++              case SPI_HOLD:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle: "
++                                  "shunt SA of HOLD: this does not make sense here, dropping.\n");
++                      ixs->stats->tx_dropped++;
++                      break;
++
++              case SPI_TRAP:
++              case SPI_TRAPSUBNET:
++              {
++                      struct sockaddr_in src, dst;
++#ifdef CONFIG_KLIPS_DEBUG
++                      char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];
++#endif /* CONFIG_KLIPS_DEBUG */
++
++                      /* Signal all listening KMds with a PF_KEY ACQUIRE */
++
++                      memset(&src, 0, sizeof(src));
++                      memset(&dst, 0, sizeof(dst));
++                      src.sin_family = AF_INET;
++                      dst.sin_family = AF_INET;
++                      src.sin_addr.s_addr = ixs->iph->saddr;
++                      dst.sin_addr.s_addr = ixs->iph->daddr;
++
++                      ixs->ips.ips_transport_protocol = 0;
++                      src.sin_port = 0;
++                      dst.sin_port = 0;
++                      
++                      if(ixs->eroute->er_eaddr.sen_proto != 0) {
++                        ixs->ips.ips_transport_protocol = ixs->iph->protocol;
++                        
++                        if(ixs->eroute->er_eaddr.sen_sport != 0) {
++                          src.sin_port = 
++                            (ixs->iph->protocol == IPPROTO_UDP
++                             ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source
++                             : (ixs->iph->protocol == IPPROTO_TCP
++                                ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source
++                                : 0));
++                        }
++                        if(ixs->eroute->er_eaddr.sen_dport != 0) {
++                          dst.sin_port = 
++                            (ixs->iph->protocol == IPPROTO_UDP
++                             ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest
++                             : (ixs->iph->protocol == IPPROTO_TCP
++                                ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest
++                                : 0));
++                        }
++                      }
++                              
++                      ixs->ips.ips_addr_s = (struct sockaddr*)(&src);
++                      ixs->ips.ips_addr_d = (struct sockaddr*)(&dst);
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle: "
++                                  "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n",
++                                  addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR",
++                                  ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port),
++                                  addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR",
++                                  ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port),
++                                  ixs->ips.ips_said.proto);
++                              
++                      /* increment count of total traps needed */
++                      ipsec_xmit_trap_count++;
++
++                      if (pfkey_acquire(&ixs->ips) == 0) {
++
++                              /* note that we succeeded */
++                              ipsec_xmit_trap_sendcount++;
++                                      
++                              if (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)) {
++                                      /*
++                                       * The spinlock is to prevent any other
++                                       * process from accessing or deleting
++                                       * the eroute while we are using and
++                                       * updating it.
++                                       */
++                                      spin_lock_bh(&eroute_lock);
++                                      ixs->eroute = ipsec_findroute(&ixs->matcher);
++                                      if(ixs->eroute) {
++                                              ixs->eroute->er_said.spi = htonl(SPI_HOLD);
++                                              ixs->eroute->er_first = ixs->skb;
++                                              ixs->skb = NULL;
++                                      }
++                                      spin_unlock_bh(&eroute_lock);
++                              } else if (create_hold_eroute(ixs->eroute,
++                                                            ixs->skb,
++                                                            ixs->iph,
++                                                            ixs->eroute_pid)) {
++                                      ixs->skb = NULL;
++                              } 
++                              /* whether or not the above succeeded, we continue */
++                              
++                      }
++                      ixs->stats->tx_dropped++;
++              }
++              default:
++                      /* XXX what do we do with an unknown shunt spi? */
++                      break;
++              } /* switch (ntohl(ixs->outgoing_said.spi)) */
++              return IPSEC_XMIT_STOLEN;
++      } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
++      
++      ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
++      ixs->sa_len = KLIPS_SATOT(debug_tunnel, &ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt));
++
++      if (ixs->ipsp == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_encap_bundle: "
++                          "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n",
++                          ixs->sa_len ? ixs->sa_txt : " (error)");
++              if(ixs->stats) {
++                      ixs->stats->tx_dropped++;
++              }
++              return IPSEC_XMIT_SAIDNOTFOUND;
++      }
++
++      return IPSEC_XMIT_OK;
++}
++
++enum ipsec_xmit_value
++ipsec_xmit_init2(struct ipsec_xmit_state *ixs)
++{
++      enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
++      struct ipsec_sa *saved_ipsp;
++#ifdef CONFIG_KLIPS_ALG
++      ixs->blocksize = 8;
++      ixs->ixt_e = NULL;
++      ixs->ixt_a = NULL;
++#endif /* CONFIG_KLIPS_ALG */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                  "found ipsec_sa -- SA:<%s%s%s> %s\n",
++                  IPS_XFORM_NAME(ixs->ipsp),
++                  ixs->sa_len ? ixs->sa_txt : " (error)");
++              
++      /*
++       * How much headroom do we need to be able to apply
++       * all the grouped transforms?
++       */
++      saved_ipsp = ixs->ipsp; /* save the head of the ipsec_sa chain */
++      while (ixs->ipsp) {
++              if (debug_tunnel & DB_TN_XMIT) {
++              ixs->sa_len = KLIPS_SATOT(debug_tunnel, &ixs->ipsp->ips_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt));
++              if(ixs->sa_len == 0) {
++                      strcpy(ixs->sa_txt, "(error)");
++              }
++              } else {
++                      *ixs->sa_txt = 0;
++                      ixs->sa_len = 0;
++              }
++
++              /* If it is in larval state, drop the packet, we cannot process yet. */
++              if(ixs->ipsp->ips_state == K_SADB_SASTATE_LARVAL) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                                  "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n",
++                                  IPS_XFORM_NAME(ixs->ipsp),
++                                  ixs->sa_len ? ixs->sa_txt : " (error)");
++                      if(ixs->stats) {
++                              ixs->stats->tx_errors++;
++                      }
++                      bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
++                      goto cleanup;
++              }
++
++              if(ixs->ipsp->ips_state == K_SADB_SASTATE_DEAD) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                                  "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n",
++                                  IPS_XFORM_NAME(ixs->ipsp),
++                                  ixs->sa_len ? ixs->sa_txt : " (error)");
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
++                      goto cleanup;
++              }
++
++              /* If the replay window counter == -1, expire SA, it will roll */
++              if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) {
++                      pfkey_expire(ixs->ipsp, 1);
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                                  "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n",
++                                  IPS_XFORM_NAME(ixs->ipsp),
++                                  ixs->sa_len ? ixs->sa_txt : " (error)");
++                      ipsec_sa_rm(ixs->ipsp);
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_REPLAYROLLED;
++                      goto cleanup;
++              }
++
++              /*
++               * if this is the first time we are using this SA, mark start time,
++               * and offset hard/soft counters by "now" for later checking.
++               */
++#if 0
++              if(ixs->ipsp->ips_life.ipl_usetime.count == 0) {
++                      ixs->ipsp->ips_life.ipl_usetime.count = jiffies;
++                      ixs->ipsp->ips_life.ipl_usetime.hard += jiffies;
++                      ixs->ipsp->ips_life.ipl_usetime.soft += jiffies;
++              }
++#endif
++                        
++
++              if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt, 
++                                      ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
++                 ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt,
++                                      ipsec_life_timebased,  ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
++                 ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt,
++                                      ipsec_life_timebased,  ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
++                 ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt,
++                                      ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) {
++                              
++                      ipsec_sa_rm(ixs->ipsp);
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_LIFETIMEFAILED;
++                      goto cleanup;
++              }
++                      
++
++              ixs->headroom = ixs->tailroom = 0;
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "calling room for <%s%s%s>, SA:%s\n", 
++                          IPS_XFORM_NAME(ixs->ipsp),
++                          ixs->sa_len ? ixs->sa_txt : " (error)");
++              switch(ixs->ipsp->ips_said.proto) {
++#ifdef CONFIG_KLIPS_AH
++              case IPPROTO_AH:
++                      ixs->headroom += sizeof(struct ahhdr);
++                      break;
++#endif /* CONFIG_KLIPS_AH */
++
++#ifdef CONFIG_KLIPS_ESP
++              case IPPROTO_ESP:
++#ifdef CONFIG_KLIPS_OCF
++                      /*
++                       * this needs cleaning up for sure - DM
++                       */
++                      if (ixs->ipsp->ocf_in_use) {
++                              switch (ixs->ipsp->ips_encalg) {
++                              case ESP_DES:
++                              case ESP_3DES:
++                                      ixs->blocksize = 8;
++                                      ixs->headroom += ESP_HEADER_LEN + 8 /* ivsize */;
++                                      break;
++                              case ESP_AES:
++                                      ixs->blocksize = 16;
++                                      ixs->headroom += ESP_HEADER_LEN + 16 /* ivsize */;
++                                      break;
++                              default:
++                                      ixs->stats->tx_errors++;
++                                      bundle_stat = IPSEC_XMIT_ESP_BADALG;
++                                      goto cleanup;
++                              }
++                      } else
++#endif /* CONFIG_KLIPS_OCF */
++#ifdef CONFIG_KLIPS_ALG
++                      ixs->ixt_e=ixs->ipsp->ips_alg_enc;
++                      if (ixs->ixt_e) {
++                              ixs->blocksize = ixs->ixt_e->ixt_common.ixt_blocksize;
++                              ixs->headroom += ESP_HEADER_LEN + ixs->ixt_e->ixt_common.ixt_support.ias_ivlen/8;
++                      } else
++#endif /* CONFIG_KLIPS_ALG */
++                      {
++                              ixs->stats->tx_errors++;
++                              bundle_stat = IPSEC_XMIT_ESP_BADALG;
++                              goto cleanup;
++                      }
++#ifdef CONFIG_KLIPS_OCF
++                      if (ixs->ipsp->ocf_in_use) {
++                              switch (ixs->ipsp->ips_authalg) {
++                              case AH_MD5:
++                              case AH_SHA:
++                                      ixs->tailroom += AHHMAC_HASHLEN;
++                                      break;
++                              case AH_NONE:
++                                      break;
++                              }
++                      } else
++#endif /* CONFIG_KLIPS_OCF */
++#ifdef CONFIG_KLIPS_ALG
++                      if ((ixs->ixt_a=ixs->ipsp->ips_alg_auth)) {
++                              ixs->tailroom += AHHMAC_HASHLEN;
++                      } else
++#endif /* CONFIG_KLIPS_ALG */
++                      switch(ixs->ipsp->ips_authalg) {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++                      case AH_MD5:
++                              ixs->tailroom += AHHMAC_HASHLEN;
++                              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++                      case AH_SHA:
++                              ixs->tailroom += AHHMAC_HASHLEN;
++                              break;
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++                      case AH_NONE:
++                              break;
++                      default:
++                              ixs->stats->tx_errors++;
++                              bundle_stat = IPSEC_XMIT_AH_BADALG;
++                              goto cleanup;
++                      }                       
++                      ixs->tailroom += ixs->blocksize != 1 ?
++                              ((ixs->blocksize - ((ixs->pyldsz + 2) % ixs->blocksize)) % ixs->blocksize) + 2 :
++                              ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++              if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
++                      ixs->natt_type = ixs->ipsp->ips_natt_type;
++                      ixs->natt_sport = ixs->ipsp->ips_natt_sport;
++                      ixs->natt_dport = ixs->ipsp->ips_natt_dport;
++                      switch (ixs->natt_type) {
++                              case ESPINUDP_WITH_NON_IKE:
++                                      ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
++                                      break;
++                                      
++                              case ESPINUDP_WITH_NON_ESP:
++                                      ixs->natt_head = sizeof(struct udphdr);
++                                      break;
++                                      
++                              default:
++                                KLIPS_PRINT(debug_tunnel & DB_TN_CROUT
++                                            , "klips_xmit: invalid nat-t type %d"
++                                            , ixs->natt_type);
++                                bundle_stat = IPSEC_XMIT_ESPUDP_BADTYPE;
++                                goto cleanup;
++                                            
++                                      break;
++                      }
++                      ixs->tailroom += ixs->natt_head;
++              }
++#endif
++                      break;
++#endif /* CONFIG_KLIPS_ESP */
++#ifdef CONFIG_KLIPS_IPIP
++              case IPPROTO_IPIP:
++                      ixs->headroom += sizeof(struct iphdr);
++                      break;
++#endif /* !CONFIG_KLIPS_IPIP */
++              case IPPROTO_COMP:
++#ifdef CONFIG_KLIPS_IPCOMP
++                      /*
++                        We can't predict how much the packet will
++                        shrink without doing the actual compression.
++                        We could do it here, if we were the first
++                        encapsulation in the chain.  That might save
++                        us a skb_copy_expand, since we might fit
++                        into the existing skb then.  However, this
++                        would be a bit unclean (and this hack has
++                        bit us once), so we better not do it. After
++                        all, the skb_copy_expand is cheap in
++                        comparison to the actual compression.
++                        At least we know the packet will not grow.
++                      */
++                      break;
++#endif /* CONFIG_KLIPS_IPCOMP */
++              default:
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_BADPROTO;
++                      goto cleanup;
++              }
++              ixs->ipsp = ixs->ipsp->ips_next;
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "Required head,tailroom: %d,%d\n", 
++                          ixs->headroom, ixs->tailroom);
++              ixs->max_headroom += ixs->headroom;
++              ixs->max_tailroom += ixs->tailroom;
++              ixs->pyldsz += (ixs->headroom + ixs->tailroom);
++      }
++      ixs->ipsp = saved_ipsp; /* restore the head of the ipsec_sa chain */
++              
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                  "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n",
++                  skb_headroom(ixs->skb), skb_tailroom(ixs->skb),
++                  ixs->max_headroom, ixs->max_tailroom);
++              
++      ixs->tot_headroom += ixs->max_headroom;
++      ixs->tot_tailroom += ixs->max_tailroom;
++
++      ixs->mtudiff = ixs->cur_mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_xmit_encap_bundle_2: "
++                  "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
++                  ixs->cur_mtu, ixs->physmtu,
++                  ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len));
++      if(ixs->cur_mtu == 0 || ixs->mtudiff > 0) {
++              int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5);
++
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_info:ipsec_xmit_encap_bundle_2: "
++                          "dev %s mtu of %d decreased by %d to %d\n",
++                          ixs->dev ? ixs->dev->name : "ifX",
++                          ixs->cur_mtu,
++                          ixs->cur_mtu - newmtu,
++                          newmtu);
++              ixs->cur_mtu = newmtu;
++
++              /* this would seem to adjust the MTU of the route as well */
++#if 0
++              ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */
++#endif /* 0 */
++      }
++
++      /* 
++         If the sender is doing PMTU discovery, and the
++         packet doesn't fit within ixs->prv->mtu, notify him
++         (unless it was an ICMP packet, or it was not the
++         zero-offset packet) and send it anyways.
++
++         Note: buggy firewall configuration may prevent the
++         ICMP packet from getting back.
++      */
++      if(sysctl_ipsec_icmp
++         && ixs->cur_mtu < ntohs(ixs->iph->tot_len)
++         && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) {
++              int notify = ixs->iph->protocol != IPPROTO_ICMP
++                      && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0;
++                      
++#ifdef IPSEC_obey_DF
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "fragmentation needed and DF set; %sdropping packet\n",
++                          notify ? "sending ICMP and " : "");
++              if (notify)
++                      ICMP_SEND(ixs->skb,
++                                ICMP_DEST_UNREACH,
++                                ICMP_FRAG_NEEDED,
++                                ixs->cur_mtu,
++                                ixs->physdev);
++              ixs->stats->tx_errors++;
++              bundle_stat = IPSEC_XMIT_CANNOTFRAG;
++              goto cleanup;
++#else /* IPSEC_obey_DF */
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "fragmentation needed and DF set; %spassing packet\n",
++                          notify ? "sending ICMP and " : "");
++              if (notify)
++                      ICMP_SEND(ixs->skb,
++                                ICMP_DEST_UNREACH,
++                                ICMP_FRAG_NEEDED,
++                                ixs->cur_mtu,
++                                ixs->physdev);
++#endif /* IPSEC_obey_DF */
++      }
++              
++#ifdef MSS_HACK
++      /*
++       * If this is a transport mode TCP packet with
++       * SYN set, determine an effective MSS based on 
++       * AH/ESP overheads determined above.
++       */
++      if (ixs->iph->protocol == IPPROTO_TCP 
++          && ixs->outgoing_said.proto != IPPROTO_IPIP) {
++              struct tcphdr *tcph = ixs->skb->h.th;
++              if (tcph->syn && !tcph->ack) {
++                      if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->cur_mtu)) {
++                              printk(KERN_WARNING
++                                     "klips_warning:ipsec_xmit_encap_bundle_2: "
++                                     "ipsec_adjust_mss() failed\n");
++                              ixs->stats->tx_errors++;
++                              bundle_stat = IPSEC_XMIT_MSSERR;
++                              goto cleanup;
++                      }
++              }
++      }
++#endif /* MSS_HACK */
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) {
++            /**
++             * NAT-Traversal and Transport Mode:
++             *   we need to force destination address to sane value
++             */
++
++            struct sockaddr_in *sv4=(struct sockaddr_in *)ixs->ipsp->ips_addr_d;
++            __u32 natt_d = sv4->sin_addr.s_addr;
++            struct iphdr *ipp = ixs->iph;
++
++            /* set the destination address to what it needs to be for the
++             * NAT encapsulation.
++             */
++            KLIPS_PRINT(debug_tunnel,
++                        "xmit: setting ND=%08x\n", natt_d);
++            ipp->daddr = natt_d;
++            ipp->check = 0;
++            ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
++      }
++#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
++
++      if(!ixs->hard_header_stripped && ixs->hard_header_len>0) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "allocating %d bytes for hardheader.\n",
++                          ixs->hard_header_len);
++              if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) {
++                      printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle_2: "
++                             "Failed, tried to allocate %d bytes for temp hard_header.\n", 
++                             ixs->hard_header_len);
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_ERRMEMALLOC;
++                      goto cleanup;
++              }
++              {
++                      int i;
++                      for (i = 0; i < ixs->hard_header_len; i++) {
++                              ixs->saved_header[i] = ixs->skb->data[i];
++                      }
++              }
++              if(ixs->skb->len < ixs->hard_header_len) {
++                      printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle_2: "
++                             "tried to skb_pull hhlen=%d, %d available.  This should never happen, please report.\n",
++                             ixs->hard_header_len, (int)(ixs->skb->len));
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR;
++                      goto cleanup;
++              }
++              skb_pull(ixs->skb, ixs->hard_header_len);
++              ixs->hard_header_stripped = 1;
++                      
++/*                    ixs->iph = (struct iphdr *) (ixs->skb->data); */
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "head,tailroom: %d,%d after hard_header stripped.\n",
++                          skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
++              KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph);
++      } else {
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "hard header already stripped.\n");
++      }
++              
++      ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15;
++
++      if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) && 
++          (skb_tailroom(ixs->skb) >= ixs->max_tailroom)
++#ifndef NET_21
++          && ixs->skb->free
++#endif /* !NET_21 */
++              ) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "data fits in existing skb\n");
++      } else {
++              struct sk_buff* tskb;
++
++              if(!ixs->oskb) {
++                      ixs->oskb = ixs->skb;
++              }
++
++              tskb = skb_copy_expand(ixs->skb,
++                                     /* The need for 2 * link layer length here remains unexplained...RGB */
++                                     ixs->max_headroom + 2 * ixs->ll_headroom,
++                                     ixs->max_tailroom,
++                                     GFP_ATOMIC);
++
++              if(tskb && ixs->skb->sk) {
++                      skb_set_owner_w(tskb, ixs->skb->sk);
++              }
++
++              if(ixs->skb != ixs->oskb) {
++                      ipsec_kfree_skb(ixs->skb);
++              }
++              ixs->skb = tskb;
++              if (!ixs->skb) {
++                      printk(KERN_WARNING
++                             "klips_debug:ipsec_xmit_encap_bundle_2: "
++                             "Failed, tried to allocate %d head and %d tailroom\n", 
++                             ixs->max_headroom, ixs->max_tailroom);
++                      ixs->stats->tx_errors++;
++                      bundle_stat = IPSEC_XMIT_ERRSKBALLOC;
++                      goto cleanup;
++              }
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_xmit_encap_bundle_2: "
++                          "head,tailroom: %d,%d after allocation\n",
++                          skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
++      }
++              
++#ifdef CONFIG_KLIPS_DEBUG
++      if(debug_tunnel & DB_TN_ENCAP) {
++              ipsec_print_ip(ixs->iph);
++      }
++#endif
++
++cleanup:
++      return bundle_stat;
++}
++
++void
++ipsec_xmit_cleanup(struct ipsec_xmit_state*ixs)
++{
++      if(ixs->dev) {
++#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
++              netif_wake_queue(ixs->dev);
++#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
++              ixs->dev->tbusy = 0;
++#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
++      }
++
++      if(ixs->saved_header) {
++              kfree(ixs->saved_header);
++              ixs->saved_header = NULL;
++      }
++      if(ixs->skb) {
++              dev_kfree_skb(ixs->skb);
++              ixs->skb=NULL;
++      }
++      if(ixs->oskb) {
++              dev_kfree_skb(ixs->oskb);
++              ixs->oskb=NULL;
++      }
++      if (ixs->ips.ips_ident_s.data) {
++              kfree(ixs->ips.ips_ident_s.data);
++              ixs->ips.ips_ident_s.data=NULL;
++      }
++      if (ixs->ips.ips_ident_d.data) {
++              kfree(ixs->ips.ips_ident_d.data);
++              ixs->ips.ips_ident_d.data=NULL;
++      }
++}
++
++#ifdef NETDEV_23
++static inline int ipsec_xmit_send2(struct sk_buff *skb)
++{
++#ifdef NETDEV_25      /* 2.6 kernels */
++      return dst_output(skb);
++#else
++      return ip_send(skb);
++#endif
++}
++#endif /* NETDEV_23 */
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++enum ipsec_xmit_value ipsec_nat_encap(struct ipsec_xmit_state *ixs)
++{
++      if (ixs->natt_type && ixs->natt_head) {
++              struct iphdr *ipp = ip_hdr(ixs->skb);
++              struct udphdr *udp;
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "encapsuling packet into UDP (NAT-Traversal) (%d %d)\n",
++                          ixs->natt_type, ixs->natt_head);
++
++              ixs->iphlen = ipp->ihl << 2;
++              ipp->tot_len =
++                      htons(ntohs(ipp->tot_len) + ixs->natt_head);
++              if(skb_tailroom(ixs->skb) < ixs->natt_head) {
++                      printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                              "tried to skb_put %d, %d available. "
++                              "This should never happen, please report.\n",
++                              ixs->natt_head,
++                              skb_tailroom(ixs->skb));
++                      ixs->stats->tx_errors++;
++                      return IPSEC_XMIT_ESPUDP;
++              }
++              skb_put(ixs->skb, ixs->natt_head);
++
++              udp = (struct udphdr *)((char *)ipp + ixs->iphlen);
++
++              /* move ESP hdr after UDP hdr */
++              memmove((void *)((char *)udp + ixs->natt_head),
++                      (void *)(udp),
++                      ntohs(ipp->tot_len) - ixs->iphlen - ixs->natt_head);
++
++#if 0
++              /* set IP destination address (matters in transport mode) */
++              {
++                struct sockaddr_in *d = (struct sockaddr_in *)ixs->ipsp->ips_addr_d;
++                ipp->daddr = d->sin_addr.s_addr;
++              }
++#endif
++
++              /* clear UDP & Non-IKE Markers (if any) */
++              memset(udp, 0, ixs->natt_head);
++
++              /* fill UDP with usefull informations ;-) */
++              udp->source = htons(ixs->natt_sport);
++              udp->dest = htons(ixs->natt_dport);
++              udp->len = htons(ntohs(ipp->tot_len) - ixs->iphlen);
++
++              /* set protocol */
++              ipp->protocol = IPPROTO_UDP;
++
++              /* fix IP checksum */
++              ipp->check = 0;
++              ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
++      }
++      return IPSEC_XMIT_OK;
++}
++#endif
++
++
++/* avoid forward reference complain on <2.5 */
++struct flowi;
++
++enum ipsec_xmit_value
++ipsec_xmit_send(struct ipsec_xmit_state*ixs, struct flowi *fl)
++{
++      int error;
++  
++#ifdef NETDEV_25
++      fl->nl_u.ip4_u.daddr = ip_hdr(ixs->skb)->daddr;
++      fl->nl_u.ip4_u.saddr = ixs->pass ? 0 : ip_hdr(ixs->skb)->saddr;
++      fl->nl_u.ip4_u.tos = RT_TOS(ip_hdr(ixs->skb)->tos);
++      fl->proto = ip_hdr(ixs->skb)->protocol;
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
++      error = ip_route_output_key(&ixs->route, &fl);
++#else
++      error = ip_route_output_key(&init_net, &ixs->route, fl);
++#endif
++      if (error) {
++
++#else
++      /*skb_orphan(ixs->skb);*/
++      if((error = ip_route_output(&ixs->route,
++                                  ip_hdr(ixs->skb)->daddr,
++                                  ixs->pass ? 0 : ip_hdr(ixs->skb)->saddr,
++                                  RT_TOS(ip_hdr(ixs->skb)->tos),
++                                    /* mcr->rgb: should this be 0 instead? */
++                                  ixs->physdev->iflink))) {
++#endif
++              ixs->stats->tx_errors++;
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_send: "
++                          "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
++                          error,
++                          ixs->route->u.dst.dev->name);
++              return IPSEC_XMIT_ROUTEERR;
++      }
++
++      if(ixs->dev == ixs->route->u.dst.dev) {
++              ip_rt_put(ixs->route);
++              /* This is recursion, drop it. */
++              ixs->stats->tx_errors++;
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_xmit_send: "
++                          "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
++                          ixs->dev->name);
++              return IPSEC_XMIT_RECURSDETECT;
++      }
++
++      dst_release(ixs->skb->dst);
++      ixs->skb->dst = &ixs->route->u.dst;
++      if(ixs->stats) {
++              ixs->stats->tx_bytes += ixs->skb->len;
++      }
++
++      if(ixs->skb->len < skb_network_header(ixs->skb) - ixs->skb->data) {
++              if(ixs->stats) {
++                      ixs->stats->tx_errors++;
++              }
++              printk(KERN_WARNING
++                     "klips_error:ipsec_xmit_send: "
++                     "tried to __skb_pull nh-data=%ld, %d available.  This should never happen, please report.\n",
++                     (unsigned long)(skb_network_header(ixs->skb) - ixs->skb->data),
++                     ixs->skb->len);
++              return IPSEC_XMIT_PUSHPULLERR;
++      }
++      __skb_pull(ixs->skb, skb_network_header(ixs->skb) - ixs->skb->data);
++      if(!ixs->pass) {
++              ipsec_nf_reset(ixs->skb);
++      }
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "klips_debug:ipsec_xmit_send: "
++                  "...done, calling ip_send() on device:%s\n",
++                  ixs->skb->dev ? ixs->skb->dev->name : "NULL");
++      KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ip_hdr(ixs->skb));
++#ifdef NETDEV_23      /* 2.4 kernels */
++      {
++              int err;
++
++/* XXX huh, we include linux/netfilter_ipv4.h where NF_IP_LOCAL_OUT is defined as 3 */
++#ifndef NF_IP_LOCAL_OUT
++#warning I dont understand why NF_IP_LOCAL_OUT is undefined when including linux/netfilter_ipv4.h
++#define NF_IP_LOCAL_OUT 3
++#endif
++              err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL,
++                            ixs->route->u.dst.dev,
++                            ipsec_xmit_send2);
++              if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
++                      if(net_ratelimit())
++                              printk(KERN_ERR
++                                     "klips_error:ipsec_xmit_send: "
++                                     "ip_send() failed, err=%d\n", 
++                                     -err);
++                      if(ixs->stats) {
++                              ixs->stats->tx_errors++;
++                              ixs->stats->tx_aborted_errors++;
++                      }
++                      ixs->skb = NULL;
++                      return IPSEC_XMIT_IPSENDFAILURE;
++              }
++      }
++#else /* NETDEV_23 */ /* 2.2 kernels */
++      ip_send(ixs->skb);
++#endif /* NETDEV_23 */
++      if(ixs->stats) {
++              ixs->stats->tx_packets++;
++      }
++
++      ixs->skb = NULL;
++      
++      return IPSEC_XMIT_OK;
++}
++
++#ifdef NETDEV_25
++enum ipsec_xmit_value
++ipsec_tunnel_send(struct ipsec_xmit_state *ixs)
++{
++      struct flowi fl;
++      memset(&fl, 0, sizeof(fl));
++
++      /* new route/dst cache code from James Morris */
++      ixs->skb->dev = ixs->physdev;
++      fl.oif = ixs->physdev->iflink;
++
++      return ipsec_xmit_send(ixs, &fl);
++}
++#else
++enum ipsec_xmit_value
++ipsec_tunnel_send(struct ipsec_xmit_state *ixs)
++{
++      return ipsec_xmit_send(ixs, NULL);
++}
++#endif
++
++
++/*
++ * here is a state machine to handle encapsulation
++ * basically we keep getting re-entered until processing is
++ * complete.  For the simple case we step down the states and finish.
++ * each state is ideally some logical part of the process.  If a state
++ * can pend (ie., require async processing to complete),  then this
++ * should be the part of last action before it returns IPSEC_RCV_PENDING
++ *
++ * Any particular action may alter the next_state in ixs to move us to
++ * a state other than the preferred "next_state",  but this is the
++ * exception and is highlighted when it is done.
++ *
++ * prototypes for state action
++ */
++
++struct {
++      enum ipsec_xmit_value (*action)(struct ipsec_xmit_state *ixs);
++      int next_state;
++} xmit_state_table[] = {
++      [IPSEC_XSM_INIT1]       = {ipsec_xmit_init1,       IPSEC_XSM_INIT2 },
++      [IPSEC_XSM_INIT2]       = {ipsec_xmit_init2,       IPSEC_XSM_ENCAP_INIT },
++      [IPSEC_XSM_ENCAP_INIT]  = {ipsec_xmit_encap_init,  IPSEC_XSM_ENCAP_SELECT },
++      [IPSEC_XSM_ENCAP_SELECT]= {ipsec_xmit_encap_select,IPSEC_XSM_DONE },
++
++#ifdef CONFIG_KLIPS_ESP
++      [IPSEC_XSM_ESP]         = {ipsec_xmit_esp,         IPSEC_XSM_ESP_AH },
++      [IPSEC_XSM_ESP_AH]      = {ipsec_xmit_esp_ah,      IPSEC_XSM_CONT },
++#endif
++
++#ifdef CONFIG_KLIPS_AH
++      [IPSEC_XSM_AH]          = {ipsec_xmit_ah,          IPSEC_XSM_CONT },
++#endif
++
++#ifdef CONFIG_KLIPS_IPIP
++      [IPSEC_XSM_IPIP]        = {ipsec_xmit_ipip,        IPSEC_XSM_CONT },
++#endif
++
++#ifdef CONFIG_KLIPS_IPCOMP
++      [IPSEC_XSM_IPCOMP]      = {ipsec_xmit_ipcomp,      IPSEC_XSM_CONT },
++#endif
++
++      [IPSEC_XSM_CONT]        = {ipsec_xmit_cont,        IPSEC_XSM_DONE },
++      [IPSEC_XSM_DONE]        = {NULL,                   IPSEC_XSM_DONE},
++};
++
++
++
++void
++ipsec_xsm(struct ipsec_xmit_state *ixs)
++{
++      enum ipsec_xmit_value stat = IPSEC_XMIT_ENCAPFAIL;
++
++      if (ixs == NULL) {
++              KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xsm: ixs == NULL.\n");
++              return;
++      }
++
++      /*
++       * make sure nothing is removed from underneath us
++       */
++      spin_lock_bh(&tdb_lock);
++
++      /*
++       * if we have a valid said,  then we must check it here to ensure it
++       * hasn't gone away while we were waiting for a task to complete
++       */
++
++      if (ixs->ipsp && ipsec_sa_getbyid(&ixs->outgoing_said) == NULL) {
++              KLIPS_PRINT(debug_tunnel,
++                          "klips_debug:ipsec_xsm: "
++                          "no ipsec_sa for SA:%s: outgoing packet with no SA dropped\n",
++                          ixs->sa_len ? ixs->sa_txt : " (error)");
++              if (ixs->stats)
++                      ixs->stats->tx_dropped++;
++
++              /* drop through and cleanup */
++              stat = IPSEC_XMIT_SAIDNOTFOUND;
++              ixs->state = IPSEC_XSM_DONE;
++      }
++
++      while (ixs->state != IPSEC_XSM_DONE) {
++
++              ixs->next_state = xmit_state_table[ixs->state].next_state;
++
++              stat = xmit_state_table[ixs->state].action(ixs);
++
++              if (stat == IPSEC_XMIT_OK) {
++                      /* some functions change the next state, see the state table */
++                      ixs->state = ixs->next_state;
++              } else if (stat == IPSEC_XMIT_PENDING) {
++                      /*
++                       * things are on hold until we return here in the next/new state
++                       * we check our SA is valid when we return
++                       */
++                      spin_unlock_bh(&tdb_lock);
++                      return;
++              } else {
++                      /* bad result, force state change to done */
++                      KLIPS_PRINT(debug_tunnel,
++                                      "klips_debug:ipsec_xsm: "
++                                      "processing completed due to %s.\n",
++                                      ipsec_xmit_err(stat));
++                      ixs->state = IPSEC_XSM_DONE;
++              }
++      }
++
++      /*
++       * all done with anything needing locks
++       */
++      spin_unlock_bh(&tdb_lock);
++
++      /* we are done with this SA */
++      if (ixs->ipsp) {
++              ipsec_sa_put(ixs->ipsp); 
++              ixs->ipsp = NULL;
++      }
++
++      /*
++       * let the caller continue with their processing
++       */
++      ixs->xsm_complete(ixs, stat);
++}
++
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/match586.S     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,357 @@
++/* match.s -- Pentium-optimized version of longest_match()
++ * Written for zlib 1.1.2
++ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License.
++ */
++
++#ifndef NO_UNDERLINE
++#define       match_init      _ipcomp_match_init
++#define       longest_match   _ipcomp_longest_match
++#else
++#define match_init    ipcomp_match_init
++#define longest_match ipcomp_longest_match
++#endif
++
++#define       MAX_MATCH       (258)
++#define       MIN_MATCH       (3)
++#define       MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
++#define       MAX_MATCH_8     ((MAX_MATCH + 7) & ~7)
++
++/* stack frame offsets */
++
++#define       wmask                   0       /* local copy of s->wmask       */
++#define       window                  4       /* local copy of s->window      */
++#define       windowbestlen           8       /* s->window + bestlen          */
++#define       chainlenscanend         12      /* high word: current chain len */
++                                      /* low word: last bytes sought  */
++#define       scanstart               16      /* first two bytes of string    */
++#define       scanalign               20      /* dword-misalignment of string */
++#define       nicematch               24      /* a good enough match size     */
++#define       bestlen                 28      /* size of best match so far    */
++#define       scan                    32      /* ptr to string wanting match  */
++
++#define       LocalVarsSize           (36)
++/*    saved ebx               36 */
++/*    saved edi               40 */
++/*    saved esi               44 */
++/*    saved ebp               48 */
++/*    return address          52 */
++#define       deflatestate            56      /* the function arguments       */
++#define       curmatch                60
++
++/* Offsets for fields in the deflate_state structure. These numbers
++ * are calculated from the definition of deflate_state, with the
++ * assumption that the compiler will dword-align the fields. (Thus,
++ * changing the definition of deflate_state could easily cause this
++ * program to crash horribly, without so much as a warning at
++ * compile time. Sigh.)
++ */
++#define       dsWSize                 36
++#define       dsWMask                 44
++#define       dsWindow                48
++#define       dsPrev                  56
++#define       dsMatchLen              88
++#define       dsPrevMatch             92
++#define       dsStrStart              100
++#define       dsMatchStart            104
++#define       dsLookahead             108
++#define       dsPrevLen               112
++#define       dsMaxChainLen           116
++#define       dsGoodMatch             132
++#define       dsNiceMatch             136
++
++
++.file "match.S"
++
++.globl        match_init, longest_match
++
++.text
++
++/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
++
++longest_match:
++
++/* Save registers that the compiler may be using, and adjust %esp to  */
++/* make room for our stack frame.                                     */
++
++              pushl   %ebp
++              pushl   %edi
++              pushl   %esi
++              pushl   %ebx
++              subl    $LocalVarsSize, %esp
++
++/* Retrieve the function arguments. %ecx will hold cur_match          */
++/* throughout the entire function. %edx will hold the pointer to the  */
++/* deflate_state structure during the function's setup (before                */
++/* entering the main loop).                                           */
++
++              movl    deflatestate(%esp), %edx
++              movl    curmatch(%esp), %ecx
++
++/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;    */
++
++              movl    dsNiceMatch(%edx), %eax
++              movl    dsLookahead(%edx), %ebx
++              cmpl    %eax, %ebx
++              jl      LookaheadLess
++              movl    %eax, %ebx
++LookaheadLess:        movl    %ebx, nicematch(%esp)
++
++/* register Bytef *scan = s->window + s->strstart;                    */
++
++              movl    dsWindow(%edx), %esi
++              movl    %esi, window(%esp)
++              movl    dsStrStart(%edx), %ebp
++              lea     (%esi,%ebp), %edi
++              movl    %edi, scan(%esp)
++
++/* Determine how many bytes the scan ptr is off from being            */
++/* dword-aligned.                                                     */
++
++              movl    %edi, %eax
++              negl    %eax
++              andl    $3, %eax
++              movl    %eax, scanalign(%esp)
++
++/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ?                     */
++/*     s->strstart - (IPos)MAX_DIST(s) : NIL;                         */
++
++              movl    dsWSize(%edx), %eax
++              subl    $MIN_LOOKAHEAD, %eax
++              subl    %eax, %ebp
++              jg      LimitPositive
++              xorl    %ebp, %ebp
++LimitPositive:
++
++/* unsigned chain_length = s->max_chain_length;                               */
++/* if (s->prev_length >= s->good_match) {                             */
++/*     chain_length >>= 2;                                            */
++/* }                                                                  */
++
++              movl    dsPrevLen(%edx), %eax
++              movl    dsGoodMatch(%edx), %ebx
++              cmpl    %ebx, %eax
++              movl    dsMaxChainLen(%edx), %ebx
++              jl      LastMatchGood
++              shrl    $2, %ebx
++LastMatchGood:
++
++/* chainlen is decremented once beforehand so that the function can   */
++/* use the sign flag instead of the zero flag for the exit test.      */
++/* It is then shifted into the high word, to make room for the scanend        */
++/* scanend value, which it will always accompany.                     */
++
++              decl    %ebx
++              shll    $16, %ebx
++
++/* int best_len = s->prev_length;                                     */
++
++              movl    dsPrevLen(%edx), %eax
++              movl    %eax, bestlen(%esp)
++
++/* Store the sum of s->window + best_len in %esi locally, and in %esi.        */
++
++              addl    %eax, %esi
++              movl    %esi, windowbestlen(%esp)
++
++/* register ush scan_start = *(ushf*)scan;                            */
++/* register ush scan_end   = *(ushf*)(scan+best_len-1);                       */
++
++              movw    (%edi), %bx
++              movw    %bx, scanstart(%esp)
++              movw    -1(%edi,%eax), %bx
++              movl    %ebx, chainlenscanend(%esp)
++
++/* Posf *prev = s->prev;                                              */
++/* uInt wmask = s->w_mask;                                            */
++
++              movl    dsPrev(%edx), %edi
++              movl    dsWMask(%edx), %edx
++              mov     %edx, wmask(%esp)
++
++/* Jump into the main loop.                                           */
++
++              jmp     LoopEntry
++
++.balign 16
++
++/* do {
++ *     match = s->window + cur_match;
++ *     if (*(ushf*)(match+best_len-1) != scan_end ||
++ *         *(ushf*)match != scan_start) continue;
++ *     [...]
++ * } while ((cur_match = prev[cur_match & wmask]) > limit
++ *          && --chain_length != 0);
++ *
++ * Here is the inner loop of the function. The function will spend the
++ * majority of its time in this loop, and majority of that time will
++ * be spent in the first ten instructions.
++ *
++ * Within this loop:
++ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
++ * %ecx = curmatch
++ * %edx = curmatch & wmask
++ * %esi = windowbestlen - i.e., (window + bestlen)
++ * %edi = prev
++ * %ebp = limit
++ *
++ * Two optimization notes on the choice of instructions:
++ *
++ * The first instruction uses a 16-bit address, which costs an extra,
++ * unpairable cycle. This is cheaper than doing a 32-bit access and
++ * zeroing the high word, due to the 3-cycle misalignment penalty which
++ * would occur half the time. This also turns out to be cheaper than
++ * doing two separate 8-bit accesses, as the memory is so rarely in the
++ * L1 cache.
++ *
++ * The window buffer, however, apparently spends a lot of time in the
++ * cache, and so it is faster to retrieve the word at the end of the
++ * match string with two 8-bit loads. The instructions that test the
++ * word at the beginning of the match string, however, are executed
++ * much less frequently, and there it was cheaper to use 16-bit
++ * instructions, which avoided the necessity of saving off and
++ * subsequently reloading one of the other registers.
++ */
++LookupLoop:
++                                                      /* 1 U & V  */
++              movw    (%edi,%edx,2), %cx              /* 2 U pipe */
++              movl    wmask(%esp), %edx               /* 2 V pipe */
++              cmpl    %ebp, %ecx                      /* 3 U pipe */
++              jbe     LeaveNow                        /* 3 V pipe */
++              subl    $0x00010000, %ebx               /* 4 U pipe */
++              js      LeaveNow                        /* 4 V pipe */
++LoopEntry:    movb    -1(%esi,%ecx), %al              /* 5 U pipe */
++              andl    %ecx, %edx                      /* 5 V pipe */
++              cmpb    %bl, %al                        /* 6 U pipe */
++              jnz     LookupLoop                      /* 6 V pipe */
++              movb    (%esi,%ecx), %ah
++              cmpb    %bh, %ah
++              jnz     LookupLoop
++              movl    window(%esp), %eax
++              movw    (%eax,%ecx), %ax
++              cmpw    scanstart(%esp), %ax
++              jnz     LookupLoop
++
++/* Store the current value of chainlen.                                       */
++
++              movl    %ebx, chainlenscanend(%esp)
++
++/* Point %edi to the string under scrutiny, and %esi to the string we */
++/* are hoping to match it up with. In actuality, %esi and %edi are    */
++/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is    */
++/* initialized to -(MAX_MATCH_8 - scanalign).                         */
++
++              movl    window(%esp), %esi
++              movl    scan(%esp), %edi
++              addl    %ecx, %esi
++              movl    scanalign(%esp), %eax
++              movl    $(-MAX_MATCH_8), %edx
++              lea     MAX_MATCH_8(%edi,%eax), %edi
++              lea     MAX_MATCH_8(%esi,%eax), %esi
++
++/* Test the strings for equality, 8 bytes at a time. At the end,
++ * adjust %edx so that it is offset to the exact byte that mismatched.
++ *
++ * We already know at this point that the first three bytes of the
++ * strings match each other, and they can be safely passed over before
++ * starting the compare loop. So what this code does is skip over 0-3
++ * bytes, as much as necessary in order to dword-align the %edi
++ * pointer. (%esi will still be misaligned three times out of four.)
++ *
++ * It should be confessed that this loop usually does not represent
++ * much of the total running time. Replacing it with a more
++ * straightforward "rep cmpsb" would not drastically degrade
++ * performance.
++ */
++LoopCmps:
++              movl    (%esi,%edx), %eax
++              movl    (%edi,%edx), %ebx
++              xorl    %ebx, %eax
++              jnz     LeaveLoopCmps
++              movl    4(%esi,%edx), %eax
++              movl    4(%edi,%edx), %ebx
++              xorl    %ebx, %eax
++              jnz     LeaveLoopCmps4
++              addl    $8, %edx
++              jnz     LoopCmps
++              jmp     LenMaximum
++LeaveLoopCmps4:       addl    $4, %edx
++LeaveLoopCmps:        testl   $0x0000FFFF, %eax
++              jnz     LenLower
++              addl    $2, %edx
++              shrl    $16, %eax
++LenLower:     subb    $1, %al
++              adcl    $0, %edx
++
++/* Calculate the length of the match. If it is longer than MAX_MATCH, */
++/* then automatically accept it as the best possible match and leave. */
++
++              lea     (%edi,%edx), %eax
++              movl    scan(%esp), %edi
++              subl    %edi, %eax
++              cmpl    $MAX_MATCH, %eax
++              jge     LenMaximum
++
++/* If the length of the match is not longer than the best match we    */
++/* have so far, then forget it and return to the lookup loop.         */
++
++              movl    deflatestate(%esp), %edx
++              movl    bestlen(%esp), %ebx
++              cmpl    %ebx, %eax
++              jg      LongerMatch
++              movl    chainlenscanend(%esp), %ebx
++              movl    windowbestlen(%esp), %esi
++              movl    dsPrev(%edx), %edi
++              movl    wmask(%esp), %edx
++              andl    %ecx, %edx
++              jmp     LookupLoop
++
++/*         s->match_start = cur_match;                                        */
++/*         best_len = len;                                            */
++/*         if (len >= nice_match) break;                              */
++/*         scan_end = *(ushf*)(scan+best_len-1);                      */
++
++LongerMatch:  movl    nicematch(%esp), %ebx
++              movl    %eax, bestlen(%esp)
++              movl    %ecx, dsMatchStart(%edx)
++              cmpl    %ebx, %eax
++              jge     LeaveNow
++              movl    window(%esp), %esi
++              addl    %eax, %esi
++              movl    %esi, windowbestlen(%esp)
++              movl    chainlenscanend(%esp), %ebx
++              movw    -1(%edi,%eax), %bx
++              movl    dsPrev(%edx), %edi
++              movl    %ebx, chainlenscanend(%esp)
++              movl    wmask(%esp), %edx
++              andl    %ecx, %edx
++              jmp     LookupLoop
++
++/* Accept the current string, with the maximum possible length.               */
++
++LenMaximum:   movl    deflatestate(%esp), %edx
++              movl    $MAX_MATCH, bestlen(%esp)
++              movl    %ecx, dsMatchStart(%edx)
++
++/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len;         */
++/* return s->lookahead;                                                       */
++
++LeaveNow:
++              movl    deflatestate(%esp), %edx
++              movl    bestlen(%esp), %ebx
++              movl    dsLookahead(%edx), %eax
++              cmpl    %eax, %ebx
++              jg      LookaheadRet
++              movl    %ebx, %eax
++LookaheadRet:
++
++/* Restore the stack and return from whence we came.                  */
++
++              addl    $LocalVarsSize, %esp
++              popl    %ebx
++              popl    %esi
++              popl    %edi
++              popl    %ebp
++match_init:   ret
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/match686.S     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,330 @@
++/* match.s -- Pentium-Pro-optimized version of longest_match()
++ * Written for zlib 1.1.2
++ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License.
++ */
++
++#ifndef NO_UNDERLINE
++#define       match_init      _ipcomp_match_init
++#define       longest_match   _ipcomp_longest_match
++#else
++#define match_init    ipcomp_match_init
++#define longest_match ipcomp_longest_match
++#endif
++
++#define       MAX_MATCH       (258)
++#define       MIN_MATCH       (3)
++#define       MIN_LOOKAHEAD   (MAX_MATCH + MIN_MATCH + 1)
++#define       MAX_MATCH_8     ((MAX_MATCH + 7) & ~7)
++
++/* stack frame offsets */
++
++#define       chainlenwmask           0       /* high word: current chain len */
++                                      /* low word: s->wmask           */
++#define       window                  4       /* local copy of s->window      */
++#define       windowbestlen           8       /* s->window + bestlen          */
++#define       scanstart               16      /* first two bytes of string    */
++#define       scanend                 12      /* last two bytes of string     */
++#define       scanalign               20      /* dword-misalignment of string */
++#define       nicematch               24      /* a good enough match size     */
++#define       bestlen                 28      /* size of best match so far    */
++#define       scan                    32      /* ptr to string wanting match  */
++
++#define       LocalVarsSize           (36)
++/*    saved ebx               36 */
++/*    saved edi               40 */
++/*    saved esi               44 */
++/*    saved ebp               48 */
++/*    return address          52 */
++#define       deflatestate            56      /* the function arguments       */
++#define       curmatch                60
++
++/* Offsets for fields in the deflate_state structure. These numbers
++ * are calculated from the definition of deflate_state, with the
++ * assumption that the compiler will dword-align the fields. (Thus,
++ * changing the definition of deflate_state could easily cause this
++ * program to crash horribly, without so much as a warning at
++ * compile time. Sigh.)
++ */
++#define       dsWSize                 36
++#define       dsWMask                 44
++#define       dsWindow                48
++#define       dsPrev                  56
++#define       dsMatchLen              88
++#define       dsPrevMatch             92
++#define       dsStrStart              100
++#define       dsMatchStart            104
++#define       dsLookahead             108
++#define       dsPrevLen               112
++#define       dsMaxChainLen           116
++#define       dsGoodMatch             132
++#define       dsNiceMatch             136
++
++
++.file "match.S"
++
++.globl        match_init, longest_match
++
++.text
++
++/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
++
++longest_match:
++
++/* Save registers that the compiler may be using, and adjust %esp to  */
++/* make room for our stack frame.                                     */
++
++              pushl   %ebp
++              pushl   %edi
++              pushl   %esi
++              pushl   %ebx
++              subl    $LocalVarsSize, %esp
++
++/* Retrieve the function arguments. %ecx will hold cur_match          */
++/* throughout the entire function. %edx will hold the pointer to the  */
++/* deflate_state structure during the function's setup (before                */
++/* entering the main loop).                                           */
++
++              movl    deflatestate(%esp), %edx
++              movl    curmatch(%esp), %ecx
++
++/* uInt wmask = s->w_mask;                                            */
++/* unsigned chain_length = s->max_chain_length;                               */
++/* if (s->prev_length >= s->good_match) {                             */
++/*     chain_length >>= 2;                                            */
++/* }                                                                  */
++
++              movl    dsPrevLen(%edx), %eax
++              movl    dsGoodMatch(%edx), %ebx
++              cmpl    %ebx, %eax
++              movl    dsWMask(%edx), %eax
++              movl    dsMaxChainLen(%edx), %ebx
++              jl      LastMatchGood
++              shrl    $2, %ebx
++LastMatchGood:
++
++/* chainlen is decremented once beforehand so that the function can   */
++/* use the sign flag instead of the zero flag for the exit test.      */
++/* It is then shifted into the high word, to make room for the wmask  */
++/* value, which it will always accompany.                             */
++
++              decl    %ebx
++              shll    $16, %ebx
++              orl     %eax, %ebx
++              movl    %ebx, chainlenwmask(%esp)
++
++/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;    */
++
++              movl    dsNiceMatch(%edx), %eax
++              movl    dsLookahead(%edx), %ebx
++              cmpl    %eax, %ebx
++              jl      LookaheadLess
++              movl    %eax, %ebx
++LookaheadLess:        movl    %ebx, nicematch(%esp)
++
++/* register Bytef *scan = s->window + s->strstart;                    */
++
++              movl    dsWindow(%edx), %esi
++              movl    %esi, window(%esp)
++              movl    dsStrStart(%edx), %ebp
++              lea     (%esi,%ebp), %edi
++              movl    %edi, scan(%esp)
++
++/* Determine how many bytes the scan ptr is off from being            */
++/* dword-aligned.                                                     */
++
++              movl    %edi, %eax
++              negl    %eax
++              andl    $3, %eax
++              movl    %eax, scanalign(%esp)
++
++/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ?                     */
++/*     s->strstart - (IPos)MAX_DIST(s) : NIL;                         */
++
++              movl    dsWSize(%edx), %eax
++              subl    $MIN_LOOKAHEAD, %eax
++              subl    %eax, %ebp
++              jg      LimitPositive
++              xorl    %ebp, %ebp
++LimitPositive:
++
++/* int best_len = s->prev_length;                                     */
++
++              movl    dsPrevLen(%edx), %eax
++              movl    %eax, bestlen(%esp)
++
++/* Store the sum of s->window + best_len in %esi locally, and in %esi.        */
++
++              addl    %eax, %esi
++              movl    %esi, windowbestlen(%esp)
++
++/* register ush scan_start = *(ushf*)scan;                            */
++/* register ush scan_end   = *(ushf*)(scan+best_len-1);                       */
++/* Posf *prev = s->prev;                                              */
++
++              movzwl  (%edi), %ebx
++              movl    %ebx, scanstart(%esp)
++              movzwl  -1(%edi,%eax), %ebx
++              movl    %ebx, scanend(%esp)
++              movl    dsPrev(%edx), %edi
++
++/* Jump into the main loop.                                           */
++
++              movl    chainlenwmask(%esp), %edx
++              jmp     LoopEntry
++
++.balign 16
++
++/* do {
++ *     match = s->window + cur_match;
++ *     if (*(ushf*)(match+best_len-1) != scan_end ||
++ *         *(ushf*)match != scan_start) continue;
++ *     [...]
++ * } while ((cur_match = prev[cur_match & wmask]) > limit
++ *          && --chain_length != 0);
++ *
++ * Here is the inner loop of the function. The function will spend the
++ * majority of its time in this loop, and majority of that time will
++ * be spent in the first ten instructions.
++ *
++ * Within this loop:
++ * %ebx = scanend
++ * %ecx = curmatch
++ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
++ * %esi = windowbestlen - i.e., (window + bestlen)
++ * %edi = prev
++ * %ebp = limit
++ */
++LookupLoop:
++              andl    %edx, %ecx
++              movzwl  (%edi,%ecx,2), %ecx
++              cmpl    %ebp, %ecx
++              jbe     LeaveNow
++              subl    $0x00010000, %edx
++              js      LeaveNow
++LoopEntry:    movzwl  -1(%esi,%ecx), %eax
++              cmpl    %ebx, %eax
++              jnz     LookupLoop
++              movl    window(%esp), %eax
++              movzwl  (%eax,%ecx), %eax
++              cmpl    scanstart(%esp), %eax
++              jnz     LookupLoop
++
++/* Store the current value of chainlen.                                       */
++
++              movl    %edx, chainlenwmask(%esp)
++
++/* Point %edi to the string under scrutiny, and %esi to the string we */
++/* are hoping to match it up with. In actuality, %esi and %edi are    */
++/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is    */
++/* initialized to -(MAX_MATCH_8 - scanalign).                         */
++
++              movl    window(%esp), %esi
++              movl    scan(%esp), %edi
++              addl    %ecx, %esi
++              movl    scanalign(%esp), %eax
++              movl    $(-MAX_MATCH_8), %edx
++              lea     MAX_MATCH_8(%edi,%eax), %edi
++              lea     MAX_MATCH_8(%esi,%eax), %esi
++
++/* Test the strings for equality, 8 bytes at a time. At the end,
++ * adjust %edx so that it is offset to the exact byte that mismatched.
++ *
++ * We already know at this point that the first three bytes of the
++ * strings match each other, and they can be safely passed over before
++ * starting the compare loop. So what this code does is skip over 0-3
++ * bytes, as much as necessary in order to dword-align the %edi
++ * pointer. (%esi will still be misaligned three times out of four.)
++ *
++ * It should be confessed that this loop usually does not represent
++ * much of the total running time. Replacing it with a more
++ * straightforward "rep cmpsb" would not drastically degrade
++ * performance.
++ */
++LoopCmps:
++              movl    (%esi,%edx), %eax
++              xorl    (%edi,%edx), %eax
++              jnz     LeaveLoopCmps
++              movl    4(%esi,%edx), %eax
++              xorl    4(%edi,%edx), %eax
++              jnz     LeaveLoopCmps4
++              addl    $8, %edx
++              jnz     LoopCmps
++              jmp     LenMaximum
++LeaveLoopCmps4:       addl    $4, %edx
++LeaveLoopCmps:        testl   $0x0000FFFF, %eax
++              jnz     LenLower
++              addl    $2, %edx
++              shrl    $16, %eax
++LenLower:     subb    $1, %al
++              adcl    $0, %edx
++
++/* Calculate the length of the match. If it is longer than MAX_MATCH, */
++/* then automatically accept it as the best possible match and leave. */
++
++              lea     (%edi,%edx), %eax
++              movl    scan(%esp), %edi
++              subl    %edi, %eax
++              cmpl    $MAX_MATCH, %eax
++              jge     LenMaximum
++
++/* If the length of the match is not longer than the best match we    */
++/* have so far, then forget it and return to the lookup loop.         */
++
++              movl    deflatestate(%esp), %edx
++              movl    bestlen(%esp), %ebx
++              cmpl    %ebx, %eax
++              jg      LongerMatch
++              movl    windowbestlen(%esp), %esi
++              movl    dsPrev(%edx), %edi
++              movl    scanend(%esp), %ebx
++              movl    chainlenwmask(%esp), %edx
++              jmp     LookupLoop
++
++/*         s->match_start = cur_match;                                        */
++/*         best_len = len;                                            */
++/*         if (len >= nice_match) break;                              */
++/*         scan_end = *(ushf*)(scan+best_len-1);                      */
++
++LongerMatch:  movl    nicematch(%esp), %ebx
++              movl    %eax, bestlen(%esp)
++              movl    %ecx, dsMatchStart(%edx)
++              cmpl    %ebx, %eax
++              jge     LeaveNow
++              movl    window(%esp), %esi
++              addl    %eax, %esi
++              movl    %esi, windowbestlen(%esp)
++              movzwl  -1(%edi,%eax), %ebx
++              movl    dsPrev(%edx), %edi
++              movl    %ebx, scanend(%esp)
++              movl    chainlenwmask(%esp), %edx
++              jmp     LookupLoop
++
++/* Accept the current string, with the maximum possible length.               */
++
++LenMaximum:   movl    deflatestate(%esp), %edx
++              movl    $MAX_MATCH, bestlen(%esp)
++              movl    %ecx, dsMatchStart(%edx)
++
++/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len;         */
++/* return s->lookahead;                                                       */
++
++LeaveNow:
++              movl    deflatestate(%esp), %edx
++              movl    bestlen(%esp), %ebx
++              movl    dsLookahead(%edx), %eax
++              cmpl    %eax, %ebx
++              jg      LookaheadRet
++              movl    %ebx, %eax
++LookaheadRet:
++
++/* Restore the stack and return from whence we came.                  */
++
++              addl    $LocalVarsSize, %esp
++              popl    %ebx
++              popl    %esi
++              popl    %edi
++              popl    %ebp
++match_init:   ret
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1587 @@
++/*
++ * @(#) RFC2367 PF_KEYv2 Key management API domain socket I/F
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++/*
++ *            Template from /usr/src/linux-2.0.36/net/unix/af_unix.c.
++ *            Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c.
++ */
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/version.h>
++#ifndef AUTOCONF_INCLUDED
++# include <linux/config.h>
++#endif
++#include <linux/kernel.h>
++
++#include "openswan/ipsec_param.h"
++
++#include <linux/major.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/stat.h>
++#include <linux/socket.h>
++#include <linux/un.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <linux/socket.h>
++#include <linux/sockios.h>
++#include <linux/net.h> /* struct socket */
++#include <linux/in.h>
++#include <linux/fs.h>
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#ifdef CONFIG_X86
++# include <asm/segment.h>
++#endif
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/sock.h> /* struct sock */
++#include <net/protocol.h>
++/* #include <net/tcp.h> */
++#include <net/af_unix.h>
++#ifdef CONFIG_PROC_FS
++# include <linux/proc_fs.h>
++#endif /* CONFIG_PROC_FS */
++#ifdef HAVE_SEQ_FILE
++# include <linux/seq_file.h>
++#endif
++
++#include <linux/types.h>
++ 
++#include <openswan.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_kern24.h"
++#include "openswan/ipsec_sysctl.h"
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++#if 0
++#ifndef SOCKOPS_WRAPPED
++#define SOCKOPS_WRAPPED(name) name
++#endif /* SOCKOPS_WRAPPED */
++#endif
++
++extern struct proto_ops SOCKOPS_WRAPPED(pfkey_ops);
++
++#ifdef NET_26
++static rwlock_t pfkey_sock_lock = RW_LOCK_UNLOCKED;
++HLIST_HEAD(pfkey_sock_list);
++static DECLARE_WAIT_QUEUE_HEAD(pfkey_sock_wait);
++static atomic_t pfkey_sock_users = ATOMIC_INIT(0);
++#else
++struct sock *pfkey_sock_list = NULL;
++#endif
++
++struct supported_list *pfkey_supported_list[K_SADB_SATYPE_MAX+1];
++
++struct socket_list *pfkey_open_sockets = NULL;
++struct socket_list *pfkey_registered_sockets[K_SADB_SATYPE_MAX+1];
++
++int pfkey_msg_interp(struct sock *, struct sadb_msg *);
++
++#ifdef NET_26_24_SKALLOC
++DEBUG_NO_STATIC int pfkey_create(struct net *net, struct socket *sock, int protocol);
++#else
++DEBUG_NO_STATIC int pfkey_create(struct socket *sock, int protocol);
++#endif
++DEBUG_NO_STATIC int pfkey_shutdown(struct socket *sock, int mode);
++DEBUG_NO_STATIC int pfkey_release(struct socket *sock);
++
++#ifdef NET_26
++DEBUG_NO_STATIC int pfkey_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len);
++DEBUG_NO_STATIC int pfkey_recvmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg
++                                , size_t size, int flags);
++#else
++DEBUG_NO_STATIC int pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm);
++DEBUG_NO_STATIC int pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm);
++#endif
++
++struct net_proto_family pfkey_family_ops = {
++        .owner  = THIS_MODULE, 
++        .family = PF_KEY,
++        .create = pfkey_create
++};
++
++struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
++        owner:          THIS_MODULE,
++      family:         PF_KEY,
++      release:        pfkey_release,
++      bind:           sock_no_bind,
++      connect:        sock_no_connect,
++      socketpair:     sock_no_socketpair,
++      accept:         sock_no_accept,
++      getname:        sock_no_getname,
++      poll:           datagram_poll,
++      ioctl:          sock_no_ioctl,
++      listen:         sock_no_listen,
++      shutdown:       pfkey_shutdown,
++      setsockopt:     sock_no_setsockopt,
++      getsockopt:     sock_no_getsockopt,
++      sendmsg:        pfkey_sendmsg,
++      recvmsg:        pfkey_recvmsg,
++      mmap:           sock_no_mmap,
++};
++
++#include <linux/smp_lock.h>
++SOCKOPS_WRAP(pfkey, PF_KEY);
++
++#ifdef NET_26
++static void pfkey_sock_list_grab(void)
++{
++      write_lock_bh(&pfkey_sock_lock);
++
++      if (atomic_read(&pfkey_sock_users)) {
++              DECLARE_WAITQUEUE(wait, current);
++
++              add_wait_queue_exclusive(&pfkey_sock_wait, &wait);
++              for(;;) {
++                      set_current_state(TASK_UNINTERRUPTIBLE);
++                      if (atomic_read(&pfkey_sock_users) == 0)
++                              break;
++                      write_unlock_bh(&pfkey_sock_lock);
++                      schedule();
++                      write_lock_bh(&pfkey_sock_lock);
++              }
++
++              __set_current_state(TASK_RUNNING);
++              remove_wait_queue(&pfkey_sock_wait, &wait);
++      }
++}
++
++static __inline__ void pfkey_sock_list_ungrab(void)
++{
++      write_unlock_bh(&pfkey_sock_lock);
++      wake_up(&pfkey_sock_wait);
++}
++
++static __inline__ void pfkey_lock_sock_list(void)
++{
++      /* read_lock() synchronizes us to pfkey_table_grab */
++
++      read_lock(&pfkey_sock_lock);
++      atomic_inc(&pfkey_sock_users);
++      read_unlock(&pfkey_sock_lock);
++}
++
++static __inline__ void pfkey_unlock_sock_list(void)
++{
++      if (atomic_dec_and_test(&pfkey_sock_users))
++              wake_up(&pfkey_sock_wait);
++}
++#endif
++
++int
++pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
++{
++      struct socket_list *socket_listp,*prev;
++
++      if(!socketp) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_remove_socket: "
++                          "NULL socketp handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      if(!sockets) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_remove_socket: "
++                          "NULL sockets list handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      socket_listp = *sockets;
++      prev = NULL;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_remove_socket: "
++                  "removing sock=0p%p\n",
++                  socketp);
++      
++      while(socket_listp != NULL) {
++              if(socket_listp->socketp == socketp) {
++                      if(prev != NULL) {
++                              prev->next = socket_listp->next;
++                      } else {
++                              *sockets = socket_listp->next;
++                      }
++                      
++                      kfree((void*)socket_listp);
++                      
++                      break;
++              }
++              prev = socket_listp;
++              socket_listp = socket_listp->next;
++      }
++
++      return 0;
++}
++
++int
++pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
++{
++      struct socket_list *socket_listp;
++
++      if(!socketp) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_socket: "
++                          "NULL socketp handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      if(!sockets) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_socket: "
++                          "NULL sockets list handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_insert_socket: "
++                  "allocating %lu bytes for socketp=0p%p\n",
++                  (unsigned long) sizeof(struct socket_list),
++                  socketp);
++      
++      if((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_socket: "
++                          "memory allocation error.\n");
++              return -ENOMEM;
++      }
++      
++      socket_listp->socketp = socketp;
++      socket_listp->next = *sockets;
++      *sockets = socket_listp;
++
++      return 0;
++}
++  
++int
++pfkey_list_remove_supported(struct ipsec_alg_supported *supported, struct supported_list **supported_list)
++{
++      struct supported_list *supported_listp = *supported_list, *prev = NULL;
++      
++      if(!supported) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_remove_supported: "
++                          "NULL supported handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      if(!supported_list) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_remove_supported: "
++                          "NULL supported_list handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_remove_supported: "
++                  "removing supported=0p%p\n",
++                  supported);
++      
++      while(supported_listp != NULL) {
++              if(supported_listp->supportedp == supported) {
++                      if(prev != NULL) {
++                              prev->next = supported_listp->next;
++                      } else {
++                              *supported_list = supported_listp->next;
++                      }
++                      
++                      kfree((void*)supported_listp);
++                      
++                      break;
++              }
++              prev = supported_listp;
++              supported_listp = supported_listp->next;
++      }
++
++      return 0;
++}
++
++int
++pfkey_list_insert_supported(struct ipsec_alg_supported *supported
++                          , struct supported_list **supported_list)
++{
++      struct supported_list *supported_listp;
++
++      if(!supported) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_supported: "
++                          "NULL supported handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      if(!supported_list) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_supported: "
++                          "NULL supported_list handed in, failed.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_insert_supported: "
++                  "allocating %lu bytes for incoming, supported=0p%p, supported_list=0p%p\n",
++                  (unsigned long) sizeof(struct supported_list),
++                  supported,
++                  supported_list);
++      
++      supported_listp = (struct supported_list *)kmalloc(sizeof(struct supported_list), GFP_KERNEL);
++
++      if(supported_listp == NULL)
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_supported: "
++                          "memory allocation error.\n");
++              return -ENOMEM;
++      }
++      
++      supported_listp->supportedp = supported;
++      supported_listp->next = *supported_list;
++      *supported_list = supported_listp;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_insert_supported: "
++                  "outgoing, supported=0p%p, supported_list=0p%p\n",
++                  supported,
++                  supported_list);
++
++      return 0;
++}
++  
++#ifdef NET_26
++DEBUG_NO_STATIC void
++pfkey_insert_socket(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_insert_socket: "
++                  "sk=0p%p\n",
++                  sk);
++      pfkey_sock_list_grab();
++      sk_add_node(sk, &pfkey_sock_list);
++      pfkey_sock_list_ungrab();
++}
++
++DEBUG_NO_STATIC void
++pfkey_remove_socket(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_remove_socket: 0p%p\n", sk);
++      pfkey_sock_list_grab();
++      sk_del_node_init(sk);
++      pfkey_sock_list_ungrab();
++      return;
++}
++#else
++
++DEBUG_NO_STATIC void
++pfkey_insert_socket(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_insert_socket: "
++                  "sk=0p%p\n",
++                  sk);
++      cli();
++      sk->next=pfkey_sock_list;
++      pfkey_sock_list=sk;
++      sti();
++}
++DEBUG_NO_STATIC void
++pfkey_remove_socket(struct sock *sk)
++{
++      struct sock **s;
++
++      s = NULL;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_remove_socket: .\n");
++
++      cli();
++      s=&pfkey_sock_list;
++
++      while(*s!=NULL) {
++              if(*s==sk) {
++                      *s=sk->next;
++                      sk->next=NULL;
++                      sti();
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_remove_socket: "
++                                  "succeeded.\n");
++                      return;
++              }
++              s=&((*s)->next);
++      }
++      sti();
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_remove_socket: "
++                  "not found.\n");
++      return;
++}
++#endif
++
++DEBUG_NO_STATIC void
++pfkey_destroy_socket(struct sock *sk)
++{
++      struct sk_buff *skb;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: 0p%p\n",sk);
++      pfkey_remove_socket(sk);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: "
++                  "pfkey_remove_socket called, sk=0p%p\n",sk);
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: "
++                  "sk(0p%p)->(&0p%p)receive_queue.{next=0p%p,prev=0p%p}.\n",
++                  sk,
++                  &(sk->sk_receive_queue),
++                  sk->sk_receive_queue.next,
++                  sk->sk_receive_queue.prev);
++
++      while(sk && ((skb=skb_dequeue(&(sk->sk_receive_queue)))!=NULL)) {
++#ifdef CONFIG_KLIPS_DEBUG
++              if(debug_pfkey && sysctl_ipsec_debug_verbose) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_destroy_socket: "
++                                  "skb=0p%p dequeued.\n", skb);
++                      printk(KERN_INFO "klips_debug:pfkey_destroy_socket: "
++                             "pfkey_skb contents:");
++                      printk(" next:0p%p", skb->next);
++                      printk(" prev:0p%p", skb->prev);
++                      printk(" sk:0p%p", skb->sk);
++                      printk(" dev:0p%p", skb->dev);
++                      if(skb->dev) {
++                              if(skb->dev->name) {
++                                      printk(" dev->name:%s", skb->dev->name);
++                              } else {
++                                      printk(" dev->name:NULL?");
++                              }
++                      } else {
++                              printk(" dev:NULL");
++                      }
++                      printk(" h:0p%p", skb_transport_header(skb));
++                      printk(" nh:0p%p", skb_network_header(skb));
++                      printk(" mac:0p%p", skb_mac_header(skb));
++                      printk(" dst:0p%p", skb->dst);
++                      if(sysctl_ipsec_debug_verbose) {
++                              int i;
++                              
++                              printk(" cb");
++                              for(i=0; i<48; i++) {
++                                      printk(":%2x", skb->cb[i]);
++                              }
++                      }
++                      printk(" len:%d", skb->len);
++                      printk(" csum:%d", skb->csum);
++#ifndef NETDEV_23
++                      printk(" used:%d", skb->used);
++                      printk(" is_clone:%d", skb->is_clone);
++#endif /* NETDEV_23 */
++                      printk(" cloned:%d", skb->cloned);
++                      printk(" pkt_type:%d", skb->pkt_type);
++                      printk(" ip_summed:%d", skb->ip_summed);
++                      printk(" priority:%d", skb->priority);
++                      printk(" protocol:%d", skb->protocol);
++#ifdef HAVE_SOCK_SECURITY
++                      printk(" security:%d", skb->security);
++#endif
++                      printk(" truesize:%d", skb->truesize);
++                      printk(" head:0p%p", skb->head);
++                      printk(" data:0p%p", skb->data);
++                      printk(" tail:0p%p", skb_tail_pointer(skb));
++                      printk(" end:0p%p", skb_end_pointer(skb));
++                      if(sysctl_ipsec_debug_verbose) {
++                              unsigned char* i;
++                              printk(" data");
++                              for(i = skb->head; i < skb_end_pointer(skb); i++) {
++                                      printk(":%2x", (unsigned char)(*(i)));
++                              }
++                      }
++                      printk(" destructor:0p%p", skb->destructor);
++                      printk("\n");
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_destroy_socket: "
++                          "skb=0p%p freed.\n",
++                          skb);
++              ipsec_kfree_skb(skb);
++      }
++
++#ifdef NET_26
++      sock_set_flag(sk, SOCK_DEAD);
++#else
++      sk->dead = 1;
++#endif
++      sk_free(sk);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: destroyed.\n");
++}
++
++int
++pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
++{
++      struct sock *sk;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "NULL socket passed in.\n");
++              return -EINVAL;
++      }
++
++      if(pfkey_msg == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "NULL pfkey_msg passed in.\n");
++              return -EINVAL;
++      }
++
++      sk = sock->sk;
++      return pfkey_upmsgsk(sk, pfkey_msg);
++}
++int
++pfkey_upmsgsk(struct sock *sk, struct sadb_msg *pfkey_msg)
++{
++      int error = 0;
++      struct sk_buff * skb = NULL;
++
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "NULL sock passed in.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_upmsg: "
++                  "allocating %d bytes...\n",
++                  (int)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN));
++      if(!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "no buffers left to send up a message.\n");
++              return -ENOBUFS;
++      }
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_upmsg: "
++                  "...allocated at 0p%p.\n",
++                  skb);
++      
++      skb->dev = NULL;
++      
++      if(skb_tailroom(skb) < pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
++              printk(KERN_WARNING "klips_error:pfkey_upmsg: "
++                     "tried to skb_put %ld, %d available.  This should never happen, please report.\n",
++                     (unsigned long int)pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN,
++                     skb_tailroom(skb));
++              ipsec_kfree_skb(skb);
++              return -ENOBUFS;
++      }
++      skb_set_transport_header(skb, ipsec_skb_offset(skb, skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)));
++      memcpy(skb_transport_header(skb), pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
++
++      if((error = sock_queue_rcv_skb(sk, skb)) < 0) {
++              skb->sk=NULL;
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "error=%d calling sock_queue_rcv_skb with skb=0p%p.\n",
++                          error,
++                          skb);
++              ipsec_kfree_skb(skb);
++              return error;
++      }
++      return error;
++}
++
++#if defined(NET_26_12_SKALLOC) || defined(NET_26_24_SKALLOC)
++
++static struct proto key_proto = {
++      .name     = "KEY",
++      .owner    = THIS_MODULE,
++      .obj_size = sizeof(struct sock),
++      
++};
++#endif
++#ifdef NET_26_24_SKALLOC
++DEBUG_NO_STATIC int
++pfkey_create(struct net *net, struct socket *sock, int protocol)
++#else
++DEBUG_NO_STATIC int
++pfkey_create(struct socket *sock, int protocol)
++#endif
++{
++      struct sock *sk;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: "
++                          "socket NULL.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_create: "
++                  "sock=0p%p type:%d state:%d flags:%ld protocol:%d\n",
++                  sock,
++                  sock->type,
++                  (unsigned int)(sock->state),
++                  sock->flags, protocol);
++
++      if(sock->type != SOCK_RAW) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: "
++                          "only SOCK_RAW supported.\n");
++              return -ESOCKTNOSUPPORT;
++      }
++
++      if(protocol != PF_KEY_V2) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: "
++                          "protocol not PF_KEY_V2.\n");
++              return -EPROTONOSUPPORT;
++      }
++
++      if((current->uid != 0)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: "
++                          "must be root to open pfkey sockets.\n");
++              return -EACCES;
++      }
++
++      sock->state = SS_UNCONNECTED;
++
++      KLIPS_INC_USE;
++
++#ifdef NET_26
++#ifdef NET_26_24_SKALLOC
++       sk=(struct sock *)sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto);
++#else
++#ifdef NET_26_12_SKALLOC
++      sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1);
++#else
++      sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1, NULL);
++#endif
++#endif
++#else
++      /* 2.4 interface */
++      sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1);
++#endif
++
++      if(sk == NULL)
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: "
++                          "Out of memory trying to allocate.\n");
++              KLIPS_DEC_USE;
++              return -ENOMEM;
++      }
++
++      sock_init_data(sock, sk);
++
++      sk->sk_destruct = NULL;
++      sk->sk_reuse = 1;
++      sock->ops = &SOCKOPS_WRAPPED(pfkey_ops);
++
++      sk->sk_family = PF_KEY;
++/*    sk->num = protocol; */
++      sk->sk_protocol = protocol;
++      key_pid(sk) = current->pid;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_create: "
++                  "sock->fasync_list=0p%p sk->sleep=0p%p.\n",
++                  sock->fasync_list,
++                  sk->sk_sleep);
++
++      pfkey_insert_socket(sk);
++      pfkey_list_insert_socket(sock, &pfkey_open_sockets);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_create: "
++                  "Socket sock=0p%p sk=0p%p initialised.\n", sock, sk);
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++#ifdef NETDEV_23
++pfkey_release(struct socket *sock)
++#else /* NETDEV_23 */
++pfkey_release(struct socket *sock, struct socket *peersock)
++#endif /* NETDEV_23 */
++{
++      struct sock *sk;
++      int i;
++
++      if(sock==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_release: "
++                          "No socket attached.\n");
++              return 0; /* -EINVAL; */
++      }
++              
++      sk=sock->sk;
++      
++      /* May not have data attached */
++      if(sk==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_release: "
++                          "No sk attached to sock=0p%p.\n", sock);
++              return 0; /* -EINVAL; */
++      }
++              
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_release: "
++                  "sock=0p%p sk=0p%p\n", sock, sk);
++
++      if(sock_flag(sk, SOCK_DEAD))
++              if(sk->sk_state_change) {
++                      sk->sk_state_change(sk);
++              }
++
++      sock->sk = NULL;
++
++      /* Try to flush out this socket. Throw out buffers at least */
++      pfkey_destroy_socket(sk);
++      pfkey_list_remove_socket(sock, &pfkey_open_sockets);
++      for(i = K_SADB_SATYPE_UNSPEC; i <= K_SADB_SATYPE_MAX; i++) {
++              pfkey_list_remove_socket(sock, &(pfkey_registered_sockets[i]));
++      }
++
++      KLIPS_DEC_USE;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_release: "
++                  "succeeded.\n");
++
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++pfkey_shutdown(struct socket *sock, int mode)
++{
++      struct sock *sk;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_shutdown: "
++                          "NULL socket passed in.\n");
++              return -EINVAL;
++      }
++
++      sk=sock->sk;
++      
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_shutdown: "
++                          "No sock attached to socket.\n");
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_shutdown: "
++                  "mode=%x.\n", mode);
++      mode++;
++      
++      if(mode&SEND_SHUTDOWN) {
++              sk->sk_shutdown|=SEND_SHUTDOWN;
++              sk->sk_state_change(sk);
++      }
++
++      if(mode&RCV_SHUTDOWN) {
++              sk->sk_shutdown|=RCV_SHUTDOWN;
++              sk->sk_state_change(sk);
++      }
++      return 0;
++}
++
++/*
++ *    Send PF_KEY data down.
++ */
++              
++DEBUG_NO_STATIC int
++#ifdef NET_26
++pfkey_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
++#else
++pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++#endif
++{
++      struct sock *sk;
++      int error = 0;
++      struct sadb_msg *pfkey_msg = NULL, *pfkey_reply = NULL;
++      
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "Null socket passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++      sk = sock->sk;
++
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "Null sock passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++      if(msg == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "Null msghdr passed in.\n");
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sendmsg: .\n");
++      if(sk->sk_err) {
++              error = sock_error(sk);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "sk->err is non-zero, returns %d.\n",
++                          error);
++              SENDERR(-error);
++      }
++
++      if((current->uid != 0)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "must be root to send messages to pfkey sockets.\n");
++              SENDERR(EACCES);
++      }
++
++      if(msg->msg_control)
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "can't set flags or set msg_control.\n");
++              SENDERR(EINVAL);
++      }
++              
++      if(sk->sk_shutdown & SEND_SHUTDOWN) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "shutdown.\n");
++              send_sig(SIGPIPE, current, 0);
++              SENDERR(EPIPE);
++      }
++      
++      if(len < sizeof(struct sadb_msg)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "bogus msg len of %d, too small.\n", (int)len);
++              SENDERR(EMSGSIZE);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sendmsg: "
++                  "allocating %d bytes for downward message.\n",
++                  (int)len);
++      if((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "memory allocation error.\n");
++              SENDERR(ENOBUFS);
++      }
++
++      memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len);
++
++      if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
++              KLIPS_PRINT(1 || debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "not PF_KEY_V2 msg, found %d, should be %d.\n",
++                          pfkey_msg->sadb_msg_version,
++                          PF_KEY_V2);
++              kfree((void*)pfkey_msg);
++              return -EINVAL;
++      }
++
++      if(len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "bogus msg len of %d, not %d byte aligned.\n",
++                          (int)len, (int)IPSEC_PFKEYv2_ALIGN);
++              SENDERR(EMSGSIZE);
++      }
++
++      if(pfkey_msg->sadb_msg_reserved) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "reserved field must be zero, set to %d.\n",
++                          pfkey_msg->sadb_msg_reserved);
++              SENDERR(EINVAL);
++      }
++      
++      if((pfkey_msg->sadb_msg_type > K_SADB_MAX) || (!pfkey_msg->sadb_msg_type)){
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "msg type too large or small:%d.\n",
++                          pfkey_msg->sadb_msg_type);
++              SENDERR(EINVAL);
++      }
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sendmsg: "
++                  "msg sent for parsing.\n");
++      
++      if((error = pfkey_msg_interp(sk, pfkey_msg))) {
++              struct socket_list *pfkey_socketsp;
++
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
++                          "pfkey_msg_parse returns %d.\n",
++                          error);
++
++              if((pfkey_reply = (struct sadb_msg*)kmalloc(sizeof(struct sadb_msg), GFP_KERNEL)) == NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_sendmsg: "
++                                  "memory allocation error.\n");
++                      SENDERR(ENOBUFS);
++              }
++              memcpy((void*)pfkey_reply, (void*)pfkey_msg, sizeof(struct sadb_msg));
++              pfkey_reply->sadb_msg_errno = -error;
++              pfkey_reply->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
++
++              for(pfkey_socketsp = pfkey_open_sockets;
++                  pfkey_socketsp;
++                  pfkey_socketsp = pfkey_socketsp->next) {
++                      int error_upmsg = 0;
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
++                                  "sending up error=%d message=0p%p to socket=0p%p.\n",
++                                  error,
++                                  pfkey_reply,
++                                  pfkey_socketsp->socketp);
++                      if((error_upmsg = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
++                                          "sending up error message to socket=0p%p failed with error=%d.\n",
++                                          pfkey_socketsp->socketp,
++                                          error_upmsg);
++                              /* pfkey_msg_free(&pfkey_reply); */
++                              /* SENDERR(-error); */
++                      }
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
++                                  "sending up error message to socket=0p%p succeeded.\n",
++                                  pfkey_socketsp->socketp);
++              }
++              
++              pfkey_msg_free(&pfkey_reply);
++              
++              SENDERR(-error);
++      }
++
++ errlab:
++      if (pfkey_msg) {
++              kfree((void*)pfkey_msg);
++      }
++      
++      if(error) {
++              return error;
++      } else {
++              return len;
++      }
++}
++
++/*
++ *    Receive PF_KEY data up.
++ */
++              
++DEBUG_NO_STATIC int
++#ifdef NET_26
++pfkey_recvmsg(struct kiocb *kiocb
++            , struct socket *sock
++            , struct msghdr *msg
++            , size_t size
++            , int flags)
++#else
++pfkey_recvmsg(struct socket *sock
++            , struct msghdr *msg
++            , int size, int flags
++            , struct scm_cookie *scm)
++#endif
++{
++      struct sock *sk;
++      int noblock = flags & MSG_DONTWAIT;
++      struct sk_buff *skb;
++      int error;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: "
++                          "Null socket passed in.\n");
++              return -EINVAL;
++      }
++
++      sk = sock->sk;
++
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: "
++                          "Null sock passed in for sock=0p%p.\n", sock);
++              return -EINVAL;
++      }
++
++      if(msg == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: "
++                          "Null msghdr passed in for sock=0p%p, sk=0p%p.\n",
++                          sock, sk);
++              return -EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                  "klips_debug:pfkey_recvmsg: sock=0p%p sk=0p%p msg=0p%p size=%d.\n",
++                  sock, sk, msg, (int)size);
++      if(flags & ~MSG_PEEK) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "flags (%d) other than MSG_PEEK not supported.\n",
++                          flags);
++              return -EOPNOTSUPP;
++      }
++              
++      msg->msg_namelen = 0; /* sizeof(*ska); */
++              
++      if(sk->sk_err) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: "
++                          "sk->sk_err=%d.\n", sk->sk_err);
++              return sock_error(sk);
++      }
++
++      if((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) {
++                return error;
++      }
++
++      if(size > skb->len) {
++              size = skb->len;
++      }
++      else if(size <skb->len) {
++              msg->msg_flags |= MSG_TRUNC;
++      }
++
++      skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
++#ifdef HAVE_KERNEL_TSTAMP
++      sk->sk_stamp = skb->tstamp;
++#elif defined(HAVE_TSTAMP)
++      sk->sk_stamp.tv_sec  = skb->tstamp.off_sec;
++      sk->sk_stamp.tv_usec = skb->tstamp.off_usec;
++#else
++        sk->sk_stamp=skb->stamp;
++#endif
++
++      skb_free_datagram(sk, skb);
++      return size;
++}
++
++#ifdef CONFIG_PROC_FS
++#ifndef PROC_FS_2325
++DEBUG_NO_STATIC
++#endif /* PROC_FS_2325 */
++int
++pfkey_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef  PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++#ifdef  PROC_EOF_DATA
++, int *eof
++, void *data
++#endif
++)
++{
++      const int max_content = length > 0? length-1 : 0;       /* limit of useful snprintf output */
++#ifdef NET_26
++      struct hlist_node *node;
++#endif
++      off_t begin=0;
++      int len=0;
++      struct sock *sk;
++      
++#ifdef CONFIG_KLIPS_DEBUG
++      if(!sysctl_ipsec_debug_verbose) {
++#endif /* CONFIG_KLIPS_DEBUG */
++      len += ipsec_snprintf(buffer, length,
++                    "    sock   pid   socket     next     prev e n p sndbf    Flags     Type St\n");
++#ifdef CONFIG_KLIPS_DEBUG
++      } else {
++      len += ipsec_snprintf(buffer, length,
++                    "    sock   pid d    sleep   socket     next     prev e r z n p sndbf    stamp    Flags     Type St\n");
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      sk_for_each(sk, node, &pfkey_sock_list) {
++
++#ifdef CONFIG_KLIPS_DEBUG
++              if(!sysctl_ipsec_debug_verbose) {
++#endif /* CONFIG_KLIPS_DEBUG */
++                len += ipsec_snprintf(buffer+len, length-len,
++                                      "%8p %5d %8p %d %d %5d %08lX %8X %2X\n",
++                                      sk,
++                                      key_pid(sk),
++                                      sk->sk_socket,
++                                      sk->sk_err,
++                                      sk->sk_protocol,
++                                      sk->sk_sndbuf,
++                                      sk->sk_socket->flags,
++                                      sk->sk_socket->type,
++                                      sk->sk_socket->state);
++#ifdef CONFIG_KLIPS_DEBUG
++              } else {
++                struct timeval t;
++                grab_socket_timeval(t, *sk);
++                len += ipsec_snprintf(buffer+len, length-len,
++                                      "%8p %5d %d %8p %8p %d %d %d %d %5d %d.%06d %08lX %8X %2X\n",
++                                      sk,
++                                      key_pid(sk),
++                                      sock_flag(sk, SOCK_DEAD),
++                                      sk->sk_sleep,
++                                      sk->sk_socket,
++                                      sk->sk_err,
++                                      sk->sk_reuse,
++#ifdef HAVE_SOCK_ZAPPED
++                                      sock_flag(sk, SOCK_ZAPPED),
++#else
++                                      sk->sk_zapped,
++#endif                                        
++                                      sk->sk_protocol,
++                                      sk->sk_sndbuf,
++                                      (unsigned int)t.tv_sec,
++                                      (unsigned int)t.tv_usec,
++                                      sk->sk_socket->flags,
++                                      sk->sk_socket->type,
++                                      sk->sk_socket->state);
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++              
++              if (len >= max_content) {
++                      /* we've done all that can fit -- stop loop */
++                      len = max_content;      /* truncate crap */
++                      break;
++              } else {
++                      const off_t pos = begin + len;  /* file position of end of what we've generated */
++
++                      if (pos <= offset) {
++                              /* all is before first interesting character:
++                               * discard, but note where we are.
++                               */
++                              len = 0;
++                              begin = pos;
++                      }
++              }
++      }
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      return len - (offset - begin);
++}
++
++#ifndef PROC_FS_2325
++DEBUG_NO_STATIC
++#endif /* PROC_FS_2325 */
++int
++pfkey_supported_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef  PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++#ifdef  PROC_EOF_DATA
++, int *eof
++, void *data
++#endif
++)
++{
++      /* limit of useful snprintf output */
++      const int max_content = length > 0? length-1 : 0;       
++      off_t begin=0;
++      int len=0;
++      int satype;
++      struct supported_list *ps;
++      
++      len += ipsec_snprintf(buffer, length,
++                    "satype exttype alg_id ivlen minbits maxbits name\n");
++      
++      for(satype = K_SADB_SATYPE_UNSPEC; satype <= K_SADB_SATYPE_MAX; satype++) {
++              ps = pfkey_supported_list[satype];
++              while(ps) {
++                      struct ipsec_alg_supported *alg = ps->supportedp;
++                      const char *n = alg->ias_name;
++                      if(n == NULL) n = "unknown";
++
++                      len += ipsec_snprintf(buffer+len, length-len,
++                                            "    %2d      %2d     %2d   %3d     %3d     %3d %20s\n",
++                                            satype,
++                                            alg->ias_exttype,
++                                            alg->ias_id,
++                                            alg->ias_ivlen,
++                                            alg->ias_keyminbits,
++                                            alg->ias_keymaxbits,
++                                            n);
++                      
++                      if (len >= max_content) {
++                              /* we've done all that can fit -- stop loop */
++                              len = max_content;      /* truncate crap */
++                              break;
++                      } else {
++                              const off_t pos = begin + len;  /* file position of end of what we've generated */
++
++                              if (pos <= offset) {
++                                      /* all is before first interesting character:
++                                       * discard, but note where we are.
++                                       */
++                                      len = 0;
++                                      begin = pos;
++                              }
++                      }
++
++                      ps = ps->next;
++              }
++      }
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      return len - (offset - begin);
++}
++
++#ifndef PROC_FS_2325
++DEBUG_NO_STATIC
++#endif /* PROC_FS_2325 */
++int
++pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef  PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++#ifdef  PROC_EOF_DATA
++, int *eof
++, void *data
++#endif
++)
++{
++      const int max_content = length > 0? length-1 : 0;       /* limit of useful snprintf output */
++      off_t begin=0;
++      int len=0;
++      int satype;
++      struct socket_list *pfkey_sockets;
++      
++      len += ipsec_snprintf(buffer, length,
++                    "satype   socket   pid       sk\n");
++      
++      for(satype = K_SADB_SATYPE_UNSPEC; satype <= K_SADB_SATYPE_MAX; satype++) {
++              pfkey_sockets = pfkey_registered_sockets[satype];
++              while(pfkey_sockets) {
++                      len += ipsec_snprintf(buffer+len, length-len,
++                                   "    %2d %8p %5d %8p\n",
++                                   satype,
++                                   pfkey_sockets->socketp,
++                                   key_pid(pfkey_sockets->socketp->sk),
++                                   pfkey_sockets->socketp->sk);
++                      
++                      if (len >= max_content) {
++                              /* we've done all that can fit -- stop loop (could stop two) */
++                              len = max_content;      /* truncate crap */
++                              break;
++                      } else {
++                              const off_t pos = begin + len;  /* file position of end of what we've generated */
++
++                              if (pos <= offset) {
++                                      /* all is before first interesting character:
++                                       * discard, but note where we are.
++                                       */
++                                      len = 0;
++                                      begin = pos;
++                              }
++                      }
++
++                      pfkey_sockets = pfkey_sockets->next;
++              }
++      }
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      return len - (offset - begin);
++}
++
++#ifndef PROC_FS_2325
++struct proc_dir_entry proc_net_pfkey =
++{
++      0,
++      6, "pf_key",
++      S_IFREG | S_IRUGO, 1, 0, 0,
++      0, &proc_net_inode_operations,
++      pfkey_get_info
++};
++struct proc_dir_entry proc_net_pfkey_supported =
++{
++      0,
++      16, "pf_key_supported",
++      S_IFREG | S_IRUGO, 1, 0, 0,
++      0, &proc_net_inode_operations,
++      pfkey_supported_get_info
++};
++struct proc_dir_entry proc_net_pfkey_registered =
++{
++      0,
++      17, "pf_key_registered",
++      S_IFREG | S_IRUGO, 1, 0, 0,
++      0, &proc_net_inode_operations,
++      pfkey_registered_get_info
++};
++#endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++DEBUG_NO_STATIC int
++supported_add_all(int satype, struct ipsec_alg_supported supported[], int size)
++{
++      int i;
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:init_pfkey: "
++                  "sizeof(supported_init_<satype=%d>)[%d]/sizeof(struct ipsec_alg_supported)[%d]=%d.\n",
++                  satype,
++                  size,
++                  (int)sizeof(struct ipsec_alg_supported),
++                  (int)(size/sizeof(struct ipsec_alg_supported)));
++
++      for(i = 0; i < size / sizeof(struct ipsec_alg_supported); i++) {
++
++              const char *n = supported[i].ias_name;
++              if(n == NULL) n="unknown";
++
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:init_pfkey: "
++                          "i=%d inserting satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d name=%s.\n",
++                          i,
++                          satype,
++                          supported[i].ias_exttype,
++                          supported[i].ias_id,
++                          supported[i].ias_ivlen,
++                          supported[i].ias_keyminbits,
++                          supported[i].ias_keymaxbits,
++                          n);                     
++                          
++              error |= pfkey_list_insert_supported(&(supported[i]),
++                                          &(pfkey_supported_list[satype]));
++      }
++      return error;
++}
++
++DEBUG_NO_STATIC int
++supported_remove_all(int satype)
++{
++      int error = 0;
++      struct ipsec_alg_supported*supportedp;
++
++      while(pfkey_supported_list[satype]) {
++              const char *n;
++              supportedp = pfkey_supported_list[satype]->supportedp;
++
++              n = supportedp->ias_name;
++              if(n == NULL) n="unknown";
++
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:init_pfkey: "
++                          "removing satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d name=%s.\n",
++                          satype,
++                          supportedp->ias_exttype,
++                          supportedp->ias_id,
++                          supportedp->ias_ivlen,
++                          supportedp->ias_keyminbits,
++                          supportedp->ias_keymaxbits, n);
++                          
++              error |= pfkey_list_remove_supported(supportedp,
++                                          &(pfkey_supported_list[satype]));
++      }
++      return error;
++}
++
++int
++pfkey_init(void)
++{
++      int error = 0;
++      int i;
++#ifdef HAVE_PROC_DIR_ENTRY
++      struct proc_dir_entry* entry;
++#endif
++
++      
++      static struct ipsec_alg_supported supported_init_ah[] = {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              {K_SADB_EXT_SUPPORTED_AUTH, K_SADB_AALG_MD5HMAC, 0, 128, 128},
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              {K_SADB_EXT_SUPPORTED_AUTH, K_SADB_AALG_SHA1HMAC, 0, 160, 160}
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++      };
++      static struct ipsec_alg_supported supported_init_esp[] = {
++#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
++              {K_SADB_EXT_SUPPORTED_AUTH, K_SADB_AALG_MD5HMAC, 0, 128, 128},
++#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
++#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
++              {K_SADB_EXT_SUPPORTED_AUTH, K_SADB_AALG_SHA1HMAC, 0, 160, 160},
++#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
++#ifdef CONFIG_KLIPS_ENC_3DES
++              {K_SADB_EXT_SUPPORTED_ENCRYPT, K_SADB_EALG_3DESCBC, 64, 168, 168},
++#endif /* CONFIG_KLIPS_ENC_3DES */
++      };
++      static struct ipsec_alg_supported supported_init_ipip[] = {
++              {K_SADB_EXT_SUPPORTED_ENCRYPT, K_SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32}
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++              , {K_SADB_EXT_SUPPORTED_ENCRYPT, K_SADB_X_TALG_IPv6_in_IPv4, 0, 128, 32}
++              , {K_SADB_EXT_SUPPORTED_ENCRYPT, K_SADB_X_TALG_IPv4_in_IPv6, 0, 32, 128}
++              , {K_SADB_EXT_SUPPORTED_ENCRYPT, K_SADB_X_TALG_IPv6_in_IPv6, 0, 128, 128}
++#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++      };
++#ifdef CONFIG_KLIPS_IPCOMP
++      static struct ipsec_alg_supported supported_init_ipcomp[] = {
++              {K_SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_CALG_DEFLATE, 0, 1, 1}
++      };
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#if 0
++        printk(KERN_INFO
++             "klips_info:pfkey_init: "
++             "FreeS/WAN: initialising PF_KEYv2 domain sockets.\n");
++#endif
++
++      for(i = K_SADB_SATYPE_UNSPEC; i <= K_SADB_SATYPE_MAX; i++) {
++              pfkey_registered_sockets[i] = NULL;
++              pfkey_supported_list[i] = NULL;
++      }
++
++      error |= supported_add_all(K_SADB_SATYPE_AH, supported_init_ah, sizeof(supported_init_ah));
++      error |= supported_add_all(K_SADB_SATYPE_ESP, supported_init_esp, sizeof(supported_init_esp));
++#ifdef CONFIG_KLIPS_IPCOMP
++      error |= supported_add_all(K_SADB_X_SATYPE_COMP, supported_init_ipcomp, sizeof(supported_init_ipcomp));
++#endif /* CONFIG_KLIPS_IPCOMP */
++      error |= supported_add_all(K_SADB_X_SATYPE_IPIP, supported_init_ipip, sizeof(supported_init_ipip));
++
++        error |= sock_register(&pfkey_family_ops);
++
++#ifdef CONFIG_PROC_FS
++#  ifndef PROC_FS_2325
++#    ifdef PROC_FS_21
++      error |= proc_register(proc_net, &proc_net_pfkey);
++      error |= proc_register(proc_net, &proc_net_pfkey_supported);
++      error |= proc_register(proc_net, &proc_net_pfkey_registered);
++#    else /* PROC_FS_21 */
++      error |= proc_register_dynamic(&proc_net, &proc_net_pfkey);
++      error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_supported);
++      error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_registered);
++#    endif /* PROC_FS_21 */
++#  else /* !PROC_FS_2325 */
++#    if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++      proc_net_create ("pf_key", 0, pfkey_get_info);
++      proc_net_create ("pf_key_supported", 0, pfkey_supported_get_info);
++      proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info);
++#    else
++      entry = create_proc_entry ("pf_key", 0, init_net.proc_net);
++      entry->read_proc = pfkey_get_info;
++      entry = create_proc_entry ("pf_key_supported", 0, init_net.proc_net);
++      entry->read_proc = pfkey_supported_get_info;
++      entry = create_proc_entry ("pf_key_registered", 0, init_net.proc_net);
++      entry->read_proc = pfkey_registered_get_info;
++#    endif
++#  endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++      return error;
++}
++
++int
++pfkey_cleanup(void)
++{
++      int error = 0;
++      
++        printk(KERN_INFO "klips_info:pfkey_cleanup: "
++             "shutting down PF_KEY domain sockets.\n");
++#ifdef VOID_SOCK_UNREGISTER
++      sock_unregister(PF_KEY);
++#else
++        error |= sock_unregister(PF_KEY);
++#endif
++
++      error |= supported_remove_all(K_SADB_SATYPE_AH);
++      error |= supported_remove_all(K_SADB_SATYPE_ESP);
++#ifdef CONFIG_KLIPS_IPCOMP
++      error |= supported_remove_all(K_SADB_X_SATYPE_COMP);
++#endif /* CONFIG_KLIPS_IPCOMP */
++      error |= supported_remove_all(K_SADB_X_SATYPE_IPIP);
++
++#ifdef CONFIG_PROC_FS
++#  ifndef PROC_FS_2325
++      if (proc_net_unregister(proc_net_pfkey.low_ino) != 0)
++              printk("klips_debug:pfkey_cleanup: "
++                     "cannot unregister /proc/net/pf_key\n");
++      if (proc_net_unregister(proc_net_pfkey_supported.low_ino) != 0)
++              printk("klips_debug:pfkey_cleanup: "
++                     "cannot unregister /proc/net/pf_key_supported\n");
++      if (proc_net_unregister(proc_net_pfkey_registered.low_ino) != 0)
++              printk("klips_debug:pfkey_cleanup: "
++                     "cannot unregister /proc/net/pf_key_registered\n");
++#  else /* !PROC_FS_2325 */
++#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++      proc_net_remove ("pf_key");
++      proc_net_remove ("pf_key_supported");
++      proc_net_remove ("pf_key_registered");
++#  else
++      proc_net_remove (&init_net, "pf_key");
++      proc_net_remove (&init_net, "pf_key_supported");
++      proc_net_remove (&init_net, "pf_key_registered");
++#    endif
++
++#  endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++      /* other module unloading cleanup happens here */
++      return error;
++}
++
++#ifdef MODULE
++#if 0
++int
++init_module(void)
++{
++      pfkey_init();
++      return 0;
++}
++
++void
++cleanup_module(void)
++{
++      pfkey_cleanup();
++}
++#endif /* 0 */
++#else /* MODULE */
++struct net_protocol;
++void pfkey_proto_init(struct net_protocol *pro)
++{
++      pfkey_init();
++}
++#endif /* MODULE */
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_build.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1452 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: pfkey_v2_build.c,v 1.53 2005/11/09 00:30:37 mcr Exp $
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parser.c.
++ */
++
++char pfkey_v2_build_c_version[] = "$Id: pfkey_v2_build.c,v 1.53 2005/11/09 00:30:37 mcr Exp $";
++
++/*
++ * Some ugly stuff to allow consistent debugging code for use in the
++ * kernel and in user space
++*/
++
++#if defined(__KERNEL__) && defined(linux)
++
++# include <linux/kernel.h>  /* for printk */
++
++# include "openswan/ipsec_kversion.h" /* for malloc switch */
++# ifdef MALLOC_SLAB
++#  include <linux/slab.h> /* kmalloc() */
++# else /* MALLOC_SLAB */
++#  include <linux/malloc.h> /* kmalloc() */
++# endif /* MALLOC_SLAB */
++# include <linux/errno.h>  /* error codes */
++# include <linux/types.h>  /* size_t */
++# include <linux/interrupt.h> /* mark_bh */
++
++# include <linux/netdevice.h>   /* struct device, and other headers */
++# include <linux/etherdevice.h> /* eth_type_trans */
++# include <linux/ip.h>          /* struct iphdr */ 
++# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++#  include <linux/ipv6.h>        /* struct ipv6hdr */
++# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++
++# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
++# define FREE(obj) kfree(obj)
++# include <openswan.h>
++#else /* __KERNEL__ */
++
++# include <sys/types.h>
++# include <sys/errno.h>
++# include <netinet/in.h>
++# include <stdlib.h>
++# include <stdio.h>
++# include <string.h> /* memset */
++
++# include <openswan.h>
++
++#endif /* __KERNEL__ */
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#ifdef __KERNEL__
++#include "openswan/radij.h"  /* rd_nodes */
++#include "openswan/ipsec_encap.h"  /* sockaddr_encap */
++#endif /* __KERNEL__ */
++
++
++#include "openswan/ipsec_sa.h"  /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
++#include "openswan/pfkey_debug.h"
++
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++void
++pfkey_extensions_init(struct sadb_ext *extensions[K_SADB_EXT_MAX + 1])
++{
++      int i;
++      
++      for (i = 0; i != K_SADB_EXT_MAX + 1; i++) {
++              extensions[i] = NULL;
++      }
++}
++
++void
++pfkey_extensions_free(struct sadb_ext *extensions[K_SADB_EXT_MAX + 1])
++{
++      int i;
++      
++      if(!extensions) {
++              return;
++      }
++
++      if(extensions[0]) {
++              memset(extensions[0], 0, sizeof(struct sadb_msg));
++              FREE(extensions[0]);
++              extensions[0] = NULL;
++      }
++      
++      for (i = 1; i != K_SADB_EXT_MAX + 1; i++) {
++              if(extensions[i]) {
++                      memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
++                      FREE(extensions[i]);
++                      extensions[i] = NULL;
++              }
++      }
++}
++
++void
++pfkey_msg_free(struct sadb_msg **pfkey_msg)
++{
++      if(*pfkey_msg) {
++              memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
++              FREE(*pfkey_msg);
++              *pfkey_msg = NULL;
++      }
++}
++
++/* Default extension builders taken from the KLIPS code */
++
++int
++pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
++                  uint8_t             msg_type,
++                  uint8_t             satype,
++                  uint8_t             msg_errno,
++                  uint32_t            seq,
++                  uint32_t            pid)
++{
++      int error = 0;
++      struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_msg_hdr_build:\n");
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_msg_hdr_build: "
++              "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
++              &pfkey_ext,
++              pfkey_ext,
++              *pfkey_ext);
++      /* sanity checks... */
++      if(pfkey_msg) {
++              ERROR("pfkey_msg_hdr_build: "
++                      "why is pfkey_msg already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(!msg_type) {
++              ERROR("pfkey_msg_hdr_build: "
++                      "msg type not set, must be non-zero..\n");
++              SENDERR(EINVAL);
++      }
++
++      if(msg_type > K_SADB_MAX) {
++              ERROR("pfkey_msg_hdr_build: "
++                      "msg type too large:%d.\n",
++                      msg_type);
++              SENDERR(EINVAL);
++      }
++
++      if(satype > K_SADB_SATYPE_MAX) {
++              ERROR("pfkey_msg_hdr_build: "
++                      "satype %d > max %d\n", 
++                      satype, SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg));
++      *pfkey_ext = (struct sadb_ext*)pfkey_msg;
++      
++      if(pfkey_msg == NULL) {
++              ERROR("pfkey_msg_hdr_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_msg, 0, sizeof(struct sadb_msg));
++
++      pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
++
++      pfkey_msg->sadb_msg_type = msg_type;
++      pfkey_msg->sadb_msg_satype = satype;
++
++      pfkey_msg->sadb_msg_version = PF_KEY_V2;
++      pfkey_msg->sadb_msg_errno = msg_errno;
++      pfkey_msg->sadb_msg_reserved = 0;
++      pfkey_msg->sadb_msg_seq = seq;
++      pfkey_msg->sadb_msg_pid = pid;
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_msg_hdr_build: "
++              "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
++              &pfkey_ext,
++              pfkey_ext,
++              *pfkey_ext);
++errlab:
++      return error;
++}     
++
++
++int
++pfkey_sa_builds(struct sadb_ext **pfkey_ext,
++              struct sadb_builds sab)
++{
++      int error = 0;
++      struct k_sadb_sa *pfkey_sa = (struct k_sadb_sa *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++                  "pfkey_sa_build: "
++                  "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
++                  ntohl(sab.sa_base.sadb_sa_spi), /* in network order */
++                  sab.sa_base.sadb_sa_replay,
++                  sab.sa_base.sadb_sa_state,
++                  sab.sa_base.sadb_sa_auth,
++                  sab.sa_base.sadb_sa_encrypt,
++                  sab.sa_base.sadb_sa_flags);
++      /* sanity checks... */
++      if(pfkey_sa) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "why is pfkey_sa already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(sab.sa_base.sadb_sa_exttype != SADB_EXT_SA &&
++         sab.sa_base.sadb_sa_exttype != K_SADB_X_EXT_SA2) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "invalid exttype=%d.\n",
++                      sab.sa_base.sadb_sa_exttype);
++              SENDERR(EINVAL);
++      }
++
++      if(sab.sa_base.sadb_sa_replay > 64) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "replay window size: %d -- must be 0 <= size <= 64\n",
++                      sab.sa_base.sadb_sa_replay);
++              SENDERR(EINVAL);
++      }
++
++      if(sab.sa_base.sadb_sa_auth > SADB_AALG_MAX) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "auth=%d > SADB_AALG_MAX=%d.\n",
++                      sab.sa_base.sadb_sa_auth,
++                      SADB_AALG_MAX);
++              SENDERR(EINVAL);
++      }
++
++#if K_SADB_EALG_MAX < 255     
++      if(sab.sa_base.sadb_sa_encrypt > K_SADB_EALG_MAX) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "encrypt=%d > K_SADB_EALG_MAX=%d.\n",
++                      sab.sa_base.sadb_sa_encrypt,
++                      K_SADB_EALG_MAX);
++              SENDERR(EINVAL);
++      }
++#endif
++
++      if(sab.sa_base.sadb_sa_state > K_SADB_SASTATE_MAX) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "sa_state=%d exceeds MAX=%d.\n",
++                      sab.sa_base.sadb_sa_state,
++                      K_SADB_SASTATE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(sab.sa_base.sadb_sa_state == K_SADB_SASTATE_DEAD) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "sa_state=%d is DEAD=%d is not allowed.\n",
++                      sab.sa_base.sadb_sa_state,
++                      K_SADB_SASTATE_DEAD);
++              SENDERR(EINVAL);
++      }
++      
++      if((IPSEC_SAREF_NULL != sab.sa_base.sadb_x_sa_ref) && (sab.sa_base.sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                        "pfkey_sa_build: "
++                        "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
++                        sab.sa_base.sadb_x_sa_ref,
++                        IPSEC_SAREF_NULL,
++                        IPSEC_SA_REF_TABLE_NUM_ENTRIES);
++              SENDERR(EINVAL);
++      }
++      
++      pfkey_sa = (struct k_sadb_sa*)MALLOC(sizeof(struct k_sadb_sa));
++      *pfkey_ext = (struct sadb_ext*)pfkey_sa;
++
++      if(pfkey_sa == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_sa_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_sa, 0, sizeof(struct k_sadb_sa));
++
++      *pfkey_sa = sab.sa_base;
++      pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
++
++errlab:
++      return error;
++}     
++
++int
++pfkey_sa_build(struct sadb_ext **     pfkey_ext,
++             uint16_t                 exttype,
++             uint32_t                 spi,
++             uint8_t                  replay_window,
++             uint8_t                  sa_state,
++             uint8_t                  auth,
++             uint8_t                  encrypt,
++             uint32_t                 flags)
++{
++      struct sadb_builds sab;
++      
++      memset(&sab, 0, sizeof(sab));
++      sab.sa_base.sadb_sa_exttype = exttype;
++      sab.sa_base.sadb_sa_spi     = spi;
++      sab.sa_base.sadb_sa_replay  = replay_window;
++      sab.sa_base.sadb_sa_state   = sa_state;
++      sab.sa_base.sadb_sa_auth    = auth;
++      sab.sa_base.sadb_sa_encrypt = encrypt;
++      sab.sa_base.sadb_sa_flags   = flags;
++      sab.sa_base.sadb_x_sa_ref   = IPSEC_SAREF_NULL;
++
++      return pfkey_sa_builds(pfkey_ext, sab);
++}
++
++int
++pfkey_lifetime_build(struct sadb_ext **       pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           allocations,
++                   uint64_t           bytes,
++                   uint64_t           addtime,
++                   uint64_t           usetime,
++                   uint32_t           packets)
++{
++      int error = 0;
++      struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_lifetime_build:\n");
++      /* sanity checks... */
++      if(pfkey_lifetime) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_lifetime_build: "
++                      "why is pfkey_lifetime already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(exttype != SADB_EXT_LIFETIME_CURRENT &&
++         exttype != SADB_EXT_LIFETIME_HARD &&
++         exttype != SADB_EXT_LIFETIME_SOFT) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_lifetime_build: "
++                      "invalid exttype=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime));
++      *pfkey_ext = (struct sadb_ext*) pfkey_lifetime;
++
++      if(pfkey_lifetime == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_lifetime_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
++
++      pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_lifetime->sadb_lifetime_exttype = exttype;
++      pfkey_lifetime->sadb_lifetime_allocations = allocations;
++      pfkey_lifetime->sadb_lifetime_bytes = bytes;
++      pfkey_lifetime->sadb_lifetime_addtime = addtime;
++      pfkey_lifetime->sadb_lifetime_usetime = usetime;
++#ifdef NOT_YET
++      /* XXX it is defined in struct sadb_lifetime, but not found?? */
++        pfkey_lifetime->sadb_x_lifetime_packets = packets;
++#endif
++
++errlab:
++      return error;
++}
++
++int
++pfkey_address_build(struct sadb_ext** pfkey_ext,
++                  uint16_t            exttype,
++                  uint8_t             proto,
++                  uint8_t             prefixlen,
++                  struct sockaddr*    address)
++{
++      int error = 0;
++      int saddr_len = 0;
++      char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/];
++      struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
++      
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_address_build: "
++              "exttype=%d proto=%d prefixlen=%d\n",
++              exttype,
++              proto,
++              prefixlen);
++      /* sanity checks... */
++      if(pfkey_address) {
++              ERROR("pfkey_address_build: "
++                    "why is pfkey_address already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if (!address)  {
++                      ERROR("pfkey_address_build: " "address is NULL\n");
++                      SENDERR(EINVAL);
++      }
++      
++      switch(exttype) {       
++      case SADB_EXT_ADDRESS_SRC:
++      case SADB_EXT_ADDRESS_DST:
++      case SADB_EXT_ADDRESS_PROXY:
++      case K_SADB_X_EXT_ADDRESS_DST2:
++      case K_SADB_X_EXT_ADDRESS_SRC_FLOW:
++      case K_SADB_X_EXT_ADDRESS_DST_FLOW:
++      case K_SADB_X_EXT_ADDRESS_SRC_MASK:
++      case K_SADB_X_EXT_ADDRESS_DST_MASK:
++#ifdef NAT_TRAVERSAL
++      case K_SADB_X_EXT_NAT_T_OA:
++#endif        
++              break;
++      default:
++              ERROR("pfkey_address_build: "
++                      "unrecognised ext_type=%d.\n", 
++                      exttype); 
++              SENDERR(EINVAL); 
++      }
++
++      switch(address->sa_family) {
++      case AF_INET:
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_address_build: "
++                      "found address family AF_INET.\n");
++              saddr_len = sizeof(struct sockaddr_in);
++              sprintf(ipaddr_txt, "%d.%d.%d.%d:%d"
++                      , (((struct sockaddr_in*)address)->sin_addr.s_addr >>  0) & 0xFF
++                      , (((struct sockaddr_in*)address)->sin_addr.s_addr >>  8) & 0xFF
++                      , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF
++                      , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF
++                      , ntohs(((struct sockaddr_in*)address)->sin_port));
++              break;
++      case AF_INET6:
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_address_build: "
++                      "found address family AF_INET6.\n");
++              saddr_len = sizeof(struct sockaddr_in6);
++              sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x"
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[0])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[1])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[2])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[3])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[4])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[5])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[6])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[7])
++                      , ntohs(((struct sockaddr_in6*)address)->sin6_port));
++              break;
++      default:
++              ERROR("pfkey_address_build: "
++                    "address->sa_family=%d not supported.\n",
++                    address->sa_family);
++              SENDERR(EPFNOSUPPORT);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_address_build: "
++              "found address=%s.\n",
++              ipaddr_txt);
++      if(prefixlen != 0) {
++              ERROR("pfkey_address_build: "
++                      "address prefixes not supported yet.\n");
++              SENDERR(EAFNOSUPPORT); /* not supported yet */
++      }
++
++      /* allocate some memory for the extension */
++      pfkey_address = (struct sadb_address*)
++              MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN));
++      *pfkey_ext = (struct sadb_ext*)pfkey_address;
++
++      if(pfkey_address == NULL ) {
++              ERROR("pfkey_lifetime_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_address,
++             0,
++             ALIGN_N(sizeof(struct sadb_address) + saddr_len,
++                   IPSEC_PFKEYv2_ALIGN));
++             
++      pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
++                                              IPSEC_PFKEYv2_ALIGN);
++      
++      pfkey_address->sadb_address_exttype = exttype;
++      pfkey_address->sadb_address_proto = proto;
++      pfkey_address->sadb_address_prefixlen = prefixlen;
++      pfkey_address->sadb_address_reserved = 0;
++
++      memcpy((char*)pfkey_address + sizeof(struct sadb_address),
++             address,
++             saddr_len);
++
++#if 0
++      for(i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) {
++              pfkey_address_s_ska.sin_zero[i] = 0;
++      }
++#endif
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++                "pfkey_address_build: "
++                "successful created len: %d.\n", pfkey_address->sadb_address_len);
++
++ errlab:
++      return error;
++}
++
++int
++pfkey_key_build(struct sadb_ext**     pfkey_ext,
++              uint16_t                exttype,
++              uint16_t                key_bits,
++              unsigned char *         key)
++{
++      int error = 0;
++      struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_key_build:\n");
++      /* sanity checks... */
++      if(pfkey_key) {
++              ERROR("pfkey_key_build: "
++                      "why is pfkey_key already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(!key_bits) {
++              ERROR("pfkey_key_build: "
++                      "key_bits is zero, it must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
++              ERROR("pfkey_key_build: "
++                      "unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_key = (struct sadb_key*)
++        MALLOC(sizeof(struct sadb_key) +
++               DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_key;
++
++      if(pfkey_key == NULL) {
++              ERROR("pfkey_key_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_key,
++             0,
++             sizeof(struct sadb_key) +
++             DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
++      
++      pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits,
++                                      64);
++      pfkey_key->sadb_key_exttype = exttype;
++      pfkey_key->sadb_key_bits = key_bits;
++      pfkey_key->sadb_key_reserved = 0;
++      memcpy((char*)pfkey_key + sizeof(struct sadb_key),
++             key,
++             DIVUP(key_bits, 8));
++
++errlab:
++      return error;
++}
++
++int
++pfkey_ident_build(struct sadb_ext**   pfkey_ext,
++                uint16_t              exttype,
++                uint16_t              ident_type,
++                uint64_t              ident_id,
++                uint8_t               ident_len,
++                char*                 ident_string)
++{
++      int error = 0;
++      struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
++      int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_ident_build:\n");
++      /* sanity checks... */
++      if(pfkey_ident) {
++              ERROR("pfkey_ident_build: "
++                      "why is pfkey_ident already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if( ! ((exttype == SADB_EXT_IDENTITY_SRC) ||
++             (exttype == SADB_EXT_IDENTITY_DST))) {
++              ERROR("pfkey_ident_build: "
++                      "unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      if((ident_type == SADB_IDENTTYPE_RESERVED)) {
++              ERROR("pfkey_ident_build: "
++                      "ident_type must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(ident_type > SADB_IDENTTYPE_MAX) {
++              ERROR("pfkey_ident_build: "
++                      "identtype=%d out of range.\n",
++                      ident_type);
++              SENDERR(EINVAL);
++      }
++
++      if(((ident_type == SADB_IDENTTYPE_PREFIX) ||
++          (ident_type == SADB_IDENTTYPE_FQDN)) &&
++         !ident_string) {
++              ERROR("pfkey_ident_build: "
++                      "string required to allocate size of extension.\n");
++              SENDERR(EINVAL);
++      }
++      
++#if 0
++      if((ident_type == SADB_IDENTTYPE_USERFQDN) ) {
++      }
++#endif
++          
++      pfkey_ident = (struct sadb_ident*)
++        MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN);
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_ident;
++
++      if(pfkey_ident == NULL) {
++              ERROR("pfkey_ident_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN);
++      
++      pfkey_ident->sadb_ident_len = ident_len;
++      pfkey_ident->sadb_ident_exttype = exttype;
++      pfkey_ident->sadb_ident_type = ident_type;
++      pfkey_ident->sadb_ident_reserved = 0;
++      pfkey_ident->sadb_ident_id = ident_id;
++      memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
++             ident_string,
++             data_len);
++
++errlab:
++      return error;
++}
++
++int
++pfkey_sens_build(struct sadb_ext**    pfkey_ext,
++               uint32_t               dpd,
++               uint8_t                sens_level,
++               uint8_t                sens_len,
++               uint64_t*              sens_bitmap,
++               uint8_t                integ_level,
++               uint8_t                integ_len,
++               uint64_t*              integ_bitmap)
++{
++      int error = 0;
++      struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
++      int i;
++      uint64_t* bitmap;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_sens_build:\n");
++      /* sanity checks... */
++      if(pfkey_sens) {
++              ERROR("pfkey_sens_build: "
++                      "why is pfkey_sens already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_sens_build: "
++              "Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++      pfkey_sens = (struct sadb_sens*)
++        MALLOC(sizeof(struct sadb_sens) +
++               (sens_len + integ_len) * sizeof(uint64_t));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_sens;
++
++      if(pfkey_sens == NULL) {
++              ERROR("pfkey_sens_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_sens,
++             0,
++             sizeof(struct sadb_sens) +
++             (sens_len + integ_len) * sizeof(uint64_t));
++      
++      pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
++                  (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
++      pfkey_sens->sadb_sens_dpd = dpd;
++      pfkey_sens->sadb_sens_sens_level = sens_level;
++      pfkey_sens->sadb_sens_sens_len = sens_len;
++      pfkey_sens->sadb_sens_integ_level = integ_level;
++      pfkey_sens->sadb_sens_integ_len = integ_len;
++      pfkey_sens->sadb_sens_reserved = 0;
++
++      bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
++      for(i = 0; i < sens_len; i++) {
++              *bitmap = sens_bitmap[i];
++              bitmap++;
++      }
++      for(i = 0; i < integ_len; i++) {
++              *bitmap = integ_bitmap[i];
++              bitmap++;
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_prop_build(struct sadb_ext**    pfkey_ext,
++               uint8_t                replay,
++               unsigned int           comb_num,
++               struct sadb_comb*      comb)
++{
++      int error = 0;
++      int i;
++      struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
++      struct sadb_comb *combp;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_prop_build:\n");
++      /* sanity checks... */
++      if(pfkey_prop) {
++              ERROR("pfkey_prop_build: "
++                      "why is pfkey_prop already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      pfkey_prop = (struct sadb_prop*)
++        MALLOC(sizeof(struct sadb_prop) +
++               comb_num * sizeof(struct sadb_comb));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_prop;
++
++      if(pfkey_prop == NULL) {
++              ERROR("pfkey_prop_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_prop,
++             0,
++             sizeof(struct sadb_prop) +
++                  comb_num * sizeof(struct sadb_comb));
++      
++      pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
++                  comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
++
++      pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
++      pfkey_prop->sadb_prop_replay = replay;
++
++      for(i=0; i<3; i++) {
++              pfkey_prop->sadb_prop_reserved[i] = 0;
++      }
++
++      combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
++      for(i = 0; i < comb_num; i++) {
++              memcpy (combp, &(comb[i]), sizeof(struct sadb_comb));
++              combp++;
++      }
++
++#if 0
++  uint8_t sadb_comb_auth;
++  uint8_t sadb_comb_encrypt;
++  uint16_t sadb_comb_flags;
++  uint16_t sadb_comb_auth_minbits;
++  uint16_t sadb_comb_auth_maxbits;
++  uint16_t sadb_comb_encrypt_minbits;
++  uint16_t sadb_comb_encrypt_maxbits;
++  uint32_t sadb_comb_reserved;
++  uint32_t sadb_comb_soft_allocations;
++  uint32_t sadb_comb_hard_allocations;
++  uint64_t sadb_comb_soft_bytes;
++  uint64_t sadb_comb_hard_bytes;
++  uint64_t sadb_comb_soft_addtime;
++  uint64_t sadb_comb_hard_addtime;
++  uint64_t sadb_comb_soft_usetime;
++  uint64_t sadb_comb_hard_usetime;
++  uint32_t sadb_comb_soft_packets;
++  uint32_t sadb_comb_hard_packets;
++#endif
++errlab:
++      return error;
++}
++
++int
++pfkey_supported_build(struct sadb_ext**       pfkey_ext,
++                    uint16_t          exttype,
++                    unsigned int      alg_num,
++                    struct sadb_alg*  alg)
++{
++      int error = 0;
++      unsigned int i;
++      struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
++      struct sadb_alg *pfkey_alg;
++
++      /* sanity checks... */
++      if(pfkey_supported) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_supported_build: "
++                      "why is pfkey_supported already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_supported_build: "
++                      "unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_supported = (struct sadb_supported*)
++        MALLOC(sizeof(struct sadb_supported) +
++                  alg_num *
++                  sizeof(struct sadb_alg));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_supported;
++
++      if(pfkey_supported == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_supported_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_supported,
++             0,
++             sizeof(struct sadb_supported) +
++                                             alg_num *
++                                             sizeof(struct sadb_alg));
++      
++      pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
++                                             alg_num *
++                                             sizeof(struct sadb_alg)) /
++                                              IPSEC_PFKEYv2_ALIGN;
++      pfkey_supported->sadb_supported_exttype = exttype;
++      pfkey_supported->sadb_supported_reserved = 0;
++
++      pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
++      for(i = 0; i < alg_num; i++) {
++              memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg));
++              pfkey_alg->sadb_alg_reserved = 0;
++              pfkey_alg++;
++      }
++      
++#if 0
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_supported_build: "
++              "Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++  uint8_t sadb_alg_id;
++  uint8_t sadb_alg_ivlen;
++  uint16_t sadb_alg_minbits;
++  uint16_t sadb_alg_maxbits;
++  uint16_t sadb_alg_reserved;
++#endif
++errlab:
++      return error;
++}
++
++int
++pfkey_spirange_build(struct sadb_ext**        pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           min, /* in network order */
++                   uint32_t           max) /* in network order */
++{
++      int error = 0;
++      struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
++      
++      /* sanity checks... */
++      if(pfkey_spirange) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_spirange_build: "
++                      "why is pfkey_spirange already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++        if(ntohl(max) < ntohl(min)) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_spirange_build: "
++                      "minspi=%08x must be < maxspi=%08x.\n",
++                      ntohl(min),
++                      ntohl(max));
++                SENDERR(EINVAL);
++        }
++      
++      if(ntohl(min) <= 255) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_spirange_build: "
++                      "minspi=%08x must be > 255.\n",
++                      ntohl(min));
++              SENDERR(EEXIST);
++      }
++      
++      pfkey_spirange = (struct sadb_spirange*)
++        MALLOC(sizeof(struct sadb_spirange));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_spirange;
++
++      if(pfkey_spirange == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_spirange_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_spirange,
++             0,
++             sizeof(struct sadb_spirange));
++      
++        pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
++
++      pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
++      pfkey_spirange->sadb_spirange_min = min;
++      pfkey_spirange->sadb_spirange_max = max;
++      pfkey_spirange->sadb_spirange_reserved = 0;
++ errlab:
++      return error;
++}
++
++int
++pfkey_x_kmprivate_build(struct sadb_ext**     pfkey_ext)
++{
++      int error = 0;
++      struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_x_kmprivate) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_kmprivate_build: "
++                      "why is pfkey_x_kmprivate already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_kmprivate_build: "
++              "Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++      pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
++        MALLOC(sizeof(struct sadb_x_kmprivate));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate;
++
++      if(pfkey_x_kmprivate == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_kmprivate_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_x_kmprivate,
++             0,
++             sizeof(struct sadb_x_kmprivate));
++      
++        pfkey_x_kmprivate->sadb_x_kmprivate_len =
++              sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
++
++        pfkey_x_kmprivate->sadb_x_kmprivate_exttype = K_SADB_X_EXT_KMPRIVATE;
++        pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
++errlab:
++      return error;
++}
++
++int
++pfkey_x_satype_build(struct sadb_ext**        pfkey_ext,
++                   uint8_t            satype)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_satype_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_satype) {
++              ERROR("pfkey_x_satype_build: "
++                      "why is pfkey_x_satype already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      if(!satype) {
++              ERROR("pfkey_x_satype_build: "
++                      "SA type not set, must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(satype > K_SADB_SATYPE_MAX) {
++              ERROR("pfkey_x_satype_build: "
++                      "satype %d > max %d\n", 
++                      satype, K_SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_x_satype = (struct sadb_x_satype*)
++        MALLOC(sizeof(struct sadb_x_satype));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_x_satype;
++      if(pfkey_x_satype == NULL) {
++              ERROR("pfkey_x_satype_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_x_satype,
++             0,
++             sizeof(struct sadb_x_satype));
++      
++        pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
++
++      pfkey_x_satype->sadb_x_satype_exttype = K_SADB_X_EXT_SATYPE2;
++      pfkey_x_satype->sadb_x_satype_satype = satype;
++      for(i=0; i<3; i++) {
++              pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
++                  uint32_t            tunnel,
++                  uint32_t            netlink,
++                  uint32_t            xform,
++                  uint32_t            eroute,
++                  uint32_t            spi,
++                  uint32_t            radij,
++                  uint32_t            esp,
++                  uint32_t            ah,
++                  uint32_t            rcv,
++                  uint32_t            pfkey,
++                  uint32_t            ipcomp,
++                  uint32_t            verbose)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_debug_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_debug) {
++              ERROR("pfkey_x_debug_build: "
++                      "why is pfkey_x_debug already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_debug_build: "
++              "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n",
++              tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose);
++
++      pfkey_x_debug = (struct sadb_x_debug*)
++        MALLOC(sizeof(struct sadb_x_debug));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_x_debug;
++
++      if(pfkey_x_debug == NULL) {
++              ERROR("pfkey_x_debug_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++#if 0
++      memset(pfkey_x_debug,
++             0,
++             sizeof(struct sadb_x_debug));
++#endif
++      
++        pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_x_debug->sadb_x_debug_exttype = K_SADB_X_EXT_DEBUG;
++
++      pfkey_x_debug->sadb_x_debug_tunnel = tunnel;
++      pfkey_x_debug->sadb_x_debug_netlink = netlink;
++      pfkey_x_debug->sadb_x_debug_xform = xform;
++      pfkey_x_debug->sadb_x_debug_eroute = eroute;
++      pfkey_x_debug->sadb_x_debug_spi = spi;
++      pfkey_x_debug->sadb_x_debug_radij = radij;
++      pfkey_x_debug->sadb_x_debug_esp = esp;
++      pfkey_x_debug->sadb_x_debug_ah = ah;
++      pfkey_x_debug->sadb_x_debug_rcv = rcv;
++      pfkey_x_debug->sadb_x_debug_pfkey = pfkey;
++      pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp;
++      pfkey_x_debug->sadb_x_debug_verbose = verbose;
++
++      for(i=0; i<4; i++) {
++              pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_x_nat_t_type_build(struct sadb_ext**    pfkey_ext,
++                       uint8_t         type)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_nat_t_type_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_nat_t_type) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_nat_t_type_build: "
++                      "why is pfkey_x_nat_t_type already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_nat_t_type_build: "
++              "type=%d\n", type);
++
++      pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
++        MALLOC(sizeof(struct sadb_x_nat_t_type));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type;
++
++      if(pfkey_x_nat_t_type == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_nat_t_type_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      
++      pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = K_SADB_X_EXT_NAT_T_TYPE;
++      pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
++      for(i=0; i<3; i++) {
++              pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_x_nat_t_port_build(struct sadb_ext**    pfkey_ext,
++                  uint16_t         exttype,
++                  uint16_t         port)
++{
++      int error = 0;
++      struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_nat_t_port_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_nat_t_port) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_nat_t_port_build: "
++                      "why is pfkey_x_nat_t_port already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      switch(exttype) {       
++      case K_SADB_X_EXT_NAT_T_SPORT:
++      case K_SADB_X_EXT_NAT_T_DPORT:
++              break;
++      default:
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_nat_t_port_build: "
++                      "unrecognised ext_type=%d.\n", 
++                      exttype); 
++              SENDERR(EINVAL); 
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++              "pfkey_x_nat_t_port_build: "
++              "ext=%d, port=%d\n", exttype, port);
++
++      pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
++        MALLOC(sizeof(struct sadb_x_nat_t_port));
++
++      *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port;
++
++      if(pfkey_x_nat_t_port == NULL) {
++              DEBUGGING(PF_KEY_DEBUG_BUILD,
++                      "pfkey_x_nat_t_port_build: "
++                      "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      
++      pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
++      pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
++      pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
++
++errlab:
++      return error;
++}
++
++int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
++                         uint8_t protocol)
++{
++      int error = 0;
++      struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext;
++      DEBUGGING(PF_KEY_DEBUG_BUILD,"pfkey_x_protocol_build: protocol=%u\n", protocol);
++      /* sanity checks... */
++      if  (p != 0) {
++              ERROR("pfkey_x_protocol_build: bogus protocol pointer\n");
++              SENDERR(EINVAL);
++      }
++      if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) {
++              ERROR("pfkey_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      *pfkey_ext = (struct sadb_ext *)p;
++      p->sadb_protocol_len = sizeof(*p) / IPSEC_PFKEYv2_ALIGN;
++      p->sadb_protocol_exttype = K_SADB_X_EXT_PROTOCOL;
++      p->sadb_protocol_proto = protocol;
++      p->sadb_protocol_flags = 0;
++      p->sadb_protocol_reserved2 = 0;
++ errlab:
++      return error;
++}
++
++int pfkey_outif_build(struct sadb_ext **pfkey_ext,
++                    uint16_t outif)
++{
++      int error = 0;
++      struct sadb_x_plumbif * p = (struct sadb_x_plumbif *)*pfkey_ext;
++
++      if ((p = (struct sadb_x_plumbif*)MALLOC(sizeof(*p))) == 0) {
++              ERROR("pfkey_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      *pfkey_ext = (struct sadb_ext *)p;
++
++      p->sadb_x_outif_len = IPSEC_PFKEYv2_WORDS(sizeof(*p));
++      p->sadb_x_outif_exttype = K_SADB_X_EXT_PLUMBIF;
++      p->sadb_x_outif_ifnum = outif;
++
++ errlab:
++      return error;
++}
++
++
++int pfkey_saref_build(struct sadb_ext **pfkey_ext,
++                    IPsecSAref_t in, IPsecSAref_t out)
++{
++      int error = 0;
++      struct sadb_x_saref* s;
++      
++      /* +4 because sadb_x_saref is not a multiple of 8 bytes */
++
++      if ((s = (struct sadb_x_saref*)MALLOC(sizeof(*s)+4)) == 0) {
++              ERROR("pfkey_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      *pfkey_ext = (struct sadb_ext *)s;
++
++      s->sadb_x_saref_len = IPSEC_PFKEYv2_WORDS(sizeof(*s));
++      s->sadb_x_saref_exttype = K_SADB_X_EXT_SAREF;
++      s->sadb_x_saref_me  = in;
++      s->sadb_x_saref_him = out;
++
++ errlab:
++      return error;
++}
++
++
++#if defined(I_DONT_THINK_THIS_WILL_BE_USEFUL) && I_DONT_THINK_THIS_WILL_BE_USEFUL
++int (*ext_default_builders[K_SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*)
++ =
++{
++      NULL, /* pfkey_msg_build, */
++      pfkey_sa_build,
++      pfkey_lifetime_build,
++      pfkey_lifetime_build,
++      pfkey_lifetime_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_key_build,
++      pfkey_key_build,
++      pfkey_ident_build,
++      pfkey_ident_build,
++      pfkey_sens_build,
++      pfkey_prop_build,
++      pfkey_supported_build,
++      pfkey_supported_build,
++      pfkey_spirange_build,
++      pfkey_x_kmprivate_build,
++      pfkey_x_satype_build,
++      pfkey_sa_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_address_build,
++      pfkey_x_ext_debug_build
++};
++#endif
++
++int
++pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
++{
++      int error = 0;
++      unsigned ext;
++      unsigned total_size;
++      struct sadb_ext *pfkey_ext;
++      pfkey_ext_track extensions_seen = 0;
++#ifndef __KERNEL__    
++      struct sadb_ext *extensions_check[K_SADB_EXT_MAX + 1];
++#endif
++      
++      if(!extensions[0]) {
++              ERROR("pfkey_msg_build: "
++                      "extensions[0] must be specified (struct sadb_msg).\n");
++              SENDERR(EINVAL);
++      }
++
++      /* figure out the total size for all the requested extensions */
++      total_size = IPSEC_PFKEYv2_WORDS(sizeof(struct sadb_msg));
++      for(ext = 1; ext <= K_SADB_EXT_MAX; ext++) {
++              if(extensions[ext]) {
++                      total_size += (extensions[ext])->sadb_ext_len;
++              }
++        }                
++
++      /* allocate that much space */
++      *pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN);
++      if(*pfkey_msg == NULL) {
++              ERROR("pfkey_msg_build: "
++                    "memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_BUILD,
++                "pfkey_msg_build: "
++                "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n",
++                *pfkey_msg,
++                (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN),
++                &(extensions[0]));
++
++      memcpy(*pfkey_msg,
++             extensions[0],
++             sizeof(struct sadb_msg));
++      (*pfkey_msg)->sadb_msg_len = total_size;
++      (*pfkey_msg)->sadb_msg_reserved = 0;
++      extensions_seen =  1 ;
++      
++      /*
++       * point pfkey_ext to immediately after the space for the header,
++       * i.e. at the first extension location.
++       */
++      pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
++
++      for(ext = 1; ext <= K_SADB_EXT_MAX; ext++) {
++              /* copy from extension[ext] to buffer */
++              if(extensions[ext]) {    
++                      /* Is this type of extension permitted for this type of message? */
++                      if(!pfkey_permitted_extension(dir,(*pfkey_msg)->sadb_msg_type,ext)) {
++                              ERROR("ext type %d not permitted for %d/%d (build)\n", 
++                                    ext,
++                                    dir,(*pfkey_msg)->sadb_msg_type);
++                              SENDERR(EINVAL);
++                      }
++
++                      DEBUGGING(PF_KEY_DEBUG_BUILD,
++                                "pfkey_msg_build: "
++                                "copying %lu bytes from extensions[%u] (type=%d)\n",
++                                (unsigned long)(extensions[ext]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN),
++                                ext,
++                                extensions[ext]->sadb_ext_type);
++
++                      {
++                        char *pfkey_ext_c = (char *)pfkey_ext;
++
++                        pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
++
++#if 0
++                        printf("memcpy(%p,%p,%d) -> %p %p:%p\n", pfkey_ext, 
++                               extensions[ext],
++                               (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN,
++                               pfkey_ext_c, (*pfkey_msg), (char *)(*pfkey_msg)+(total_size*IPSEC_PFKEYv2_ALIGN));
++#endif
++                        memcpy(pfkey_ext,
++                               extensions[ext],
++                               (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
++                        pfkey_ext = (struct sadb_ext *)pfkey_ext_c;
++                      }
++
++                      /* Mark that we have seen this extension */
++                      pfkey_mark_extension(ext,&extensions_seen);
++              }
++      }
++
++      if(pfkey_extensions_missing(dir,(*pfkey_msg)->sadb_msg_type,extensions_seen)) {
++              ERROR("required extensions missing. seen=%08llx\n", (unsigned long long)extensions_seen);
++              SENDERR(EINVAL);
++      }
++
++#ifndef __KERNEL__    
++/*
++ * this is silly, there is no need to reparse the message that we just built.
++ *
++ */
++      if((error = pfkey_msg_parse(*pfkey_msg,NULL,extensions_check, dir))) {
++              ERROR("pfkey_msg_build: "
++                    "Trouble parsing newly built pfkey message, error=%d.\n",
++                    error);
++              SENDERR(-error);
++      }
++#endif
++
++errlab:
++
++      return error;
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_debug.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,144 @@
++/*
++ * @(#) pfkey version 2 debugging messages
++ *
++ * Copyright (C) 2001  Richard Guy Briggs  <rgb@openswan.org>
++ *                 and Michael Richardson  <mcr@openswan.org>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: pfkey_v2_debug.c,v 1.11 2005/04/06 17:45:16 mcr Exp $
++ *
++ */
++
++#ifdef __KERNEL__
++
++# include <linux/kernel.h>  /* for printk */
++
++# include "openswan/ipsec_kversion.h" /* for malloc switch */
++# ifdef MALLOC_SLAB
++#  include <linux/slab.h> /* kmalloc() */
++# else /* MALLOC_SLAB */
++#  include <linux/malloc.h> /* kmalloc() */
++# endif /* MALLOC_SLAB */
++# include <linux/errno.h>  /* error codes */
++# include <linux/types.h>  /* size_t */
++# include <linux/interrupt.h> /* mark_bh */
++
++# include <linux/netdevice.h>   /* struct device, and other headers */
++# include <linux/etherdevice.h> /* eth_type_trans */
++extern int debug_pfkey;
++
++#else /* __KERNEL__ */
++
++#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
++# include <sys/types.h>
++#else
++# include <sys/types.h>
++# include <linux/types.h>
++# include <linux/errno.h>
++#endif
++
++#endif /* __KERNEL__ */
++
++#include "openswan.h"
++#include "openswan/pfkeyv2.h"
++#include "openswan/pfkey.h"
++
++/* 
++ * This file provides ASCII translations of PF_KEY magic numbers.
++ *
++ */
++
++static char *pfkey_sadb_ext_strings[]={
++  "reserved",                     /* K_SADB_EXT_RESERVED             0 */
++  "security-association",         /* K_SADB_EXT_SA                   1 */
++  "lifetime-current",             /* K_SADB_EXT_LIFETIME_CURRENT     2 */
++  "lifetime-hard",                /* K_SADB_EXT_LIFETIME_HARD        3 */
++  "lifetime-soft",                /* K_SADB_EXT_LIFETIME_SOFT        4 */
++  "source-address",               /* K_SADB_EXT_ADDRESS_SRC          5 */
++  "destination-address",          /* K_SADB_EXT_ADDRESS_DST          6 */
++  "proxy-address",                /* K_SADB_EXT_ADDRESS_PROXY        7 */
++  "authentication-key",           /* K_SADB_EXT_KEY_AUTH             8 */
++  "cipher-key",                   /* K_SADB_EXT_KEY_ENCRYPT          9 */
++  "source-identity",              /* K_SADB_EXT_IDENTITY_SRC         10 */
++  "destination-identity",         /* K_SADB_EXT_IDENTITY_DST         11 */
++  "sensitivity-label",            /* K_SADB_EXT_SENSITIVITY          12 */
++  "proposal",                     /* K_SADB_EXT_PROPOSAL             13 */
++  "supported-auth",               /* K_SADB_EXT_SUPPORTED_AUTH       14 */
++  "supported-cipher",             /* K_SADB_EXT_SUPPORTED_ENCRYPT    15 */
++  "spi-range",                    /* K_SADB_EXT_SPIRANGE             16 */
++  "X-kmpprivate",                 /* K_SADB_X_EXT_KMPRIVATE          17 */
++  "X-satype2",                    /* K_SADB_X_EXT_SATYPE2            18 */
++  "X-security-association",       /* K_SADB_X_EXT_SA2                19 */
++  "X-destination-address2",       /* K_SADB_X_EXT_ADDRESS_DST2       20 */
++  "X-source-flow-address",        /* K_SADB_X_EXT_ADDRESS_SRC_FLOW   21 */
++  "X-dest-flow-address",          /* K_SADB_X_EXT_ADDRESS_DST_FLOW   22 */
++  "X-source-mask",                /* K_SADB_X_EXT_ADDRESS_SRC_MASK   23 */
++  "X-dest-mask",                  /* K_SADB_X_EXT_ADDRESS_DST_MASK   24 */
++  "X-set-debug",                  /* K_SADB_X_EXT_DEBUG              25 */
++  /* NAT_TRAVERSAL */
++  "X-ext-protocol",               /* K_SADB_X_EXT_PROTOCOL           26 */
++  "X-NAT-T-type",                 /* K_SADB_X_EXT_NAT_T_TYPE         27 */
++  "X-NAT-T-sport",                /* K_SADB_X_EXT_NAT_T_SPORT        28 */
++  "X-NAT-T-dport",                /* K_SADB_X_EXT_NAT_T_DPORT        29 */
++  "X-NAT-T-OA",                   /* K_SADB_X_EXT_NAT_T_OA           30 */
++  "X-plumbif",                    /* K_SADB_X_EXT_PLUMBIF            31 */
++  "X-saref",                      /* K_SADB_X_EXT_SAREF              32 */
++};
++
++const char *
++pfkey_v2_sadb_ext_string(int ext)
++{
++  if(ext <= K_SADB_EXT_MAX) {
++    return pfkey_sadb_ext_strings[ext];
++  } else {
++    return "unknown-ext";
++  }
++}
++
++
++static char *pfkey_sadb_type_strings[]={
++      "reserved",                     /* K_SADB_RESERVED      */
++      "getspi",                       /* K_SADB_GETSPI        */
++      "update",                       /* K_SADB_UPDATE        */
++      "add",                          /* K_SADB_ADD           */
++      "delete",                       /* K_SADB_DELETE        */
++      "get",                          /* K_SADB_GET           */
++      "acquire",                      /* K_SADB_ACQUIRE       */
++      "register",                     /* K_SADB_REGISTER      */
++      "expire",                       /* K_SADB_EXPIRE        */
++      "flush",                        /* K_SADB_FLUSH         */
++      "dump",                         /* K_SADB_DUMP          */
++      "x-promisc",                    /* K_SADB_X_PROMISC     */
++      "x-pchange",                    /* K_SADB_X_PCHANGE     */
++      "x-groupsa",                    /* K_SADB_X_GRPSA       */
++      "x-addflow(eroute)",            /* K_SADB_X_ADDFLOW     */
++      "x-delflow(eroute)",            /* K_SADB_X_DELFLOW     */
++      "x-debug",                      /* K_SADB_X_DEBUG       */
++};
++
++const char *
++pfkey_v2_sadb_type_string(int sadb_type)
++{
++  if(sadb_type <= K_SADB_MAX) {
++    return pfkey_sadb_type_strings[sadb_type];
++  } else {
++    return "unknown-sadb-type";
++  }
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_ext_bits.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,814 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: pfkey_v2_ext_bits.c,v 1.22 2005/05/11 01:45:31 mcr Exp $
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parse.c.
++ */
++
++char pfkey_v2_ext_bits_c_version[] = "$Id: pfkey_v2_ext_bits.c,v 1.22 2005/05/11 01:45:31 mcr Exp $";
++
++/*
++ * Some ugly stuff to allow consistent debugging code for use in the
++ * kernel and in user space
++*/
++
++#if defined(__KERNEL__) && defined(linux)
++
++# include <linux/kernel.h>  /* for printk */
++
++# include "openswan/ipsec_kversion.h" /* for malloc switch */
++# ifdef MALLOC_SLAB
++#  include <linux/slab.h> /* kmalloc() */
++# else /* MALLOC_SLAB */
++#  include <linux/malloc.h> /* kmalloc() */
++# endif /* MALLOC_SLAB */
++# include <linux/errno.h>  /* error codes */
++# include <linux/types.h>  /* size_t */
++# include <linux/interrupt.h> /* mark_bh */
++
++# include <linux/netdevice.h>   /* struct device, and other headers */
++# include <linux/etherdevice.h> /* eth_type_trans */
++# include <linux/ip.h>          /* struct iphdr */ 
++# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++#  include <linux/ipv6.h>
++# endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++
++#else /* __KERNEL__ */
++
++# include <sys/types.h>
++# include <sys/errno.h>
++# include <stdio.h>
++#endif
++
++#include <openswan.h>
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/pfkey_debug.h"
++
++
++pfkey_ext_track extensions_bitmaps[2/*in/out*/][2/*perm/req*/][K_SADB_MAX+1]={
++
++/* INBOUND EXTENSIONS */
++{
++
++/* PERMITTED IN */
++{
++/* K_SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_SPIRANGE
++,
++/* SADB_UPDATE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_ADD */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_TYPE
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_OA
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++| 1ULL<<K_SADB_X_EXT_SAREF
++,
++/* SADB_DELETE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_ACQUIRE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++,
++/* K_SADB_REGISTER */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* K_SADB_EXPIRE */
++0
++,
++/* K_SADB_FLUSH */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* K_SADB_DUMP */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* SADB_X_PROMISC */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_ADDFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<K_SADB_X_EXT_PROTOCOL
++,
++/* SADB_X_DELFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<K_SADB_X_EXT_PROTOCOL
++,
++/* SADB_X_DEBUG */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_DEBUG
++,
++/* SADB_X_NAT_T_NEW_MAPPING */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_X_PLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++,
++/* SADB_X_UNPLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++},
++
++/* REQUIRED IN */
++{
++/* K_SADB_RESERVED */
++0
++,
++/* K_SADB_GETSPI */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_EXT_SPIRANGE
++,
++/* K_SADB_UPDATE */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_SA
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++/*| 1ULL<<K_SADB_EXT_KEY_AUTH*/
++/*| 1ULL<<K_SADB_EXT_KEY_ENCRYPT*/
++,
++/* K_SADB_ADD */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_SA
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++/*| 1ULL<<K_SADB_EXT_KEY_AUTH*/
++/*| 1ULL<<K_SADB_EXT_KEY_ENCRYPT*/
++,
++/* K_SADB_DELETE */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_SA
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++,
++/* K_SADB_GET */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_SA
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++,
++/* K_SADB_ACQUIRE */
++1ULL<<K_SADB_EXT_RESERVED
++| 1ULL<<K_SADB_EXT_ADDRESS_SRC
++| 1ULL<<K_SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_EXT_PROPOSAL
++,
++/* K_SADB_REGISTER */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* K_SADB_EXPIRE */
++0
++,
++/* K_SADB_FLUSH */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* K_SADB_DUMP */
++1ULL<<K_SADB_EXT_RESERVED
++,
++/* SADB_X_PROMISC */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++/*| 1ULL<<K_SADB_X_EXT_SATYPE2*/
++/*| 1ULL<<K_SADB_X_EXT_SA2*/
++/*| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2*/
++,
++/* SADB_X_ADDFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1ULL<<SADB_EXT_RESERVED
++/*| 1ULL<<SADB_EXT_SA*/
++#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++#endif
++,
++/* SADB_X_DEBUG */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_DEBUG
++,
++/* SADB_X_NAT_T_NEW_MAPPING */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_X_PLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++,
++/* SADB_X_UNPLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++}
++
++},
++
++/* OUTBOUND EXTENSIONS */
++{
++
++/* PERMITTED OUT */
++{
++/* K_SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_UPDATE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_ADD */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_TYPE
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_OA
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++| 1ULL<<K_SADB_X_EXT_SAREF
++,
++/* SADB_DELETE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_TYPE
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_OA
++,
++/* SADB_ACQUIRE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++,
++/* SADB_EXPIRE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_FLUSH */
++1ULL<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<K_SADB_X_EXT_NAT_T_TYPE
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_OA
++,
++/* SADB_X_PROMISC */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_ADDFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++| 1ULL<<K_SADB_X_EXT_PROTOCOL
++,
++/* SADB_X_DELFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++| 1ULL<<K_SADB_X_EXT_PROTOCOL
++,
++/* SADB_X_DEBUG */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_DEBUG
++,
++/* SADB_X_NAT_T_NEW_MAPPING */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_X_PLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++,
++/* SADB_X_UNPLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++},
++
++/* REQUIRED OUT */
++{
++/* K_SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_UPDATE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_ADD */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_DELETE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++/* | 1ULL<<SADB_EXT_KEY_AUTH */
++/* | 1ULL<<SADB_EXT_KEY_ENCRYPT */
++,
++/* SADB_ACQUIRE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1ULL<<SADB_EXT_RESERVED
++/* | 1ULL<<SADB_EXT_SUPPORTED_AUTH
++   | 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT */
++,
++/* SADB_EXPIRE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++/* | 1ULL<<SADB_EXT_LIFETIME_HARD
++   | 1ULL<<SADB_EXT_LIFETIME_SOFT */
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_FLUSH */
++1ULL<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++,
++/* SADB_X_PROMISC */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_LIFETIME_CURRENT
++| 1ULL<<SADB_EXT_LIFETIME_HARD
++| 1ULL<<SADB_EXT_LIFETIME_SOFT
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<SADB_EXT_ADDRESS_PROXY
++| 1ULL<<SADB_EXT_KEY_AUTH
++| 1ULL<<SADB_EXT_KEY_ENCRYPT
++| 1ULL<<SADB_EXT_IDENTITY_SRC
++| 1ULL<<SADB_EXT_IDENTITY_DST
++| 1ULL<<SADB_EXT_SENSITIVITY
++| 1ULL<<SADB_EXT_PROPOSAL
++| 1ULL<<SADB_EXT_SUPPORTED_AUTH
++| 1ULL<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1ULL<<SADB_EXT_SPIRANGE
++| 1ULL<<K_SADB_X_EXT_KMPRIVATE
++| 1ULL<<K_SADB_X_EXT_SATYPE2
++| 1ULL<<K_SADB_X_EXT_SA2
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_X_ADDFLOW */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1ULL<<SADB_EXT_RESERVED
++/*| 1ULL<<SADB_EXT_SA*/
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_FLOW
++| 1ULL<<K_SADB_X_EXT_ADDRESS_SRC_MASK
++| 1ULL<<K_SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DEBUG */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_DEBUG
++,
++/* SADB_X_NAT_T_NEW_MAPPING */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<SADB_EXT_SA
++| 1ULL<<SADB_EXT_ADDRESS_SRC
++| 1ULL<<SADB_EXT_ADDRESS_DST
++| 1ULL<<K_SADB_X_EXT_NAT_T_SPORT
++| 1ULL<<K_SADB_X_EXT_NAT_T_DPORT
++,
++/* SADB_X_PLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++,
++/* SADB_X_UNPLUMBIF */
++1ULL<<SADB_EXT_RESERVED
++| 1ULL<<K_SADB_X_EXT_PLUMBIF
++}
++}
++};
++
++int pfkey_required_extension(enum pfkey_ext_required inout,
++                           enum sadb_msg_t sadb_operation,
++                           enum sadb_extension_t exttype)
++{
++      return (extensions_bitmaps[inout][EXT_BITS_REQ][sadb_operation] & (1ULL<<exttype)) != 0;
++}
++
++int pfkey_permitted_extension(enum pfkey_ext_required inout,
++                            enum sadb_msg_t sadb_operation,
++                            enum sadb_extension_t exttype)
++{
++      return (extensions_bitmaps[inout][EXT_BITS_PERM][sadb_operation] & (1ULL<<exttype)) != 0;
++}
++
++
++int pfkey_extensions_missing(enum pfkey_ext_required inout,
++                           enum sadb_msg_t sadb_operation,
++                           pfkey_ext_track extensions_seen)
++
++{
++      pfkey_ext_track req = extensions_bitmaps[inout][EXT_BITS_REQ][sadb_operation];
++
++      if((extensions_seen & req) != req) {
++              ERROR("extensions for op: %d seen: %08llx required %08llx, missing: %08llx\n",
++                    sadb_operation,
++                    (unsigned long long)extensions_seen,
++                    (unsigned long long)req,
++                    (unsigned long long)req & ~(req & extensions_seen));
++              return 1;
++      }
++      return 0;
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_ext_process.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,880 @@
++/*
++ * @(#) RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1998-2003   Richard Guy Briggs.
++ * Copyright (C) 2004-2006   Michael Richardson <mcr@xelerance.com>
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++
++#include <openswan.h>
++
++#include <klips-crypto/des.h>
++
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++#ifdef NET_21
++# include <linux/in6.h>
++# define IS_MYADDR RTN_LOCAL
++#endif
++
++#include <net/ip.h>
++#ifdef NETLINK_SOCK
++# include <linux/netlink.h>
++#else
++# include <net/netlink.h>
++#endif
++
++#include <linux/random.h>     /* get_random_bytes() */
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipcomp.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++
++#ifdef CONFIG_KLIPS_OCF
++#include "ipsec_ocf.h"
++#endif
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++/* returns 0 on success */
++int
++pfkey_sa_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      struct k_sadb_sa *k_pfkey_sa = (struct k_sadb_sa *)pfkey_ext;
++      struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
++      int error = 0;
++      struct ipsec_sa* ipsp;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sa_process: .\n");
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sa_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_ext->sadb_ext_type) {
++      case K_SADB_EXT_SA:
++              ipsp = extr->ips;
++              break;
++      case K_SADB_X_EXT_SA2:
++              if(extr->ips2 == NULL) {
++                      extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
++              }
++              if(extr->ips2 == NULL) {
++                      SENDERR(-error);
++              }
++              ipsp = extr->ips2;
++              break;
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sa_process: "
++                          "invalid exttype=%d.\n",
++                          pfkey_ext->sadb_ext_type);
++              SENDERR(EINVAL);
++      }
++
++      ipsp->ips_said.spi = pfkey_sa->sadb_sa_spi;
++      ipsp->ips_replaywin = pfkey_sa->sadb_sa_replay;
++      ipsp->ips_state = pfkey_sa->sadb_sa_state;
++      ipsp->ips_flags = pfkey_sa->sadb_sa_flags;
++      ipsp->ips_replaywin_lastseq = ipsp->ips_replaywin_bitmap = 0;
++
++      if(k_pfkey_sa->sadb_sa_len > sizeof(struct sadb_sa)/IPSEC_PFKEYv2_ALIGN) {
++              ipsp->ips_ref = k_pfkey_sa->sadb_x_sa_ref;
++      }
++      
++      switch(ipsp->ips_said.proto) {
++      case IPPROTO_AH:
++              ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
++              ipsp->ips_encalg = K_SADB_EALG_NONE;
++#ifdef CONFIG_KLIPS_OCF
++              if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, 0))
++                  break;
++#endif
++              break;
++      case IPPROTO_ESP:
++              ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
++              ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
++#ifdef CONFIG_KLIPS_OCF
++              if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, ipsp->ips_encalg))
++                  break;
++#endif
++#ifdef CONFIG_KLIPS_ALG
++              ipsec_alg_sa_init(ipsp);
++#endif
++              break;
++      case IPPROTO_IPIP:
++              ipsp->ips_authalg = AH_NONE;
++              ipsp->ips_encalg = ESP_NONE;
++              break;
++#ifdef CONFIG_KLIPS_IPCOMP
++      case IPPROTO_COMP:
++              ipsp->ips_authalg = AH_NONE;
++              ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
++              break;
++#endif /* CONFIG_KLIPS_IPCOMP */
++      case IPPROTO_INT:
++              ipsp->ips_authalg = AH_NONE;
++              ipsp->ips_encalg = ESP_NONE;
++              break;
++      case 0:
++              break;
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sa_process: "
++                          "unknown proto=%d.\n",
++                          ipsp->ips_said.proto);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_lifetime_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_lifetime_process: .\n");
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_lifetime_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_lifetime->sadb_lifetime_exttype) {
++      case K_SADB_EXT_LIFETIME_CURRENT:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_lifetime_process: "
++                          "lifetime_current not supported yet.\n");
++              SENDERR(EINVAL);
++              break;
++      case K_SADB_EXT_LIFETIME_HARD:
++              ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_allocations,
++                                        pfkey_lifetime->sadb_lifetime_allocations);
++
++              ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_bytes,
++                                        pfkey_lifetime->sadb_lifetime_bytes);
++
++              ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_addtime,
++                                        pfkey_lifetime->sadb_lifetime_addtime);
++
++              ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_usetime,
++                                        pfkey_lifetime->sadb_lifetime_usetime);
++
++              break;
++
++      case K_SADB_EXT_LIFETIME_SOFT:
++              ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_allocations,
++                                         pfkey_lifetime->sadb_lifetime_allocations);
++
++              ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_bytes,
++                                         pfkey_lifetime->sadb_lifetime_bytes);
++
++              ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_addtime,
++                                         pfkey_lifetime->sadb_lifetime_addtime);
++
++              ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_usetime,
++                                         pfkey_lifetime->sadb_lifetime_usetime);
++
++              break;
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_lifetime_process: "
++                          "invalid exttype=%d.\n",
++                          pfkey_ext->sadb_ext_type);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_address_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      int saddr_len = 0;
++      char ipaddr_txt[ADDRTOA_BUF];
++      unsigned char **sap;
++      unsigned short * portp = 0;
++      struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
++      struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
++      struct ipsec_sa* ipsp;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_address_process:\n");
++      
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(s->sa_family) {
++      case AF_INET:
++              saddr_len = sizeof(struct sockaddr_in);
++              if (debug_pfkey)
++                      addrtoa(((struct sockaddr_in*)s)->sin_addr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found address family=%d, AF_INET, %s.\n",
++                          s->sa_family,
++                          ipaddr_txt);
++              break;
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++      case AF_INET6:
++              saddr_len = sizeof(struct sockaddr_in6);
++              break;
++#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "s->sa_family=%d not supported.\n",
++                          s->sa_family);
++              SENDERR(EPFNOSUPPORT);
++      }
++      
++      switch(pfkey_address->sadb_address_exttype) {
++      case K_SADB_EXT_ADDRESS_SRC:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found src address.\n");
++              sap = (unsigned char **)&(extr->ips->ips_addr_s);
++              extr->ips->ips_addr_s_size = saddr_len;
++              break;
++      case K_SADB_EXT_ADDRESS_DST:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found dst address.\n");
++              sap = (unsigned char **)&(extr->ips->ips_addr_d);
++              extr->ips->ips_addr_d_size = saddr_len;
++              break;
++      case K_SADB_EXT_ADDRESS_PROXY:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found proxy address.\n");
++              sap = (unsigned char **)&(extr->ips->ips_addr_p);
++              extr->ips->ips_addr_p_size = saddr_len;
++              break;
++      case K_SADB_X_EXT_ADDRESS_DST2:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found 2nd dst address.\n");
++              if(extr->ips2 == NULL) {
++                      extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
++              }
++              if(extr->ips2 == NULL) {
++                      SENDERR(-error);
++              }
++              sap = (unsigned char **)&(extr->ips2->ips_addr_d);
++              extr->ips2->ips_addr_d_size = saddr_len;
++              break;
++      case K_SADB_X_EXT_ADDRESS_SRC_FLOW:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found src flow address.\n");
++              if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_src);
++              portp = &(extr->eroute->er_eaddr.sen_sport);
++              break;
++      case K_SADB_X_EXT_ADDRESS_DST_FLOW:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found dst flow address.\n");
++              if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_dst);
++              portp = &(extr->eroute->er_eaddr.sen_dport);
++              break;
++      case K_SADB_X_EXT_ADDRESS_SRC_MASK:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found src mask address.\n");
++              if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_src);
++              portp = &(extr->eroute->er_emask.sen_sport);
++              break;
++      case K_SADB_X_EXT_ADDRESS_DST_MASK:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found dst mask address.\n");
++              if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_dst);
++              portp = &(extr->eroute->er_emask.sen_dport);
++              break;
++#ifdef NAT_TRAVERSAL
++      case K_SADB_X_EXT_NAT_T_OA:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "found NAT-OA address.\n");
++              sap = (unsigned char **)&(extr->ips->ips_natt_oa);
++              extr->ips->ips_natt_oa_size = saddr_len;
++              break;
++#endif
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "unrecognised ext_type=%d.\n",
++                          pfkey_address->sadb_address_exttype);
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_address->sadb_address_exttype) {
++      case K_SADB_EXT_ADDRESS_SRC:
++      case K_SADB_EXT_ADDRESS_DST:
++      case K_SADB_EXT_ADDRESS_PROXY:
++      case K_SADB_X_EXT_ADDRESS_DST2:
++#ifdef NAT_TRAVERSAL
++      case K_SADB_X_EXT_NAT_T_OA:
++#endif
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: "
++                          "allocating %d bytes for saddr.\n",
++                          saddr_len);
++              if(!(*sap = kmalloc(saddr_len, GFP_KERNEL))) {
++                      SENDERR(ENOMEM);
++              }
++              memcpy(*sap, s, saddr_len);
++              break;
++      default:
++              if(s->sa_family != AF_INET) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: "
++                                  "s->sa_family=%d not supported.\n",
++                                  s->sa_family);
++                      SENDERR(EPFNOSUPPORT);
++              }
++              {
++                      *(struct in_addr *)sap = ((struct sockaddr_in *)s)->sin_addr;
++              }
++
++              if (portp != 0)
++                      *portp = ((struct sockaddr_in*)s)->sin_port;
++#ifdef CONFIG_KLIPS_DEBUG
++              if(extr->eroute) {
++                      char buf1[64], buf2[64];
++                      if (debug_pfkey) {
++                              subnettoa(extr->eroute->er_eaddr.sen_ip_src,
++                                        extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
++                              subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
++                                        extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_address_parse: "
++                                          "extr->eroute set to %s:%d->%s:%d\n",
++                                          buf1,
++                                          ntohs(extr->eroute->er_eaddr.sen_sport),
++                                          buf2,
++                                          ntohs(extr->eroute->er_eaddr.sen_dport));
++                      }
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++      }
++
++      ipsp = extr->ips;
++      switch(pfkey_address->sadb_address_exttype) {
++      case K_SADB_X_EXT_ADDRESS_DST2:
++              ipsp = extr->ips2;
++      case K_SADB_EXT_ADDRESS_DST:
++              if(s->sa_family == AF_INET) {
++                      ipsp->ips_said.dst.u.v4.sin_addr.s_addr = ((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr.s_addr;
++                      ipsp->ips_said.dst.u.v4.sin_family      = AF_INET;
++                      if (debug_pfkey)
++                              addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
++                              0,
++                              ipaddr_txt,
++                              sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: "
++                                  "ips_said.dst set to %s.\n",
++                                  ipaddr_txt);
++              } else {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: "
++                                  "uh, ips_said.dst doesn't do address family=%d yet, said will be invalid.\n",
++                                  s->sa_family);
++              }
++      default:
++              break;
++      }
++      
++      /* XXX check if port!=0 */
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_address_process: successful.\n");
++ errlab:
++      return error;
++}
++
++int
++pfkey_key_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++        struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_key_process: .\n");
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_key_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++        switch(pfkey_key->sadb_key_exttype) {
++        case K_SADB_EXT_KEY_AUTH:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_key_process: "
++                          "allocating %d bytes for authkey.\n",
++                          DIVUP(pfkey_key->sadb_key_bits, 8));
++              if(!(extr->ips->ips_key_a = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_key_process: "
++                                  "memory allocation error.\n");
++                      SENDERR(ENOMEM);
++              }
++                extr->ips->ips_key_bits_a = pfkey_key->sadb_key_bits;
++                extr->ips->ips_key_a_size = DIVUP(pfkey_key->sadb_key_bits, 8);
++              memcpy(extr->ips->ips_key_a,
++                     (char*)pfkey_key + sizeof(struct sadb_key),
++                     extr->ips->ips_key_a_size);
++              break;
++      case K_SADB_EXT_KEY_ENCRYPT: /* Key(s) */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_key_process: "
++                          "allocating %d bytes for enckey.\n",
++                          DIVUP(pfkey_key->sadb_key_bits, 8));
++              if(!(extr->ips->ips_key_e = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_key_process: "
++                                  "memory allocation error.\n");
++                      SENDERR(ENOMEM);
++              }
++              extr->ips->ips_key_bits_e = pfkey_key->sadb_key_bits;
++              extr->ips->ips_key_e_size = DIVUP(pfkey_key->sadb_key_bits, 8);
++              memcpy(extr->ips->ips_key_e,
++                     (char*)pfkey_key + sizeof(struct sadb_key),
++                     extr->ips->ips_key_e_size);
++              break;
++      default:
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_key_process: "
++                  "success.\n");
++errlab:
++      return error;
++}
++
++int
++pfkey_ident_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++        struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
++      int data_len;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_ident_process: .\n");
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_ident_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_ident->sadb_ident_exttype) {
++      case K_SADB_EXT_IDENTITY_SRC:
++              data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++              
++              extr->ips->ips_ident_s.type = pfkey_ident->sadb_ident_type;
++              extr->ips->ips_ident_s.id = pfkey_ident->sadb_ident_id;
++              extr->ips->ips_ident_s.len = pfkey_ident->sadb_ident_len;
++              if(data_len) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_ident_process: "
++                                  "allocating %d bytes for ident_s.\n",
++                                  data_len);
++                      if(!(extr->ips->ips_ident_s.data
++                           = kmalloc(data_len, GFP_KERNEL))) {
++                                SENDERR(ENOMEM);
++                        }
++                      memcpy(extr->ips->ips_ident_s.data,
++                               (char*)pfkey_ident + sizeof(struct sadb_ident),
++                             data_len);
++                } else {
++                      extr->ips->ips_ident_s.data = NULL;
++                }
++                break;
++      case K_SADB_EXT_IDENTITY_DST: /* Identity(ies) */
++              data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
++              
++              extr->ips->ips_ident_d.type = pfkey_ident->sadb_ident_type;
++              extr->ips->ips_ident_d.id = pfkey_ident->sadb_ident_id;
++              extr->ips->ips_ident_d.len = pfkey_ident->sadb_ident_len;
++              if(data_len) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_ident_process: "
++                                  "allocating %d bytes for ident_d.\n",
++                                  data_len);
++                      if(!(extr->ips->ips_ident_d.data
++                           = kmalloc(data_len, GFP_KERNEL))) {
++                                SENDERR(ENOMEM);
++                        }
++                      memcpy(extr->ips->ips_ident_d.data,
++                               (char*)pfkey_ident + sizeof(struct sadb_ident),
++                             data_len);
++                } else {
++                      extr->ips->ips_ident_d.data = NULL;
++                }
++                break;
++      default:
++              SENDERR(EINVAL);
++      }
++errlab:
++      return error;
++}
++
++int
++pfkey_sens_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sens_process: "
++                  "Sorry, I can't process exttype=%d yet.\n",
++                  pfkey_ext->sadb_ext_type);
++        SENDERR(EINVAL); /* don't process these yet */
++ errlab:
++        return error;
++}
++
++int
++pfkey_prop_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_prop_process: "
++                  "Sorry, I can't process exttype=%d yet.\n",
++                  pfkey_ext->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++      
++ errlab:
++      return error;
++}
++
++int
++pfkey_supported_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_supported_process: "
++                  "Sorry, I can't process exttype=%d yet.\n",
++                  pfkey_ext->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++errlab:
++      return error;
++}
++
++int
++pfkey_spirange_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++        int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_spirange_process: .\n");
++/* errlab: */
++      return error;
++}
++
++int
++pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_kmprivate_process: "
++                  "Sorry, I can't process exttype=%d yet.\n",
++                  pfkey_ext->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++errlab:
++      return error;
++}
++
++int
++pfkey_x_satype_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "pfkey_x_satype_process: .\n");
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "pfkey_x_satype_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      if(extr->ips2 == NULL) {
++              extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
++      }
++      if(extr->ips2 == NULL) {
++              SENDERR(-error);
++      }
++      if(!(extr->ips2->ips_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
++              KLIPS_ERROR(debug_pfkey,
++                          "pfkey_x_satype_process: "
++                          "proto lookup from satype=%d failed.\n",
++                          pfkey_x_satype->sadb_x_satype_satype);
++              SENDERR(EINVAL);
++      }
++      KLIPS_PRINT(debug_pfkey,
++                  "pfkey_x_satype_process: "
++                  "protocol==%d decoded from satype==%d(%s).\n",
++                  extr->ips2->ips_said.proto,
++                  pfkey_x_satype->sadb_x_satype_satype,
++                  satype2name(pfkey_x_satype->sadb_x_satype_satype));
++      
++errlab:
++      return error;
++}
++
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++int
++pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)pfkey_ext;
++
++      if(!pfkey_x_nat_t_type) {
++              printk("klips_debug:pfkey_x_nat_t_type_process: "
++                     "null pointer passed in\n");
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_nat_t_type_process: %d.\n",
++                      pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_nat_t_type_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_x_nat_t_type->sadb_x_nat_t_type_type) {
++              case ESPINUDP_WITH_NON_IKE: /* with Non-IKE (older version) */
++              case ESPINUDP_WITH_NON_ESP: /* with Non-ESP */
++
++                      extr->ips->ips_natt_type = pfkey_x_nat_t_type->sadb_x_nat_t_type_type;
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_nat_t_type_process: "
++                          "unknown type %d.\n",
++                          pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
++                      SENDERR(EINVAL);
++                      break;
++      }
++
++errlab:
++      return error;
++}
++
++int
++pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)pfkey_ext;
++
++      if(!pfkey_x_nat_t_port) {
++              printk("klips_debug:pfkey_x_nat_t_port_process: "
++                     "null pointer passed in\n");
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_nat_t_port_process: %d/%d.\n",
++                      pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype,
++                      pfkey_x_nat_t_port->sadb_x_nat_t_port_port);
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_nat_t_type_process: "
++                          "extr or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype) {
++              case K_SADB_X_EXT_NAT_T_SPORT:
++                      extr->ips->ips_natt_sport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
++                      break;
++              case K_SADB_X_EXT_NAT_T_DPORT:
++                      extr->ips->ips_natt_dport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_nat_t_port_process: "
++                          "unknown exttype %d.\n",
++                          pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype);
++                      SENDERR(EINVAL);
++                      break;
++      }
++
++errlab:
++      return error;
++}
++#endif
++
++int
++pfkey_x_debug_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
++
++      if(!pfkey_x_debug) {
++              printk("klips_debug:pfkey_x_debug_process: "
++                     "null pointer passed in\n");
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_debug_process: .\n");
++
++#ifdef CONFIG_KLIPS_DEBUG
++              if(pfkey_x_debug->sadb_x_debug_netlink >>
++                 (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 - 1)) {
++                      pfkey_x_debug->sadb_x_debug_netlink &=
++                              ~(1 << (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 -1));
++                      debug_tunnel  |= pfkey_x_debug->sadb_x_debug_tunnel;
++                      debug_netlink |= pfkey_x_debug->sadb_x_debug_netlink;
++                      debug_xform   |= pfkey_x_debug->sadb_x_debug_xform;
++                      debug_eroute  |= pfkey_x_debug->sadb_x_debug_eroute;
++                      debug_spi     |= pfkey_x_debug->sadb_x_debug_spi;
++                      debug_radij   |= pfkey_x_debug->sadb_x_debug_radij;
++                      debug_esp     |= pfkey_x_debug->sadb_x_debug_esp;
++                      debug_ah      |= pfkey_x_debug->sadb_x_debug_ah;
++                      debug_rcv     |= pfkey_x_debug->sadb_x_debug_rcv;
++                      debug_pfkey   |= pfkey_x_debug->sadb_x_debug_pfkey;
++#ifdef CONFIG_KLIPS_IPCOMP
++                      sysctl_ipsec_debug_ipcomp  |= pfkey_x_debug->sadb_x_debug_ipcomp;
++#endif /* CONFIG_KLIPS_IPCOMP */
++                      sysctl_ipsec_debug_verbose |= pfkey_x_debug->sadb_x_debug_verbose;
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_debug_process: "
++                                  "set\n");
++              } else {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_debug_process: "
++                                  "unset\n");
++                      debug_tunnel  &= pfkey_x_debug->sadb_x_debug_tunnel;
++                      debug_netlink &= pfkey_x_debug->sadb_x_debug_netlink;
++                      debug_xform   &= pfkey_x_debug->sadb_x_debug_xform;
++                      debug_eroute  &= pfkey_x_debug->sadb_x_debug_eroute;
++                      debug_spi     &= pfkey_x_debug->sadb_x_debug_spi;
++                      debug_radij   &= pfkey_x_debug->sadb_x_debug_radij;
++                      debug_esp     &= pfkey_x_debug->sadb_x_debug_esp;
++                      debug_ah      &= pfkey_x_debug->sadb_x_debug_ah;
++                      debug_rcv     &= pfkey_x_debug->sadb_x_debug_rcv;
++                      debug_pfkey   &= pfkey_x_debug->sadb_x_debug_pfkey;
++#ifdef CONFIG_KLIPS_IPCOMP
++                      sysctl_ipsec_debug_ipcomp  &= pfkey_x_debug->sadb_x_debug_ipcomp;
++#endif /* CONFIG_KLIPS_IPCOMP */
++                      sysctl_ipsec_debug_verbose &= pfkey_x_debug->sadb_x_debug_verbose;
++              }
++#else /* CONFIG_KLIPS_DEBUG */
++              printk("klips_debug:pfkey_x_debug_process: "
++                     "debugging not enabled\n");
++              SENDERR(EINVAL);
++#endif /* CONFIG_KLIPS_DEBUG */
++      
++errlab:
++      return error;
++}
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_parse.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1597 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: pfkey_v2_parse.c,v 1.65 2005/04/06 17:46:05 mcr Exp $
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parser.c.
++ */
++
++char pfkey_v2_parse_c_version[] = "$Id: pfkey_v2_parse.c,v 1.65 2005/04/06 17:46:05 mcr Exp $";
++
++/*
++ * Some ugly stuff to allow consistent debugging code for use in the
++ * kernel and in user space
++*/
++
++#ifdef __KERNEL__
++
++# include <linux/kernel.h>  /* for printk */
++
++#include "openswan/ipsec_kversion.h" /* for malloc switch */
++
++# ifdef MALLOC_SLAB
++#  include <linux/slab.h> /* kmalloc() */
++# else /* MALLOC_SLAB */
++#  include <linux/malloc.h> /* kmalloc() */
++# endif /* MALLOC_SLAB */
++# include <linux/errno.h>  /* error codes */
++# include <linux/types.h>  /* size_t */
++# include <linux/interrupt.h> /* mark_bh */
++
++# include <linux/netdevice.h>   /* struct device, and other headers */
++# include <linux/etherdevice.h> /* eth_type_trans */
++# include <linux/ip.h>          /* struct iphdr */ 
++# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++#  include <linux/ipv6.h>        /* struct ipv6hdr */
++# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++extern int debug_pfkey;
++
++# include <openswan.h>
++
++#include "openswan/ipsec_encap.h"
++
++#else /* __KERNEL__ */
++
++# include <sys/types.h>
++# include <sys/errno.h>
++# include <stdio.h>
++
++# include <openswan.h>
++# include "constants.h" 
++
++#endif /* __KERNEL__ */
++
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_sa.h"  /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
++
++/* 
++ * how to handle debugging for pfkey.
++ */
++#include <openswan/pfkey_debug.h>
++
++unsigned int pfkey_lib_debug = PF_KEY_DEBUG_PARSE_NONE;
++int (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
++int (*pfkey_error_func)(const char *message, ...) PRINTF_LIKE(1);
++
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++struct satype_tbl {
++      uint8_t proto;
++      uint8_t satype;
++      char* name;
++} static satype_tbl[] = {
++#ifdef __KERNEL__
++      { IPPROTO_ESP,  K_SADB_SATYPE_ESP,      "ESP"  },
++      { IPPROTO_AH,   K_SADB_SATYPE_AH,               "AH"   },
++      { IPPROTO_IPIP, K_SADB_X_SATYPE_IPIP,   "IPIP" },
++#ifdef CONFIG_KLIPS_IPCOMP
++      { IPPROTO_COMP, K_SADB_X_SATYPE_COMP,   "COMP" },
++#endif /* CONFIG_KLIPS_IPCOMP */
++      { IPPROTO_INT,  K_SADB_X_SATYPE_INT,    "INT" },
++#else /* __KERNEL__ */
++      { SA_ESP,       K_SADB_SATYPE_ESP,      "ESP"  },
++      { SA_AH,        K_SADB_SATYPE_AH,               "AH"   },
++      { SA_IPIP,      K_SADB_X_SATYPE_IPIP,   "IPIP" },
++      { SA_COMP,      K_SADB_X_SATYPE_COMP,   "COMP" },
++      { SA_INT,       K_SADB_X_SATYPE_INT,    "INT" },
++#endif /* __KERNEL__ */
++      { 0,            0,                      "UNKNOWN" }
++};
++
++uint8_t
++satype2proto(uint8_t satype)
++{
++      int i =0;
++
++      while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
++              i++;
++      }
++      return satype_tbl[i].proto;
++}
++
++uint8_t
++proto2satype(uint8_t proto)
++{
++      int i = 0;
++
++      while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
++              i++;
++      }
++      return satype_tbl[i].satype;
++}
++
++char*
++satype2name(uint8_t satype)
++{
++      int i = 0;
++
++      while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
++              i++;
++      }
++      return satype_tbl[i].name;
++}
++
++char*
++proto2name(uint8_t proto)
++{
++      int i = 0;
++
++      while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
++              i++;
++      }
++      return satype_tbl[i].name;
++}
++
++/* Default extension parsers taken from the KLIPS code */
++
++DEBUG_NO_STATIC int
++pfkey_sa_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct k_sadb_sa *pfkey_sa = (struct k_sadb_sa *)pfkey_ext;
++      
++      /* sanity checks... */
++      if(!pfkey_sa) {
++              ERROR("pfkey_sa_parse: "
++                        "NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++
++
++      if(pfkey_sa->sadb_sa_len !=sizeof(struct k_sadb_sa)/IPSEC_PFKEYv2_ALIGN
++         && pfkey_sa->sadb_sa_len!=sizeof(struct sadb_sa)/IPSEC_PFKEYv2_ALIGN) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
++                        pfkey_sa->sadb_sa_len,
++                        (int)sizeof(struct k_sadb_sa));
++              SENDERR(EINVAL);
++      }
++
++#if K_SADB_EALG_MAX < 255     
++      if(pfkey_sa->sadb_sa_encrypt > K_SADB_EALG_MAX) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "pfkey_sa->sadb_sa_encrypt=%d > K_SADB_EALG_MAX=%d.\n",
++                        pfkey_sa->sadb_sa_encrypt,
++                        K_SADB_EALG_MAX);
++              SENDERR(EINVAL);
++      }
++#endif
++      
++#if K_SADB_AALG_MAX < 255     
++      if(pfkey_sa->sadb_sa_auth > K_SADB_AALG_MAX) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "pfkey_sa->sadb_sa_auth=%d > K_SADB_AALG_MAX=%d.\n",
++                        pfkey_sa->sadb_sa_auth,
++                        K_SADB_AALG_MAX);
++              SENDERR(EINVAL);
++      }
++#endif
++      
++#if K_SADB_SASTATE_MAX < 255  
++      if(pfkey_sa->sadb_sa_state > K_SADB_SASTATE_MAX) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "state=%d exceeds MAX=%d.\n",
++                        pfkey_sa->sadb_sa_state,
++                        K_SADB_SASTATE_MAX);
++              SENDERR(EINVAL);
++      }
++#endif
++      
++      if(pfkey_sa->sadb_sa_state == K_SADB_SASTATE_DEAD) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "state=%d is DEAD=%d.\n",
++                        pfkey_sa->sadb_sa_state,
++                        K_SADB_SASTATE_DEAD);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_replay > 64) {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "replay window size: %d -- must be 0 <= size <= 64\n",
++                        pfkey_sa->sadb_sa_replay);
++              SENDERR(EINVAL);
++      }
++      
++      if(! ((pfkey_sa->sadb_sa_exttype ==  K_SADB_EXT_SA) ||
++            (pfkey_sa->sadb_sa_exttype ==  K_SADB_X_EXT_SA2)))
++      {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "unknown exttype=%d, expecting K_SADB_EXT_SA=%d or K_SADB_X_EXT_SA2=%d.\n",
++                        pfkey_sa->sadb_sa_exttype,
++                        K_SADB_EXT_SA,
++                        K_SADB_X_EXT_SA2);
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_sa->sadb_sa_len > sizeof(struct sadb_sa)/IPSEC_PFKEYv2_ALIGN) {
++              if(pfkey_sa->sadb_x_sa_ref == IPSEC_SAREF_NULL ||
++                 pfkey_sa->sadb_x_sa_ref == ~(IPSEC_SAREF_NULL))
++              {
++                      pfkey_sa->sadb_x_sa_ref = IPSEC_SAREF_NULL;
++              }
++      }
++
++      if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref)
++         && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH)))
++      {
++              ERROR(
++                        "pfkey_sa_parse: "
++                        "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
++                        pfkey_sa->sadb_x_sa_ref,
++                        IPSEC_SAREF_NULL,
++                        IPSEC_SA_REF_TABLE_NUM_ENTRIES);
++              SENDERR(EINVAL);
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_sa_parse: "
++                "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n",
++                pfkey_sa->sadb_sa_len,
++                pfkey_sa->sadb_sa_exttype,
++                pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype),
++                (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi),
++                pfkey_sa->sadb_sa_replay,
++                pfkey_sa->sadb_sa_state,
++                pfkey_sa->sadb_sa_auth,
++                pfkey_sa->sadb_sa_encrypt,
++                pfkey_sa->sadb_sa_flags,
++                pfkey_sa->sadb_x_sa_ref);
++      
++ errlab:
++      return error;
++}     
++
++DEBUG_NO_STATIC int
++pfkey_lifetime_parse(struct sadb_ext  *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++                "pfkey_lifetime_parse:enter\n");
++      /* sanity checks... */
++      if(!pfkey_lifetime) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_lifetime_parse: "
++                        "NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_lifetime->sadb_lifetime_len !=
++         sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_lifetime_parse: "
++                        "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
++                        pfkey_lifetime->sadb_lifetime_len,
++                        (int)sizeof(struct sadb_lifetime));
++              SENDERR(EINVAL);
++      }
++
++      if((pfkey_lifetime->sadb_lifetime_exttype != K_SADB_EXT_LIFETIME_HARD) &&
++         (pfkey_lifetime->sadb_lifetime_exttype != K_SADB_EXT_LIFETIME_SOFT) &&
++         (pfkey_lifetime->sadb_lifetime_exttype != K_SADB_EXT_LIFETIME_CURRENT)) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_lifetime_parse: "
++                        "unexpected ext_type=%d.\n", 
++                        pfkey_lifetime->sadb_lifetime_exttype); 
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_lifetime_parse: "
++                "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u.\n", 
++                pfkey_lifetime->sadb_lifetime_exttype,
++                pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype),
++                pfkey_lifetime->sadb_lifetime_allocations,
++                (unsigned)pfkey_lifetime->sadb_lifetime_bytes,
++                (unsigned)pfkey_lifetime->sadb_lifetime_addtime,
++                (unsigned)pfkey_lifetime->sadb_lifetime_usetime);
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_address_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      int saddr_len = 0;
++      struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
++      struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
++      char ipaddr_txt[ADDRTOT_BUF];
++      
++      /* sanity checks... */
++      if(!pfkey_address) {
++              ERROR(
++                      "pfkey_address_parse: "
++                      "NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_address->sadb_address_len <
++         (sizeof(struct sadb_address) + sizeof(struct sockaddr))/
++         IPSEC_PFKEYv2_ALIGN) {
++              ERROR("pfkey_address_parse: "
++                        "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
++                        pfkey_address->sadb_address_len,
++                        (int)sizeof(struct sadb_address),
++                        (int)sizeof(struct sockaddr));
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_address->sadb_address_reserved) {
++              ERROR("pfkey_address_parse: "
++                        "res=%d, must be zero.\n",
++                        pfkey_address->sadb_address_reserved);
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_address->sadb_address_exttype) {   
++      case K_SADB_EXT_ADDRESS_SRC:
++      case K_SADB_EXT_ADDRESS_DST:
++      case K_SADB_EXT_ADDRESS_PROXY:
++      case K_SADB_X_EXT_ADDRESS_DST2:
++      case K_SADB_X_EXT_ADDRESS_SRC_FLOW:
++      case K_SADB_X_EXT_ADDRESS_DST_FLOW:
++      case K_SADB_X_EXT_ADDRESS_SRC_MASK:
++      case K_SADB_X_EXT_ADDRESS_DST_MASK:
++#ifdef NAT_TRAVERSAL
++      case K_SADB_X_EXT_NAT_T_OA:
++#endif
++              break;
++      default:
++              ERROR(
++                      "pfkey_address_parse: "
++                      "unexpected ext_type=%d.\n",
++                      pfkey_address->sadb_address_exttype);
++              SENDERR(ENODEV);
++      }
++
++      switch(s->sa_family) {
++      case AF_INET:
++              saddr_len = sizeof(struct sockaddr_in);
++              sprintf(ipaddr_txt, "%d.%d.%d.%d"
++                      , (((struct sockaddr_in*)s)->sin_addr.s_addr >>  0) & 0xFF
++                      , (((struct sockaddr_in*)s)->sin_addr.s_addr >>  8) & 0xFF
++                      , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF
++                      , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF);
++              DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                        "pfkey_address_parse: "
++                        "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n",
++                        pfkey_address->sadb_address_exttype,
++                        pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
++                        s->sa_family,
++                        ipaddr_txt,
++                        pfkey_address->sadb_address_proto,
++                        ntohs(((struct sockaddr_in*)s)->sin_port));
++              break;
++      case AF_INET6:
++              saddr_len = sizeof(struct sockaddr_in6);
++              sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x"
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[0])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[1])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[2])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[3])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[4])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[5])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[6])
++                      , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[7]));
++              DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                        "pfkey_address_parse: "
++                        "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n",
++                        pfkey_address->sadb_address_exttype,
++                        pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
++                        s->sa_family,
++                        ipaddr_txt,
++                        pfkey_address->sadb_address_proto,
++                        ((struct sockaddr_in6*)s)->sin6_port);
++              break;
++      default:
++              ERROR(
++                      "pfkey_address_parse: "
++                      "s->sa_family=%d not supported.\n",
++                      s->sa_family);
++              SENDERR(EPFNOSUPPORT);
++      }
++      
++      if(pfkey_address->sadb_address_len !=
++         DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) {
++              ERROR(
++                        "pfkey_address_parse: "
++                        "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
++                        pfkey_address->sadb_address_len,
++                        (int)sizeof(struct sadb_address),
++                        saddr_len);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_address->sadb_address_prefixlen != 0) {
++              ERROR(
++                      "pfkey_address_parse: "
++                      "address prefixes not supported yet.\n");
++              SENDERR(EAFNOSUPPORT); /* not supported yet */
++      }
++      
++      /* XXX check if port!=0 */
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++              "pfkey_address_parse: successful.\n");
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_key_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
++
++      /* sanity checks... */
++
++      if(!pfkey_key) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
++              ERROR(
++                        "pfkey_key_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_key->sadb_key_len,
++                        (int)sizeof(struct sadb_key));
++              SENDERR(EINVAL);
++      }
++
++      if(!pfkey_key->sadb_key_bits) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "key length set to zero, must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_key->sadb_key_len !=
++         DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits,
++               PFKEYBITS)) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "key length=%d does not agree with extension length=%d.\n",
++                      pfkey_key->sadb_key_bits,
++                      pfkey_key->sadb_key_len);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_key->sadb_key_reserved) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "res=%d, must be zero.\n",
++                      pfkey_key->sadb_key_reserved);
++              SENDERR(EINVAL);
++      }
++
++      if(! ( (pfkey_key->sadb_key_exttype == K_SADB_EXT_KEY_AUTH) ||
++             (pfkey_key->sadb_key_exttype == K_SADB_EXT_KEY_ENCRYPT))) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "expecting extension type AUTH or ENCRYPT, got %d.\n",
++                      pfkey_key->sadb_key_exttype);
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_key_parse: "
++                "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n",
++                pfkey_key->sadb_key_len,
++                pfkey_key->sadb_key_exttype,
++                pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype),
++                pfkey_key->sadb_key_bits,
++                pfkey_key->sadb_key_reserved);
++
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_ident_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
++              ERROR(
++                        "pfkey_ident_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_ident->sadb_ident_len,
++                        (int)sizeof(struct sadb_ident));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_ident->sadb_ident_type > K_SADB_IDENTTYPE_MAX) {
++              ERROR(
++                      "pfkey_ident_parse: "
++                      "ident_type=%d out of range, must be less than %d.\n",
++                      pfkey_ident->sadb_ident_type,
++                      K_SADB_IDENTTYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_ident->sadb_ident_reserved) {
++              ERROR(
++                      "pfkey_ident_parse: "
++                      "res=%d, must be zero.\n",
++                      pfkey_ident->sadb_ident_reserved);
++              SENDERR(EINVAL);
++      }
++
++      /* string terminator/padding must be zero */
++      if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
++              if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) {
++                      ERROR(
++                              "pfkey_ident_parse: "
++                              "string padding must be zero, last is 0x%02x.\n",
++                              *((char*)pfkey_ident +
++                                pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1));
++                      SENDERR(EINVAL);
++              }
++      }
++      
++      if( ! ((pfkey_ident->sadb_ident_exttype == K_SADB_EXT_IDENTITY_SRC) ||
++             (pfkey_ident->sadb_ident_exttype == K_SADB_EXT_IDENTITY_DST))) {
++              ERROR(
++                      "pfkey_key_parse: "
++                      "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
++                      pfkey_ident->sadb_ident_exttype);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_sens_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_sens_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_sens->sadb_sens_len,
++                        (int)sizeof(struct sadb_sens));
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++              "pfkey_sens_parse: "
++              "Sorry, I can't parse exttype=%d yet.\n",
++              pfkey_ext->sadb_ext_type);
++#if 0
++      SENDERR(EINVAL); /* don't process these yet */
++#endif
++
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_prop_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      int i, num_comb;
++      struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
++      struct k_sadb_comb *k_pfkey_comb = (struct k_sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop));
++
++      /* sanity checks... */
++      if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) || 
++         (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_prop_parse: "
++                        "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n",
++                        pfkey_prop->sadb_prop_len,
++                        (int)sizeof(struct sadb_prop),
++                        (int)sizeof(struct sadb_comb));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_prop->sadb_prop_replay > 64) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_prop_parse: "
++                      "replay window size: %d -- must be 0 <= size <= 64\n",
++                      pfkey_prop->sadb_prop_replay);
++              SENDERR(EINVAL);
++      }
++      
++      for(i=0; i<3; i++) {
++              if(pfkey_prop->sadb_prop_reserved[i]) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_prop_parse: "
++                              "res[%d]=%d, must be zero.\n",
++                              i, pfkey_prop->sadb_prop_reserved[i]);
++                      SENDERR(EINVAL);
++              }
++      }
++
++      num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
++
++      for(i = 0; i < num_comb; i++) {
++              struct sadb_comb *pfkey_comb = (struct sadb_comb *)k_pfkey_comb;
++              if(pfkey_comb->sadb_comb_auth > K_SADB_AALG_MAX) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_prop_parse: "
++                              "pfkey_comb[%d]->sadb_comb_auth=%d > K_SADB_AALG_MAX=%d.\n",
++                              i,
++                              pfkey_comb->sadb_comb_auth,
++                              K_SADB_AALG_MAX);
++                      SENDERR(EINVAL);
++              }
++
++              if(pfkey_comb->sadb_comb_auth) {
++                      if(!pfkey_comb->sadb_comb_auth_minbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n",
++                                      i);
++                              SENDERR(EINVAL);
++                      }
++                      if(!pfkey_comb->sadb_comb_auth_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n",
++                                      i);
++                              SENDERR(EINVAL);
++                      }
++                      if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_auth_minbits,
++                                      pfkey_comb->sadb_comb_auth_maxbits);
++                              SENDERR(EINVAL);
++                      }
++              } else {
++                      if(pfkey_comb->sadb_comb_auth_minbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_auth_minbits);
++                              SENDERR(EINVAL);
++                      }
++                      if(pfkey_comb->sadb_comb_auth_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_auth_maxbits);
++                              SENDERR(EINVAL);
++                      }
++              }
++
++#if K_SADB_EALG_MAX < 255     
++              if(pfkey_comb->sadb_comb_encrypt > K_SADB_EALG_MAX) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_comb_parse: "
++                              "pfkey_comb[%d]->sadb_comb_encrypt=%d > K_SADB_EALG_MAX=%d.\n",
++                              i,
++                              pfkey_comb->sadb_comb_encrypt,
++                              K_SADB_EALG_MAX);
++                      SENDERR(EINVAL);
++              }
++#endif
++
++              if(pfkey_comb->sadb_comb_encrypt) {
++                      if(!pfkey_comb->sadb_comb_encrypt_minbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n",
++                                      i);
++                              SENDERR(EINVAL);
++                      }
++                      if(!pfkey_comb->sadb_comb_encrypt_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n",
++                                      i);
++                              SENDERR(EINVAL);
++                      }
++                      if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_encrypt_minbits,
++                                      pfkey_comb->sadb_comb_encrypt_maxbits);
++                              SENDERR(EINVAL);
++                      }
++              } else {
++                      if(pfkey_comb->sadb_comb_encrypt_minbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_encrypt_minbits);
++                              SENDERR(EINVAL);
++                      }
++                      if(pfkey_comb->sadb_comb_encrypt_maxbits) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_prop_parse: "
++                                      "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n",
++                                      i,
++                                      pfkey_comb->sadb_comb_encrypt_maxbits);
++                              SENDERR(EINVAL);
++                      }
++              }
++
++              /* XXX do sanity check on flags */
++
++              if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_prop_parse: "
++                                "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n",
++                                i,
++                                pfkey_comb->sadb_comb_soft_allocations,
++                                pfkey_comb->sadb_comb_hard_allocations);
++                      SENDERR(EINVAL);
++              }
++
++              if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_prop_parse: "
++                                "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n",
++                                i,
++                                (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes,
++                                (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes);
++                      SENDERR(EINVAL);
++              }
++
++              if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_prop_parse: "
++                                "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n",
++                                i,
++                                (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime,
++                                (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime);
++                      SENDERR(EINVAL);
++              }
++
++              if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_prop_parse: "
++                                "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n",
++                                i,
++                                (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime,
++                                (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime);
++                      SENDERR(EINVAL);
++              }
++
++#ifdef COMB_PACKETS
++              if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_prop_parse: "
++                              "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n",
++                              i,
++                              k_pfkey_comb->sadb_x_comb_soft_packets,
++                              k_pfkey_comb->sadb_x_comb_hard_packets);
++                      SENDERR(EINVAL);
++              }
++#endif
++
++              pfkey_comb++;
++      }
++
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_supported_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      unsigned int i, num_alg;
++      struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext;
++      struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
++
++      /* sanity checks... */
++      if((pfkey_supported->sadb_supported_len <
++         sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) ||
++         (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) -
++           sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) {
++
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_supported_parse: "
++                        "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n",
++                        pfkey_supported->sadb_supported_len,
++                        (int)sizeof(struct sadb_supported),
++                        (int)sizeof(struct sadb_alg));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_supported->sadb_supported_reserved) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_supported_parse: "
++                      "res=%d, must be zero.\n",
++                      pfkey_supported->sadb_supported_reserved);
++              SENDERR(EINVAL);
++      }
++
++      num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
++
++      for(i = 0; i < num_alg; i++) {
++              /* process algo description */
++              if(pfkey_alg->sadb_alg_reserved) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_supported_parse: "
++                              "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n",
++                              i,
++                              pfkey_alg->sadb_alg_id,
++                              pfkey_alg->sadb_alg_ivlen,
++                              pfkey_alg->sadb_alg_minbits,
++                              pfkey_alg->sadb_alg_maxbits,
++                              pfkey_alg->sadb_alg_reserved);
++                      SENDERR(EINVAL);
++              }
++
++              /* XXX can alg_id auth/enc be determined from info given?
++                 Yes, but OpenBSD's method does not iteroperate with rfc2367.
++                 rgb, 2000-04-06 */
++
++              switch(pfkey_supported->sadb_supported_exttype) {
++              case K_SADB_EXT_SUPPORTED_AUTH:
++                      if(pfkey_alg->sadb_alg_id > K_SADB_AALG_MAX) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_supported_parse: "
++                                      "alg[%d], alg_id=%d > K_SADB_AALG_MAX=%d, fatal.\n",
++                                      i,
++                                      pfkey_alg->sadb_alg_id,
++                                      K_SADB_AALG_MAX);
++                              SENDERR(EINVAL);
++                      }
++                      break;
++              case SADB_EXT_SUPPORTED_ENCRYPT:
++#if K_SADB_EALG_MAX < 255     
++                      if(pfkey_alg->sadb_alg_id > K_SADB_EALG_MAX) {
++                              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                      "pfkey_supported_parse: "
++                                      "alg[%d], alg_id=%d > K_SADB_EALG_MAX=%d, fatal.\n",
++                                      i,
++                                      pfkey_alg->sadb_alg_id,
++                                      K_SADB_EALG_MAX);
++                              SENDERR(EINVAL);
++                      }
++#endif
++                      break;
++              default:
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_supported_parse: "
++                              "alg[%d], alg_id=%d > K_SADB_EALG_MAX=%d, fatal.\n",
++                              i,
++                              pfkey_alg->sadb_alg_id,
++                              K_SADB_EALG_MAX);
++                      SENDERR(EINVAL);
++              }
++              pfkey_alg++;
++      }
++      
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_spirange_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext;
++      
++      /* sanity checks... */
++        if(pfkey_spirange->sadb_spirange_len !=
++         sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_spirange_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_spirange->sadb_spirange_len,
++                        (int)sizeof(struct sadb_spirange));
++                SENDERR(EINVAL);
++        }
++      
++        if(pfkey_spirange->sadb_spirange_reserved) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_spirange_parse: "
++                      "reserved=%d must be set to zero.\n",
++                      pfkey_spirange->sadb_spirange_reserved);
++                SENDERR(EINVAL);
++        }
++      
++        if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_spirange_parse: "
++                      "minspi=%08x must be < maxspi=%08x.\n",
++                      ntohl(pfkey_spirange->sadb_spirange_min),
++                      ntohl(pfkey_spirange->sadb_spirange_max));
++                SENDERR(EINVAL);
++        }
++      
++      if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_spirange_parse: "
++                      "minspi=%08x must be > 255.\n",
++                      ntohl(pfkey_spirange->sadb_spirange_min));
++              SENDERR(EEXIST);
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_spirange_parse: "
++                "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n",
++                pfkey_spirange->sadb_spirange_len,
++                pfkey_spirange->sadb_spirange_exttype,
++                pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype),
++                pfkey_spirange->sadb_spirange_min,
++                pfkey_spirange->sadb_spirange_max,
++                pfkey_spirange->sadb_spirange_reserved);
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_x_kmprivate->sadb_x_kmprivate_len <
++         sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_x_kmprivate_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_x_kmprivate->sadb_x_kmprivate_len,
++                        (int)sizeof(struct sadb_x_kmprivate));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_x_kmprivate_parse: "
++                        "reserved=%d must be set to zero.\n",
++                        pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                "pfkey_x_kmprivate_parse: "
++                "Sorry, I can't parse exttype=%d yet.\n",
++                pfkey_ext->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_satype_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++              "pfkey_x_satype_parse: enter\n");
++      /* sanity checks... */
++      if(pfkey_x_satype->sadb_x_satype_len !=
++         sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_x_satype_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_x_satype->sadb_x_satype_len,
++                        (int)sizeof(struct sadb_x_satype));
++              SENDERR(EINVAL);
++      }
++      
++      if(!pfkey_x_satype->sadb_x_satype_satype) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_x_satype_parse: "
++                      "satype is zero, must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_x_satype->sadb_x_satype_satype > K_SADB_SATYPE_MAX) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_x_satype_parse: "
++                      "satype %d > max %d, invalid.\n", 
++                      pfkey_x_satype->sadb_x_satype_satype, K_SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_x_satype_parse: "
++                      "proto lookup from satype=%d failed.\n",
++                      pfkey_x_satype->sadb_x_satype_satype);
++              SENDERR(EINVAL);
++      }
++
++      for(i = 0; i < 3; i++) {
++              if(pfkey_x_satype->sadb_x_satype_reserved[i]) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_x_satype_parse: "
++                              "reserved[%d]=%d must be set to zero.\n",
++                              i, pfkey_x_satype->sadb_x_satype_reserved[i]);
++                      SENDERR(EINVAL);
++              }
++      }
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_x_satype_parse: "
++                "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n",
++                pfkey_x_satype->sadb_x_satype_len,
++                pfkey_x_satype->sadb_x_satype_exttype,
++                pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype),
++                pfkey_x_satype->sadb_x_satype_satype,
++                satype2name(pfkey_x_satype->sadb_x_satype_satype),
++                pfkey_x_satype->sadb_x_satype_reserved[0],
++                pfkey_x_satype->sadb_x_satype_reserved[1],
++                pfkey_x_satype->sadb_x_satype_reserved[2]);
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++              "pfkey_x_debug_parse: enter\n");
++      /* sanity checks... */
++      if(pfkey_x_debug->sadb_x_debug_len !=
++         sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_x_debug_parse: "
++                        "size wrong ext_len=%d, key_ext_len=%d.\n",
++                        pfkey_x_debug->sadb_x_debug_len,
++                        (int)sizeof(struct sadb_x_debug));
++              SENDERR(EINVAL);
++      }
++      
++      for(i = 0; i < 4; i++) {
++              if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_x_debug_parse: "
++                              "reserved[%d]=%d must be set to zero.\n",
++                              i, pfkey_x_debug->sadb_x_debug_reserved[i]);
++                      SENDERR(EINVAL);
++              }
++      }
++      
++errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext;
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n");
++      /* sanity checks... */
++      
++      if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                        p->sadb_protocol_len, (int)sizeof(*p));
++              SENDERR(EINVAL);
++      }
++      
++      if (p->sadb_protocol_reserved2 != 0) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                        "pfkey_protocol_parse: res=%d, must be zero.\n",
++                        p->sadb_protocol_reserved2);
++              SENDERR(EINVAL);
++      }
++
++ errlab:
++      return error;
++}
++
++#ifdef NAT_TRAVERSAL
++DEBUG_NO_STATIC int
++pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
++{
++      return 0;
++}
++DEBUG_NO_STATIC int
++pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
++{
++      return 0;
++}
++#endif
++
++DEBUG_NO_STATIC int
++pfkey_x_ext_outif_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_x_plumbif *p = (struct sadb_x_plumbif *)pfkey_ext;
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_outif_parse:\n");
++      /* sanity checks... */
++      
++      if (p->sadb_x_outif_len != IPSEC_PFKEYv2_WORDS(sizeof(*p))) {
++                  DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                            "pfkey_x_outif_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                            p->sadb_x_outif_len, (int)sizeof(*p));
++                  SENDERR(EINVAL);
++      }
++      
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_ext_saref_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_x_saref *p = (struct sadb_x_saref *)pfkey_ext;
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_saref_parse:\n");
++      /* sanity checks... */
++      
++      if (p->sadb_x_saref_len != IPSEC_PFKEYv2_WORDS(sizeof(*p))) {
++                  DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                            "pfkey_x_saref_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                            p->sadb_x_saref_len, (int)sizeof(*p));
++                  SENDERR(EINVAL);
++      }
++      
++ errlab:
++      return error;
++}
++
++
++#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
++
++DEFINEPARSER(pfkey_sa_parse);
++DEFINEPARSER(pfkey_lifetime_parse);
++DEFINEPARSER(pfkey_address_parse);
++DEFINEPARSER(pfkey_key_parse);
++DEFINEPARSER(pfkey_ident_parse);
++DEFINEPARSER(pfkey_sens_parse);
++DEFINEPARSER(pfkey_prop_parse);
++DEFINEPARSER(pfkey_supported_parse);
++DEFINEPARSER(pfkey_spirange_parse);
++DEFINEPARSER(pfkey_x_kmprivate_parse);
++DEFINEPARSER(pfkey_x_satype_parse);
++DEFINEPARSER(pfkey_x_ext_debug_parse);
++DEFINEPARSER(pfkey_x_ext_protocol_parse);
++#ifdef NAT_TRAVERSAL
++DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
++DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
++#endif
++DEFINEPARSER(pfkey_x_ext_outif_parse);
++DEFINEPARSER(pfkey_x_ext_saref_parse);
++
++struct pf_key_ext_parsers_def *ext_default_parsers[]=
++{
++      NULL,                 /* pfkey_msg_parse, */
++      &pfkey_sa_parse_def,
++      &pfkey_lifetime_parse_def,
++      &pfkey_lifetime_parse_def,
++      &pfkey_lifetime_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_key_parse_def,
++      &pfkey_key_parse_def,
++      &pfkey_ident_parse_def,
++      &pfkey_ident_parse_def,
++      &pfkey_sens_parse_def,
++      &pfkey_prop_parse_def,
++      &pfkey_supported_parse_def,
++      &pfkey_supported_parse_def,
++      &pfkey_spirange_parse_def,
++      &pfkey_x_kmprivate_parse_def,
++      &pfkey_x_satype_parse_def,
++      &pfkey_sa_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_address_parse_def,
++      &pfkey_x_ext_debug_parse_def,
++      &pfkey_x_ext_protocol_parse_def,
++#ifdef NAT_TRAVERSAL
++      &pfkey_x_ext_nat_t_type_parse_def,
++      &pfkey_x_ext_nat_t_port_parse_def,
++      &pfkey_x_ext_nat_t_port_parse_def,
++      &pfkey_address_parse_def,
++#else
++      NULL,NULL,NULL,NULL,
++#endif
++      &pfkey_x_ext_outif_parse_def,
++      &pfkey_x_ext_saref_parse_def,
++};
++
++int
++pfkey_msg_parse(struct sadb_msg *pfkey_msg,
++              struct pf_key_ext_parsers_def *ext_parsers[],
++              struct sadb_ext *extensions[],
++              int dir)
++{
++      int error = 0;
++      int remain;
++      struct sadb_ext *pfkey_ext;
++      pfkey_ext_track extensions_seen = 0;
++      
++      DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                "pfkey_msg_parse: "
++                "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", 
++                pfkey_msg->sadb_msg_version,
++                pfkey_msg->sadb_msg_type,
++                pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
++                pfkey_msg->sadb_msg_errno,
++                pfkey_msg->sadb_msg_satype,
++                satype2name(pfkey_msg->sadb_msg_satype),
++                pfkey_msg->sadb_msg_len,
++                pfkey_msg->sadb_msg_reserved,
++                pfkey_msg->sadb_msg_seq,
++                pfkey_msg->sadb_msg_pid);
++      
++      if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
++      
++      pfkey_extensions_init(extensions);
++      
++      remain = pfkey_msg->sadb_msg_len;
++      remain -= IPSEC_PFKEYv2_WORDS(sizeof(struct sadb_msg));
++      
++      pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
++                                     sizeof(struct sadb_msg));
++      
++      extensions[0] = (struct sadb_ext *) pfkey_msg;
++      
++      
++      if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
++              ERROR("pfkey_msg_parse: "
++                      "not PF_KEY_V2 msg, found %d, should be %d.\n",
++                      pfkey_msg->sadb_msg_version,
++                      PF_KEY_V2);
++              SENDERR(EINVAL);
++      }
++
++      if(!pfkey_msg->sadb_msg_type) {
++              ERROR("pfkey_msg_parse: "
++                      "msg type not set, must be non-zero..\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_msg->sadb_msg_type > K_SADB_MAX) {
++              ERROR("pfkey_msg_parse: "
++                      "msg type=%d > max=%d.\n",
++                      pfkey_msg->sadb_msg_type,
++                      K_SADB_MAX);
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_msg->sadb_msg_type) {
++      case K_SADB_GETSPI:
++      case K_SADB_UPDATE:
++      case K_SADB_ADD:
++      case K_SADB_DELETE:
++      case K_SADB_GET:
++      case K_SADB_X_GRPSA:
++      case K_SADB_X_ADDFLOW:
++              if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
++                      ERROR("pfkey_msg_parse: "
++                                "satype %d conversion to proto failed for msg_type %d (%s).\n",
++                                pfkey_msg->sadb_msg_satype,
++                                pfkey_msg->sadb_msg_type,
++                                pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
++                      SENDERR(EINVAL);
++              } else {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_msg_parse: "
++                                "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
++                                pfkey_msg->sadb_msg_satype,
++                                satype2name(pfkey_msg->sadb_msg_satype),
++                                satype2proto(pfkey_msg->sadb_msg_satype),
++                                pfkey_msg->sadb_msg_type,
++                                pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
++              }
++      case K_SADB_ACQUIRE:
++      case K_SADB_REGISTER:
++      case K_SADB_EXPIRE:
++              if(!pfkey_msg->sadb_msg_satype) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                                "pfkey_msg_parse: "
++                                "satype is zero, must be non-zero for msg_type %d(%s).\n",
++                                pfkey_msg->sadb_msg_type,
++                                pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
++                      SENDERR(EINVAL);
++              }
++      default:
++              break;
++      }
++      
++      /* errno must not be set in downward messages */
++      /* this is not entirely true... a response to an ACQUIRE could return an error */
++      if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != K_SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                          "pfkey_msg_parse: "
++                          "errno set to %d.\n",
++                          pfkey_msg->sadb_msg_errno);
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++                "pfkey_msg_parse: "
++                "remain=%d\n", 
++                remain
++                );
++
++      extensions_seen = 1;
++      
++      while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
++              /* Is there enough message left to support another extension header? */
++              if(remain < pfkey_ext->sadb_ext_len) {
++                      ERROR("pfkey_msg_parse: "
++                              "remain %d less than ext len %d.\n", 
++                              remain, pfkey_ext->sadb_ext_len);
++                      SENDERR(EINVAL);
++              }
++              
++              DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++                      "pfkey_msg_parse: "
++                      "parsing ext type=%d(%s) remain=%d.\n",
++                      pfkey_ext->sadb_ext_type,
++                      pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
++                      remain);
++              
++              /* Is the extension header type valid? */
++              if((pfkey_ext->sadb_ext_type > K_SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_msg_parse: "
++                              "ext type %d(%s) invalid, K_SADB_EXT_MAX=%d.\n", 
++                              pfkey_ext->sadb_ext_type,
++                              pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
++                              K_SADB_EXT_MAX);
++                      SENDERR(EINVAL);
++              }
++              
++              /* Have we already seen this type of extension? */
++              if(extensions[pfkey_ext->sadb_ext_type] != NULL)
++              {
++                      ERROR("pfkey_msg_parse: "
++                              "ext type %d(%s) already seen.\n", 
++                              pfkey_ext->sadb_ext_type,
++                              pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
++                      SENDERR(EINVAL);
++              }
++
++              /* Do I even know about this type of extension? */
++              if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
++                      ERROR("pfkey_msg_parse: "
++                              "ext type %d(%s) unknown, ignoring.\n", 
++                              pfkey_ext->sadb_ext_type,
++                              pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
++                      goto next_ext;
++              }
++
++              /* Is this type of extension permitted for this type of message? */
++              if(!pfkey_permitted_extension(dir,pfkey_msg->sadb_msg_type,pfkey_ext->sadb_ext_type)) {
++                      ERROR("ext type %d(%s) not permitted (parse)\n", 
++                            pfkey_ext->sadb_ext_type, 
++                            pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
++                      SENDERR(EINVAL);
++              }
++
++              DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
++                        "pfkey_msg_parse: "
++                        "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
++                        remain,
++                        pfkey_ext->sadb_ext_type,
++                        pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
++                        pfkey_ext->sadb_ext_len,
++                        pfkey_ext,
++                        ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
++              
++              /* Parse the extension */
++              if((error =
++                  (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
++                      ERROR("pfkey_msg_parse: "
++                              "extension parsing for type %d(%s) failed with error %d.\n",
++                              pfkey_ext->sadb_ext_type,
++                              pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
++                              error); 
++                      SENDERR(-error);
++              }
++              DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
++                      "pfkey_msg_parse: "
++                      "Extension %d(%s) parsed.\n",
++                      pfkey_ext->sadb_ext_type,
++                      pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
++              
++              /* Mark that we have seen this extension and remember the header location */
++              extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
++              pfkey_mark_extension(pfkey_ext->sadb_ext_type,&extensions_seen);
++
++      next_ext:               
++              /* Calculate how much message remains */
++              remain -= pfkey_ext->sadb_ext_len;
++
++              if(!remain) {
++                      break;
++              }
++              /* Find the next extension header */
++              pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
++                      pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
++      }
++
++      if(remain) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_msg_parse: "
++                      "unexpected remainder of %d.\n", 
++                      remain);
++              /* why is there still something remaining? */
++              SENDERR(EINVAL);
++      }
++
++      /* don't check further if it is an error return message since it
++         may not have a body */
++      if(pfkey_msg->sadb_msg_errno) {
++              SENDERR(-error);
++      }
++
++      if(pfkey_extensions_missing(dir,pfkey_msg->sadb_msg_type,extensions_seen)) {
++              ERROR("required extensions missing.seen=%08llx.\n",(unsigned long long)extensions_seen);
++              SENDERR(EINVAL);
++      }
++      
++      if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == K_SADB_X_DELFLOW)
++         && ((extensions_seen & K_SADB_X_EXT_ADDRESS_DELFLOW)
++             != K_SADB_X_EXT_ADDRESS_DELFLOW)
++         && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
++         || ((((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
++              & SADB_X_SAFLAGS_CLEARFLOW)
++             != SADB_X_SAFLAGS_CLEARFLOW))) {
++              DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                      "pfkey_msg_parse: "
++                      "required SADB_X_DELFLOW extensions missing: either %16llx must be present or %16llx must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
++                      (unsigned long long)K_SADB_X_EXT_ADDRESS_DELFLOW
++                      - (extensions_seen & K_SADB_X_EXT_ADDRESS_DELFLOW),
++                      (unsigned long long)(1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_msg->sadb_msg_type) {
++      case K_SADB_ADD:
++      case K_SADB_UPDATE:
++              /* check maturity */
++              if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
++                 K_SADB_SASTATE_MATURE) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_msg_parse: "
++                              "state=%d for add or update should be MATURE=%d.\n",
++                              ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
++                              K_SADB_SASTATE_MATURE);
++                      SENDERR(EINVAL);
++              }
++              
++              /* check AH and ESP */
++              switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
++              case SADB_SATYPE_AH:
++                      if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
++                           ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
++                           SADB_AALG_NONE)) {
++                              ERROR("pfkey_msg_parse: "
++                                      "auth alg is zero, must be non-zero for AH SAs.\n");
++                              SENDERR(EINVAL);
++                      }
++                      if(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
++                         SADB_EALG_NONE) {
++                              ERROR("pfkey_msg_parse: "
++                                      "AH handed encalg=%d, must be zero.\n",
++                                      ((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
++                              SENDERR(EINVAL);
++                      }
++                      break;
++              case SADB_SATYPE_ESP:
++                      if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
++                           ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
++                           SADB_EALG_NONE)) {
++                              ERROR("pfkey_msg_parse: "
++                                      "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
++                                      ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
++                                      ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
++                              SENDERR(EINVAL);
++                      }
++                      if((((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
++                          SADB_EALG_NULL) &&
++                         (((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
++                          SADB_AALG_NONE) ) {
++                              ERROR("pfkey_msg_parse: "
++                                      "ESP handed encNULL+authNONE, illegal combination.\n");
++                              SENDERR(EINVAL);
++                      }
++                      break;
++              case K_SADB_X_SATYPE_COMP:
++                      if(!(((struct k_sadb_sa*)extensions[SADB_EXT_SA]) &&
++                           ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
++                           SADB_EALG_NONE)) {
++                              ERROR("pfkey_msg_parse: "
++                                      "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
++                                      ((struct k_sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
++                                      ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
++                              SENDERR(EINVAL);
++                      }
++                      if(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
++                         SADB_AALG_NONE) {
++                              ERROR("pfkey_msg_parse: "
++                                      "COMP handed auth=%d, must be zero.\n",
++                                      ((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
++                              SENDERR(EINVAL);
++                      }
++                      break;
++              default:
++                      break;
++              }
++              if(ntohl(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
++                      DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
++                              "pfkey_msg_parse: "
++                              "spi=%08x must be > 255.\n",
++                              ntohl(((struct k_sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
++                      SENDERR(EINVAL);
++              }
++      default:        
++              break;
++      }
++
++errlab:
++      return error;
++}
++
++/*
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/pfkey_v2_parser.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,3063 @@
++/*
++ * @(#) RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs <rgb@freeswan.org>
++ * 
++ * OCF support written by David McCullough <dmccullough@cyberguard.com>
++ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
++ */
++
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++
++#include <openswan.h>
++
++#include <klips-crypto/des.h>
++
++#ifdef SPINLOCK
++# ifdef SPINLOCK_23
++#  include <linux/spinlock.h> /* *lock* */
++# else /* SPINLOCK_23 */
++#  include <asm/spinlock.h> /* *lock* */
++# endif /* SPINLOCK_23 */
++#endif /* SPINLOCK */
++#ifdef NET_21
++# include <net/route.h>          /* inet_addr_type */
++# include <linux/in6.h>
++# define IS_MYADDR RTN_LOCAL
++#endif
++
++#include <net/ip.h>
++#ifdef NETLINK_SOCK
++# include <linux/netlink.h>
++#else
++# include <net/netlink.h>
++#endif
++
++#include <linux/random.h>     /* get_random_bytes() */
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_sa.h"
++
++#include "openswan/ipsec_radij.h"
++#include "openswan/ipsec_xform.h"
++#include "openswan/ipsec_ah.h"
++#include "openswan/ipsec_esp.h"
++#include "openswan/ipsec_tunnel.h"
++#include "openswan/ipsec_mast.h"
++#include "openswan/ipsec_rcv.h"
++#include "openswan/ipcomp.h"
++
++#include <openswan/pfkeyv2.h>
++#include <openswan/pfkey.h>
++
++#include "openswan/ipsec_proto.h"
++#include "openswan/ipsec_alg.h"
++
++#include "openswan/ipsec_kern24.h"
++
++#include "ipsec_ocf.h"
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++struct sklist_t {
++      struct socket *sk;
++      struct sklist_t* next;
++} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev;
++
++__u32 pfkey_msg_seq = 0;
++
++
++#if 0
++#define DUMP_SAID dump_said(&extr->ips->ips_said, __LINE__)
++#define DUMP_SAID2 dump_said(&extr.ips->ips_said, __LINE__)
++static void dump_said(ip_said *s, int line)
++{ 
++      char msa[SATOT_BUF];
++      size_t msa_len;
++      
++      msa_len = satot(s, 0, msa, sizeof(msa));
++      
++      printk("line: %d msa: %s\n", line, msa);
++}
++#endif
++
++
++int
++pfkey_alloc_eroute(struct eroute** eroute)
++{
++      int error = 0;
++      if(*eroute) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_alloc_eroute: "
++                          "eroute struct already allocated\n");
++              SENDERR(EEXIST);
++      }
++
++      if((*eroute = kmalloc(sizeof(**eroute), GFP_ATOMIC) ) == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_alloc_eroute: "
++                          "memory allocation error\n");
++              SENDERR(ENOMEM);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_alloc_eroute: "
++                  "allocating %lu bytes for an eroute at 0p%p\n",
++                  (unsigned long) sizeof(**eroute), *eroute);
++
++      memset((caddr_t)*eroute, 0, sizeof(**eroute));
++      (*eroute)->er_eaddr.sen_len =
++              (*eroute)->er_emask.sen_len = sizeof(struct sockaddr_encap);
++      (*eroute)->er_eaddr.sen_family =
++              (*eroute)->er_emask.sen_family = AF_ENCAP;
++      (*eroute)->er_eaddr.sen_type = SENT_IP4;
++      (*eroute)->er_emask.sen_type = 255;
++      (*eroute)->er_pid = 0;
++      (*eroute)->er_count = 0;
++      (*eroute)->er_lasttime = jiffies/HZ;
++
++ errlab:
++      return(error);
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_protocol_process(struct sadb_ext *pfkey_ext,
++                       struct pfkey_extracted_data *extr)
++{
++      int error = 0;
++      struct sadb_protocol * p = (struct sadb_protocol *)pfkey_ext;
++
++      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_protocol_process: %p\n", extr);
++
++      if (extr == 0) {
++              KLIPS_PRINT(debug_pfkey,
++                         "klips_debug:pfkey_x_protocol_process:"
++                          "extr is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++      if (extr->eroute == 0) {
++              KLIPS_PRINT(debug_pfkey,
++                        "klips_debug:pfkey_x_protocol_process:"
++                          "extr->eroute is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      extr->eroute->er_eaddr.sen_proto = p->sadb_protocol_proto;
++      extr->eroute->er_emask.sen_proto = p->sadb_protocol_proto ? ~0:0;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_protocol_process: protocol = %d.\n",
++                  p->sadb_protocol_proto);
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_ipsec_sa_init(struct ipsec_sa *ipsp)
++{
++        int rc;
++      KLIPS_PRINT(debug_pfkey, "Calling SA_INIT\n");
++      rc = ipsec_sa_init(ipsp);
++        return rc;
++}
++
++int
++pfkey_safe_build(int error, struct sadb_ext *extensions[K_SADB_MAX+1])
++{
++      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build: "
++                  "error=%d\n",
++                  error);
++      if (!error) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
++                          "success.\n");
++              return 1;
++      } else {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
++                          "caught error %d\n",
++                          error);
++              pfkey_extensions_free(extensions);
++              return 0;
++      }
++}
++
++
++DEBUG_NO_STATIC int
++pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      ipsec_spi_t minspi = htonl(256), maxspi = htonl(-1L);
++      int found_avail = 0;
++      struct ipsec_sa *ipsq;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getspi_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(extr == NULL || extr->ips == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_getspi_parse: "
++                          "error, extr or extr->ipsec_sa pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      if(extensions[K_SADB_EXT_SPIRANGE]) {
++              minspi = ((struct sadb_spirange *)extensions[K_SADB_EXT_SPIRANGE])->sadb_spirange_min;
++              maxspi = ((struct sadb_spirange *)extensions[K_SADB_EXT_SPIRANGE])->sadb_spirange_max;
++      }
++
++      if(maxspi == minspi) {
++              extr->ips->ips_said.spi = maxspi;
++              ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
++              if(ipsq != NULL) {
++                      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++                      ipsec_sa_put(ipsq);
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_getspi_parse: "
++                                  "EMT_GETSPI found an old ipsec_sa for SA: %s, delete it first.\n",
++                                  sa_len ? sa : " (error)");
++                      SENDERR(EEXIST);
++              } else {
++                      found_avail = 1;
++              }
++      } else {
++              int i = 0;
++              __u32 rand_val;
++              __u32 spi_diff;
++              while( ( i < (spi_diff = (ntohl(maxspi) - ntohl(minspi)))) && !found_avail ) {
++                      prng_bytes(&ipsec_prng, (char *) &(rand_val),
++                                       ( (spi_diff < (2^8))  ? 1 :
++                                         ( (spi_diff < (2^16)) ? 2 :
++                                           ( (spi_diff < (2^24)) ? 3 :
++                                         4 ) ) ) );
++                      extr->ips->ips_said.spi = htonl(ntohl(minspi) +
++                                            (rand_val %
++                                            (spi_diff + 1)));
++                      i++;
++                      ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
++                      if(ipsq == NULL) {
++                              found_avail = 1;
++                      } else {
++                              ipsec_sa_put(ipsq);
++                      }
++              }
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++      if (!found_avail) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_getspi_parse: "
++                          "found an old ipsec_sa for SA: %s, delete it first.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(EEXIST);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
++              extr->ips->ips_flags |= EMT_INBOUND;
++      }
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getspi_parse: "
++                  "existing ipsec_sa not found (this is good) for SA: %s, %s-bound, allocating.\n",
++                  sa_len ? sa : " (error)",
++                  extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
++      
++      /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
++      extr->ips->ips_rcvif = NULL;
++      extr->ips->ips_life.ipl_addtime.ipl_count = jiffies/HZ;
++
++      extr->ips->ips_state = K_SADB_SASTATE_LARVAL;
++
++      if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
++              extr->ips->ips_life.ipl_allocations.ipl_count += 1;
++      }
++
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_GETSPI,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      0,
++                                                      K_SADB_SASTATE_LARVAL,
++                                                      0,
++                                                      0,
++                                                      0),
++                               extensions_reply)
++
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                   K_SADB_EXT_ADDRESS_SRC,
++                                                   0, /*extr->ips->ips_said.proto,*/
++                                                   0,
++                                                   extr->ips->ips_addr_s),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                   K_SADB_EXT_ADDRESS_DST,
++                                                   0, /*extr->ips->ips_said.proto,*/
++                                                   0,
++                                                   extr->ips->ips_addr_d),
++                               extensions_reply) )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
++                          "failed to build the getspi reply message extensions\n");
++              goto errlab;
++      }
++      
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
++                          "failed to build the getspi reply message\n");
++              SENDERR(-error);
++      }
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
++                                  "sending up getspi reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
++                          "sending up getspi reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++      if((error = ipsec_sa_add(extr->ips))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
++                          "failed to add the larval SA=%s with error=%d.\n",
++                          sa_len ? sa : " (error)",
++                          error);
++              SENDERR(-error);
++      }
++      extr->ips = NULL;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getspi_parse: "
++                  "successful for SA: %s\n",
++                  sa_len ? sa : " (error)");
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct ipsec_sa* ipsq;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      struct ipsec_sa *nat_t_ips_saved = NULL;
++#endif
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(((struct sadb_sa*)extensions[K_SADB_EXT_SA])->sadb_sa_state != K_SADB_SASTATE_MATURE) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: "
++                          "error, sa_state=%d must be MATURE=%d\n",
++                          ((struct sadb_sa*)extensions[K_SADB_EXT_SA])->sadb_sa_state,
++                          K_SADB_SASTATE_MATURE);
++              SENDERR(EINVAL);
++      }
++
++      if(extr == NULL || extr->ips == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: "
++                          "error, extr or extr->ips pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++      spin_lock_bh(&tdb_lock);
++
++      ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
++      if (ipsq == NULL) {
++              spin_unlock_bh(&tdb_lock);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: "
++                          "reserved ipsec_sa for SA: %s not found.  Call K_SADB_GETSPI first or call K_SADB_ADD instead.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(ENOENT);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
++              extr->ips->ips_flags |= EMT_INBOUND;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse: "
++                  "existing ipsec_sa found (this is good) for SA: %s, %s-bound, updating.\n",
++                  sa_len ? sa : " (error)",
++                  extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) {
++              KLIPS_PRINT(debug_pfkey,
++                      "klips_debug:pfkey_update_parse: only updating NAT-T ports "
++                      "(%u:%u -> %u:%u)\n", 
++                      ipsq->ips_natt_sport, ipsq->ips_natt_dport,
++                      extr->ips->ips_natt_sport, extr->ips->ips_natt_dport);
++
++              if (extr->ips->ips_natt_sport) {
++                      ipsq->ips_natt_sport = extr->ips->ips_natt_sport;
++                      if (ipsq->ips_addr_s->sa_family == AF_INET) {
++                              ((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport);
++                      }
++              }
++
++              if (extr->ips->ips_natt_dport) {
++                      ipsq->ips_natt_dport = extr->ips->ips_natt_dport;
++                      if (ipsq->ips_addr_d->sa_family == AF_INET) {
++                              ((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport);
++                      }
++              }
++
++              nat_t_ips_saved = extr->ips;
++              extr->ips = ipsq;
++      }
++      else 
++#endif
++      {
++              /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
++              extr->ips->ips_rcvif = NULL;
++              if ((error = pfkey_ipsec_sa_init(extr->ips))) {
++                      ipsec_sa_put(ipsq);
++                      spin_unlock_bh(&tdb_lock);
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_update_parse: "
++                                  "not successful for SA: %s, deleting.\n",
++                                  sa_len ? sa : " (error)");
++                      SENDERR(-error);
++              }
++              
++              extr->ips->ips_life.ipl_addtime.ipl_count = ipsq->ips_life.ipl_addtime.ipl_count;
++
++              /* this will call delchain-equivalent if refcount=>0 */
++              ipsec_sa_put(ipsq);
++      }
++
++      spin_unlock_bh(&tdb_lock);
++      
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_UPDATE,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                      extr->ips->ips_flags),
++                               extensions_reply)
++           /* The 3 lifetime extentions should only be sent if non-zero. */
++           && (extensions[K_SADB_EXT_LIFETIME_HARD]
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_HARD],
++                                                               K_SADB_EXT_LIFETIME_HARD,
++                                                               extr->ips->ips_life.ipl_allocations.ipl_hard,
++                                                               extr->ips->ips_life.ipl_bytes.ipl_hard,
++                                                               extr->ips->ips_life.ipl_addtime.ipl_hard,
++                                                               extr->ips->ips_life.ipl_usetime.ipl_hard,
++                                                               extr->ips->ips_life.ipl_packets.ipl_hard),
++                                  extensions_reply) : 1)
++           && (extensions[K_SADB_EXT_LIFETIME_SOFT]
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_SOFT],
++                                                               K_SADB_EXT_LIFETIME_SOFT,
++                                                               extr->ips->ips_life.ipl_allocations.ipl_count,
++                                                               extr->ips->ips_life.ipl_bytes.ipl_count,
++                                                               extr->ips->ips_life.ipl_addtime.ipl_count,
++                                                               extr->ips->ips_life.ipl_usetime.ipl_count,
++                                                               extr->ips->ips_life.ipl_packets.ipl_count),
++                                  extensions_reply) : 1)
++           && (extr->ips->ips_life.ipl_allocations.ipl_count
++               || extr->ips->ips_life.ipl_bytes.ipl_count
++               || extr->ips->ips_life.ipl_addtime.ipl_count
++               || extr->ips->ips_life.ipl_usetime.ipl_count
++               || extr->ips->ips_life.ipl_packets.ipl_count
++
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_CURRENT],
++                                                               K_SADB_EXT_LIFETIME_CURRENT,
++                                                               extr->ips->ips_life.ipl_allocations.ipl_count,
++                                                               extr->ips->ips_life.ipl_bytes.ipl_count,
++                                                               extr->ips->ips_life.ipl_addtime.ipl_count,
++                                                               extr->ips->ips_life.ipl_usetime.ipl_count,
++                                                               extr->ips->ips_life.ipl_packets.ipl_count),
++                                  extensions_reply) : 1)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                           K_SADB_EXT_ADDRESS_SRC,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_s),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                           K_SADB_EXT_ADDRESS_DST,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_d),
++                               extensions_reply)
++           && (extr->ips->ips_ident_s.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_SRC],
++                                                              K_SADB_EXT_IDENTITY_SRC,
++                                                            extr->ips->ips_ident_s.type,
++                                                            extr->ips->ips_ident_s.id,
++                                                              extr->ips->ips_ident_s.len,
++                                                            extr->ips->ips_ident_s.data),
++                                    extensions_reply) : 1)
++           && (extr->ips->ips_ident_d.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_DST],
++                                                              K_SADB_EXT_IDENTITY_DST,
++                                                            extr->ips->ips_ident_d.type,
++                                                            extr->ips->ips_ident_d.id,
++                                                              extr->ips->ips_ident_d.len,
++                                                            extr->ips->ips_ident_d.data),
++                                    extensions_reply) : 1)
++#if 0
++           /* FIXME: This won't work yet because I have not finished
++              it. */
++           && (extr->ips->ips_sens_
++               ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[K_SADB_EXT_SENSITIVITY],
++                                                           extr->ips->ips_sens_dpd,
++                                                           extr->ips->ips_sens_sens_level,
++                                                           extr->ips->ips_sens_sens_len,
++                                                           extr->ips->ips_sens_sens_bitmap,
++                                                           extr->ips->ips_sens_integ_level,
++                                                           extr->ips->ips_sens_integ_len,
++                                                           extr->ips->ips_sens_integ_bitmap),
++                                  extensions_reply) : 1)
++#endif
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
++                          "failed to build the update reply message extensions\n");
++              SENDERR(-error);
++      }
++              
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
++                          "failed to build the update reply message\n");
++              SENDERR(-error);
++      }
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
++                                  "sending up update reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
++                          "sending up update reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      if (nat_t_ips_saved) {
++              /**
++               * As we _really_ update existing SA, we keep tdbq and need to delete
++               * parsed ips (nat_t_ips_saved, was extr->ips).
++               *
++               * goto errlab with extr->ips = nat_t_ips_saved will free it.
++               */
++
++              extr->ips = nat_t_ips_saved;
++
++              error = 0;
++              KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse (NAT-T ports): "
++                  "successful for SA: %s\n",
++                  sa_len ? sa : " (error)");
++
++              goto errlab;
++      }
++#endif
++
++      if((error = ipsec_sa_add(extr->ips))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
++                          "failed to update the mature SA=%s with error=%d.\n",
++                          sa_len ? sa : " (error)",
++                          error);
++              SENDERR(-error);
++      }
++      extr->ips = NULL;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse: "
++                  "successful for SA: %s\n",
++                  sa_len ? sa : " (error)");
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct ipsec_sa* ipsq;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(((struct sadb_sa*)extensions[K_SADB_EXT_SA])->sadb_sa_state != K_SADB_SASTATE_MATURE) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: "
++                          "error, sa_state=%d must be MATURE=%d\n",
++                          ((struct sadb_sa*)extensions[K_SADB_EXT_SA])->sadb_sa_state,
++                          K_SADB_SASTATE_MATURE);
++              SENDERR(EINVAL);
++      }
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: "
++                          "extr or extr->ips pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++      ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
++      if(ipsq != NULL) {
++              ipsec_sa_put(ipsq);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: "
++                          "found an old ipsec_sa for SA%s, delete it first.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(EEXIST);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
++              extr->ips->ips_flags |= EMT_INBOUND;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: "
++                  "existing ipsec_sa not found (this is good) for SA%s, %s-bound, allocating.\n",
++                  sa_len ? sa : " (error)",
++                  extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
++      
++      /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
++      extr->ips->ips_rcvif = NULL;
++      
++      if ((error = ipsec_sa_init(extr->ips))) {
++              KLIPS_ERROR(debug_pfkey,
++                          "pfkey_add_parse: "
++                          "not successful for SA: %s, deleting.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(-error);
++      }
++
++      if(extr->sarefme!=IPSEC_SAREF_NULL
++         && extr->ips->ips_ref==IPSEC_SAREF_NULL) {
++              extr->ips->ips_ref=extr->sarefme;
++      }
++
++      if(extr->sarefhim!=IPSEC_SAREF_NULL
++         && extr->ips->ips_refhim==IPSEC_SAREF_NULL) {
++              extr->ips->ips_refhim=extr->sarefhim;
++      }
++
++      /* attach it to the SAref table */
++      if((error = ipsec_sa_intern(extr->ips)) != 0) {
++              KLIPS_ERROR(debug_pfkey,
++                          "pfkey_add_parse: "
++                          "failed to intern SA as SAref#%lu\n"
++                          , (unsigned long)extr->ips->ips_ref);
++              SENDERR(-error);
++      }
++
++      extr->ips->ips_life.ipl_addtime.ipl_count = jiffies / HZ;
++      if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
++              extr->ips->ips_life.ipl_allocations.ipl_count += 1;
++      }
++
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_ADD,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                          extr->ips->ips_flags),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_saref_build(&extensions_reply[K_SADB_X_EXT_SAREF],
++                                                         extr->ips->ips_ref,
++                                                         extr->ips->ips_refhim),
++                               extensions_reply)
++           /* The 3 lifetime extentions should only be sent if non-zero. */
++           && (extensions[K_SADB_EXT_LIFETIME_HARD]
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_HARD],
++                                                               K_SADB_EXT_LIFETIME_HARD,
++                                                               extr->ips->ips_life.ipl_allocations.ipl_hard,
++                                                               extr->ips->ips_life.ipl_bytes.ipl_hard,
++                                                               extr->ips->ips_life.ipl_addtime.ipl_hard,
++                                                               extr->ips->ips_life.ipl_usetime.ipl_hard,
++                                                               extr->ips->ips_life.ipl_packets.ipl_hard),
++                                  extensions_reply) : 1)
++           && (extensions[K_SADB_EXT_LIFETIME_SOFT]
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_SOFT],
++                                                               K_SADB_EXT_LIFETIME_SOFT,
++                                                               extr->ips->ips_life.ipl_allocations.ipl_soft,
++                                                               extr->ips->ips_life.ipl_bytes.ipl_soft,
++                                                               extr->ips->ips_life.ipl_addtime.ipl_soft,
++                                                               extr->ips->ips_life.ipl_usetime.ipl_soft,
++                                                               extr->ips->ips_life.ipl_packets.ipl_soft),
++                                  extensions_reply) : 1)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                           K_SADB_EXT_ADDRESS_SRC,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_s),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                           K_SADB_EXT_ADDRESS_DST,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_d),
++                               extensions_reply)
++            && (extr->ips->ips_ident_s.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_SRC],
++                                                              K_SADB_EXT_IDENTITY_SRC,
++                                                            extr->ips->ips_ident_s.type,
++                                                            extr->ips->ips_ident_s.id,
++                                                              extr->ips->ips_ident_s.len,
++                                                            extr->ips->ips_ident_s.data),
++                                    extensions_reply) : 1)
++            && (extr->ips->ips_ident_d.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_DST],
++                                                              K_SADB_EXT_IDENTITY_DST,
++                                                            extr->ips->ips_ident_d.type,
++                                                            extr->ips->ips_ident_d.id,
++                                                              extr->ips->ips_ident_d.len,
++                                                            extr->ips->ips_ident_d.data),
++                                    extensions_reply) : 1)
++#if 0
++           /* FIXME: This won't work yet because I have not finished
++              it. */
++           && (extr->ips->ips_sens_
++               ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[K_SADB_EXT_SENSITIVITY],
++                                                           extr->ips->ips_sens_dpd,
++                                                           extr->ips->ips_sens_sens_level,
++                                                           extr->ips->ips_sens_sens_len,
++                                                           extr->ips->ips_sens_sens_bitmap,
++                                                           extr->ips->ips_sens_integ_level,
++                                                           extr->ips->ips_sens_integ_len,
++                                                           extr->ips->ips_sens_integ_bitmap),
++                                  extensions_reply) : 1)
++#endif
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
++                          "failed to build the add reply message extensions\n");
++              SENDERR(-error);
++      }
++              
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
++                          "failed to build the add reply message\n");
++              SENDERR(-error);
++      }
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
++                                  "sending up add reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
++                          "sending up add reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++
++      if(extr->outif != 0 && extr->outif != -1) {
++              extr->ips->ips_out = ipsec_mast_get_device(extr->outif);
++              extr->ips->ips_transport_direct = ipsec_mast_is_transport(extr->outif); 
++      }
++
++      if((error = ipsec_sa_add(extr->ips))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
++                          "failed to add the mature SA=%s with error=%d.\n",
++                          sa_len ? sa : " (error)",
++                          error);
++              SENDERR(-error);
++      }
++      ipsec_sa_put(extr->ips);
++      extr->ips = NULL;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: "
++                  "successful for SA: %s\n",
++                  sa_len ? sa : " (error)");
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      struct ipsec_sa *ipsp;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++      int error = 0;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++      IPsecSAref_t ref;
++      struct sadb_builds sab;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_delete_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_delete_parse: "
++                          "extr or extr->ips pointer NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++      spin_lock_bh(&tdb_lock);
++
++      ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
++      if (ipsp == NULL) {
++              spin_unlock_bh(&tdb_lock);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_delete_parse: "
++                          "ipsec_sa not found for SA:%s, could not delete.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(ESRCH);
++      }
++
++      /* remove it from SAref tables */
++      ref = ipsp->ips_ref;
++      ipsec_sa_untern(ipsp); 
++      ipsec_sa_rm(ipsp);
++
++      /* this will call delchain-equivalent if refcount -> 0
++       * noting that get() above, added to ref count */
++      ipsec_sa_put(ipsp);
++      spin_unlock_bh(&tdb_lock);
++
++      memset(&sab, 0, sizeof(sab));
++      sab.sa_base.sadb_sa_exttype = K_SADB_EXT_SA;
++      sab.sa_base.sadb_sa_spi     = extr->ips->ips_said.spi;
++      sab.sa_base.sadb_sa_replay  = 0;
++      sab.sa_base.sadb_sa_state   = 0;
++      sab.sa_base.sadb_sa_auth    = 0;
++      sab.sa_base.sadb_sa_encrypt = 0;
++      sab.sa_base.sadb_sa_flags   = 0;
++      sab.sa_base.sadb_x_sa_ref   = ref;
++
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_DELETE,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_builds(&extensions_reply[K_SADB_EXT_SA], sab),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                           K_SADB_EXT_ADDRESS_SRC,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_s),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                           K_SADB_EXT_ADDRESS_DST,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_d),
++                               extensions_reply)
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
++                          "failed to build the delete reply message extensions\n");
++              SENDERR(-error);
++      }
++      
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
++                          "failed to build the delete reply message\n");
++              SENDERR(-error);
++      }
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
++                                  "sending up delete reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
++                          "sending up delete reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct ipsec_sa *ipsp;
++      char sa[SATOT_BUF];
++      size_t sa_len;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_get_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(!extr || !extr->ips) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_get_parse: "
++                          "extr or extr->ips pointer NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++      spin_lock_bh(&tdb_lock);
++
++      ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
++      if (ipsp == NULL) {
++              spin_unlock_bh(&tdb_lock);
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
++                          "ipsec_sa not found for SA=%s, could not get.\n",
++                          sa_len ? sa : " (error)");
++              SENDERR(ESRCH);
++      }
++      
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_GET,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                      extr->ips->ips_flags),
++                               extensions_reply)
++           /* The 3 lifetime extentions should only be sent if non-zero. */
++           && (ipsp->ips_life.ipl_allocations.ipl_count
++               || ipsp->ips_life.ipl_bytes.ipl_count
++               || ipsp->ips_life.ipl_addtime.ipl_count
++               || ipsp->ips_life.ipl_usetime.ipl_count
++               || ipsp->ips_life.ipl_packets.ipl_count
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_CURRENT],
++                                                               K_SADB_EXT_LIFETIME_CURRENT,
++                                                               ipsp->ips_life.ipl_allocations.ipl_count,
++                                                               ipsp->ips_life.ipl_bytes.ipl_count,
++                                                               ipsp->ips_life.ipl_addtime.ipl_count,
++                                                               ipsp->ips_life.ipl_usetime.ipl_count,
++                                                               ipsp->ips_life.ipl_packets.ipl_count),
++                                  extensions_reply) : 1)
++           && (ipsp->ips_life.ipl_allocations.ipl_hard
++               || ipsp->ips_life.ipl_bytes.ipl_hard
++               || ipsp->ips_life.ipl_addtime.ipl_hard
++               || ipsp->ips_life.ipl_usetime.ipl_hard
++               || ipsp->ips_life.ipl_packets.ipl_hard
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_HARD],
++                                                               K_SADB_EXT_LIFETIME_HARD,
++                                                               ipsp->ips_life.ipl_allocations.ipl_hard,
++                                                               ipsp->ips_life.ipl_bytes.ipl_hard,
++                                                               ipsp->ips_life.ipl_addtime.ipl_hard,
++                                                               ipsp->ips_life.ipl_usetime.ipl_hard,
++                                                               ipsp->ips_life.ipl_packets.ipl_hard),
++                                  extensions_reply) : 1)
++           && (ipsp->ips_life.ipl_allocations.ipl_soft
++               || ipsp->ips_life.ipl_bytes.ipl_soft
++               || ipsp->ips_life.ipl_addtime.ipl_soft
++               || ipsp->ips_life.ipl_usetime.ipl_soft
++               || ipsp->ips_life.ipl_packets.ipl_soft
++               ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[K_SADB_EXT_LIFETIME_SOFT],
++                                                               K_SADB_EXT_LIFETIME_SOFT,
++                                                               ipsp->ips_life.ipl_allocations.ipl_soft,
++                                                               ipsp->ips_life.ipl_bytes.ipl_soft,
++                                                               ipsp->ips_life.ipl_addtime.ipl_soft,
++                                                               ipsp->ips_life.ipl_usetime.ipl_soft,
++                                                               ipsp->ips_life.ipl_packets.ipl_soft),
++                                  extensions_reply) : 1)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                           K_SADB_EXT_ADDRESS_SRC,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_s),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                           K_SADB_EXT_ADDRESS_DST,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_d),
++                               extensions_reply)
++           && (extr->ips->ips_addr_p
++               ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_PROXY],
++                                                              K_SADB_EXT_ADDRESS_PROXY,
++                                                              0, /*extr->ips->ips_said.proto,*/
++                                                              0,
++                                                              extr->ips->ips_addr_p),
++                                  extensions_reply) : 1)
++#if 0
++           /* FIXME: This won't work yet because the keys are not
++              stored directly in the ipsec_sa.  They are stored as
++              contexts. */
++           && (extr->ips->ips_key_a_size
++               ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[K_SADB_EXT_KEY_AUTH],
++                                                          K_SADB_EXT_KEY_AUTH,
++                                                          extr->ips->ips_key_a_size * 8,
++                                                          extr->ips->ips_key_a),
++                                  extensions_reply) : 1)
++           /* FIXME: This won't work yet because the keys are not
++              stored directly in the ipsec_sa.  They are stored as
++              key schedules. */
++           && (extr->ips->ips_key_e_size
++               ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[K_SADB_EXT_KEY_ENCRYPT],
++                                                          K_SADB_EXT_KEY_ENCRYPT,
++                                                          extr->ips->ips_key_e_size * 8,
++                                                          extr->ips->ips_key_e),
++                                  extensions_reply) : 1)
++#endif
++           && (extr->ips->ips_ident_s.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_SRC],
++                                                              K_SADB_EXT_IDENTITY_SRC,
++                                                            extr->ips->ips_ident_s.type,
++                                                            extr->ips->ips_ident_s.id,
++                                                              extr->ips->ips_ident_s.len,
++                                                            extr->ips->ips_ident_s.data),
++                                    extensions_reply) : 1)
++           && (extr->ips->ips_ident_d.data
++                 ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[K_SADB_EXT_IDENTITY_DST],
++                                                              K_SADB_EXT_IDENTITY_DST,
++                                                            extr->ips->ips_ident_d.type,
++                                                            extr->ips->ips_ident_d.id,
++                                                              extr->ips->ips_ident_d.len,
++                                                            extr->ips->ips_ident_d.data),
++                                    extensions_reply) : 1)
++#if 0
++           /* FIXME: This won't work yet because I have not finished
++              it. */
++           && (extr->ips->ips_sens_
++               ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[K_SADB_EXT_SENSITIVITY],
++                                                           extr->ips->ips_sens_dpd,
++                                                           extr->ips->ips_sens_sens_level,
++                                                           extr->ips->ips_sens_sens_len,
++                                                           extr->ips->ips_sens_sens_bitmap,
++                                                           extr->ips->ips_sens_integ_level,
++                                                           extr->ips->ips_sens_integ_len,
++                                                           extr->ips->ips_sens_integ_bitmap),
++                                  extensions_reply) : 1)
++#endif
++                   )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
++                          "failed to build the get reply message extensions\n");
++              ipsec_sa_put(ipsp);
++              spin_unlock_bh(&tdb_lock);
++              SENDERR(-error);
++      }
++              
++      ipsec_sa_put(ipsp);
++      spin_unlock_bh(&tdb_lock);
++      
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
++                          "failed to build the get reply message\n");
++              SENDERR(-error);
++      }
++      
++      if((error = pfkey_upmsg(sk->sk_socket, pfkey_reply))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
++                          "failed to send the get reply message\n");
++              SENDERR(-error);
++      }
++      
++      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
++                  "succeeded in sending get reply message.\n");
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_acquire_parse: .\n");
++
++      /* XXX I don't know if we want an upper bound, since userspace may
++         want to register itself for an satype > K_SADB_SATYPE_MAX. */
++      if((satype == 0) || (satype > K_SADB_SATYPE_MAX)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_acquire_parse: "
++                          "SATYPE=%d invalid.\n",
++                          satype);
++              SENDERR(EINVAL);
++      }
++
++      if(!(pfkey_registered_sockets[satype])) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
++                          "no sockets registered for SAtype=%d(%s).\n",
++                          satype,
++                          satype2name(satype));
++              SENDERR(EPROTONOSUPPORT);
++      }
++
++      for(pfkey_socketsp = pfkey_registered_sockets[satype];
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp,
++                                      ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
++                                  "sending up acquire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
++                          "sending up acquire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_register_parse: .\n");
++
++      /* XXX I don't know if we want an upper bound, since userspace may
++         want to register itself for an satype > K_SADB_SATYPE_MAX. */
++      if((satype == 0) || (satype > K_SADB_SATYPE_MAX)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_parse: "
++                          "SATYPE=%d invalid.\n",
++                          satype);
++              SENDERR(EINVAL);
++      }
++
++      if(!pfkey_list_insert_socket(sk->sk_socket,
++                               &(pfkey_registered_sockets[satype]))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_parse: "
++                          "SATYPE=%02d(%s) successfully registered by KMd (pid=%d).\n",
++                          satype,
++                          satype2name(satype),
++                          key_pid(sk));
++      };
++      
++      /* send up register msg with supported SATYPE algos */
++
++      error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[K_SADB_EXT_RESERVED]);
++ errlab:
++      return error;
++}
++
++int
++pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
++{
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      struct supported_list *pfkey_supported_listp;
++      unsigned int alg_num_a = 0, alg_num_e = 0;
++      struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
++      int error = 0;
++
++      pfkey_extensions_init(extensions_reply);
++
++      if((satype == 0) || (satype > K_SADB_SATYPE_MAX)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                          "SAtype=%d unspecified or unknown.\n",
++                          satype);
++              SENDERR(EINVAL);
++      }
++      if(!(pfkey_registered_sockets[satype])) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                          "no sockets registered for SAtype=%d(%s).\n",
++                          satype,
++                          satype2name(satype));
++              SENDERR(EPROTONOSUPPORT);
++      }
++      /* send up register msg with supported SATYPE algos */
++      pfkey_supported_listp = pfkey_supported_list[satype];
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_register_reply: "
++                  "pfkey_supported_list[%d]=0p%p\n",
++                  satype,
++                  pfkey_supported_list[satype]);
++      while(pfkey_supported_listp) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_reply: "
++                          "checking supported=0p%p\n",
++                          pfkey_supported_listp);
++              if(pfkey_supported_listp->supportedp->ias_exttype == K_SADB_EXT_SUPPORTED_AUTH) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_register_reply: "
++                                  "adding auth alg.\n");
++                      alg_num_a++;
++              }
++              if(pfkey_supported_listp->supportedp->ias_exttype == K_SADB_EXT_SUPPORTED_ENCRYPT) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_register_reply: "
++                                  "adding encrypt alg.\n");
++                      alg_num_e++;
++              }
++              pfkey_supported_listp = pfkey_supported_listp->next;
++      }
++      
++      if(alg_num_a) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_reply: "
++                          "allocating %lu bytes for auth algs.\n",
++                          (unsigned long) (alg_num_a * sizeof(struct sadb_alg)));
++              if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_register_reply: "
++                                  "auth alg memory allocation error\n");
++                      SENDERR(ENOMEM);
++              }
++              alg_ap = alg_a;
++      }
++      
++      if(alg_num_e) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_reply: "
++                          "allocating %lu bytes for enc algs.\n",
++                          (unsigned long) (alg_num_e * sizeof(struct sadb_alg)));
++              if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_register_reply: "
++                                  "enc alg memory allocation error\n");
++                      SENDERR(ENOMEM);
++              }
++              alg_ep = alg_e;
++      }
++      
++      pfkey_supported_listp = pfkey_supported_list[satype];
++      while(pfkey_supported_listp) {
++              if(alg_num_a) {
++                      if(pfkey_supported_listp->supportedp->ias_exttype == K_SADB_EXT_SUPPORTED_AUTH) {
++                              alg_ap->sadb_alg_id = pfkey_supported_listp->supportedp->ias_id;
++                              alg_ap->sadb_alg_ivlen = pfkey_supported_listp->supportedp->ias_ivlen;
++                              alg_ap->sadb_alg_minbits = pfkey_supported_listp->supportedp->ias_keyminbits;
++                              alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->ias_keymaxbits;
++                              alg_ap->sadb_alg_reserved = 0;
++                              KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                          "klips_debug:pfkey_register_reply: "
++                                          "adding auth=0p%p\n",
++                                          alg_ap);
++                              alg_ap++;
++                      }
++              }
++              if(alg_num_e) {
++                      if(pfkey_supported_listp->supportedp->ias_exttype == K_SADB_EXT_SUPPORTED_ENCRYPT) {
++                              alg_ep->sadb_alg_id = pfkey_supported_listp->supportedp->ias_id;
++                              alg_ep->sadb_alg_ivlen = pfkey_supported_listp->supportedp->ias_ivlen;
++                              alg_ep->sadb_alg_minbits = pfkey_supported_listp->supportedp->ias_keyminbits;
++                              alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->ias_keymaxbits;
++                              alg_ep->sadb_alg_reserved = 0;
++                              KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
++                                          "klips_debug:pfkey_register_reply: "
++                                          "adding encrypt=0p%p\n",
++                                          alg_ep);
++                              alg_ep++;
++                      }
++              }
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_register_reply: "
++                          "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_supported_listp->supportedp->ias_exttype,
++                          pfkey_supported_listp->supportedp->ias_id,
++                          pfkey_supported_listp->supportedp->ias_ivlen,
++                          pfkey_supported_listp->supportedp->ias_keyminbits,
++                          pfkey_supported_listp->supportedp->ias_keymaxbits);
++              pfkey_supported_listp = pfkey_supported_listp->next;
++      }
++      
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_REGISTER,
++                                                        satype,
++                                                        0,
++                                                        sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq,
++                                                        sadb_msg? sadb_msg->sadb_msg_pid: current->pid),
++                            extensions_reply) &&
++           (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[K_SADB_EXT_SUPPORTED_AUTH],
++                                                                      K_SADB_EXT_SUPPORTED_AUTH,
++                                                                      alg_num_a,
++                                                                      alg_a),
++                                        extensions_reply) : 1) &&
++           (alg_num_e ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[K_SADB_EXT_SUPPORTED_ENCRYPT],
++                                                                      K_SADB_EXT_SUPPORTED_ENCRYPT,
++                                                                      alg_num_e,
++                                                                      alg_e),
++                                        extensions_reply) : 1))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                          "failed to build the register message extensions_reply\n");
++              SENDERR(-error);
++      }
++      
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                          "failed to build the register message\n");
++              SENDERR(-error);
++      }
++      /* this should go to all registered sockets for that satype only */
++      for(pfkey_socketsp = pfkey_registered_sockets[satype];
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                                  "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
++                          "sending up register message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      if(alg_a) {
++              kfree(alg_a);
++      }
++      if(alg_e) {
++              kfree(alg_e);
++      }
++
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct socket_list *pfkey_socketsp;
++#ifdef CONFIG_KLIPS_DEBUG
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++#endif /* CONFIG_KLIPS_DEBUG */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_expire_parse: .\n");
++
++      if(pfkey_open_sockets) {
++              for(pfkey_socketsp = pfkey_open_sockets;
++                  pfkey_socketsp;
++                  pfkey_socketsp = pfkey_socketsp->next) {
++                      if((error = pfkey_upmsg(pfkey_socketsp->socketp,
++                                              ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])))) {
++                              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
++                                          "sending up expire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                          satype,
++                                          satype2name(satype),
++                                          pfkey_socketsp->socketp,
++                                          error);
++                              SENDERR(-error);
++                      }
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
++                                  "sending up expire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp);
++              }
++      }
++
++ errlab:
++      return error;
++}
++
++
++/*
++ *
++ * flush all SAs from the table
++ */
++DEBUG_NO_STATIC int
++pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++      uint8_t proto = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_flush_parse: "
++                  "flushing type %d SAs\n",
++                  satype);
++
++      if(satype && !(proto = satype2proto(satype))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_flush_parse: "
++                          "satype %d lookup failed.\n", 
++                          ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype);
++              SENDERR(EINVAL);
++      }
++
++      if ((error = ipsec_sadb_cleanup(proto))) {
++              SENDERR(-error);
++      }
++
++      if(pfkey_open_sockets) {
++              for(pfkey_socketsp = pfkey_open_sockets;
++                  pfkey_socketsp;
++                  pfkey_socketsp = pfkey_socketsp->next) {
++                      if((error = pfkey_upmsg(pfkey_socketsp->socketp,
++                                              ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])))) {
++                              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
++                                          "sending up flush reply message for satype=%d(%s) (proto=%d) to socket=0p%p failed with error=%d.\n",
++                                          satype,
++                                          satype2name(satype),
++                                          proto,
++                                          pfkey_socketsp->socketp,
++                                          error);
++                              SENDERR(-error);
++                      }
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
++                                  "sending up flush reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp);
++              }
++      }
++
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_dump_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_dump_parse: .\n");
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_promisc_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_promisc_parse: .\n");
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_pchange_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_pchange_parse: .\n");
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      struct ipsec_sa *ips1p, *ips2p, *ipsp;
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++      char sa1[SATOT_BUF], sa2[SATOT_BUF];
++      size_t sa_len1, sa_len2 = 0;
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_grpsa_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      if(extr == NULL || extr->ips == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_grpsa_parse: "
++                          "extr or extr->ips is NULL, fatal.\n");
++              SENDERR(EINVAL);
++      }
++
++      sa_len1 = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa1, sizeof(sa1));
++      if(extr->ips2 != NULL) {
++              sa_len2 = KLIPS_SATOT(debug_pfkey, &extr->ips2->ips_said, 0, sa2, sizeof(sa2));
++      }
++
++      spin_lock_bh(&tdb_lock);
++
++      ips1p = ipsec_sa_getbyid(&(extr->ips->ips_said));
++      if(ips1p == NULL) {
++              spin_unlock_bh(&tdb_lock);
++              KLIPS_ERROR(debug_pfkey,
++                          "klips_debug:pfkey_x_grpsa_parse: "
++                          "reserved ipsec_sa for SA1: %s not found.  Call K_SADB_ADD/UPDATE first.\n",
++                          sa_len1 ? sa1 : " (error)");
++              SENDERR(ENOENT);
++      }
++
++      if(extr->ips2) { /* GRPSA */
++
++              /* group ips2p to be after ips1p */
++
++              ips2p = ipsec_sa_getbyid(&(extr->ips2->ips_said));
++              if(ips2p == NULL) {
++                      ipsec_sa_put(ips1p);
++                      spin_unlock_bh(&tdb_lock);
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_grpsa_parse: "
++                                  "reserved ipsec_sa for SA2: %s not found.  Call K_SADB_ADD/UPDATE first.\n",
++                                  sa_len2 ? sa2 : " (error)");
++                      SENDERR(ENOENT);
++              }
++
++              /* userspace puts things in inner to outer order */
++              if(ips2p->ips_flags & EMT_INBOUND) {
++                      struct ipsec_sa *t;
++
++                      /* exchange ips and ips2 */
++                      t = ips1p;
++                      ips1p = ips2p;
++                      ips2p = t;
++              }
++
++              /* Is ips1p already linked? */
++              if(ips1p->ips_next) {
++                      ipsec_sa_put(ips1p);
++                      ipsec_sa_put(ips2p);
++                      spin_unlock_bh(&tdb_lock);
++                      KLIPS_ERROR(debug_pfkey,
++                                  "klips_debug:pfkey_x_grpsa_parse: "
++                                  "ipsec_sa for SA: %s is already linked.\n",
++                                  sa_len1 ? sa1 : " (error)");
++                      SENDERR(EEXIST);
++              }
++              
++              /* Is extr->ips already linked to extr->ips2? */
++              ipsp = ips2p;
++              while(ipsp) {
++                      if(ipsp == ips1p) {
++                              ipsec_sa_put(ips1p);
++                              ipsec_sa_put(ips2p);
++                              spin_unlock_bh(&tdb_lock);
++                              KLIPS_ERROR(debug_pfkey,
++                                          "klips_debug:pfkey_x_grpsa_parse: "
++                                          "ipsec_sa for SA: %s is already linked to %s.\n",
++                                          sa_len1 ? sa1 : " (error)",
++                                          sa_len2 ? sa2 : " (error)");
++                              SENDERR(EEXIST);
++                      }
++                      ipsp = ipsp->ips_next;
++              }
++              
++              /* link 'em */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_grpsa_parse: "
++                          "linking ipsec_sa SA: %s with %s.\n",
++                          sa_len1 ? sa1 : " (error)",
++                          sa_len2 ? sa2 : " (error)");
++              ips1p->ips_next = ips2p;
++      } else { /* UNGRPSA */
++              while(ips1p) {
++                      struct ipsec_sa *ipsn;
++
++                      /* take the reference to next */
++                      ipsn = ips1p->ips_next;
++                      ips1p->ips_next = NULL;
++
++                      /* drop reference to current */
++                      ipsec_sa_put(ips1p);
++
++                      ips1p = ipsn;
++              }
++
++              /* note: we have dropped reference to ips1p, and
++               * it is now NULL
++               */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_grpsa_parse: "
++                          "unlinking ipsec_sa SA: %s.\n",
++                          sa_len1 ? sa1 : " (error)");
++      }
++
++      spin_unlock_bh(&tdb_lock);
++
++      /* MCR: not only is this ugly to read, and impossible
++       *   to debug through, but it's also really inefficient.
++       * XXX simplify me.
++       */
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_X_GRPSA,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                      extr->ips->ips_flags),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                           K_SADB_EXT_ADDRESS_DST,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           extr->ips->ips_addr_d),
++                               extensions_reply)
++           && (extr->ips2
++               ? (pfkey_safe_build(error = pfkey_x_satype_build(&extensions_reply[K_SADB_X_EXT_SATYPE2],
++                                                                ((struct sadb_x_satype*)extensions[K_SADB_X_EXT_SATYPE2])->sadb_x_satype_satype
++                                                                /* proto2satype(extr->ips2->ips_said.proto) */),
++                                                                extensions_reply)
++                  && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_X_EXT_SA2],
++                                                             K_SADB_X_EXT_SA2,
++                                                             extr->ips2->ips_said.spi,
++                                                             extr->ips2->ips_replaywin,
++                                                             extr->ips2->ips_state,
++                                                             extr->ips2->ips_authalg,
++                                                             extr->ips2->ips_encalg,
++                                                             extr->ips2->ips_flags),
++                                      extensions_reply)
++                  && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_DST2],
++                                                                  K_SADB_X_EXT_ADDRESS_DST2,
++                                                                  0, /*extr->ips->ips_said.proto,*/
++                                                                  0,
++                                                                  extr->ips2->ips_addr_d),
++                                      extensions_reply) ) : 1 )
++                   )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
++                          "failed to build the x_grpsa reply message extensions\n");
++              SENDERR(-error);
++      }
++         
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
++                          "failed to build the x_grpsa reply message\n");
++              SENDERR(-error);
++      }
++      
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
++                                  "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
++                          "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
++                  "succeeded in sending x_grpsa reply message.\n");
++      
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++#ifdef CONFIG_KLIPS_DEBUG
++      char buf1[64], buf2[64];
++#endif /* CONFIG_KLIPS_DEBUG */
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++      ip_address srcflow, dstflow, srcmask, dstmask;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      memset((caddr_t)&srcflow, 0, sizeof(srcflow));
++      memset((caddr_t)&dstflow, 0, sizeof(dstflow));
++      memset((caddr_t)&srcmask, 0, sizeof(srcmask));
++      memset((caddr_t)&dstmask, 0, sizeof(dstmask));
++
++      if(!extr || !(extr->ips) || !(extr->eroute)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "missing extr, ipsec_sa or eroute data.\n");
++              SENDERR(EINVAL);
++      }
++
++      srcflow.u.v4.sin_family = AF_INET;
++      dstflow.u.v4.sin_family = AF_INET;
++      srcmask.u.v4.sin_family = AF_INET;
++      dstmask.u.v4.sin_family = AF_INET;
++      srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
++      dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
++      srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
++      dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
++
++#ifdef CONFIG_KLIPS_DEBUG
++      if (debug_pfkey) {
++              subnettoa(extr->eroute->er_eaddr.sen_ip_src,
++                        extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
++              subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
++                        extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "calling breakeroute and/or makeroute for %s->%s\n",
++                          buf1, buf2);
++      }
++#endif /* CONFIG_KLIPS_DEBUG */
++      if(extr->ips->ips_flags & SADB_X_SAFLAGS_INFLOW) {
++/*    if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) */ 
++              struct ipsec_sa *ipsp, *ipsq;
++              char sa[SATOT_BUF];
++              size_t sa_len;
++
++              ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
++              if(ipsq == NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "ipsec_sa not found, cannot set incoming policy.\n");
++                      SENDERR(ENOENT);
++              }
++
++              ipsp = ipsq;
++              while(ipsp && ipsp->ips_said.proto != IPPROTO_IPIP) {
++                      ipsp = ipsp->ips_next;
++              }
++
++              if(ipsp == NULL) {
++                      ipsec_sa_put(ipsq);
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "SA chain does not have an IPIP SA, cannot set incoming policy.\n");
++                      SENDERR(ENOENT);
++              }
++              
++              sa_len = KLIPS_SATOT(debug_pfkey, &extr->ips->ips_said, 0, sa, sizeof(sa));
++
++              ipsp->ips_flags |= SADB_X_SAFLAGS_INFLOW;
++              ipsp->ips_flow_s = srcflow;
++              ipsp->ips_flow_d = dstflow;
++              ipsp->ips_mask_s = srcmask;
++              ipsp->ips_mask_d = dstmask;
++
++              ipsec_sa_put(ipsq);
++
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "inbound eroute, setting incoming policy information in IPIP ipsec_sa for SA: %s.\n",
++                          sa_len ? sa : " (error)");
++      } else {
++              struct sk_buff *first = NULL, *last = NULL;
++
++              if(extr->ips->ips_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "REPLACEFLOW flag set, calling breakeroute.\n");
++                      if ((error = ipsec_breakroute(&(extr->eroute->er_eaddr),
++                                                    &(extr->eroute->er_emask),
++                                                    &first, &last))) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_x_addflow_parse: "
++                                          "breakeroute returned %d.  first=0p%p, last=0p%p\n",
++                                          error,
++                                          first,
++                                          last);
++                              if(first != NULL) {
++                                      ipsec_kfree_skb(first);
++                              }
++                              if(last != NULL) {
++                                      ipsec_kfree_skb(last);
++                              }
++                              SENDERR(-error);
++                      }
++              }
++              
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "calling makeroute.\n");
++              
++              if ((error = ipsec_makeroute(&(extr->eroute->er_eaddr),
++                                           &(extr->eroute->er_emask),
++                                           extr->ips->ips_said,
++                                           ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid,
++                                           NULL,
++                                           &(extr->ips->ips_ident_s),
++                                           &(extr->ips->ips_ident_d)))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "makeroute returned %d.\n", error);
++                      SENDERR(-error);
++              }
++              if(first != NULL) {
++                      KLIPS_PRINT(debug_eroute,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "first=0p%p HOLD packet re-injected.\n",
++                                  first);
++                      dst_output(first);
++              }
++              if(last != NULL) {
++                      KLIPS_PRINT(debug_eroute,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "last=0p%p HOLD packet re-injected.\n",
++                                  last);
++                      dst_output(last);
++              }
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: "
++                  "makeroute call successful.\n");
++
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_X_ADDFLOW,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                      extr->ips->ips_flags),
++                               extensions_reply)
++           && (extensions[K_SADB_EXT_ADDRESS_SRC]
++               ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_SRC],
++                                                              K_SADB_EXT_ADDRESS_SRC,
++                                                              0, /*extr->ips->ips_said.proto,*/
++                                                              0,
++                                                              extr->ips->ips_addr_s),
++                                  extensions_reply) : 1)
++           && (extensions[K_SADB_EXT_ADDRESS_DST]
++               ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_EXT_ADDRESS_DST],
++                                                              K_SADB_EXT_ADDRESS_DST,
++                                                              0, /*extr->ips->ips_said.proto,*/
++                                                              0,
++                                                              extr->ips->ips_addr_d),
++                                  extensions_reply) : 1)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_SRC_FLOW],
++                                                           K_SADB_X_EXT_ADDRESS_SRC_FLOW,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&srcflow),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_DST_FLOW],
++                                                           K_SADB_X_EXT_ADDRESS_DST_FLOW,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&dstflow),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_SRC_MASK],
++                                                           K_SADB_X_EXT_ADDRESS_SRC_MASK,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&srcmask),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_DST_MASK],
++                                                           K_SADB_X_EXT_ADDRESS_DST_MASK,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&dstmask),
++                               extensions_reply)
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
++                          "failed to build the x_addflow reply message extensions\n");
++              SENDERR(-error);
++      }
++              
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
++                          "failed to build the x_addflow reply message\n");
++              SENDERR(-error);
++      }
++      
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
++                                  "sending up x_addflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
++                          "sending up x_addflow reply message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          extr->ips->ips_said.proto,
++                          pfkey_socketsp->socketp);
++      }
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: "
++                  "extr->ips cleaned up and freed.\n");
++
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++#ifdef CONFIG_KLIPS_DEBUG
++      char buf1[64], buf2[64];
++#endif /* CONFIG_KLIPS_DEBUG */
++      struct sadb_ext *extensions_reply[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_reply = NULL;
++      struct socket_list *pfkey_socketsp;
++      uint8_t satype = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_satype;
++      ip_address srcflow, dstflow, srcmask, dstmask;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_delflow_parse: .\n");
++
++      pfkey_extensions_init(extensions_reply);
++
++      memset((caddr_t)&srcflow, 0, sizeof(srcflow));
++      memset((caddr_t)&dstflow, 0, sizeof(dstflow));
++      memset((caddr_t)&srcmask, 0, sizeof(srcmask));
++      memset((caddr_t)&dstmask, 0, sizeof(dstmask));
++
++      if(!extr || !(extr->ips)) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_delflow_parse: "
++                          "extr, or extr->ips is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      if(extr->ips->ips_flags & SADB_X_SAFLAGS_CLEARFLOW) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_delflow_parse: "
++                          "CLEARFLOW flag set, calling cleareroutes.\n");
++              if ((error = ipsec_cleareroutes())) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_delflow_parse: "
++                                  "cleareroutes returned %d.\n", error);
++                      SENDERR(-error);
++              }
++      } else {
++              struct sk_buff *first = NULL, *last = NULL;
++
++              if(!(extr->eroute)) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_delflow_parse: "
++                                  "extr->eroute is NULL, fatal.\n");
++                      SENDERR(EINVAL);
++              }
++              
++              srcflow.u.v4.sin_family = AF_INET;
++              dstflow.u.v4.sin_family = AF_INET;
++              srcmask.u.v4.sin_family = AF_INET;
++              dstmask.u.v4.sin_family = AF_INET;
++              srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
++              dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
++              srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
++              dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
++
++#ifdef CONFIG_KLIPS_DEBUG
++              if (debug_pfkey) {
++                      subnettoa(extr->eroute->er_eaddr.sen_ip_src,
++                                extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
++                      subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
++                                extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_delflow_parse: "
++                                  "calling breakeroute for %s->%s\n",
++                                  buf1, buf2);
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++              error = ipsec_breakroute(&(extr->eroute->er_eaddr),
++                                           &(extr->eroute->er_emask),
++                                           &first, &last);
++              if(error) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_delflow_parse: "
++                                  "breakeroute returned %d.  first=0p%p, last=0p%p\n",
++                                  error,
++                                  first,
++                                  last);
++              }
++              if(first != NULL) {
++                      ipsec_kfree_skb(first);
++              }
++              if(last != NULL) {
++                      ipsec_kfree_skb(last);
++              }
++              if(error) {
++                      SENDERR(-error);
++              }
++      }
++      
++      if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
++                                                        K_SADB_X_DELFLOW,
++                                                        satype,
++                                                        0,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_seq,
++                                                        ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED])->sadb_msg_pid),
++                            extensions_reply)
++           && pfkey_safe_build(error = pfkey_sa_build(&extensions_reply[K_SADB_EXT_SA],
++                                                      K_SADB_EXT_SA,
++                                                      extr->ips->ips_said.spi,
++                                                      extr->ips->ips_replaywin,
++                                                      extr->ips->ips_state,
++                                                      extr->ips->ips_authalg,
++                                                      extr->ips->ips_encalg,
++                                                      extr->ips->ips_flags),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_SRC_FLOW],
++                                                           K_SADB_X_EXT_ADDRESS_SRC_FLOW,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&srcflow),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_DST_FLOW],
++                                                           K_SADB_X_EXT_ADDRESS_DST_FLOW,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&dstflow),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_SRC_MASK],
++                                                           K_SADB_X_EXT_ADDRESS_SRC_MASK,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&srcmask),
++                               extensions_reply)
++           && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[K_SADB_X_EXT_ADDRESS_DST_MASK],
++                                                           K_SADB_X_EXT_ADDRESS_DST_MASK,
++                                                           0, /*extr->ips->ips_said.proto,*/
++                                                           0,
++                                                           (struct sockaddr*)&dstmask),
++                               extensions_reply)
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
++                          "failed to build the x_delflow reply message extensions\n");
++              SENDERR(-error);
++      }
++              
++      if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
++                          "failed to build the x_delflow reply message\n");
++              SENDERR(-error);
++      }
++      
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
++                                  "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
++                          "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_delflow_parse: "
++                  "extr->ips cleaned up and freed.\n");
++
++ errlab:
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++      pfkey_extensions_free(extensions_reply);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_msg_debug_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_msg_debug_parse: .\n");
++
++/* errlab:*/
++      return error;
++}
++
++/* pfkey_expire expects the ipsec_sa table to be locked before being called. */
++int
++pfkey_expire(struct ipsec_sa *ipsp, int hard)
++{
++      struct sadb_ext *extensions[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_msg = NULL;
++      struct socket_list *pfkey_socketsp;
++      int error = 0;
++      uint8_t satype;
++
++      pfkey_extensions_init(extensions);
++
++      if(!(satype = proto2satype(ipsp->ips_said.proto))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_expire: "
++                          "satype lookup for protocol %d lookup failed.\n", 
++                          ipsp->ips_said.proto);
++              SENDERR(EINVAL);
++      }
++      
++      if(!pfkey_open_sockets) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                          "no sockets listening.\n");
++              SENDERR(EPROTONOSUPPORT);
++      }
++
++      if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
++                                                         K_SADB_EXPIRE,
++                                                         satype,
++                                                         0,
++                                                         ++pfkey_msg_seq,
++                                                         0),
++                             extensions)
++            && pfkey_safe_build(error = pfkey_sa_build(&extensions[K_SADB_EXT_SA],
++                                                       K_SADB_EXT_SA,
++                                                       ipsp->ips_said.spi,
++                                                       ipsp->ips_replaywin,
++                                                       ipsp->ips_state,
++                                                       ipsp->ips_authalg,
++                                                       ipsp->ips_encalg,
++                                                       ipsp->ips_flags),
++                                extensions)
++            && pfkey_safe_build(error = pfkey_lifetime_build(&extensions[K_SADB_EXT_LIFETIME_CURRENT],
++                                                             K_SADB_EXT_LIFETIME_CURRENT,
++                                                             ipsp->ips_life.ipl_allocations.ipl_count,
++                                                             ipsp->ips_life.ipl_bytes.ipl_count,
++                                                             ipsp->ips_life.ipl_addtime.ipl_count,
++                                                             ipsp->ips_life.ipl_usetime.ipl_count,
++                                                             ipsp->ips_life.ipl_packets.ipl_count),
++                                extensions)
++            && (hard ? 
++                pfkey_safe_build(error = pfkey_lifetime_build(&extensions[K_SADB_EXT_LIFETIME_HARD],
++                                                              K_SADB_EXT_LIFETIME_HARD,
++                                                              ipsp->ips_life.ipl_allocations.ipl_hard,
++                                                              ipsp->ips_life.ipl_bytes.ipl_hard,
++                                                              ipsp->ips_life.ipl_addtime.ipl_hard,
++                                                              ipsp->ips_life.ipl_usetime.ipl_hard,
++                                                              ipsp->ips_life.ipl_packets.ipl_hard),
++                                 extensions)
++                : pfkey_safe_build(error = pfkey_lifetime_build(&extensions[K_SADB_EXT_LIFETIME_SOFT],
++                                                                K_SADB_EXT_LIFETIME_SOFT,
++                                                                ipsp->ips_life.ipl_allocations.ipl_soft,
++                                                                ipsp->ips_life.ipl_bytes.ipl_soft,
++                                                                ipsp->ips_life.ipl_addtime.ipl_soft,
++                                                                ipsp->ips_life.ipl_usetime.ipl_soft,
++                                                                ipsp->ips_life.ipl_packets.ipl_soft),
++                                   extensions))
++            && pfkey_safe_build(error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_SRC],
++                                                            K_SADB_EXT_ADDRESS_SRC,
++                                                            0, /* ipsp->ips_said.proto, */
++                                                            0,
++                                                            ipsp->ips_addr_s),
++                                extensions)
++            && pfkey_safe_build(error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_DST],
++                                                            K_SADB_EXT_ADDRESS_DST,
++                                                            0, /* ipsp->ips_said.proto, */
++                                                            0,
++                                                            ipsp->ips_addr_d),
++                                extensions))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                          "failed to build the expire message extensions\n");
++              spin_unlock_bh(&tdb_lock);
++              goto errlab;
++      }
++      
++      if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                          "failed to build the expire message\n");
++              SENDERR(-error);
++      }
++      
++      for(pfkey_socketsp = pfkey_open_sockets;
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                                  "sending up expire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                          "sending up expire message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          ipsp->ips_said.proto,
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      if (pfkey_msg) {
++              pfkey_msg_free(&pfkey_msg);
++      }
++      pfkey_extensions_free(extensions);
++      return error;
++}
++
++int
++pfkey_acquire(struct ipsec_sa *ipsp)
++{
++      struct sadb_ext *extensions[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_msg = NULL;
++      struct socket_list *pfkey_socketsp;
++      int error = 0;
++      struct sadb_comb comb[] = {
++              /* auth; encrypt; flags; */
++              /* auth_minbits; auth_maxbits; encrypt_minbits; encrypt_maxbits; */
++              /* reserved; soft_allocations; hard_allocations; soft_bytes; hard_bytes; */
++              /* soft_addtime; hard_addtime; soft_usetime; hard_usetime; */
++              /* soft_packets; hard_packets; */
++              { K_SADB_AALG_MD5HMAC,  K_SADB_EALG_3DESCBC, SADB_SAFLAGS_PFS,
++                128, 128, 168, 168,
++                0, 0, 0, 0, 0,
++                57600, 86400, 57600, 86400},
++              { K_SADB_AALG_SHA1HMAC, K_SADB_EALG_3DESCBC, SADB_SAFLAGS_PFS,
++                160, 160, 168, 168,
++                0, 0, 0, 0, 0,
++                57600, 86400, 57600, 86400},
++      };
++       
++      /* XXX This should not be hard-coded.  It should be taken from the spdb */
++      uint8_t satype = K_SADB_SATYPE_ESP;
++
++      pfkey_extensions_init(extensions);
++
++      if((satype == 0) || (satype > K_SADB_SATYPE_MAX)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
++                          "SAtype=%d unspecified or unknown.\n",
++                          satype);
++              SENDERR(EINVAL);
++      }
++
++      if(!(pfkey_registered_sockets[satype])) {
++              KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
++                          "no sockets registered for SAtype=%d(%s).\n",
++                          satype,
++                          satype2name(satype));
++              SENDERR(EPROTONOSUPPORT);
++      }
++      
++      if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
++                                                        K_SADB_ACQUIRE,
++                                                        satype,
++                                                        0,
++                                                        ++pfkey_msg_seq,
++                                                        0),
++                            extensions)
++            && pfkey_safe_build(error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_SRC],
++                                                            K_SADB_EXT_ADDRESS_SRC,
++                                                            ipsp->ips_transport_protocol,
++                                                            0,
++                                                            ipsp->ips_addr_s),
++                                extensions)
++            && pfkey_safe_build(error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_DST],
++                                                            K_SADB_EXT_ADDRESS_DST,
++                                                            ipsp->ips_transport_protocol,
++                                                            0,
++                                                            ipsp->ips_addr_d),
++                                extensions)
++#if 0
++            && (ipsp->ips_addr_p
++                ? pfkey_safe_build(error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_PROXY],
++                                                               K_SADB_EXT_ADDRESS_PROXY,
++                                                               ipsp->ips_transport_protocol,
++                                                               0,
++                                                               ipsp->ips_addr_p),
++                                   extensions) : 1)
++#endif
++            && (ipsp->ips_ident_s.type != SADB_IDENTTYPE_RESERVED
++                ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC],
++                                                             K_SADB_EXT_IDENTITY_SRC,
++                                                             ipsp->ips_ident_s.type,
++                                                             ipsp->ips_ident_s.id,
++                                                             ipsp->ips_ident_s.len,
++                                                             ipsp->ips_ident_s.data),
++                                   extensions) : 1)
++
++            && (ipsp->ips_ident_d.type != SADB_IDENTTYPE_RESERVED
++                ? pfkey_safe_build(error = pfkey_ident_build(&extensions[K_SADB_EXT_IDENTITY_DST],
++                                                             K_SADB_EXT_IDENTITY_DST,
++                                                             ipsp->ips_ident_d.type,
++                                                             ipsp->ips_ident_d.id,
++                                                             ipsp->ips_ident_d.len,
++                                                             ipsp->ips_ident_d.data),
++                                   extensions) : 1)
++#if 0
++            /* FIXME: This won't work yet because I have not finished
++               it. */
++            && (ipsp->ips_sens_
++                ? pfkey_safe_build(error = pfkey_sens_build(&extensions[K_SADB_EXT_SENSITIVITY],
++                                                            ipsp->ips_sens_dpd,
++                                                            ipsp->ips_sens_sens_level,
++                                                            ipsp->ips_sens_sens_len,
++                                                            ipsp->ips_sens_sens_bitmap,
++                                                            ipsp->ips_sens_integ_level,
++                                                            ipsp->ips_sens_integ_len,
++                                                            ipsp->ips_sens_integ_bitmap),
++                                   extensions) : 1)
++#endif
++            && pfkey_safe_build(error = pfkey_prop_build(&extensions[K_SADB_EXT_PROPOSAL],
++                                                         64, /* replay */
++                                                         sizeof(comb)/sizeof(struct sadb_comb),
++                                                         &(comb[0])),
++                                extensions)
++              )) {
++              KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
++                          "failed to build the acquire message extensions\n");
++              SENDERR(-error);
++      }
++      
++      if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
++              KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
++                          "failed to build the acquire message\n");
++              SENDERR(-error);
++      }
++
++#ifdef KLIPS_PFKEY_ACQUIRE_LOSSAGE
++#  if KLIPS_PFKEY_ACQUIRE_LOSSAGE > 0
++      if(sysctl_ipsec_regress_pfkey_lossage) {
++              return(0);
++      }
++#  endif
++#endif
++      
++      /* this should go to all registered sockets for that satype only */
++      for(pfkey_socketsp = pfkey_registered_sockets[satype];
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
++                      KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
++                                  "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
++                          "sending up acquire message for satype=%d(%s) to socket=0p%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      if (pfkey_msg) {
++              pfkey_msg_free(&pfkey_msg);
++      }
++      pfkey_extensions_free(extensions);
++      return error;
++}
++
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++int
++pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr,
++      __u16 sport)
++{
++      struct sadb_ext *extensions[K_SADB_EXT_MAX+1];
++      struct sadb_msg *pfkey_msg = NULL;
++      struct socket_list *pfkey_socketsp;
++      int error = 0;
++      uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? K_SADB_SATYPE_ESP : 0;
++
++      /* Construct K_SADB_X_NAT_T_NEW_MAPPING message */
++
++      pfkey_extensions_init(extensions);
++
++      if((satype == 0) || (satype > K_SADB_SATYPE_MAX)) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                          "SAtype=%d unspecified or unknown.\n",
++                          satype);
++              SENDERR(EINVAL);
++      }
++
++      if(!(pfkey_registered_sockets[satype])) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                          "no sockets registered for SAtype=%d(%s).\n",
++                          satype,
++                          satype2name(satype));
++              SENDERR(EPROTONOSUPPORT);
++      }
++
++      if (!(pfkey_safe_build
++              (error = pfkey_msg_hdr_build(&extensions[0], K_SADB_X_NAT_T_NEW_MAPPING,
++                      satype, 0, ++pfkey_msg_seq, 0), extensions)
++              /* SA */
++              && pfkey_safe_build
++              (error = pfkey_sa_build(&extensions[K_SADB_EXT_SA],
++                      K_SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions)
++              /* ADDRESS_SRC = old addr */
++              && pfkey_safe_build
++              (error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_SRC],
++                      K_SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s),
++                      extensions)
++              /* NAT_T_SPORT = old port */
++          && pfkey_safe_build
++              (error = pfkey_x_nat_t_port_build(&extensions[K_SADB_X_EXT_NAT_T_SPORT],
++                      K_SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions)
++              /* ADDRESS_DST = new addr */
++              && pfkey_safe_build
++              (error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_DST],
++                      K_SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions)
++              /* NAT_T_DPORT = new port */
++          && pfkey_safe_build
++              (error = pfkey_x_nat_t_port_build(&extensions[K_SADB_X_EXT_NAT_T_DPORT],
++                      K_SADB_X_EXT_NAT_T_DPORT, sport), extensions)
++              )) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                          "failed to build the nat_t_new_mapping message extensions\n");
++              SENDERR(-error);
++      }
++      
++      if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                          "failed to build the nat_t_new_mapping message\n");
++              SENDERR(-error);
++      }
++
++      /* this should go to all registered sockets for that satype only */
++      for(pfkey_socketsp = pfkey_registered_sockets[satype];
++          pfkey_socketsp;
++          pfkey_socketsp = pfkey_socketsp->next) {
++              if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                                  "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n",
++                                  satype,
++                                  satype2name(satype),
++                                  pfkey_socketsp->socketp,
++                                  error);
++                      SENDERR(-error);
++              }
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
++                          "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n",
++                          satype,
++                          satype2name(satype),
++                          pfkey_socketsp->socketp);
++      }
++      
++ errlab:
++      if (pfkey_msg) {
++              pfkey_msg_free(&pfkey_msg);
++      }
++      pfkey_extensions_free(extensions);
++      return error;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      /* K_SADB_X_NAT_T_NEW_MAPPING not used in kernel */
++      return -EINVAL;
++}
++#endif
++
++/*******************************
++ * EXTENSION PARSERS FOR KLIPS
++ ********************************/
++
++DEBUG_NO_STATIC int
++pfkey_x_outif_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      struct sadb_x_plumbif *oif;
++
++      oif = (struct sadb_x_plumbif *)pfkey_ext;
++
++      extr->outif = oif->sadb_x_outif_ifnum;
++      
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_saref_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      struct sadb_x_saref *saf;
++
++      saf = (struct sadb_x_saref *)pfkey_ext;
++
++      extr->sarefme  = saf->sadb_x_saref_me;
++      extr->sarefhim = saf->sadb_x_saref_him;
++      
++      return 0;
++}
++
++DEBUG_NO_STATIC int (*ext_processors[K_SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) =
++{
++      NULL, /* pfkey_msg_process, */
++        pfkey_sa_process,
++        pfkey_lifetime_process,
++        pfkey_lifetime_process,
++        pfkey_lifetime_process,
++        pfkey_address_process,
++        pfkey_address_process,
++        pfkey_address_process,
++        pfkey_key_process,
++        pfkey_key_process,
++        pfkey_ident_process,
++        pfkey_ident_process,
++        pfkey_sens_process,
++        pfkey_prop_process,
++        pfkey_supported_process,
++        pfkey_supported_process,
++        pfkey_spirange_process,
++        pfkey_x_kmprivate_process,
++        pfkey_x_satype_process,
++        pfkey_sa_process,
++        pfkey_address_process,
++        pfkey_address_process,
++        pfkey_address_process,
++        pfkey_address_process,
++        pfkey_address_process,
++      pfkey_x_debug_process,
++        pfkey_x_protocol_process,
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      pfkey_x_nat_t_type_process,
++      pfkey_x_nat_t_port_process,
++      pfkey_x_nat_t_port_process,
++      pfkey_address_process,
++#else
++      NULL, NULL, NULL, NULL,
++#endif
++      pfkey_x_outif_process,
++      pfkey_x_saref_process,
++};
++
++
++/*******************************
++ * MESSAGE PARSERS FOR KLIPS
++ ********************************/
++
++DEBUG_NO_STATIC int
++pfkey_x_simple_reply(struct sock *sk , struct sadb_ext *extensions[], int err)
++{
++      struct sadb_msg *pfkey_reply = NULL;
++      int error = 0;
++      struct sadb_msg *m = ((struct sadb_msg*)extensions[K_SADB_EXT_RESERVED]);
++
++      m->sadb_msg_errno = err;
++
++      if ((error = pfkey_msg_build(&pfkey_reply, extensions, EXT_BITS_OUT))) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
++                          "failed to build the expire message\n");
++              SENDERR(-error);
++      }
++
++      error = pfkey_upmsgsk(sk, pfkey_reply);
++
++      if(error) {
++              KLIPS_ERROR(debug_pfkey, "pfkey_simple reply:"
++                          "sending up simple reply to pid=%d error=%d.\n",
++                           m->sadb_msg_pid, err);
++      }
++
++errlab:        
++      if (pfkey_reply) {
++              pfkey_msg_free(&pfkey_reply);
++      }
++
++      return error;
++}
++
++/*
++ * this is a request to create a new device. Figure out which kind, and call appropriate
++ * routine in mast or tunnel code.
++ */
++DEBUG_NO_STATIC int
++pfkey_x_plumb_parse(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
++{
++      unsigned int vifnum;
++      int err;
++
++      vifnum = extr->outif;
++      if(vifnum > IPSECDEV_OFFSET) {
++              err = ipsec_tunnel_createnum(vifnum-IPSECDEV_OFFSET);
++      } else {
++              err = ipsec_mast_createnum(vifnum);
++      }
++
++      return pfkey_x_simple_reply(sk, extensions, err);
++}
++
++DEBUG_NO_STATIC int
++pfkey_x_unplumb_parse(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
++{
++      unsigned int vifnum;
++      int err;
++
++      vifnum = extr->outif;
++      if(vifnum > IPSECDEV_OFFSET) {
++              err =  ipsec_tunnel_deletenum(vifnum-IPSECDEV_OFFSET);
++      } else {
++              err = ipsec_mast_deletenum(vifnum);
++      }
++
++      return pfkey_x_simple_reply(sk, extensions, err);
++}
++
++
++DEBUG_NO_STATIC int (*msg_parsers[K_SADB_MAX +1])(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
++ =
++{
++      NULL, /* RESERVED */
++      pfkey_getspi_parse,
++      pfkey_update_parse,
++      pfkey_add_parse,
++      pfkey_delete_parse,
++      pfkey_get_parse,
++      pfkey_acquire_parse,
++      pfkey_register_parse,
++      pfkey_expire_parse,
++      pfkey_flush_parse,
++      pfkey_dump_parse,
++      pfkey_x_promisc_parse,
++      pfkey_x_pchange_parse,
++      pfkey_x_grpsa_parse,
++      pfkey_x_addflow_parse,
++      pfkey_x_delflow_parse,
++      pfkey_x_msg_debug_parse,
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++      pfkey_x_nat_t_new_mapping_parse,
++#else
++      NULL,
++#endif
++      pfkey_x_plumb_parse,
++      pfkey_x_unplumb_parse,
++};
++
++int
++pfkey_build_reply(struct sadb_msg *pfkey_msg,
++                struct pfkey_extracted_data *extr,
++                struct sadb_msg **pfkey_reply)
++{
++      struct sadb_ext *extensions[K_SADB_EXT_MAX+1];
++      int error = 0;
++      int msg_type = pfkey_msg->sadb_msg_type;
++      int seq = pfkey_msg->sadb_msg_seq;
++
++      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
++                  "building reply with type: %d\n",
++                  msg_type);
++      pfkey_extensions_init(extensions);
++      if (!extr || !extr->ips) {
++                      KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
++                                  "bad ipsec_sa passed\n");
++                      return EINVAL; // TODO: should this not be negative?
++      }
++      error = pfkey_safe_build(pfkey_msg_hdr_build(&extensions[0],
++                                                   msg_type,
++                                                   proto2satype(extr->ips->ips_said.proto),
++                                                   0,
++                                                   seq,
++                                                   pfkey_msg->sadb_msg_pid),
++                               extensions);
++
++      if(!error
++         && pfkey_required_extension(EXT_BITS_OUT, msg_type, K_SADB_EXT_SA)) {
++              
++              error = pfkey_sa_build(&extensions[K_SADB_EXT_SA],
++                                     K_SADB_EXT_SA,
++                                     extr->ips->ips_said.spi,
++                                     extr->ips->ips_replaywin,
++                                     extr->ips->ips_state,
++                                     extr->ips->ips_authalg,
++                                     extr->ips->ips_encalg,
++                                     extr->ips->ips_flags);
++              pfkey_safe_build(error, extensions);
++      }
++
++      if(!error
++         && pfkey_required_extension(EXT_BITS_OUT, msg_type, K_SADB_X_EXT_SAREF)) {
++              error = pfkey_saref_build(&extensions[K_SADB_X_EXT_SAREF],
++                                        extr->ips->ips_ref,
++                                        extr->ips->ips_refhim);
++              pfkey_safe_build(error, extensions);
++      }
++              
++      if(!error
++         && pfkey_required_extension(EXT_BITS_OUT,msg_type,K_SADB_EXT_LIFETIME_CURRENT)) {
++              error = pfkey_lifetime_build(&extensions
++                                           [K_SADB_EXT_LIFETIME_CURRENT],
++                                           K_SADB_EXT_LIFETIME_CURRENT,
++                                           extr->ips->ips_life.ipl_allocations.ipl_count,
++                                           extr->ips->ips_life.ipl_bytes.ipl_count,
++                                           extr->ips->ips_life.ipl_addtime.ipl_count,
++                                           extr->ips->ips_life.ipl_usetime.ipl_count,
++                                           extr->ips->ips_life.ipl_packets.ipl_count);
++              pfkey_safe_build(error, extensions);
++      }
++
++      if(!error
++         && pfkey_required_extension(EXT_BITS_OUT,msg_type,K_SADB_EXT_ADDRESS_SRC)) {
++              error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_SRC],
++                                          K_SADB_EXT_ADDRESS_SRC,
++                                          extr->ips->ips_said.proto,
++                                          0,
++                                          extr->ips->ips_addr_s);
++              pfkey_safe_build(error, extensions);
++      }
++
++      if(!error
++         && pfkey_required_extension(EXT_BITS_OUT,msg_type,K_SADB_EXT_ADDRESS_DST)) {
++              error = pfkey_address_build(&extensions[K_SADB_EXT_ADDRESS_DST],
++                                          K_SADB_EXT_ADDRESS_DST,
++                                          extr->ips->ips_said.proto,
++                                          0,
++                                          extr->ips->ips_addr_d);
++              pfkey_safe_build(error, extensions);
++      }
++
++      if (error == 0) {
++              KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
++                          "building extensions failed\n");
++              return EINVAL;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_build_reply: "
++                  "built extensions, proceed to build the message\n");
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_build_reply: "
++                  "extensions[1]=0p%p\n",
++                  extensions[1]);
++      error = pfkey_msg_build(pfkey_reply, extensions, EXT_BITS_OUT);
++      pfkey_extensions_free(extensions);
++
++      return error;
++}
++
++/*
++ * interpret a pfkey message for klips usage.
++ * it used to be that we provided a reply in a seperate buffer,
++ * but now we overwrite the request buffer and return it.
++ */
++int
++pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg)
++{
++      int error = 0;
++      int i;
++      struct sadb_ext *extensions[K_SADB_EXT_MAX+1];    /* should be kalloc */
++      struct pfkey_extracted_data extr;
++
++      memset(&extr, 0, sizeof(extr));
++      
++      pfkey_extensions_init(extensions);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_msg_interp: "
++                  "parsing message ver=%d, type=%d, errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", 
++                  pfkey_msg->sadb_msg_version,
++                  pfkey_msg->sadb_msg_type,
++                  pfkey_msg->sadb_msg_errno,
++                  pfkey_msg->sadb_msg_satype,
++                  satype2name(pfkey_msg->sadb_msg_satype),
++                  pfkey_msg->sadb_msg_len,
++                  pfkey_msg->sadb_msg_reserved,
++                  pfkey_msg->sadb_msg_seq,
++                  pfkey_msg->sadb_msg_pid);
++      
++      extr.ips = ipsec_sa_alloc(&error); /* pass in error var by pointer */
++      if(extr.ips == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: "
++                          "memory allocation error.\n");
++              SENDERR(-error);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_msg_interp: "
++                  "allocated extr->ips=0p%p.\n",
++                  extr.ips);
++      
++      if(pfkey_msg->sadb_msg_satype > K_SADB_SATYPE_MAX) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: "
++                          "satype %d > max %d\n", 
++                          pfkey_msg->sadb_msg_satype,
++                          K_SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_msg->sadb_msg_type) {
++      case K_SADB_GETSPI:
++      case K_SADB_UPDATE:
++      case K_SADB_ADD:
++      case K_SADB_DELETE:
++      case K_SADB_X_GRPSA:
++      case K_SADB_X_ADDFLOW:
++              if(!(extr.ips->ips_said.proto = satype2proto(pfkey_msg->sadb_msg_satype))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_msg_interp: "
++                                  "satype %d lookup failed.\n", 
++                                  pfkey_msg->sadb_msg_satype);
++                      SENDERR(EINVAL);
++              } else {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_msg_interp: "
++                                  "satype %d lookups to proto=%d.\n", 
++                                  pfkey_msg->sadb_msg_satype,
++                                  extr.ips->ips_said.proto);
++              }
++              break;
++      default:
++              break;
++      }
++      
++      /* The NULL below causes the default extension parsers to be used */
++      /* Parse the extensions */
++      if((error = pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_IN)))
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: "
++                          "message parsing failed with error %d.\n",
++                          error); 
++              SENDERR(-error);
++      }
++      
++      /* Process the extensions */
++      for(i=1; i <= K_SADB_EXT_MAX;i++)       {
++              if(extensions[i] != NULL && ext_processors[i]!=NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_msg_interp: "
++                                  "processing ext %d 0p%p with processor 0p%p.\n", 
++                                  i, extensions[i], ext_processors[i]);
++                      if((error = ext_processors[i](extensions[i], &extr))) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_msg_interp: "
++                                          "extension processing for type %d failed with error %d.\n",
++                                          i,
++                                          error); 
++                              SENDERR(-error);
++                      }
++                      
++              }
++              
++      }
++      
++      /* Parse the message types */
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_msg_interp: "
++                  "parsing message type %d(%s) with msg_parser 0p%p.\n",
++                  pfkey_msg->sadb_msg_type,
++                  pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
++                  msg_parsers[pfkey_msg->sadb_msg_type]); 
++      if((error = msg_parsers[pfkey_msg->sadb_msg_type](sk, extensions, &extr))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: "
++                          "message parsing failed with error %d.\n",
++                          error); 
++              SENDERR(-error);
++      }
++
++ errlab:
++      if(extr.ips != NULL) {
++              ipsec_sa_put(extr.ips);
++      }
++      if(extr.ips2 != NULL) {
++              ipsec_sa_put(extr.ips2);
++      }
++      if (extr.eroute != NULL) {
++              kfree(extr.eroute);
++      }
++      return(error);
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/prng.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,202 @@
++/*
++ * crypto-class pseudorandom number generator
++ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
++ * Copyright (C) 2002  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: prng.c,v 1.8 2005/08/25 01:20:21 paul Exp $
++ */
++#include "openswan.h"
++
++/*
++ - prng_init - initialize PRNG from a key
++ */
++void
++prng_init(prng, key, keylen)
++struct prng *prng;
++const unsigned char *key;
++size_t keylen;
++{
++      unsigned char k[256];
++      int i, j;
++      unsigned const char *p;
++      unsigned const char *keyend = key + keylen;
++      unsigned char t;
++
++      for (i = 0; i <= 255; i++)
++              prng->sbox[i] = i;
++      p = key;
++      for (i = 0; i <= 255; i++) {
++              k[i] = *p++;
++              if (p >= keyend)
++                      p = key;
++      }
++      j = 0;
++      for (i = 0; i <= 255; i++) {
++              j = (j + prng->sbox[i] + k[i]) & 0xff;
++              t = prng->sbox[i];
++              prng->sbox[i] = prng->sbox[j];
++              prng->sbox[j] = t;
++              k[i] = 0;       /* clear out key memory */
++      }
++      prng->i = 0;
++      prng->j = 0;
++      prng->count = 0;
++}
++
++/*
++ - prng_bytes - get some pseudorandom bytes from PRNG
++ */
++void
++prng_bytes(prng, dst, dstlen)
++struct prng *prng;
++unsigned char *dst;
++size_t dstlen;
++{
++      int i, j, t;
++      unsigned char *p = dst;
++      size_t remain = dstlen;
++#     define  MAXCOUNT        4000000000ul
++
++      while (remain > 0) {
++              i = (prng->i + 1) & 0xff;
++              prng->i = i;
++              j = (prng->j + prng->sbox[i]) & 0xff;
++              prng->j = j;
++              t = prng->sbox[i];
++              prng->sbox[i] = prng->sbox[j];
++              prng->sbox[j] = t;
++              t = (t + prng->sbox[i]) & 0xff;
++              *p++ = prng->sbox[t];
++              remain--;
++      }
++      if (prng->count < MAXCOUNT - dstlen)
++              prng->count += dstlen;
++      else
++              prng->count = MAXCOUNT;
++}
++
++/*
++ - prnt_count - how many bytes have been extracted from PRNG so far?
++ */
++unsigned long
++prng_count(prng)
++struct prng *prng;
++{
++      return prng->count;
++}
++
++/*
++ - prng_final - clear out PRNG to ensure nothing left in memory
++ */
++void
++prng_final(prng)
++struct prng *prng;
++{
++      int i;
++
++      for (i = 0; i <= 255; i++)
++              prng->sbox[i] = 0;
++      prng->i = 0;
++      prng->j = 0;
++      prng->count = 0;        /* just for good measure */
++}
++
++
++
++#ifdef PRNG_MAIN
++
++#include <stdio.h>
++#include <stdlib.h>
++
++void regress();
++
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++      struct prng pr;
++      unsigned char buf[100];
++      unsigned char *p;
++      size_t n;
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
++              exit(2);
++      }
++
++      if (strcmp(argv[1], "-r") == 0) {
++              regress();
++              fprintf(stderr, "regress() returned?!?\n");
++              exit(1);
++      }
++
++      prng_init(&pr, argv[1], strlen(argv[1]));
++      prng_bytes(&pr, buf, 32);
++      printf("0x");
++      for (p = buf, n = 32; n > 0; p++, n--)
++              printf("%02x", *p);
++      printf("\n%lu bytes\n", prng_count(&pr));
++      prng_final(&pr);
++      exit(0);
++}
++
++void
++regress()
++{
++      struct prng pr;
++      unsigned char buf[100];
++      unsigned char *p;
++      size_t n;
++      /* somewhat non-random sample key */
++      unsigned char key[] = "here we go gathering nuts in May";
++      /* first thirty bytes of output from that key */
++      unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
++                              "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
++                              "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
++      int nzero, none;
++      int show = 0;
++
++      prng_init(&pr, key, strlen(key));
++      prng_bytes(&pr, buf, sizeof(buf));
++      for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
++              if (*p == 0)
++                      nzero++;
++              if (*p == 255)
++                      none++;
++      }
++      if (nzero > 3 || none > 3) {
++              fprintf(stderr, "suspiciously non-random output!\n");
++              show = 1;
++      }
++      if (memcmp(buf, good, strlen(good)) != 0) {
++              fprintf(stderr, "incorrect output!\n");
++              show = 1;
++      }
++      if (show) {
++              fprintf(stderr, "0x");
++              for (p = buf, n = sizeof(buf); n > 0; p++, n--)
++                      fprintf(stderr, "%02x", *p);
++              fprintf(stderr, "\n");
++              exit(1);
++      }
++      if (prng_count(&pr) != sizeof(buf)) {
++              fprintf(stderr, "got %u bytes, but count is %lu\n",
++                                      sizeof(buf), prng_count(&pr));
++              exit(1);
++      }
++      prng_final(&pr);
++      exit(0);
++}
++
++#endif /* PRNG_MAIN */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/radij.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1013 @@
++char radij_c_version[] = "RCSID $Id: radij.c,v 1.48 2005/04/29 05:10:22 mcr Exp $";
++
++/*
++ * This file is defived from ${SRC}/sys/net/radix.c of BSD 4.4lite
++ *
++ * Variable and procedure names have been modified so that they don't
++ * conflict with the original BSD code, as a small number of modifications
++ * have been introduced and we may want to reuse this code in BSD.
++ * 
++ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
++ * chi or a German ch sound (as `doch', not as in `milch'), or even a 
++ * spanish j as in Juan.  It is not as far back in the throat like
++ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
++ * It has nothing to do with the Dutch ij sound.
++ * 
++ * Here is the appropriate copyright notice:
++ */
++
++/*
++ * Copyright (c) 1988, 1989, 1993
++ *    The Regents of the University of California.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by the University of
++ *    California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ *    @(#)radix.c     8.2 (Berkeley) 1/4/94
++ */
++
++/*
++ * Routines to build and maintain radix trees for routing lookups.
++ */
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif
++#include <linux/version.h>
++#include <linux/kernel.h> /* printk() */
++
++#include "openswan/ipsec_param.h"
++
++#ifdef MALLOC_SLAB
++# include <linux/slab.h> /* kmalloc() */
++#else /* MALLOC_SLAB */
++# include <linux/malloc.h> /* kmalloc() */
++#endif /* MALLOC_SLAB */
++#include <linux/errno.h>  /* error codes */
++#include <linux/types.h>  /* size_t */
++#include <linux/interrupt.h> /* mark_bh */
++
++#include <linux/netdevice.h>   /* struct device, and other headers */
++#include <linux/etherdevice.h> /* eth_type_trans */
++#include <linux/ip.h>          /* struct iphdr */
++#include <linux/skbuff.h>
++#ifdef NET_21
++# include <linux/in6.h>
++#endif /* NET_21 */
++
++#include <net/ip.h>
++
++#include <openswan.h>
++
++#include "openswan/radij.h"
++#include "openswan/ipsec_encap.h"
++#include "openswan/ipsec_radij.h"
++
++int   maj_keylen;
++struct radij_mask *rj_mkfreelist;
++struct radij_node_head *mask_rjhead;
++static int gotOddMasks;
++static char *maskedKey;
++static char *rj_zeroes, *rj_ones;
++
++#define rj_masktop (mask_rjhead->rnh_treetop)
++#ifdef Bcmp
++# undef Bcmp
++#endif /* Bcmp */
++#define Bcmp(a, b, l) (l == 0 ? 0 : memcmp((caddr_t)(b), (caddr_t)(a), (size_t)l))
++/*
++ * The data structure for the keys is a radix tree with one way
++ * branching removed.  The index rj_b at an internal node n represents a bit
++ * position to be tested.  The tree is arranged so that all descendants
++ * of a node n have keys whose bits all agree up to position rj_b - 1.
++ * (We say the index of n is rj_b.)
++ *
++ * There is at least one descendant which has a one bit at position rj_b,
++ * and at least one with a zero there.
++ *
++ * A route is determined by a pair of key and mask.  We require that the
++ * bit-wise logical and of the key and mask to be the key.
++ * We define the index of a route to associated with the mask to be
++ * the first bit number in the mask where 0 occurs (with bit number 0
++ * representing the highest order bit).
++ * 
++ * We say a mask is normal if every bit is 0, past the index of the mask.
++ * If a node n has a descendant (k, m) with index(m) == index(n) == rj_b,
++ * and m is a normal mask, then the route applies to every descendant of n.
++ * If the index(m) < rj_b, this implies the trailing last few bits of k
++ * before bit b are all 0, (and hence consequently true of every descendant
++ * of n), so the route applies to all descendants of the node as well.
++ *
++ * The present version of the code makes no use of normal routes,
++ * but similar logic shows that a non-normal mask m such that
++ * index(m) <= index(n) could potentially apply to many children of n.
++ * Thus, for each non-host route, we attach its mask to a list at an internal
++ * node as high in the tree as we can go. 
++ */
++
++struct radij_node *
++rj_search(v_arg, head)
++      void *v_arg;
++      struct radij_node *head;
++{
++      register struct radij_node *x;
++      register caddr_t v;
++
++      for (x = head, v = v_arg; x->rj_b >= 0;) {
++              if (x->rj_bmask & v[x->rj_off])
++                      x = x->rj_r;
++              else
++                      x = x->rj_l;
++      }
++      return (x);
++};
++
++struct radij_node *
++rj_search_m(v_arg, head, m_arg)
++      struct radij_node *head;
++      void *v_arg, *m_arg;
++{
++      register struct radij_node *x;
++      register caddr_t v = v_arg, m = m_arg;
++
++      for (x = head; x->rj_b >= 0;) {
++              if ((x->rj_bmask & m[x->rj_off]) &&
++                  (x->rj_bmask & v[x->rj_off]))
++                      x = x->rj_r;
++              else
++                      x = x->rj_l;
++      }
++      return x;
++};
++
++int
++rj_refines(m_arg, n_arg)
++      void *m_arg, *n_arg;
++{
++      register caddr_t m = m_arg, n = n_arg;
++      register caddr_t lim, lim2 = lim = n + *(u_char *)n;
++      int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
++      int masks_are_equal = 1;
++
++      if (longer > 0)
++              lim -= longer;
++      while (n < lim) {
++              if (*n & ~(*m))
++                      return 0;
++              if (*n++ != *m++)
++                      masks_are_equal = 0;
++                      
++      }
++      while (n < lim2)
++              if (*n++)
++                      return 0;
++      if (masks_are_equal && (longer < 0))
++              for (lim2 = m - longer; m < lim2; )
++                      if (*m++)
++                              return 1;
++      return (!masks_are_equal);
++}
++
++
++struct radij_node *
++rj_match(v_arg, head)
++      void *v_arg;
++      struct radij_node_head *head;
++{
++      caddr_t v = v_arg;
++      register struct radij_node *t = head->rnh_treetop, *x;
++      register caddr_t cp = v, cp2, cp3;
++      caddr_t cplim, mstart;
++      struct radij_node *saved_t, *top = t;
++      int off = t->rj_off, vlen = *(u_char *)cp, matched_off;
++
++      /*
++       * Open code rj_search(v, top) to avoid overhead of extra
++       * subroutine call.
++       */
++      for (; t->rj_b >= 0; ) {
++              if (t->rj_bmask & cp[t->rj_off])
++                      t = t->rj_r;
++              else
++                      t = t->rj_l;
++      }
++      /*
++       * See if we match exactly as a host destination
++       */
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:rj_match: "
++                  "* See if we match exactly as a host destination\n");
++      
++      cp += off; cp2 = t->rj_key + off; cplim = v + vlen;
++      for (; cp < cplim; cp++, cp2++)
++              if (*cp != *cp2)
++                      goto on1;
++      /*
++       * This extra grot is in case we are explicitly asked
++       * to look up the default.  Ugh!
++       */
++      if ((t->rj_flags & RJF_ROOT) && t->rj_dupedkey)
++              t = t->rj_dupedkey;
++      return t;
++on1:
++      matched_off = cp - v;
++      saved_t = t;
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:rj_match: "
++                  "** try to match a leaf, t=0p%p\n", t);
++      do {
++          if (t->rj_mask) {
++              /*
++               * Even if we don't match exactly as a hosts;
++               * we may match if the leaf we wound up at is
++               * a route to a net.
++               */
++              cp3 = matched_off + t->rj_mask;
++              cp2 = matched_off + t->rj_key;
++              for (; cp < cplim; cp++)
++                      if ((*cp2++ ^ *cp) & *cp3++)
++                              break;
++              if (cp == cplim)
++                      return t;
++              cp = matched_off + v;
++          }
++      } while ((t = t->rj_dupedkey));
++      t = saved_t;
++      /* start searching up the tree */
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:rj_match: "
++                  "*** start searching up the tree, t=0p%p\n",
++                  t);
++      do {
++              register struct radij_mask *m;
++              
++              t = t->rj_p;
++              KLIPS_PRINT(debug_radij,
++                          "klips_debug:rj_match: "
++                          "**** t=0p%p\n",
++                          t);
++              if ((m = t->rj_mklist)) {
++                      /*
++                       * After doing measurements here, it may
++                       * turn out to be faster to open code
++                       * rj_search_m here instead of always
++                       * copying and masking.
++                       */
++                      /* off = min(t->rj_off, matched_off); */
++                      off = t->rj_off;
++                      if (matched_off < off)
++                              off = matched_off;
++                      mstart = maskedKey + off;
++                      do {
++                              cp2 = mstart;
++                              cp3 = m->rm_mask + off;
++                              KLIPS_PRINT(debug_radij,
++                                          "klips_debug:rj_match: "
++                                          "***** cp2=0p%p cp3=0p%p\n",
++                                          cp2, cp3);
++                              for (cp = v + off; cp < cplim;)
++                                      *cp2++ =  *cp++ & *cp3++;
++                              x = rj_search(maskedKey, t);
++                              while (x && x->rj_mask != m->rm_mask)
++                                      x = x->rj_dupedkey;
++                              if (x &&
++                                  (Bcmp(mstart, x->rj_key + off,
++                                      vlen - off) == 0))
++                                          return x;
++                      } while ((m = m->rm_mklist));
++              }
++      } while (t != top);
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:rj_match: "
++                  "***** not found.\n");
++      return 0;
++};
++              
++#ifdef RJ_DEBUG
++int   rj_nodenum;
++struct        radij_node *rj_clist;
++int   rj_saveinfo;
++DEBUG_NO_STATIC void traverse(struct radij_node *);
++#ifdef RJ_DEBUG2
++int   rj_debug =  1;
++#else
++int   rj_debug =  0;
++#endif /* RJ_DEBUG2 */
++#endif /* RJ_DEBUG */
++
++struct radij_node *
++rj_newpair(v, b, nodes)
++      void *v;
++      int b;
++      struct radij_node nodes[2];
++{
++      register struct radij_node *tt = nodes, *t = tt + 1;
++      t->rj_b = b; t->rj_bmask = 0x80 >> (b & 7);
++      t->rj_l = tt; t->rj_off = b >> 3;
++      tt->rj_b = -1; tt->rj_key = (caddr_t)v; tt->rj_p = t;
++      tt->rj_flags = t->rj_flags = RJF_ACTIVE;
++#ifdef RJ_DEBUG
++      tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
++      tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
++#endif /* RJ_DEBUG */
++      return t;
++}
++
++struct radij_node *
++rj_insert(v_arg, head, dupentry, nodes)
++      void *v_arg;
++      struct radij_node_head *head;
++      int *dupentry;
++      struct radij_node nodes[2];
++{
++      caddr_t v = v_arg;
++      struct radij_node *top = head->rnh_treetop;
++      int head_off = top->rj_off, vlen = (int)*((u_char *)v);
++      register struct radij_node *t = rj_search(v_arg, top);
++      register caddr_t cp = v + head_off;
++      register int b;
++      struct radij_node *tt;
++      /*
++       *find first bit at which v and t->rj_key differ
++       */
++    {
++      register caddr_t cp2 = t->rj_key + head_off;
++      register int cmp_res;
++      caddr_t cplim = v + vlen;
++
++      while (cp < cplim)
++              if (*cp2++ != *cp++)
++                      goto on1;
++      *dupentry = 1;
++      return t;
++on1:
++      *dupentry = 0;
++      cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
++      for (b = (cp - v) << 3; cmp_res; b--)
++              cmp_res >>= 1;
++    }
++    {
++      register struct radij_node *p, *x = top;
++      cp = v;
++      do {
++              p = x;
++              if (cp[x->rj_off] & x->rj_bmask) 
++                      x = x->rj_r;
++              else x = x->rj_l;
++      } while (b > (unsigned) x->rj_b); /* x->rj_b < b && x->rj_b >= 0 */
++#ifdef RJ_DEBUG
++      if (rj_debug)
++              printk("klips_debug:rj_insert: Going In:\n"), traverse(p);
++#endif /* RJ_DEBUG */
++      t = rj_newpair(v_arg, b, nodes); tt = t->rj_l;
++      if ((cp[p->rj_off] & p->rj_bmask) == 0)
++              p->rj_l = t;
++      else
++              p->rj_r = t;
++      x->rj_p = t; t->rj_p = p; /* frees x, p as temp vars below */
++      if ((cp[t->rj_off] & t->rj_bmask) == 0) {
++              t->rj_r = x;
++      } else {
++              t->rj_r = tt; t->rj_l = x;
++      }
++#ifdef RJ_DEBUG
++      if (rj_debug)
++              printk("klips_debug:rj_insert: Coming out:\n"), traverse(p);
++#endif /* RJ_DEBUG */
++    }
++      return (tt);
++}
++
++struct radij_node *
++rj_addmask(n_arg, search, skip)
++      int search, skip;
++      void *n_arg;
++{
++      caddr_t netmask = (caddr_t)n_arg;
++      register struct radij_node *x;
++      register caddr_t cp, cplim;
++      register int b, mlen, j;
++      int maskduplicated;
++
++      mlen = *(u_char *)netmask;
++      if (search) {
++              x = rj_search(netmask, rj_masktop);
++              mlen = *(u_char *)netmask;
++              if (Bcmp(netmask, x->rj_key, mlen) == 0)
++                      return (x);
++      }
++      R_Malloc(x, struct radij_node *, maj_keylen + 2 * sizeof (*x));
++      if (x == 0)
++              return (0);
++      Bzero(x, maj_keylen + 2 * sizeof (*x));
++      cp = (caddr_t)(x + 2);
++      Bcopy(netmask, cp, mlen);
++      netmask = cp;
++      x = rj_insert(netmask, mask_rjhead, &maskduplicated, x);
++      /*
++       * Calculate index of mask.
++       */
++      cplim = netmask + mlen;
++      for (cp = netmask + skip; cp < cplim; cp++)
++              if (*(u_char *)cp != 0xff)
++                      break;
++      b = (cp - netmask) << 3;
++      if (cp != cplim) {
++              if (*cp != 0) {
++                      gotOddMasks = 1;
++                      for (j = 0x80; j; b++, j >>= 1)  
++                              if ((j & *cp) == 0)
++                                      break;
++              }
++      }
++      x->rj_b = -1 - b;
++      return (x);
++}
++
++#if 0
++struct radij_node *
++#endif
++int
++rj_addroute(v_arg, n_arg, head, treenodes)
++      void *v_arg, *n_arg;
++      struct radij_node_head *head;
++      struct radij_node treenodes[2];
++{
++      caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
++      register struct radij_node *t, *x=NULL, *tt;
++      struct radij_node *saved_tt, *top = head->rnh_treetop;
++      short b = 0, b_leaf;
++      int mlen, keyduplicated;
++      caddr_t cplim;
++      struct radij_mask *m, **mp;
++
++      /*
++       * In dealing with non-contiguous masks, there may be
++       * many different routes which have the same mask.
++       * We will find it useful to have a unique pointer to
++       * the mask to speed avoiding duplicate references at
++       * nodes and possibly save time in calculating indices.
++       */
++      if (netmask)  {
++              x = rj_search(netmask, rj_masktop);
++              mlen = *(u_char *)netmask;
++              if (Bcmp(netmask, x->rj_key, mlen) != 0) {
++                      x = rj_addmask(netmask, 0, top->rj_off);
++                      if (x == 0)
++                              return -ENOMEM; /* (0) rgb */
++              }
++              netmask = x->rj_key;
++              b = -1 - x->rj_b;
++      }
++      /*
++       * Deal with duplicated keys: attach node to previous instance
++       */
++      saved_tt = tt = rj_insert(v, head, &keyduplicated, treenodes);
++#ifdef RJ_DEBUG
++      printk("addkey: duplicated: %d\n", keyduplicated);
++#endif
++      if (keyduplicated) {
++              do {
++                      if (tt->rj_mask == netmask)
++                              return -EEXIST; /* -ENXIO; (0) rgb */
++                      t = tt;
++                      if (netmask == 0 ||
++                          (tt->rj_mask && rj_refines(netmask, tt->rj_mask)))
++                              break;
++              } while ((tt = tt->rj_dupedkey));
++              /*
++               * If the mask is not duplicated, we wouldn't
++               * find it among possible duplicate key entries
++               * anyway, so the above test doesn't hurt.
++               *
++               * We sort the masks for a duplicated key the same way as
++               * in a masklist -- most specific to least specific.
++               * This may require the unfortunate nuisance of relocating
++               * the head of the list.
++               */
++              if (tt && t == saved_tt) {
++                      struct  radij_node *xx = x;
++                      /* link in at head of list */
++                      (tt = treenodes)->rj_dupedkey = t;
++                      tt->rj_flags = t->rj_flags;
++                      tt->rj_p = x = t->rj_p;
++                      if (x->rj_l == t) x->rj_l = tt; else x->rj_r = tt;
++                      saved_tt = tt; x = xx;
++              } else {
++                      (tt = treenodes)->rj_dupedkey = t->rj_dupedkey;
++                      t->rj_dupedkey = tt;
++              }
++#ifdef RJ_DEBUG
++              t=tt+1; tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
++              tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
++#endif /* RJ_DEBUG */
++              t = saved_tt;
++              tt->rj_key = (caddr_t) v;
++              tt->rj_b = -1;
++              tt->rj_flags = t->rj_flags & ~RJF_ROOT;
++      }
++      /*
++       * Put mask in tree.
++       */
++      if (netmask) {
++              tt->rj_mask = netmask;
++              tt->rj_b = x->rj_b;
++      }
++      t = saved_tt->rj_p;
++      b_leaf = -1 - t->rj_b;
++      if (t->rj_r == saved_tt) x = t->rj_l; else x = t->rj_r;
++      /* Promote general routes from below */
++      if (x->rj_b < 0) { 
++              if (x->rj_mask && (x->rj_b >= b_leaf) && x->rj_mklist == 0) {
++                      MKGet(m);
++                      if (m) {
++                              Bzero(m, sizeof *m);
++                              m->rm_b = x->rj_b;
++                              m->rm_mask = x->rj_mask;
++                              x->rj_mklist = t->rj_mklist = m;
++                      }
++              }
++      } else if (x->rj_mklist) {
++              /*
++               * Skip over masks whose index is > that of new node
++               */
++              for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
++                      if (m->rm_b >= b_leaf)
++                              break;
++              t->rj_mklist = m; *mp = 0;
++      }
++      /* Add new route to highest possible ancestor's list */
++      if ((netmask == 0) || (b > t->rj_b )) {
++#ifdef RJ_DEBUG
++              printk("klips:radij.c: netmask = %p or b(%d)>t->rjb(%d)\n", netmask, b, t->rj_b);
++#endif
++              return 0; /* tt rgb */ /* can't lift at all */
++      }
++      b_leaf = tt->rj_b;
++      do {
++              x = t;
++              t = t->rj_p;
++      } while (b <= t->rj_b && x != top);
++      /*
++       * Search through routes associated with node to
++       * insert new route according to index.
++       * For nodes of equal index, place more specific
++       * masks first.
++       */
++      cplim = netmask + mlen;
++      for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist) {
++              if (m->rm_b < b_leaf)
++                      continue;
++              if (m->rm_b > b_leaf)
++                      break;
++              if (m->rm_mask == netmask) {
++                      m->rm_refs++;
++                      tt->rj_mklist = m;
++#ifdef RJ_DEBUG
++                      printk("klips:radij.c: m->rm_mask %p == netmask\n", netmask);
++#endif
++                      return 0; /* tt rgb */
++              }
++              if (rj_refines(netmask, m->rm_mask))
++                      break;
++      }
++      MKGet(m);
++      if (m == 0) {
++              printk("klips_debug:rj_addroute: "
++                     "Mask for route not entered\n");
++              return 0; /* (tt) rgb */
++      }
++      Bzero(m, sizeof *m);
++      m->rm_b = b_leaf;
++      m->rm_mask = netmask;
++      m->rm_mklist = *mp;
++      *mp = m;
++      tt->rj_mklist = m;
++#ifdef RJ_DEBUG
++      printk("klips:radij.c: addroute done\n");
++#endif
++      return 0; /* tt rgb */
++}
++
++int
++rj_delete(v_arg, netmask_arg, head, node)
++      void *v_arg, *netmask_arg;
++      struct radij_node_head *head;
++      struct radij_node **node;
++{
++      register struct radij_node *t, *p, *x, *tt;
++      struct radij_mask *m, *saved_m, **mp;
++      struct radij_node *dupedkey, *saved_tt, *top;
++      caddr_t v, netmask;
++      int b, head_off, vlen;
++
++      v = v_arg;
++      netmask = netmask_arg;
++      x = head->rnh_treetop;
++      tt = rj_search(v, x);
++      head_off = x->rj_off;
++      vlen =  *(u_char *)v;
++      saved_tt = tt;
++      top = x;
++      if (tt == 0 ||
++          Bcmp(v + head_off, tt->rj_key + head_off, vlen - head_off))
++              return -EFAULT; /* (0) rgb */
++      /*
++       * Delete our route from mask lists.
++       */
++      if ((dupedkey = tt->rj_dupedkey)) {
++              if (netmask) 
++                      netmask = rj_search(netmask, rj_masktop)->rj_key;
++              while (tt->rj_mask != netmask)
++                      if ((tt = tt->rj_dupedkey) == 0)
++                              return -ENOENT; /* -ENXIO; (0) rgb */
++      }
++      if (tt->rj_mask == 0 || (saved_m = m = tt->rj_mklist) == 0)
++              goto on1;
++      if (m->rm_mask != tt->rj_mask) {
++              printk("klips_debug:rj_delete: "
++                     "inconsistent annotation\n");
++              goto on1;
++      }
++      if (--m->rm_refs >= 0)
++              goto on1;
++      b = -1 - tt->rj_b;
++      t = saved_tt->rj_p;
++      if (b > t->rj_b)
++              goto on1; /* Wasn't lifted at all */
++      do {
++              x = t;
++              t = t->rj_p;
++      } while (b <= t->rj_b && x != top);
++      for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
++              if (m == saved_m) {
++                      *mp = m->rm_mklist;
++                      MKFree(m);
++                      break;
++              }
++      if (m == 0)
++              printk("klips_debug:rj_delete: "
++                     "couldn't find our annotation\n");
++on1:
++      /*
++       * Eliminate us from tree
++       */
++      if (tt->rj_flags & RJF_ROOT)
++              return -EFAULT; /* (0) rgb */
++#ifdef RJ_DEBUG
++      /* Get us out of the creation list */
++      for (t = rj_clist; t && t->rj_ybro != tt; t = t->rj_ybro) {}
++      if (t) t->rj_ybro = tt->rj_ybro;
++#endif /* RJ_DEBUG */
++      t = tt->rj_p;
++      if (dupedkey) {
++              if (tt == saved_tt) {
++                      x = dupedkey; x->rj_p = t;
++                      if (t->rj_l == tt) t->rj_l = x; else t->rj_r = x;
++              } else {
++                      for (x = p = saved_tt; p && p->rj_dupedkey != tt;)
++                              p = p->rj_dupedkey;
++                      if (p) p->rj_dupedkey = tt->rj_dupedkey;
++                      else printk("klips_debug:rj_delete: "
++                                     "couldn't find node that we started with\n");
++              }
++              t = tt + 1;
++              if  (t->rj_flags & RJF_ACTIVE) {
++#ifndef RJ_DEBUG
++                      *++x = *t; p = t->rj_p;
++#else
++                      b = t->rj_info; *++x = *t; t->rj_info = b; p = t->rj_p;
++#endif /* RJ_DEBUG */
++                      if (p->rj_l == t) p->rj_l = x; else p->rj_r = x;
++                      x->rj_l->rj_p = x; x->rj_r->rj_p = x;
++              }
++              goto out;
++      }
++      if (t->rj_l == tt) x = t->rj_r; else x = t->rj_l;
++      p = t->rj_p;
++      if (p->rj_r == t) p->rj_r = x; else p->rj_l = x;
++      x->rj_p = p;
++      /*
++       * Demote routes attached to us.
++       */
++      if (t->rj_mklist) {
++              if (x->rj_b >= 0) {
++                      for (mp = &x->rj_mklist; (m = *mp);)
++                              mp = &m->rm_mklist;
++                      *mp = t->rj_mklist;
++              } else {
++                      for (m = t->rj_mklist; m;) {
++                              struct radij_mask *mm = m->rm_mklist;
++                              if (m == x->rj_mklist && (--(m->rm_refs) < 0)) {
++                                      x->rj_mklist = 0;
++                                      MKFree(m);
++                              } else 
++                                      printk("klips_debug:rj_delete: "
++                                          "Orphaned Mask 0p%p at 0p%p\n", m, x);
++                              m = mm;
++                      }
++              }
++      }
++      /*
++       * We may be holding an active internal node in the tree.
++       */
++      x = tt + 1;
++      if (t != x) {
++#ifndef RJ_DEBUG
++              *t = *x;
++#else
++              b = t->rj_info; *t = *x; t->rj_info = b;
++#endif /* RJ_DEBUG */
++              t->rj_l->rj_p = t; t->rj_r->rj_p = t;
++              p = x->rj_p;
++              if (p->rj_l == x) p->rj_l = t; else p->rj_r = t;
++      }
++out:
++      tt->rj_flags &= ~RJF_ACTIVE;
++      tt[1].rj_flags &= ~RJF_ACTIVE;
++      *node = tt;
++      return 0; /* (tt) rgb */
++}
++
++int
++rj_walktree(h, f, w)
++      struct radij_node_head *h;
++      register int (*f)(struct radij_node *,void *);
++      void *w;
++{
++      int error;
++      struct radij_node *base, *next;
++      register struct radij_node *rn;
++
++      if(!h || !f /* || !w */) {
++              return -ENODATA;
++      }
++
++      rn = h->rnh_treetop;
++      /*
++       * This gets complicated because we may delete the node
++       * while applying the function f to it, so we need to calculate
++       * the successor node in advance.
++       */
++      /* First time through node, go left */
++      while (rn->rj_b >= 0)
++              rn = rn->rj_l;
++      for (;;) {
++#ifdef CONFIG_KLIPS_DEBUG
++              if(debug_radij) {
++                      printk("klips_debug:rj_walktree: "
++                             "for: rn=0p%p rj_b=%d rj_flags=%x",
++                             rn,
++                             rn->rj_b,
++                             rn->rj_flags);
++                      rn->rj_b >= 0 ?
++                              printk(" node off=%x\n",
++                                     rn->rj_off) :
++                              printk(" leaf key = %08x->%08x\n",
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
++                              ;
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++              base = rn;
++              /* If at right child go back up, otherwise, go right */
++              while (rn->rj_p->rj_r == rn && (rn->rj_flags & RJF_ROOT) == 0)
++                      rn = rn->rj_p;
++              /* Find the next *leaf* since next node might vanish, too */
++              for (rn = rn->rj_p->rj_r; rn->rj_b >= 0;)
++                      rn = rn->rj_l;
++              next = rn;
++#ifdef CONFIG_KLIPS_DEBUG
++              if(debug_radij) {
++                      printk("klips_debug:rj_walktree: "
++                             "processing leaves, rn=0p%p rj_b=%d rj_flags=%x",
++                             rn,
++                             rn->rj_b,
++                             rn->rj_flags);
++                      rn->rj_b >= 0 ?
++                              printk(" node off=%x\n",
++                                     rn->rj_off) :
++                              printk(" leaf key = %08x->%08x\n",
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
++                              ;
++              }
++#endif /* CONFIG_KLIPS_DEBUG */
++              /* Process leaves */
++              while ((rn = base)) {
++                      base = rn->rj_dupedkey;
++#ifdef CONFIG_KLIPS_DEBUG
++                      if(debug_radij) {
++                              printk("klips_debug:rj_walktree: "
++                                     "while: base=0p%p rn=0p%p rj_b=%d rj_flags=%x",
++                                     base,
++                                     rn,
++                                     rn->rj_b,
++                                     rn->rj_flags);
++                              rn->rj_b >= 0 ?
++                                      printk(" node off=%x\n",
++                                             rn->rj_off) :
++                                      printk(" leaf key = %08x->%08x\n",
++                                             (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
++                                             (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
++                                      ;
++                      }
++#endif /* CONFIG_KLIPS_DEBUG */
++                      if (!(rn->rj_flags & RJF_ROOT) && (error = (*f)(rn, w)))
++                              return (-error);
++              }
++              rn = next;
++              if (rn->rj_flags & RJF_ROOT)
++                      return (0);
++      }
++      /* NOTREACHED */
++}
++
++int
++rj_inithead(head, off)
++      void **head;
++      int off;
++{
++      register struct radij_node_head *rnh;
++      register struct radij_node *t, *tt, *ttt;
++      if (*head)
++              return (1);
++      R_Malloc(rnh, struct radij_node_head *, sizeof (*rnh));
++      if (rnh == NULL)
++              return (0);
++      Bzero(rnh, sizeof (*rnh));
++      *head = rnh;
++      t = rj_newpair(rj_zeroes, off, rnh->rnh_nodes);
++      ttt = rnh->rnh_nodes + 2;
++      t->rj_r = ttt;
++      t->rj_p = t;
++      tt = t->rj_l;
++      tt->rj_flags = t->rj_flags = RJF_ROOT | RJF_ACTIVE;
++      tt->rj_b = -1 - off;
++      *ttt = *tt;
++      ttt->rj_key = rj_ones;
++      rnh->rnh_addaddr = rj_addroute;
++      rnh->rnh_deladdr = rj_delete;
++      rnh->rnh_matchaddr = rj_match;
++      rnh->rnh_walktree = rj_walktree;
++      rnh->rnh_treetop = t;
++      return (1);
++}
++
++void
++rj_init()
++{
++      char *cp, *cplim;
++
++      if (maj_keylen == 0) {
++              printk("klips_debug:rj_init: "
++                     "radij functions require maj_keylen be set\n");
++              return;
++      }
++      R_Malloc(rj_zeroes, char *, 3 * maj_keylen);
++      if (rj_zeroes == NULL)
++              panic("rj_init");
++      Bzero(rj_zeroes, 3 * maj_keylen);
++      rj_ones = cp = rj_zeroes + maj_keylen;
++      maskedKey = cplim = rj_ones + maj_keylen;
++      while (cp < cplim)
++              *cp++ = -1;
++      if (rj_inithead((void **)&mask_rjhead, 0) == 0)
++              panic("rj_init 2");
++}
++
++void
++rj_preorder(struct radij_node *rn, int l)
++{
++      int i;
++      
++      if (rn == NULL){
++              printk("klips_debug:rj_preorder: "
++                     "NULL pointer\n");
++              return;
++      }
++      
++      if (rn->rj_b >= 0){
++              rj_preorder(rn->rj_l, l+1);
++              rj_preorder(rn->rj_r, l+1);
++              printk("klips_debug:");
++              for (i=0; i<l; i++)
++                      printk("*");
++              printk(" off = %d\n",
++                     rn->rj_off);
++      } else {
++              printk("klips_debug:");
++              for (i=0; i<l; i++)
++                      printk("@");
++              printk(" flags = %x",
++                     (u_int)rn->rj_flags);
++              if (rn->rj_flags & RJF_ACTIVE) {
++                      printk(" @key=0p%p",
++                             rn->rj_key);
++                      printk(" key = %08x->%08x",
++                             (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
++                             (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr));
++                      printk(" @mask=0p%p",
++                             rn->rj_mask);
++                      if (rn->rj_mask)
++                              printk(" mask = %08x->%08x",
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_src.s_addr),
++                                     (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_dst.s_addr));
++                      if (rn->rj_dupedkey)
++                              printk(" dupedkey = 0p%p",
++                                     rn->rj_dupedkey);
++              }
++              printk("\n");
++      }
++}
++
++#ifdef RJ_DEBUG
++DEBUG_NO_STATIC void traverse(struct radij_node *p)
++{
++  rj_preorder(p, 0);
++}
++#endif /* RJ_DEBUG */
++
++void
++rj_dumptrees(void)
++{
++      rj_preorder(rnh->rnh_treetop, 0);
++}
++
++void
++rj_free_mkfreelist(void)
++{
++      struct radij_mask *mknp, *mknp2;
++
++      mknp = rj_mkfreelist;
++      while(mknp)
++      {
++              mknp2 = mknp;
++              mknp = mknp->rm_mklist;
++              kfree(mknp2);
++      }
++}
++
++int
++radijcleartree(void)
++{
++      return rj_walktree(rnh, ipsec_rj_walker_delete, NULL);
++}
++
++int
++radijcleanup(void)
++{
++      int error = 0;
++
++      error = radijcleartree();
++
++      rj_free_mkfreelist();
++
++/*    rj_walktree(mask_rjhead, ipsec_rj_walker_delete, NULL); */
++      if(mask_rjhead) {
++              kfree(mask_rjhead);
++      }
++
++      if(rj_zeroes) {
++              kfree(rj_zeroes);
++      }
++
++      if(rnh) {
++              kfree(rnh);
++      }
++
++      return error;
++}
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/rangetoa.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,60 @@
++/*
++ * convert binary form of address range to ASCII
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: rangetoa.c,v 1.9 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - rangetoa - convert address range to ASCII
++ */
++size_t                                /* space needed for full conversion */
++rangetoa(addrs, format, dst, dstlen)
++struct in_addr addrs[2];
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t len;
++      size_t rest;
++      int n;
++      char *p;
++
++      switch (format) {
++      case 0:
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      len = addrtoa(addrs[0], 0, dst, dstlen);
++      if (len < dstlen)
++              for (p = dst + len - 1, n = 3; len < dstlen && n > 0;
++                                                              p++, len++, n--)
++                      *p = '.';
++      else
++              p = NULL;
++      if (len < dstlen)
++              rest = dstlen - len;
++      else {
++              if (dstlen > 0)
++                      *(dst + dstlen - 1) = '\0';
++              rest = 0;
++      }
++
++      len += addrtoa(addrs[1], 0, p, rest);
++
++      return len;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/satot.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,134 @@
++/*
++ * convert from binary form of SA ID to text
++ * Copyright (C) 2000, 2001  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: satot.c,v 1.13 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++static struct typename {
++      char type;
++      char *name;
++} typenames[] = {
++      { SA_AH,        "ah" },
++      { SA_ESP,       "esp" },
++      { SA_IPIP,      "tun" },
++      { SA_COMP,      "comp" },
++      { SA_INT,       "int" },
++      { 0,            NULL }
++};
++
++/*
++ - satot - convert SA to text "ah507@1.2.3.4"
++ */
++size_t                                /* space needed for full conversion */
++satot(sa, format, dst, dstlen)
++const ip_said *sa;
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t len = 0;         /* 0 means "not recognized yet" */
++      int base;
++      int showversion;        /* use delimiter to show IP version? */
++      struct typename *tn;
++      char *p;
++      char *pre;
++      char buf[10+1+ULTOT_BUF+ADDRTOT_BUF];
++      char unk[10];
++
++      switch (format) {
++      case 0:
++              base = 16;
++              showversion = 1;
++              break;
++      case 'f':
++              base = 17;
++              showversion = 1;
++              break;
++      case 'x':
++              base = 'x';
++              showversion = 0;
++              break;
++      case 'd':
++              base = 10;
++              showversion = 0;
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      memset(buf, 0, sizeof(buf));
++
++      pre = NULL;
++      for (tn = typenames; tn->name != NULL; tn++)
++              if (sa->proto == tn->type) {
++                      pre = tn->name;
++                      break;                  /* NOTE BREAK OUT */
++              }
++      if (pre == NULL) {              /* unknown protocol */
++              strcpy(unk, "unk");
++              (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk),
++                                              sizeof(unk)-strlen(unk));
++              pre = unk;
++      }
++
++      if (strcmp(pre, PASSTHROUGHTYPE) == 0 &&
++                                      sa->spi == PASSTHROUGHSPI &&
++                                      isunspecaddr(&sa->dst)) {
++              strcpy(buf, (addrtypeof(&sa->dst) == AF_INET) ?
++                                                      PASSTHROUGH4NAME :
++                                                      PASSTHROUGH6NAME);
++              len = strlen(buf);
++      }
++
++      if (sa->proto == SA_INT) {
++              char intunk[10];
++              switch (ntohl(sa->spi)) {
++              case SPI_PASS:  p = "%pass";    break;
++              case SPI_DROP:  p = "%drop";    break;
++              case SPI_REJECT:        p = "%reject";  break;
++              case SPI_HOLD:  p = "%hold";    break;
++              case SPI_TRAP:  p = "%trap";    break;
++              case SPI_TRAPSUBNET:    p = "%trapsubnet";      break;
++              default:        snprintf(intunk, 10, "%%unk-%d", ntohl(sa->spi)); p = intunk;   break;
++              }
++              if (p != NULL) {
++                      strcpy(buf, p);
++                      len = strlen(buf);
++              }
++      }
++
++      if (len == 0) {                 /* general case needed */
++              strcpy(buf, pre);
++              len = strlen(buf);
++              if (showversion) {
++                      *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' :
++                                                                      ':';
++                      len++;
++                      *(buf+len) = '\0';
++              }
++              len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len);
++              *(buf+len-1) = '@';
++              len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len);
++              *(buf+len) = '\0';
++      }
++
++      if (dst != NULL) {
++              if (len > dstlen)
++                      *(buf+dstlen-1) = '\0';
++              strcpy(dst, buf);
++      }
++      return len;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/subnetof.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,59 @@
++/*
++ * minor network-address manipulation utilities
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: subnetof.c,v 1.8 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - subnetof - given address and mask, return subnet part
++ */
++struct in_addr
++subnetof(addr, mask)
++struct in_addr addr;
++struct in_addr mask;
++{
++      struct in_addr result;
++
++      result.s_addr = addr.s_addr & mask.s_addr;
++      return result;
++}
++
++/*
++ - hostof - given address and mask, return host part
++ */
++struct in_addr
++hostof(addr, mask)
++struct in_addr addr;
++struct in_addr mask;
++{
++      struct in_addr result;
++
++      result.s_addr = addr.s_addr & ~mask.s_addr;
++      return result;
++}
++
++/*
++ - broadcastof - given (network) address and mask, return broadcast address
++ */
++struct in_addr
++broadcastof(addr, mask)
++struct in_addr addr;
++struct in_addr mask;
++{
++      struct in_addr result;
++
++      result.s_addr = addr.s_addr | ~mask.s_addr;
++      return result;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/subnettoa.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,61 @@
++/*
++ * convert binary form of subnet description to ASCII
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: subnettoa.c,v 1.11 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - subnettoa - convert address and mask to ASCII "addr/mask"
++ * Output expresses the mask as a bit count if possible, else dotted decimal.
++ */
++size_t                                /* space needed for full conversion */
++subnettoa(addr, mask, format, dst, dstlen)
++struct in_addr addr;
++struct in_addr mask;
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t len;
++      size_t rest;
++      int n;
++      char *p;
++
++      switch (format) {
++      case 0:
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      len = addrtoa(addr, 0, dst, dstlen);
++      if (len < dstlen) {
++              dst[len - 1] = '/';
++              p = dst + len;
++              rest = dstlen - len;
++      } else {
++              p = NULL;
++              rest = 0;
++      }
++
++      n = masktobits(mask);
++      if (n >= 0)
++              len += ultoa((unsigned long)n, 10, p, rest);
++      else
++              len += addrtoa(mask, 0, p, rest);
++
++      return len;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/sysctl_net_ipsec.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,387 @@
++/*
++ * sysctl interface to net IPSEC subsystem.
++ * Copyright (C) 1998, 1999, 2000, 2001         Richard Guy Briggs.
++ * 
++ * This program is free software; you can redistribute it and/or 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
++ * 
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * for more details.
++ *
++ * RCSID $Id: sysctl_net_ipsec.c,v 1.17.10.2 2007/10/30 21:42:25 paul Exp $
++ */
++
++/* -*- linux-c -*-
++ *
++ * Initiated April 3, 1998, Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
++ */
++
++#include <linux/version.h>
++#include <linux/mm.h>
++#include <linux/sysctl.h>
++
++#include "openswan/ipsec_param.h"
++
++#ifdef CONFIG_SYSCTL
++
++#define NET_IPSEC 2112 /* Random number */                                        
++#ifdef CONFIG_KLIPS_DEBUG
++extern int       debug_ah;
++extern int       debug_esp;
++extern int       debug_mast;
++extern int       debug_tunnel;
++extern int       debug_xmit;
++extern int       debug_eroute;
++extern int       debug_spi;
++extern int       debug_radij;
++extern int       debug_netlink;
++extern int       debug_xform;
++extern int       debug_rcv;
++extern int       debug_pfkey;
++extern int sysctl_ipsec_debug_verbose;
++#ifdef CONFIG_KLIPS_IPCOMP
++extern int sysctl_ipsec_debug_ipcomp;
++#endif /* CONFIG_KLIPS_IPCOMP */
++#endif /* CONFIG_KLIPS_DEBUG */
++
++extern int sysctl_ipsec_icmp;
++extern int sysctl_ipsec_inbound_policy_check;
++extern int sysctl_ipsec_tos;
++int sysctl_ipsec_regress_pfkey_lossage;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#ifdef CONFIG_KLIPS_DEBUG
++      #define NET_IPSEC_DEBUG_AH              CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_ESP             CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_TUNNEL          CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_EROUTE          CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_SPI             CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_RADIJ           CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_NETLINK         CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_XFORM           CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_RCV             CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_PFKEY           CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_VERBOSE         CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_IPCOMP          CTL_UNNUMBERED
++#endif /* CONFIG_KLIPS_DEBUG */
++      #define NET_IPSEC_ICMP                  CTL_UNNUMBERED
++      #define NET_IPSEC_INBOUND_POLICY_CHECK  CTL_UNNUMBERED
++      #define NET_IPSEC_TOS                   CTL_UNNUMBERED
++      #define NET_IPSEC_REGRESS_PFKEY_LOSSAGE CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_MAST            CTL_UNNUMBERED
++      #define NET_IPSEC_DEBUG_XMIT            CTL_UNNUMBERED
++#else
++enum {
++#ifdef CONFIG_KLIPS_DEBUG
++      NET_IPSEC_DEBUG_AH=1,
++      NET_IPSEC_DEBUG_ESP=2,
++      NET_IPSEC_DEBUG_TUNNEL=3,
++      NET_IPSEC_DEBUG_EROUTE=4,
++      NET_IPSEC_DEBUG_SPI=5,
++      NET_IPSEC_DEBUG_RADIJ=6,
++      NET_IPSEC_DEBUG_NETLINK=7,
++      NET_IPSEC_DEBUG_XFORM=8,
++      NET_IPSEC_DEBUG_RCV=9,
++      NET_IPSEC_DEBUG_PFKEY=10,
++      NET_IPSEC_DEBUG_VERBOSE=11,
++      NET_IPSEC_DEBUG_IPCOMP=12,
++#endif /* CONFIG_KLIPS_DEBUG */
++      NET_IPSEC_ICMP=13,
++      NET_IPSEC_INBOUND_POLICY_CHECK=14,
++      NET_IPSEC_TOS=15,
++      NET_IPSEC_REGRESS_PFKEY_LOSSAGE=16,
++      NET_IPSEC_DEBUG_MAST=17,
++      NET_IPSEC_DEBUG_XMIT=18,
++};
++#endif
++
++static ctl_table ipsec_table[] = {
++
++#ifdef CONFIG_KLIPS_DEBUG
++#ifdef CTL_TABLE_PARENT
++       { .ctl_name = NET_IPSEC_DEBUG_AH,
++         .procname = "debug_ah",
++         .data     = &debug_ah,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_ESP,
++         .procname = "debug_esp",
++         .data     = &debug_esp,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_MAST,
++         .procname = "debug_mast",
++         .data     = &debug_mast,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_TUNNEL,
++         .procname = "debug_tunnel",
++         .data     = &debug_tunnel,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_XMIT,
++         .procname = "debug_xmit",
++         .data     = &debug_xmit,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_EROUTE,
++         .procname = "debug_eroute",
++         .data     = &debug_eroute,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_SPI,
++         .procname = "debug_spi",
++         .data     = &debug_spi,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_RADIJ,
++         .procname = "debug_radij",
++         .data     = &debug_radij,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_NETLINK,
++         .procname = "debug_netlink",
++         .data     = &debug_netlink,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_XFORM,
++         .procname = "debug_xform",
++         .data     = &debug_xform,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_RCV,
++         .procname = "debug_rcv",
++         .data     = &debug_rcv,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_PFKEY,
++         .procname = "debug_pfkey",
++         .data     = &debug_pfkey,
++          .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++        { .ctl_name = NET_IPSEC_DEBUG_VERBOSE,
++         .procname = "debug_verbose",
++         .data     = &sysctl_ipsec_debug_verbose,
++         .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++#else
++      { NET_IPSEC_DEBUG_AH, "debug_ah", &debug_ah,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_ESP, "debug_esp", &debug_esp,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_MAST, "debug_mast", &debug_mast,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_TUNNEL, "debug_tunnel", &debug_tunnel,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_TUNNEL, "debug_xmit", &debug_xmit,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_EROUTE, "debug_eroute", &debug_eroute,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_SPI, "debug_spi", &debug_spi,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_RADIJ, "debug_radij", &debug_radij,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_NETLINK, "debug_netlink", &debug_netlink,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_XFORM, "debug_xform", &debug_xform,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_RCV, "debug_rcv", &debug_rcv,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &debug_pfkey,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_DEBUG_VERBOSE, "debug_verbose",&sysctl_ipsec_debug_verbose,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++#endif /* CTL_TABLE_PARENT */
++#endif /* CONFIG_KLIPS_DEBUG */
++
++#ifdef CONFIG_KLIPS_IPCOMP
++#ifdef CTL_TABLE_PARENT
++        { .ctl_name = NET_IPSEC_DEBUG_IPCOMP,
++         .procname = "debug_ipcomp",
++         .data     = &sysctl_ipsec_debug_ipcomp,
++         .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++#else
++      { NET_IPSEC_DEBUG_IPCOMP, "debug_ipcomp", &sysctl_ipsec_debug_ipcomp,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++#endif
++#endif /* CONFIG_KLIPS_IPCOMP */
++
++#ifdef CONFIG_KLIPS_REGRESS
++#ifdef CTL_TABLE_PARENT
++       {
++         .ctl_name = NET_IPSEC_REGRESS_PFKEY_LOSSAGE,
++         .procname = "pfkey_lossage",
++         .data     = &sysctl_ipsec_regress_pfkey_lossage,
++         .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++#else
++      { NET_IPSEC_REGRESS_PFKEY_LOSSAGE, "pfkey_lossage",
++        &sysctl_ipsec_regress_pfkey_lossage,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},
++#endif /* CTL_TABLE_PARENT */
++#endif /* CONFIG_KLIPS_REGRESS */
++
++#ifdef CTL_TABLE_PARENT
++       { .ctl_name = NET_IPSEC_ICMP,
++         .procname = "icmp",
++         .data     = &sysctl_ipsec_icmp,
++         .maxlen   = sizeof(int),
++         .mode     = 0644,
++         .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++       { .ctl_name = NET_IPSEC_INBOUND_POLICY_CHECK,
++         .procname = "inbound_policy_check",
++         .data     = &sysctl_ipsec_inbound_policy_check,
++          .maxlen   = sizeof(int),
++          .mode     = 0644,
++          .child    = NULL,
++         .proc_handler = &proc_dointvec,
++       },
++
++       { .ctl_name = NET_IPSEC_TOS,
++          .procname = "tos",
++          .data     = &sysctl_ipsec_tos,
++          .maxlen   = sizeof(int),
++          .mode     = 0644,
++          .child    = NULL,
++          .proc_handler = &proc_dointvec,
++       },
++       {0}
++#else
++      { NET_IPSEC_ICMP, "icmp", &sysctl_ipsec_icmp,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_INBOUND_POLICY_CHECK, "inbound_policy_check", &sysctl_ipsec_inbound_policy_check,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      { NET_IPSEC_TOS, "tos", &sysctl_ipsec_tos,
++        sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
++      {0}
++#endif
++};
++
++static ctl_table ipsec_net_table[] = {
++#ifdef CTL_TABLE_PARENT
++       { .ctl_name = NET_IPSEC,
++          .procname = "ipsec",
++          .data     = NULL,
++          .maxlen   = 0,
++          .mode     = 0555,
++          .child    = ipsec_table,
++          .proc_handler = NULL,
++        },
++       { 0 }
++#else
++        { NET_IPSEC, "ipsec", NULL, 0, 0555, ipsec_table },
++        { 0 }
++#endif
++};
++ 
++static ctl_table ipsec_root_table[] = {
++#ifdef CTL_TABLE_PARENT
++       { .ctl_name = CTL_NET,
++          .procname = "net",
++          .data     = NULL,
++          .maxlen   = 0,
++          .mode     = 0555,
++          .child    = ipsec_net_table,
++          .proc_handler = NULL,
++        },
++       { 0 }
++#else
++        { CTL_NET, "net", NULL, 0, 0555, ipsec_net_table },
++        { 0 }
++#endif
++};
++ 
++static struct ctl_table_header *ipsec_table_header;
++
++int ipsec_sysctl_register(void)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++        ipsec_table_header = register_sysctl_table(ipsec_root_table);
++#else
++        ipsec_table_header = register_sysctl_table(ipsec_root_table, 0);
++#endif
++        if (!ipsec_table_header) {
++                return -ENOMEM;
++      }
++        return 0;
++}
++ 
++void ipsec_sysctl_unregister(void)
++{
++        unregister_sysctl_table(ipsec_table_header);
++}
++
++#endif /* CONFIG_SYSCTL */
++
++/*
++ *
++ * Local Variables:
++ * c-file-style: "linux"
++ * End:
++ *
++ */
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/trees.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,1214 @@
++/* trees.c -- output deflated data using Huffman coding
++ * Copyright (C) 1995-2002 Jean-loup Gailly
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/*
++ *  ALGORITHM
++ *
++ *      The "deflation" process uses several Huffman trees. The more
++ *      common source values are represented by shorter bit sequences.
++ *
++ *      Each code tree is stored in a compressed form which is itself
++ * a Huffman encoding of the lengths of all the code strings (in
++ * ascending order by source values).  The actual code strings are
++ * reconstructed from the lengths in the inflate process, as described
++ * in the deflate specification.
++ *
++ *  REFERENCES
++ *
++ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
++ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
++ *
++ *      Storer, James A.
++ *          Data Compression:  Methods and Theory, pp. 49-50.
++ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
++ *
++ *      Sedgewick, R.
++ *          Algorithms, p290.
++ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
++ */
++
++/* @(#) $Id: trees.c,v 1.4 2004/07/10 07:48:39 mcr Exp $ */
++
++/* #define GEN_TREES_H */
++
++#include "deflate.h"
++
++#ifdef DEBUG
++#  include <ctype.h>
++#endif
++
++/* ===========================================================================
++ * Constants
++ */
++
++#define MAX_BL_BITS 7
++/* Bit length codes must not exceed MAX_BL_BITS bits */
++
++#define END_BLOCK 256
++/* end of block literal code */
++
++#define REP_3_6      16
++/* repeat previous bit length 3-6 times (2 bits of repeat count) */
++
++#define REPZ_3_10    17
++/* repeat a zero length 3-10 times  (3 bits of repeat count) */
++
++#define REPZ_11_138  18
++/* repeat a zero length 11-138 times  (7 bits of repeat count) */
++
++local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
++   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
++
++local const int extra_dbits[D_CODES] /* extra bits for each distance code */
++   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
++
++local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
++   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
++
++local const uch bl_order[BL_CODES]
++   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
++/* The lengths of the bit length codes are sent in order of decreasing
++ * probability, to avoid transmitting the lengths for unused bit length codes.
++ */
++
++#define Buf_size (8 * 2*sizeof(char))
++/* Number of bits used within bi_buf. (bi_buf might be implemented on
++ * more than 16 bits on some systems.)
++ */
++
++/* ===========================================================================
++ * Local data. These are initialized only once.
++ */
++
++#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
++
++#if defined(GEN_TREES_H) || !defined(STDC)
++/* non ANSI compilers may not accept trees.h */
++
++local ct_data static_ltree[L_CODES+2];
++/* The static literal tree. Since the bit lengths are imposed, there is no
++ * need for the L_CODES extra codes used during heap construction. However
++ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
++ * below).
++ */
++
++local ct_data static_dtree[D_CODES];
++/* The static distance tree. (Actually a trivial tree since all codes use
++ * 5 bits.)
++ */
++
++uch _dist_code[DIST_CODE_LEN];
++/* Distance codes. The first 256 values correspond to the distances
++ * 3 .. 258, the last 256 values correspond to the top 8 bits of
++ * the 15 bit distances.
++ */
++
++uch _length_code[MAX_MATCH-MIN_MATCH+1];
++/* length code for each normalized match length (0 == MIN_MATCH) */
++
++local int base_length[LENGTH_CODES];
++/* First normalized length for each code (0 = MIN_MATCH) */
++
++local int base_dist[D_CODES];
++/* First normalized distance for each code (0 = distance of 1) */
++
++#else
++#  include "trees.h"
++#endif /* GEN_TREES_H */
++
++struct static_tree_desc_s {
++    const ct_data *static_tree;  /* static tree or NULL */
++    const intf *extra_bits;      /* extra bits for each code or NULL */
++    int     extra_base;          /* base index for extra_bits */
++    int     elems;               /* max number of elements in the tree */
++    int     max_length;          /* max bit length for the codes */
++};
++
++local static_tree_desc  static_l_desc =
++{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
++
++local static_tree_desc  static_d_desc =
++{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
++
++local static_tree_desc  static_bl_desc =
++{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
++
++/* ===========================================================================
++ * Local (static) routines in this file.
++ */
++
++local void tr_static_init OF((void));
++local void init_block     OF((deflate_state *s));
++local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
++local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
++local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
++local void build_tree     OF((deflate_state *s, tree_desc *desc));
++local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
++local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
++local int  build_bl_tree  OF((deflate_state *s));
++local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
++                              int blcodes));
++local void compress_block OF((deflate_state *s, const ct_data *ltree,
++                              const ct_data *dtree));
++local void set_data_type  OF((deflate_state *s));
++local unsigned bi_reverse OF((unsigned value, int length));
++local void bi_windup      OF((deflate_state *s));
++local void bi_flush       OF((deflate_state *s));
++local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
++                              int header));
++
++#ifdef GEN_TREES_H
++local void gen_trees_header OF((void));
++#endif
++
++#ifndef DEBUG
++#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
++   /* Send a code of the given tree. c and tree must not have side effects */
++
++#else /* DEBUG */
++#  define send_code(s, c, tree) \
++     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
++       send_bits(s, tree[c].Code, tree[c].Len); }
++#endif
++
++/* ===========================================================================
++ * Output a short LSB first on the stream.
++ * IN assertion: there is enough room in pendingBuf.
++ */
++#define put_short(s, w) { \
++    put_byte(s, (uch)((w) & 0xff)); \
++    put_byte(s, (uch)((ush)(w) >> 8)); \
++}
++
++/* ===========================================================================
++ * Send a value on a given number of bits.
++ * IN assertion: length <= 16 and value fits in length bits.
++ */
++#ifdef DEBUG
++local void send_bits      OF((deflate_state *s, int value, int length));
++
++local void send_bits(s, value, length)
++    deflate_state *s;
++    int value;  /* value to send */
++    int length; /* number of bits */
++{
++    Tracevv((stderr," l %2d v %4x ", length, value));
++    Assert(length > 0 && length <= 15, "invalid length");
++    s->bits_sent += (ulg)length;
++
++    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
++     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
++     * unused bits in value.
++     */
++    if (s->bi_valid > (int)Buf_size - length) {
++        s->bi_buf |= (value << s->bi_valid);
++        put_short(s, s->bi_buf);
++        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
++        s->bi_valid += length - Buf_size;
++    } else {
++        s->bi_buf |= value << s->bi_valid;
++        s->bi_valid += length;
++    }
++}
++#else /* !DEBUG */
++
++#define send_bits(s, value, length) \
++{ int len = length;\
++  if (s->bi_valid > (int)Buf_size - len) {\
++    int val = value;\
++    s->bi_buf |= (val << s->bi_valid);\
++    put_short(s, s->bi_buf);\
++    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
++    s->bi_valid += len - Buf_size;\
++  } else {\
++    s->bi_buf |= (value) << s->bi_valid;\
++    s->bi_valid += len;\
++  }\
++}
++#endif /* DEBUG */
++
++
++#define MAX(a,b) (a >= b ? a : b)
++/* the arguments must not have side effects */
++
++/* ===========================================================================
++ * Initialize the various 'constant' tables.
++ */
++local void tr_static_init()
++{
++#if defined(GEN_TREES_H) || !defined(STDC)
++    static int static_init_done = 0;
++    int n;        /* iterates over tree elements */
++    int bits;     /* bit counter */
++    int length;   /* length value */
++    int code;     /* code value */
++    int dist;     /* distance index */
++    ush bl_count[MAX_BITS+1];
++    /* number of codes at each bit length for an optimal tree */
++
++    if (static_init_done) return;
++
++    /* For some embedded targets, global variables are not initialized: */
++    static_l_desc.static_tree = static_ltree;
++    static_l_desc.extra_bits = extra_lbits;
++    static_d_desc.static_tree = static_dtree;
++    static_d_desc.extra_bits = extra_dbits;
++    static_bl_desc.extra_bits = extra_blbits;
++
++    /* Initialize the mapping length (0..255) -> length code (0..28) */
++    length = 0;
++    for (code = 0; code < LENGTH_CODES-1; code++) {
++        base_length[code] = length;
++        for (n = 0; n < (1<<extra_lbits[code]); n++) {
++            _length_code[length++] = (uch)code;
++        }
++    }
++    Assert (length == 256, "tr_static_init: length != 256");
++    /* Note that the length 255 (match length 258) can be represented
++     * in two different ways: code 284 + 5 bits or code 285, so we
++     * overwrite length_code[255] to use the best encoding:
++     */
++    _length_code[length-1] = (uch)code;
++
++    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
++    dist = 0;
++    for (code = 0 ; code < 16; code++) {
++        base_dist[code] = dist;
++        for (n = 0; n < (1<<extra_dbits[code]); n++) {
++            _dist_code[dist++] = (uch)code;
++        }
++    }
++    Assert (dist == 256, "tr_static_init: dist != 256");
++    dist >>= 7; /* from now on, all distances are divided by 128 */
++    for ( ; code < D_CODES; code++) {
++        base_dist[code] = dist << 7;
++        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
++            _dist_code[256 + dist++] = (uch)code;
++        }
++    }
++    Assert (dist == 256, "tr_static_init: 256+dist != 512");
++
++    /* Construct the codes of the static literal tree */
++    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
++    n = 0;
++    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
++    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
++    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
++    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
++    /* Codes 286 and 287 do not exist, but we must include them in the
++     * tree construction to get a canonical Huffman tree (longest code
++     * all ones)
++     */
++    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
++
++    /* The static distance tree is trivial: */
++    for (n = 0; n < D_CODES; n++) {
++        static_dtree[n].Len = 5;
++        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
++    }
++    static_init_done = 1;
++
++#  ifdef GEN_TREES_H
++    gen_trees_header();
++#  endif
++#endif /* defined(GEN_TREES_H) || !defined(STDC) */
++}
++
++/* ===========================================================================
++ * Genererate the file trees.h describing the static trees.
++ */
++#ifdef GEN_TREES_H
++#  ifndef DEBUG
++#    include <stdio.h>
++#  endif
++
++#  define SEPARATOR(i, last, width) \
++      ((i) == (last)? "\n};\n\n" :    \
++       ((i) % (width) == (width)-1 ? ",\n" : ", "))
++
++void gen_trees_header()
++{
++    FILE *header = fopen("trees.h", "w");
++    int i;
++
++    Assert (header != NULL, "Can't open trees.h");
++    fprintf(header,
++          "/* header created automatically with -DGEN_TREES_H */\n\n");
++
++    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
++    for (i = 0; i < L_CODES+2; i++) {
++      fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
++              static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
++    }
++
++    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
++    for (i = 0; i < D_CODES; i++) {
++      fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
++              static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
++    }
++
++    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
++    for (i = 0; i < DIST_CODE_LEN; i++) {
++      fprintf(header, "%2u%s", _dist_code[i],
++              SEPARATOR(i, DIST_CODE_LEN-1, 20));
++    }
++
++    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
++    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
++      fprintf(header, "%2u%s", _length_code[i],
++              SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
++    }
++
++    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
++    for (i = 0; i < LENGTH_CODES; i++) {
++      fprintf(header, "%1u%s", base_length[i],
++              SEPARATOR(i, LENGTH_CODES-1, 20));
++    }
++
++    fprintf(header, "local const int base_dist[D_CODES] = {\n");
++    for (i = 0; i < D_CODES; i++) {
++      fprintf(header, "%5u%s", base_dist[i],
++              SEPARATOR(i, D_CODES-1, 10));
++    }
++
++    fclose(header);
++}
++#endif /* GEN_TREES_H */
++
++/* ===========================================================================
++ * Initialize the tree data structures for a new zlib stream.
++ */
++void _tr_init(s)
++    deflate_state *s;
++{
++    tr_static_init();
++
++    s->l_desc.dyn_tree = s->dyn_ltree;
++    s->l_desc.stat_desc = &static_l_desc;
++
++    s->d_desc.dyn_tree = s->dyn_dtree;
++    s->d_desc.stat_desc = &static_d_desc;
++
++    s->bl_desc.dyn_tree = s->bl_tree;
++    s->bl_desc.stat_desc = &static_bl_desc;
++
++    s->bi_buf = 0;
++    s->bi_valid = 0;
++    s->last_eob_len = 8; /* enough lookahead for inflate */
++#ifdef DEBUG
++    s->compressed_len = 0L;
++    s->bits_sent = 0L;
++#endif
++
++    /* Initialize the first block of the first file: */
++    init_block(s);
++}
++
++/* ===========================================================================
++ * Initialize a new block.
++ */
++local void init_block(s)
++    deflate_state *s;
++{
++    int n; /* iterates over tree elements */
++
++    /* Initialize the trees. */
++    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
++    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
++    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
++
++    s->dyn_ltree[END_BLOCK].Freq = 1;
++    s->opt_len = s->static_len = 0L;
++    s->last_lit = s->matches = 0;
++}
++
++#define SMALLEST 1
++/* Index within the heap array of least frequent node in the Huffman tree */
++
++
++/* ===========================================================================
++ * Remove the smallest element from the heap and recreate the heap with
++ * one less element. Updates heap and heap_len.
++ */
++#define pqremove(s, tree, top) \
++{\
++    top = s->heap[SMALLEST]; \
++    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
++    pqdownheap(s, tree, SMALLEST); \
++}
++
++/* ===========================================================================
++ * Compares to subtrees, using the tree depth as tie breaker when
++ * the subtrees have equal frequency. This minimizes the worst case length.
++ */
++#define smaller(tree, n, m, depth) \
++   (tree[n].Freq < tree[m].Freq || \
++   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
++
++/* ===========================================================================
++ * Restore the heap property by moving down the tree starting at node k,
++ * exchanging a node with the smallest of its two sons if necessary, stopping
++ * when the heap property is re-established (each father smaller than its
++ * two sons).
++ */
++local void pqdownheap(s, tree, k)
++    deflate_state *s;
++    ct_data *tree;  /* the tree to restore */
++    int k;               /* node to move down */
++{
++    int v = s->heap[k];
++    int j = k << 1;  /* left son of k */
++    while (j <= s->heap_len) {
++        /* Set j to the smallest of the two sons: */
++        if (j < s->heap_len &&
++            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
++            j++;
++        }
++        /* Exit if v is smaller than both sons */
++        if (smaller(tree, v, s->heap[j], s->depth)) break;
++
++        /* Exchange v with the smallest son */
++        s->heap[k] = s->heap[j];  k = j;
++
++        /* And continue down the tree, setting j to the left son of k */
++        j <<= 1;
++    }
++    s->heap[k] = v;
++}
++
++/* ===========================================================================
++ * Compute the optimal bit lengths for a tree and update the total bit length
++ * for the current block.
++ * IN assertion: the fields freq and dad are set, heap[heap_max] and
++ *    above are the tree nodes sorted by increasing frequency.
++ * OUT assertions: the field len is set to the optimal bit length, the
++ *     array bl_count contains the frequencies for each bit length.
++ *     The length opt_len is updated; static_len is also updated if stree is
++ *     not null.
++ */
++local void gen_bitlen(s, desc)
++    deflate_state *s;
++    tree_desc *desc;    /* the tree descriptor */
++{
++    ct_data *tree        = desc->dyn_tree;
++    int max_code         = desc->max_code;
++    const ct_data *stree = desc->stat_desc->static_tree;
++    const intf *extra    = desc->stat_desc->extra_bits;
++    int base             = desc->stat_desc->extra_base;
++    int max_length       = desc->stat_desc->max_length;
++    int h;              /* heap index */
++    int n, m;           /* iterate over the tree elements */
++    int bits;           /* bit length */
++    int xbits;          /* extra bits */
++    ush f;              /* frequency */
++    int overflow = 0;   /* number of elements with bit length too large */
++
++    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
++
++    /* In a first pass, compute the optimal bit lengths (which may
++     * overflow in the case of the bit length tree).
++     */
++    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
++
++    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
++        n = s->heap[h];
++        bits = tree[tree[n].Dad].Len + 1;
++        if (bits > max_length) bits = max_length, overflow++;
++        tree[n].Len = (ush)bits;
++        /* We overwrite tree[n].Dad which is no longer needed */
++
++        if (n > max_code) continue; /* not a leaf node */
++
++        s->bl_count[bits]++;
++        xbits = 0;
++        if (n >= base) xbits = extra[n-base];
++        f = tree[n].Freq;
++        s->opt_len += (ulg)f * (bits + xbits);
++        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
++    }
++    if (overflow == 0) return;
++
++    Trace((stderr,"\nbit length overflow\n"));
++    /* This happens for example on obj2 and pic of the Calgary corpus */
++
++    /* Find the first bit length which could increase: */
++    do {
++        bits = max_length-1;
++        while (s->bl_count[bits] == 0) bits--;
++        s->bl_count[bits]--;      /* move one leaf down the tree */
++        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
++        s->bl_count[max_length]--;
++        /* The brother of the overflow item also moves one step up,
++         * but this does not affect bl_count[max_length]
++         */
++        overflow -= 2;
++    } while (overflow > 0);
++
++    /* Now recompute all bit lengths, scanning in increasing frequency.
++     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
++     * lengths instead of fixing only the wrong ones. This idea is taken
++     * from 'ar' written by Haruhiko Okumura.)
++     */
++    for (bits = max_length; bits != 0; bits--) {
++        n = s->bl_count[bits];
++        while (n != 0) {
++            m = s->heap[--h];
++            if (m > max_code) continue;
++            if (tree[m].Len != (unsigned) bits) {
++                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
++                s->opt_len += ((long)bits - (long)tree[m].Len)
++                              *(long)tree[m].Freq;
++                tree[m].Len = (ush)bits;
++            }
++            n--;
++        }
++    }
++}
++
++/* ===========================================================================
++ * Generate the codes for a given tree and bit counts (which need not be
++ * optimal).
++ * IN assertion: the array bl_count contains the bit length statistics for
++ * the given tree and the field len is set for all tree elements.
++ * OUT assertion: the field code is set for all tree elements of non
++ *     zero code length.
++ */
++local void gen_codes (tree, max_code, bl_count)
++    ct_data *tree;             /* the tree to decorate */
++    int max_code;              /* largest code with non zero frequency */
++    ushf *bl_count;            /* number of codes at each bit length */
++{
++    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
++    ush code = 0;              /* running code value */
++    int bits;                  /* bit index */
++    int n;                     /* code index */
++
++    /* The distribution counts are first used to generate the code values
++     * without bit reversal.
++     */
++    for (bits = 1; bits <= MAX_BITS; bits++) {
++        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
++    }
++    /* Check that the bit counts in bl_count are consistent. The last code
++     * must be all ones.
++     */
++    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
++            "inconsistent bit counts");
++    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
++
++    for (n = 0;  n <= max_code; n++) {
++        int len = tree[n].Len;
++        if (len == 0) continue;
++        /* Now reverse the bits */
++        tree[n].Code = bi_reverse(next_code[len]++, len);
++
++        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
++             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
++    }
++}
++
++/* ===========================================================================
++ * Construct one Huffman tree and assigns the code bit strings and lengths.
++ * Update the total bit length for the current block.
++ * IN assertion: the field freq is set for all tree elements.
++ * OUT assertions: the fields len and code are set to the optimal bit length
++ *     and corresponding code. The length opt_len is updated; static_len is
++ *     also updated if stree is not null. The field max_code is set.
++ */
++local void build_tree(s, desc)
++    deflate_state *s;
++    tree_desc *desc; /* the tree descriptor */
++{
++    ct_data *tree         = desc->dyn_tree;
++    const ct_data *stree  = desc->stat_desc->static_tree;
++    int elems             = desc->stat_desc->elems;
++    int n, m;          /* iterate over heap elements */
++    int max_code = -1; /* largest code with non zero frequency */
++    int node;          /* new node being created */
++
++    /* Construct the initial heap, with least frequent element in
++     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
++     * heap[0] is not used.
++     */
++    s->heap_len = 0, s->heap_max = HEAP_SIZE;
++
++    for (n = 0; n < elems; n++) {
++        if (tree[n].Freq != 0) {
++            s->heap[++(s->heap_len)] = max_code = n;
++            s->depth[n] = 0;
++        } else {
++            tree[n].Len = 0;
++        }
++    }
++
++    /* The pkzip format requires that at least one distance code exists,
++     * and that at least one bit should be sent even if there is only one
++     * possible code. So to avoid special checks later on we force at least
++     * two codes of non zero frequency.
++     */
++    while (s->heap_len < 2) {
++        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
++        tree[node].Freq = 1;
++        s->depth[node] = 0;
++        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
++        /* node is 0 or 1 so it does not have extra bits */
++    }
++    desc->max_code = max_code;
++
++    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
++     * establish sub-heaps of increasing lengths:
++     */
++    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
++
++    /* Construct the Huffman tree by repeatedly combining the least two
++     * frequent nodes.
++     */
++    node = elems;              /* next internal node of the tree */
++    do {
++        pqremove(s, tree, n);  /* n = node of least frequency */
++        m = s->heap[SMALLEST]; /* m = node of next least frequency */
++
++        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
++        s->heap[--(s->heap_max)] = m;
++
++        /* Create a new node father of n and m */
++        tree[node].Freq = tree[n].Freq + tree[m].Freq;
++        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
++        tree[n].Dad = tree[m].Dad = (ush)node;
++#ifdef DUMP_BL_TREE
++        if (tree == s->bl_tree) {
++            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
++                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
++        }
++#endif
++        /* and insert the new node in the heap */
++        s->heap[SMALLEST] = node++;
++        pqdownheap(s, tree, SMALLEST);
++
++    } while (s->heap_len >= 2);
++
++    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
++
++    /* At this point, the fields freq and dad are set. We can now
++     * generate the bit lengths.
++     */
++    gen_bitlen(s, (tree_desc *)desc);
++
++    /* The field len is now set, we can generate the bit codes */
++    gen_codes ((ct_data *)tree, max_code, s->bl_count);
++}
++
++/* ===========================================================================
++ * Scan a literal or distance tree to determine the frequencies of the codes
++ * in the bit length tree.
++ */
++local void scan_tree (s, tree, max_code)
++    deflate_state *s;
++    ct_data *tree;   /* the tree to be scanned */
++    int max_code;    /* and its largest code of non zero frequency */
++{
++    int n;                     /* iterates over all tree elements */
++    int prevlen = -1;          /* last emitted length */
++    int curlen;                /* length of current code */
++    int nextlen = tree[0].Len; /* length of next code */
++    int count = 0;             /* repeat count of the current code */
++    int max_count = 7;         /* max repeat count */
++    int min_count = 4;         /* min repeat count */
++
++    if (nextlen == 0) max_count = 138, min_count = 3;
++    tree[max_code+1].Len = (ush)0xffff; /* guard */
++
++    for (n = 0; n <= max_code; n++) {
++        curlen = nextlen; nextlen = tree[n+1].Len;
++        if (++count < max_count && curlen == nextlen) {
++            continue;
++        } else if (count < min_count) {
++            s->bl_tree[curlen].Freq += count;
++        } else if (curlen != 0) {
++            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
++            s->bl_tree[REP_3_6].Freq++;
++        } else if (count <= 10) {
++            s->bl_tree[REPZ_3_10].Freq++;
++        } else {
++            s->bl_tree[REPZ_11_138].Freq++;
++        }
++        count = 0; prevlen = curlen;
++        if (nextlen == 0) {
++            max_count = 138, min_count = 3;
++        } else if (curlen == nextlen) {
++            max_count = 6, min_count = 3;
++        } else {
++            max_count = 7, min_count = 4;
++        }
++    }
++}
++
++/* ===========================================================================
++ * Send a literal or distance tree in compressed form, using the codes in
++ * bl_tree.
++ */
++local void send_tree (s, tree, max_code)
++    deflate_state *s;
++    ct_data *tree; /* the tree to be scanned */
++    int max_code;       /* and its largest code of non zero frequency */
++{
++    int n;                     /* iterates over all tree elements */
++    int prevlen = -1;          /* last emitted length */
++    int curlen;                /* length of current code */
++    int nextlen = tree[0].Len; /* length of next code */
++    int count = 0;             /* repeat count of the current code */
++    int max_count = 7;         /* max repeat count */
++    int min_count = 4;         /* min repeat count */
++
++    /* tree[max_code+1].Len = -1; */  /* guard already set */
++    if (nextlen == 0) max_count = 138, min_count = 3;
++
++    for (n = 0; n <= max_code; n++) {
++        curlen = nextlen; nextlen = tree[n+1].Len;
++        if (++count < max_count && curlen == nextlen) {
++            continue;
++        } else if (count < min_count) {
++            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
++
++        } else if (curlen != 0) {
++            if (curlen != prevlen) {
++                send_code(s, curlen, s->bl_tree); count--;
++            }
++            Assert(count >= 3 && count <= 6, " 3_6?");
++            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
++
++        } else if (count <= 10) {
++            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
++
++        } else {
++            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
++        }
++        count = 0; prevlen = curlen;
++        if (nextlen == 0) {
++            max_count = 138, min_count = 3;
++        } else if (curlen == nextlen) {
++            max_count = 6, min_count = 3;
++        } else {
++            max_count = 7, min_count = 4;
++        }
++    }
++}
++
++/* ===========================================================================
++ * Construct the Huffman tree for the bit lengths and return the index in
++ * bl_order of the last bit length code to send.
++ */
++local int build_bl_tree(s)
++    deflate_state *s;
++{
++    int max_blindex;  /* index of last bit length code of non zero freq */
++
++    /* Determine the bit length frequencies for literal and distance trees */
++    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
++    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
++
++    /* Build the bit length tree: */
++    build_tree(s, (tree_desc *)(&(s->bl_desc)));
++    /* opt_len now includes the length of the tree representations, except
++     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
++     */
++
++    /* Determine the number of bit length codes to send. The pkzip format
++     * requires that at least 4 bit length codes be sent. (appnote.txt says
++     * 3 but the actual value used is 4.)
++     */
++    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
++        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
++    }
++    /* Update opt_len to include the bit length tree and counts */
++    s->opt_len += 3*(max_blindex+1) + 5+5+4;
++    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
++            s->opt_len, s->static_len));
++
++    return max_blindex;
++}
++
++/* ===========================================================================
++ * Send the header for a block using dynamic Huffman trees: the counts, the
++ * lengths of the bit length codes, the literal tree and the distance tree.
++ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
++ */
++local void send_all_trees(s, lcodes, dcodes, blcodes)
++    deflate_state *s;
++    int lcodes, dcodes, blcodes; /* number of codes for each tree */
++{
++    int rank;                    /* index in bl_order */
++
++    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
++    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
++            "too many codes");
++    Tracev((stderr, "\nbl counts: "));
++    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
++    send_bits(s, dcodes-1,   5);
++    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
++    for (rank = 0; rank < blcodes; rank++) {
++        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
++        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
++    }
++    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
++
++    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
++    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
++
++    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
++    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
++}
++
++/* ===========================================================================
++ * Send a stored block
++ */
++void _tr_stored_block(s, buf, stored_len, eof)
++    deflate_state *s;
++    charf *buf;       /* input block */
++    ulg stored_len;   /* length of input block */
++    int eof;          /* true if this is the last block for a file */
++{
++    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
++#ifdef DEBUG
++    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
++    s->compressed_len += (stored_len + 4) << 3;
++#endif
++    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
++}
++
++/* ===========================================================================
++ * Send one empty static block to give enough lookahead for inflate.
++ * This takes 10 bits, of which 7 may remain in the bit buffer.
++ * The current inflate code requires 9 bits of lookahead. If the
++ * last two codes for the previous block (real code plus EOB) were coded
++ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
++ * the last real code. In this case we send two empty static blocks instead
++ * of one. (There are no problems if the previous block is stored or fixed.)
++ * To simplify the code, we assume the worst case of last real code encoded
++ * on one bit only.
++ */
++void _tr_align(s)
++    deflate_state *s;
++{
++    send_bits(s, STATIC_TREES<<1, 3);
++    send_code(s, END_BLOCK, static_ltree);
++#ifdef DEBUG
++    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
++#endif
++    bi_flush(s);
++    /* Of the 10 bits for the empty block, we have already sent
++     * (10 - bi_valid) bits. The lookahead for the last real code (before
++     * the EOB of the previous block) was thus at least one plus the length
++     * of the EOB plus what we have just sent of the empty static block.
++     */
++    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
++        send_bits(s, STATIC_TREES<<1, 3);
++        send_code(s, END_BLOCK, static_ltree);
++#ifdef DEBUG
++        s->compressed_len += 10L;
++#endif
++        bi_flush(s);
++    }
++    s->last_eob_len = 7;
++}
++
++/* ===========================================================================
++ * Determine the best encoding for the current block: dynamic trees, static
++ * trees or store, and output the encoded block to the zip file.
++ */
++void _tr_flush_block(s, buf, stored_len, eof)
++    deflate_state *s;
++    charf *buf;       /* input block, or NULL if too old */
++    ulg stored_len;   /* length of input block */
++    int eof;          /* true if this is the last block for a file */
++{
++    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
++    int max_blindex = 0;  /* index of last bit length code of non zero freq */
++
++    /* Build the Huffman trees unless a stored block is forced */
++    if (s->level > 0) {
++
++       /* Check if the file is ascii or binary */
++      if (s->data_type == Z_UNKNOWN) set_data_type(s);
++
++      /* Construct the literal and distance trees */
++      build_tree(s, (tree_desc *)(&(s->l_desc)));
++      Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
++              s->static_len));
++
++      build_tree(s, (tree_desc *)(&(s->d_desc)));
++      Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
++              s->static_len));
++      /* At this point, opt_len and static_len are the total bit lengths of
++       * the compressed block data, excluding the tree representations.
++       */
++
++      /* Build the bit length tree for the above two trees, and get the index
++       * in bl_order of the last bit length code to send.
++       */
++      max_blindex = build_bl_tree(s);
++
++      /* Determine the best encoding. Compute first the block length in bytes*/
++      opt_lenb = (s->opt_len+3+7)>>3;
++      static_lenb = (s->static_len+3+7)>>3;
++
++      Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
++              opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
++              s->last_lit));
++
++      if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
++
++    } else {
++        Assert(buf != (char*)0, "lost buf");
++      opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
++    }
++
++#ifdef FORCE_STORED
++    if (buf != (char*)0) { /* force stored block */
++#else
++    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
++                       /* 4: two words for the lengths */
++#endif
++        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
++         * Otherwise we can't have processed more than WSIZE input bytes since
++         * the last block flush, because compression would have been
++         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
++         * transform a block into a stored block.
++         */
++        _tr_stored_block(s, buf, stored_len, eof);
++
++#ifdef FORCE_STATIC
++    } else if (static_lenb >= 0) { /* force static trees */
++#else
++    } else if (static_lenb == opt_lenb) {
++#endif
++        send_bits(s, (STATIC_TREES<<1)+eof, 3);
++        compress_block(s, static_ltree, static_dtree);
++#ifdef DEBUG
++        s->compressed_len += 3 + s->static_len;
++#endif
++    } else {
++        send_bits(s, (DYN_TREES<<1)+eof, 3);
++        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
++                       max_blindex+1);
++        compress_block(s, s->dyn_ltree, s->dyn_dtree);
++#ifdef DEBUG
++        s->compressed_len += 3 + s->opt_len;
++#endif
++    }
++    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
++    /* The above check is made mod 2^32, for files larger than 512 MB
++     * and uLong implemented on 32 bits.
++     */
++    init_block(s);
++
++    if (eof) {
++        bi_windup(s);
++#ifdef DEBUG
++        s->compressed_len += 7;  /* align on byte boundary */
++#endif
++    }
++    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
++           s->compressed_len-7*eof));
++}
++
++/* ===========================================================================
++ * Save the match info and tally the frequency counts. Return true if
++ * the current block must be flushed.
++ */
++int _tr_tally (s, dist, lc)
++    deflate_state *s;
++    unsigned dist;  /* distance of matched string */
++    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
++{
++    s->d_buf[s->last_lit] = (ush)dist;
++    s->l_buf[s->last_lit++] = (uch)lc;
++    if (dist == 0) {
++        /* lc is the unmatched char */
++        s->dyn_ltree[lc].Freq++;
++    } else {
++        s->matches++;
++        /* Here, lc is the match length - MIN_MATCH */
++        dist--;             /* dist = match distance - 1 */
++        Assert((ush)dist < (ush)MAX_DIST(s) &&
++               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
++               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
++
++        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
++        s->dyn_dtree[d_code(dist)].Freq++;
++    }
++
++#ifdef TRUNCATE_BLOCK
++    /* Try to guess if it is profitable to stop the current block here */
++    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
++        /* Compute an upper bound for the compressed length */
++        ulg out_length = (ulg)s->last_lit*8L;
++        ulg in_length = (ulg)((long)s->strstart - s->block_start);
++        int dcode;
++        for (dcode = 0; dcode < D_CODES; dcode++) {
++            out_length += (ulg)s->dyn_dtree[dcode].Freq *
++                (5L+extra_dbits[dcode]);
++        }
++        out_length >>= 3;
++        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
++               s->last_lit, in_length, out_length,
++               100L - out_length*100L/in_length));
++        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
++    }
++#endif
++    return (s->last_lit == s->lit_bufsize-1);
++    /* We avoid equality with lit_bufsize because of wraparound at 64K
++     * on 16 bit machines and because stored blocks are restricted to
++     * 64K-1 bytes.
++     */
++}
++
++/* ===========================================================================
++ * Send the block data compressed using the given Huffman trees
++ */
++local void compress_block(s, ltree, dtree)
++    deflate_state *s;
++    const ct_data *ltree; /* literal tree */
++    const ct_data *dtree; /* distance tree */
++{
++    unsigned dist;      /* distance of matched string */
++    int lc;             /* match length or unmatched char (if dist == 0) */
++    unsigned lx = 0;    /* running index in l_buf */
++    unsigned code;      /* the code to send */
++    int extra;          /* number of extra bits to send */
++
++    if (s->last_lit != 0) do {
++        dist = s->d_buf[lx];
++        lc = s->l_buf[lx++];
++        if (dist == 0) {
++            send_code(s, lc, ltree); /* send a literal byte */
++            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
++        } else {
++            /* Here, lc is the match length - MIN_MATCH */
++            code = _length_code[lc];
++            send_code(s, code+LITERALS+1, ltree); /* send the length code */
++            extra = extra_lbits[code];
++            if (extra != 0) {
++                lc -= base_length[code];
++                send_bits(s, lc, extra);       /* send the extra length bits */
++            }
++            dist--; /* dist is now the match distance - 1 */
++            code = d_code(dist);
++            Assert (code < D_CODES, "bad d_code");
++
++            send_code(s, code, dtree);       /* send the distance code */
++            extra = extra_dbits[code];
++            if (extra != 0) {
++                dist -= base_dist[code];
++                send_bits(s, dist, extra);   /* send the extra distance bits */
++            }
++        } /* literal or match pair ? */
++
++        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
++        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
++
++    } while (lx < s->last_lit);
++
++    send_code(s, END_BLOCK, ltree);
++    s->last_eob_len = ltree[END_BLOCK].Len;
++}
++
++/* ===========================================================================
++ * Set the data type to ASCII or BINARY, using a crude approximation:
++ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
++ * IN assertion: the fields freq of dyn_ltree are set and the total of all
++ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
++ */
++local void set_data_type(s)
++    deflate_state *s;
++{
++    int n = 0;
++    unsigned ascii_freq = 0;
++    unsigned bin_freq = 0;
++    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
++    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
++    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
++    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
++}
++
++/* ===========================================================================
++ * Reverse the first len bits of a code, using straightforward code (a faster
++ * method would use a table)
++ * IN assertion: 1 <= len <= 15
++ */
++local unsigned bi_reverse(code, len)
++    unsigned code; /* the value to invert */
++    int len;       /* its bit length */
++{
++    register unsigned res = 0;
++    do {
++        res |= code & 1;
++        code >>= 1, res <<= 1;
++    } while (--len > 0);
++    return res >> 1;
++}
++
++/* ===========================================================================
++ * Flush the bit buffer, keeping at most 7 bits in it.
++ */
++local void bi_flush(s)
++    deflate_state *s;
++{
++    if (s->bi_valid == 16) {
++        put_short(s, s->bi_buf);
++        s->bi_buf = 0;
++        s->bi_valid = 0;
++    } else if (s->bi_valid >= 8) {
++        put_byte(s, (Byte)s->bi_buf);
++        s->bi_buf >>= 8;
++        s->bi_valid -= 8;
++    }
++}
++
++/* ===========================================================================
++ * Flush the bit buffer and align the output on a byte boundary
++ */
++local void bi_windup(s)
++    deflate_state *s;
++{
++    if (s->bi_valid > 8) {
++        put_short(s, s->bi_buf);
++    } else if (s->bi_valid > 0) {
++        put_byte(s, (Byte)s->bi_buf);
++    }
++    s->bi_buf = 0;
++    s->bi_valid = 0;
++#ifdef DEBUG
++    s->bits_sent = (s->bits_sent+7) & ~7;
++#endif
++}
++
++/* ===========================================================================
++ * Copy a stored block, storing first the length and its
++ * one's complement if requested.
++ */
++local void copy_block(s, buf, len, header)
++    deflate_state *s;
++    charf    *buf;    /* the input data */
++    unsigned len;     /* its length */
++    int      header;  /* true if block header must be written */
++{
++    bi_windup(s);        /* align on byte boundary */
++    s->last_eob_len = 8; /* enough lookahead for inflate */
++
++    if (header) {
++        put_short(s, (ush)len);   
++        put_short(s, (ush)~len);
++#ifdef DEBUG
++        s->bits_sent += 2*16;
++#endif
++    }
++#ifdef DEBUG
++    s->bits_sent += (ulg)len<<3;
++#endif
++    while (len--) {
++        put_byte(s, *buf++);
++    }
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/trees.h     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,128 @@
++/* header created automatically with -DGEN_TREES_H */
++
++local const ct_data static_ltree[L_CODES+2] = {
++{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
++{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
++{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
++{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
++{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
++{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
++{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
++{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
++{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
++{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
++{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
++{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
++{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
++{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
++{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
++{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
++{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
++{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
++{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
++{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
++{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
++{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
++{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
++{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
++{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
++{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
++{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
++{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
++{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
++{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
++{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
++{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
++{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
++{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
++{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
++{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
++{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
++{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
++{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
++{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
++{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
++{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
++{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
++{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
++{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
++{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
++{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
++{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
++{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
++{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
++{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
++{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
++{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
++{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
++{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
++{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
++{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
++{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
++};
++
++local const ct_data static_dtree[D_CODES] = {
++{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
++{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
++{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
++{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
++{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
++{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
++};
++
++const uch _dist_code[DIST_CODE_LEN] = {
++ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
++ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
++10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
++11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
++12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
++13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
++13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
++14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
++14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
++14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
++15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
++15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
++15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
++18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
++23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
++24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
++26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
++26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
++27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
++27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
++28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
++28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
++28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
++29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
++};
++
++const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
++ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
++13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
++17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
++19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
++21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
++22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
++23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
++24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
++25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
++25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
++26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
++26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
++27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
++};
++
++local const int base_length[LENGTH_CODES] = {
++0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
++64, 80, 96, 112, 128, 160, 192, 224, 0
++};
++
++local const int base_dist[D_CODES] = {
++    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
++   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
++ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
++};
++
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ultoa.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,66 @@
++/*
++ * convert unsigned long to ASCII
++ * Copyright (C) 1998, 1999  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: ultoa.c,v 1.10 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - ultoa - convert unsigned long to decimal ASCII
++ */
++size_t                                /* length required for full conversion */
++ultoa(n, base, dst, dstlen)
++unsigned long n;
++int base;
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      char buf[3*sizeof(unsigned long) + 1];
++      char *bufend = buf + sizeof(buf);
++      size_t len;
++      char *p;
++      static char hex[] = "0123456789abcdef";
++
++      p = bufend;
++      *--p = '\0';
++      if (base == 10) {
++              do {
++                      *--p = n%10 + '0';
++                      n /= 10;
++              } while (n != 0);
++      } else if (base == 16) {
++              do {
++                      *--p = hex[n&0xf];
++                      n >>= 4;
++              } while (n != 0);
++              *--p = 'x';
++              *--p = '0';
++      } else if (base == 8) {
++              do {
++                      *--p = (n&07) + '0';
++                      n >>= 3;
++              } while (n != 0);
++              *--p = '0';
++      } else
++              *--p = '?';
++
++      len = bufend - p;
++
++      if (dstlen > 0) {
++              if (len > dstlen)
++                      *(p + dstlen - 1) = '\0';
++              strcpy(dst, p);
++      }
++      return len;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/ultot.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,82 @@
++/*
++ * convert unsigned long to text
++ * Copyright (C) 2000  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: ultot.c,v 1.5 2004/07/10 07:48:37 mcr Exp $
++ */
++#include "openswan.h"
++
++/*
++ - ultot - convert unsigned long to text
++ */
++size_t                                /* length required for full conversion */
++ultot(n, base, dst, dstlen)
++unsigned long n;
++int base;
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      char buf[3*sizeof(unsigned long) + 1];
++      char *bufend = buf + sizeof(buf);
++      size_t len;
++      char *p;
++      static char hex[] = "0123456789abcdef";
++#     define  HEX32   (32/4)
++
++      p = bufend;
++      *--p = '\0';
++      switch (base) {
++      case 10:
++      case 'd':
++              do {
++                      *--p = n%10 + '0';
++                      n /= 10;
++              } while (n != 0);
++              break;
++      case 16:
++      case 17:
++      case 'x':
++              do {
++                      *--p = hex[n&0xf];
++                      n >>= 4;
++              } while (n != 0);
++              if (base == 17)
++                      while (bufend - p < HEX32 + 1)
++                              *--p = '0';
++              if (base == 'x') {
++                      *--p = 'x';
++                      *--p = '0';
++              }
++              break;
++      case 8:
++      case 'o':
++              do {
++                      *--p = (n&07) + '0';
++                      n >>= 3;
++              } while (n != 0);
++              if (base == 'o')
++                      *--p = '0';
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      len = bufend - p;
++      if (dstlen > 0) {
++              if (len > dstlen)
++                      *(p + dstlen - 1) = '\0';
++              strcpy(dst, p);
++      }
++      return len;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/version.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,44 @@
++/*
++ * return IPsec version information
++ * Copyright (C) 2001  Henry Spencer.
++ * 
++ * This library is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Library General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
++ * 
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
++ * License for more details.
++ *
++ * RCSID $Id: version.in.c,v 1.2 2004/04/14 05:09:46 ken Exp $
++ */
++
++#ifdef __KERNEL__
++#include <linux/netdevice.h>
++#endif
++
++#include "openswan.h"
++
++#define       V       "2.6.16dr2"             /* substituted in by Makefile */
++static const char openswan_number[] = V;
++static const char openswan_string[] = "Openswan " V;
++
++/*
++ - ipsec_version_code - return IPsec version number/code, as string
++ */
++const char *
++ipsec_version_code()
++{
++      return openswan_number;
++}
++
++/*
++ - ipsec_version_string - return full version string
++ */
++const char *
++ipsec_version_string()
++{
++      return openswan_string;
++}
+--- /dev/null   Tue Mar 11 13:02:56 2003
++++ linux/net/ipsec/zutil.c     Mon Feb  9 13:51:03 2004
+@@ -0,0 +1,227 @@
++/* zutil.c -- target dependent utility functions for the compression library
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* @(#) $Id: zutil.c,v 1.5 2004/07/10 07:48:40 mcr Exp $ */
++
++#include <zlib/zutil.h>
++
++#define MY_ZCALLOC
++
++struct internal_state      {int dummy;}; /* for buggy compilers */
++
++#ifndef STDC
++extern void exit OF((int));
++#endif
++
++const char *z_errmsg[10] = {
++"need dictionary",     /* Z_NEED_DICT       2  */
++"stream end",          /* Z_STREAM_END      1  */
++"",                    /* Z_OK              0  */
++"file error",          /* Z_ERRNO         (-1) */
++"stream error",        /* Z_STREAM_ERROR  (-2) */
++"data error",          /* Z_DATA_ERROR    (-3) */
++"insufficient memory", /* Z_MEM_ERROR     (-4) */
++"buffer error",        /* Z_BUF_ERROR     (-5) */
++"incompatible version",/* Z_VERSION_ERROR (-6) */
++""};
++
++
++const char * ZEXPORT zlibVersion()
++{
++    return ZLIB_VERSION;
++}
++
++#ifdef DEBUG
++
++#  ifndef verbose
++#    define verbose 0
++#  endif
++int z_verbose = verbose;
++
++void z_error (m)
++    char *m;
++{
++    fprintf(stderr, "%s\n", m);
++    exit(1);
++}
++#endif
++
++/* exported to allow conversion of error code to string for compress() and
++ * uncompress()
++ */
++const char * ZEXPORT zError(err)
++    int err;
++{
++    return ERR_MSG(err);
++}
++
++
++#ifndef HAVE_MEMCPY
++
++void zmemcpy(dest, source, len)
++    Bytef* dest;
++    const Bytef* source;
++    uInt  len;
++{
++    if (len == 0) return;
++    do {
++        *dest++ = *source++; /* ??? to be unrolled */
++    } while (--len != 0);
++}
++
++int zmemcmp(s1, s2, len)
++    const Bytef* s1;
++    const Bytef* s2;
++    uInt  len;
++{
++    uInt j;
++
++    for (j = 0; j < len; j++) {
++        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
++    }
++    return 0;
++}
++
++void zmemzero(dest, len)
++    Bytef* dest;
++    uInt  len;
++{
++    if (len == 0) return;
++    do {
++        *dest++ = 0;  /* ??? to be unrolled */
++    } while (--len != 0);
++}
++#endif
++
++#ifdef __TURBOC__
++#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
++/* Small and medium model in Turbo C are for now limited to near allocation
++ * with reduced MAX_WBITS and MAX_MEM_LEVEL
++ */
++#  define MY_ZCALLOC
++
++/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
++ * and farmalloc(64K) returns a pointer with an offset of 8, so we
++ * must fix the pointer. Warning: the pointer must be put back to its
++ * original form in order to free it, use zcfree().
++ */
++
++#define MAX_PTR 10
++/* 10*64K = 640K */
++
++local int next_ptr = 0;
++
++typedef struct ptr_table_s {
++    voidpf org_ptr;
++    voidpf new_ptr;
++} ptr_table;
++
++local ptr_table table[MAX_PTR];
++/* This table is used to remember the original form of pointers
++ * to large buffers (64K). Such pointers are normalized with a zero offset.
++ * Since MSDOS is not a preemptive multitasking OS, this table is not
++ * protected from concurrent access. This hack doesn't work anyway on
++ * a protected system like OS/2. Use Microsoft C instead.
++ */
++
++voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
++{
++    voidpf buf = opaque; /* just to make some compilers happy */
++    ulg bsize = (ulg)items*size;
++
++    /* If we allocate less than 65520 bytes, we assume that farmalloc
++     * will return a usable pointer which doesn't have to be normalized.
++     */
++    if (bsize < 65520L) {
++        buf = farmalloc(bsize);
++        if (*(ush*)&buf != 0) return buf;
++    } else {
++        buf = farmalloc(bsize + 16L);
++    }
++    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
++    table[next_ptr].org_ptr = buf;
++
++    /* Normalize the pointer to seg:0 */
++    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
++    *(ush*)&buf = 0;
++    table[next_ptr++].new_ptr = buf;
++    return buf;
++}
++
++void  zcfree (voidpf opaque, voidpf ptr)
++{
++    int n;
++    if (*(ush*)&ptr != 0) { /* object < 64K */
++        farfree(ptr);
++        return;
++    }
++    /* Find the original pointer */
++    for (n = 0; n < next_ptr; n++) {
++        if (ptr != table[n].new_ptr) continue;
++
++        farfree(table[n].org_ptr);
++        while (++n < next_ptr) {
++            table[n-1] = table[n];
++        }
++        next_ptr--;
++        return;
++    }
++    ptr = opaque; /* just to make some compilers happy */
++    Assert(0, "zcfree: ptr not found");
++}
++#endif
++#endif /* __TURBOC__ */
++
++
++#if defined(M_I86) && !defined(__32BIT__)
++/* Microsoft C in 16-bit mode */
++
++#  define MY_ZCALLOC
++
++#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
++#  define _halloc  halloc
++#  define _hfree   hfree
++#endif
++
++voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
++{
++    if (opaque) opaque = 0; /* to make compiler happy */
++    return _halloc((long)items, size);
++}
++
++void  zcfree (voidpf opaque, voidpf ptr)
++{
++    if (opaque) opaque = 0; /* to make compiler happy */
++    _hfree(ptr);
++}
++
++#endif /* MSC */
++
++
++#ifndef MY_ZCALLOC /* Any system without a special alloc function */
++
++#ifndef STDC
++extern voidp  calloc OF((uInt items, uInt size));
++extern void   free   OF((voidpf ptr));
++#endif
++
++voidpf zcalloc (opaque, items, size)
++    voidpf opaque;
++    unsigned items;
++    unsigned size;
++{
++    if (opaque) items += size - size; /* make compiler happy */
++    return (voidpf)calloc(items, size);
++}
++
++void  zcfree (opaque, ptr)
++    voidpf opaque;
++    voidpf ptr;
++{
++    free(ptr);
++    if (opaque) return; /* make compiler happy */
++}
++
++#endif /* MY_ZCALLOC */
+--- swan26/net/ipv4/af_inet.c.orig     Wed Jun 16 01:18:58 2004
++++ swan26/net/ipv4/af_inet.c  Fri Aug 13 23:09:27 2004
+@@ -1169,6 +1169,18 @@
+ #if defined(CONFIG_IP_MROUTE)
+       ip_mr_init();
+ #endif
++
++#if defined(CONFIG_KLIPS)
++      {
++               extern int ipsec_klips_init(void);
++              /*
++               *  Initialise AF_INET ESP and AH protocol support including 
++               *  e-routing and SA tables
++               */
++              ipsec_klips_init();
++      }
++#endif /* CONFIG_IPSEC */
++
+       /*
+        *      Initialise per-cpu ipv4 mibs
+        */ 
+--- /dev/null   Fri May 10 13:59:54 2002
++++ linux/net/ipsec/Makefile.ver  Sun Jul 28 22:10:40 2002
+@@ -0,0 +1 @@
++IPSECVERSION='2.6.16dr2'