]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- FreeS/WAN patch
authorJacek Konieczny <jajcus@pld-linux.org>
Tue, 25 Apr 2000 15:34:34 +0000 (15:34 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    linux-2.2.14-freeswan-1.3.patch -> 1.1

linux-2.2.14-freeswan-1.3.patch [new file with mode: 0644]

diff --git a/linux-2.2.14-freeswan-1.3.patch b/linux-2.2.14-freeswan-1.3.patch
new file mode 100644 (file)
index 0000000..3f88d1e
--- /dev/null
@@ -0,0 +1,29960 @@
+
+ This patch is manualy made after patching fresh kernel with freswan distribution
+
+diff -durN linux-2.2.14.orig/Documentation/Configure.help linux-2.2.14/Documentation/Configure.help
+--- linux-2.2.14.orig/Documentation/Configure.help     Tue Jan  4 19:12:10 2000
++++ linux-2.2.14/Documentation/Configure.help  Mon Apr 24 13:10:59 2000
+@@ -3531,6 +3531,88 @@
+   This is a backward compatibility option, choose Y for now.
+   This option will be removed soon.
++IP Security Protocol (IPSEC) (EXPERIMENTAL)
++CONFIG_IPSEC
++  This unit is experimental code.
++  Pick 'y' for static linking, 'm' for module support or 'n' for none.
++  This option adds support for network layer packet encryption and/or
++  authentication with participating hosts.  The standards start with:
++  RFCs 2411, 2407 and 2401.  Others are mentioned where they refer to
++  specific features below.  There are more pending which can be found
++  at:  ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipsec-*.
++  A description of each document can also be found at: 
++  http://ietf.org/ids.by.wg/ipsec.html.
++  Their charter can be found at: 
++  http://www.ietf.org/html.charters/ipsec-charter.html
++  Snapshots and releases of the current work can be found at: 
++  http://www.freeswan.org/
++
++IPSEC: IP-in-IP encapsulation
++CONFIG_IPSEC_IPIP
++  This option provides support for tunnel mode IPSEC.  It is recommended
++  to enable this.
++
++IPSEC: PF_KEYv2 kernel/user interface
++CONFIG_IPSEC_PFKEYv2
++  This option provides support for RFC2367 defined PF_KEYv2 sockets
++  to the kernel for sending keying information down from and reporting the
++  expiry of SAs up to the keying daemons.  This was done previously by
++  netlink device writes, and expiry was not previously possible.  Expiry
++  has not yet been implemented, but is coming soon.
++  At this time, netlink and PF_KEYv2 methods can be
++  used side-by side, so you can compile the kernel with this turned on
++  and then turn it off before compiling user-space programs and it will
++  not interfere.  If it is turned on while compiling user-space programs,
++  it must be turned on for compiling the kernel for it to work.  After
++  changing this setting, a clean make must be done for which ever part
++  you would like to see the changes take effect as libraries must be
++  re-compiled cleanly.  This is new code that may still some rough edges
++  but seems to be relatively stable.  This option will eventually go away
++  as it will become the standard interface to the kernel and netlink
++  support will go away.
++
++IPSEC: Enable ICMP PMTU messages
++CONFIG_IPSEC_ICMP
++  Say 'N' if hosts behind the security gateway get confused by the
++  combination of ICMP Path MTU Discovery messages (RFC1191) and
++  successful, albeit inefficient transport of packets.  This will
++  prevent the ICMP Path MTU Discovery packets from being sent.  Say
++  'N' for robustness, 'Y' for efficiency.  If some of your hosts break
++  behind this Security Gateway, you may need to say 'N' and/or try to
++  fix the hosts.
++
++IPSEC: Authentication Header
++CONFIG_IPSEC_AH
++  This option provides support for the IPSEC Authentication Header
++  (IP protocol 51) which provides packet layer sender and content
++  authentication.  It is recommended to enable this.  RFC2402
++
++HMAC-MD5 algorithm
++CONFIG_IPSEC_AUTH_HMAC_MD5
++  Provides support for authentication using the HMAC MD5
++  algorithm with 96 bits of hash used as the authenticator.  RFC2403
++
++HMAC-SHA1 algorithm
++CONFIG_IPSEC_AUTH_HMAC_SHA1
++  Provides support for Authentication Header using the HMAC SHA1
++  algorithm with 96 bits of hash used as the authenticator.  RFC2404
++
++IPSEC: Encapsulating Security Payload
++CONFIG_IPSEC_ESP
++  This option provides support for the IPSEC Encapsulation Security
++  Payload (IP protocol 50) which provides packet layer content
++  hiding.  It is recommended to enable this.  RFC2406
++
++3DES algorithm
++CONFIG_IPSEC_ENC_3DES
++  Provides support for Encapsulation Security Payload protocol, using
++  the triple DES encryption algorithm.  RFC2451
++
++IPSEC Debugging Option
++DEBUG_IPSEC
++  Enables IPSEC kernel debugging.  It is further controlled by the
++  user space utility 'klipsdebug'.
++
+ SCSI support?
+ CONFIG_SCSI
+   If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or
+diff -durN linux-2.2.14.orig/arch/i386/defconfig linux-2.2.14/arch/i386/defconfig
+--- linux-2.2.14.orig/arch/i386/defconfig      Thu Aug 26 02:29:46 1999
++++ linux-2.2.14/arch/i386/defconfig   Mon Apr 24 13:11:00 2000
+@@ -357,3 +357,82 @@
+ # Kernel hacking
+ #
+ # CONFIG_MAGIC_SYSRQ is not set
++#
++# RCSID $Id$
++#
++
++#
++# FreeS/WAN 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
++#
++# This must be on to talk to klips until PF_KEYv2 works.
++CONFIG_NETLINK=y
++# This must be set for 2.2.x support.
++CONFIG_NETLINK_DEV=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_IPSEC=y
++
++# To do tunnel mode IPSec, this must be enabled.
++CONFIG_IPSEC_IPIP=y
++
++# To use PF_KEYv2 (RFC2367) for sending down keying information rather
++# than netlink.  Netlink will eventually go away.
++CONFIG_IPSEC_PFKEYv2=y
++
++# To go for robustness, disable this.  To go for efficiency, enable.
++CONFIG_IPSEC_ICMP=y
++
++# To enable authentication, say 'y'.   (Highly recommended)
++CONFIG_IPSEC_AH=y
++
++# Authentication algorithm(s):
++CONFIG_IPSEC_AUTH_HMAC_MD5=y
++CONFIG_IPSEC_AUTH_HMAC_SHA1=y
++
++# To enable encryption, say 'y'.   (Highly recommended)
++CONFIG_IPSEC_ESP=y
++
++# Encryption algorithm(s):
++CONFIG_IPSEC_ENC_3DES=y
++
++# Disable insecure encryption algorithm(s):
++CONFIG_IPSEC_INSECURE=n
++CONFIG_IPSEC_ENC_DES=n
++CONFIG_IPSEC_ENC_NULL=n
++
++# To enable userspace-switchable KLIPS debugging, say 'y'.
++DEBUG_IPSEC=y
++
++#
++# $Log$
++# Revision 1.10  2000/01/11 03:09:42  rgb
++# Added a default of 'y' to PF_KEYv2 keying I/F.
++#
++# Revision 1.9  1999/05/08 21:23:12  rgb
++# Added support for 2.2.x kernels.
++#
++# Revision 1.8  1999/04/06 04:54:25  rgb
++# Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++# patch shell fixes.
++#
++#
+diff -durN linux-2.2.14.orig/include/linux/netlink.h linux-2.2.14/include/linux/netlink.h
+--- linux-2.2.14.orig/include/linux/netlink.h  Fri Aug 28 04:33:08 1998
++++ linux-2.2.14/include/linux/netlink.h       Mon Apr 24 13:10:59 2000
+@@ -6,6 +6,7 @@
+ #define NETLINK_USERSOCK      2       /* Reserved for user mode socket protocols      */
+ #define NETLINK_FIREWALL      3       /* Firewalling hook                             */
+ #define NETLINK_ARPD          8
++#define NETLINK_IPSEC         10      /* IPSEC */
+ #define NETLINK_ROUTE6                11      /* af_inet6 route comm channel */
+ #define NETLINK_IP6_FW                13
+ #define NETLINK_TAPBASE               16      /* 16 to 31 are ethertap */
+diff -durN linux-2.2.14.orig/net/Config.in linux-2.2.14/net/Config.in
+--- linux-2.2.14.orig/net/Config.in    Tue Jan  4 19:12:26 2000
++++ linux-2.2.14/net/Config.in Mon Apr 24 13:10:59 2000
+@@ -66,4 +66,8 @@
+   endmenu
+   fi
+ fi
++tristate 'IP Security Protocol (FreeS/WAN IPSEC)' CONFIG_IPSEC
++if [ "$CONFIG_IPSEC" != "n" ]; then
++  source net/ipsec/Config.in
++fi
+ endmenu
+diff -durN linux-2.2.14.orig/net/Makefile linux-2.2.14/net/Makefile
+--- linux-2.2.14.orig/net/Makefile     Mon Mar 22 20:18:17 1999
++++ linux-2.2.14/net/Makefile  Mon Apr 24 13:10:59 2000
+@@ -174,6 +174,16 @@
+ endif
+ endif
++ifeq ($(CONFIG_IPSEC),y)
++ALL_SUB_DIRS += ipsec
++SUB_DIRS += ipsec
++else
++  ifeq ($(CONFIG_IPSEC),m)
++  ALL_SUB_DIRS += ipsec
++  MOD_SUB_DIRS += ipsec
++  endif
++endif
++
+ L_TARGET     := network.a
+ L_OBJS             := $(SOCK) protocols.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+diff -durN linux-2.2.14.orig/net/ipsec/Config.in linux-2.2.14/net/ipsec/Config.in
+--- linux-2.2.14.orig/net/ipsec/Config.in      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/Config.in   Tue Dec 14 21:06:36 1999
+@@ -0,0 +1,123 @@
++#
++# IPSEC configuration
++# Copyright (C) 1998, 1999  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$
++
++comment 'IPSec options (FreeS/WAN)'
++
++bool '   IPSEC: IP-in-IP encapsulation' CONFIG_IPSEC_IPIP
++
++bool '   IPSEC: PF_KEYv2 kernel/user interface' CONFIG_IPSEC_PFKEYv2
++
++bool '   IPSEC: Enable ICMP PMTU messages' CONFIG_IPSEC_ICMP
++
++bool '   IPSEC: Authentication Header' CONFIG_IPSEC_AH
++if [ "$CONFIG_IPSEC_AH" = "y" -o "$CONFIG_IPSEC_ESP" = "y" ]; then
++  bool '      HMAC-MD5 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_MD5
++  bool '      HMAC-SHA1 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_SHA1
++fi
++
++bool '   IPSEC: Encapsulating Security Payload' CONFIG_IPSEC_ESP
++if [ "$CONFIG_IPSEC_ESP" = "y" ]; then
++  bool '      3DES encryption algorithm' CONFIG_IPSEC_ENC_3DES
++fi
++
++bool '   IPSEC Debugging Option' DEBUG_IPSEC
++
++#
++# $Log$
++# Revision 1.14  1999/12/14 20:06:36  rgb
++# Removed all references to insecure/experimental ciphers/hashes to avoid
++# tempting those prone to shooting themselves in the feet.
++#
++# Revision 1.13  1999/04/15 15:37:23  rgb
++# Forward check changes from POST1_00 branch.
++#
++# Revision 1.8.2.2  1999/04/02 04:26:14  rgb
++# Backcheck from HEAD, pre1.0.
++#
++# Revision 1.8.2.1  1999/03/30 17:29:17  rgb
++# Add support for pfkey.
++#
++# Revision 1.12  1999/04/11 00:28:55  henry
++# GPL boilerplate
++#
++# Revision 1.11  1999/04/06 04:54:24  rgb
++# Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++# patch shell fixes.
++#
++# Revision 1.10  1999/04/01 09:28:15  rgb
++# Invert meaning of ICMP PMTUD config option and clarify.
++#
++# Revision 1.9  1999/03/31 08:30:30  rgb
++# Add switch to shut off ICMP PMTUD packets.
++#
++# Revision 1.8  1999/02/20 15:47:39  rgb
++# Disable DES configuration.
++#
++# Revision 1.7  1999/02/17 16:48:54  rgb
++# Ditch NET_IPIP dependancy.
++#
++# Revision 1.6  1999/01/26 01:45:03  rgb
++# Change from transform switch to algorithm switch.
++# Add switch for disabling insecure algorithms (DES, NULL).
++# Automatically define CONFIG_NET_IPIP when CONFIG_IPSEC_IPIP is set.
++# Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++#
++# Revision 1.5  1999/01/22 06:15:39  rgb
++# Added algorithm switch code config option.
++#
++# Revision 1.4  1998/11/21 01:35:31  rgb
++# Delete bogus default config idea.
++# Add config file comment.
++#
++# Revision 1.3  1998/11/17 21:08:45  rgb
++# Alert kernel configurating operator of NULL cleartext 'feature' and
++# rearrange transform options to be in a more logical order.
++#
++# Revision 1.2  1998/08/12 00:04:52  rgb
++# Added new xforms to config script.
++#
++# Revision 1.1  1998/06/18 21:27:42  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/06/11 05:52:27  rgb
++# Added notation for experimental and obsolete transforms.
++#
++# Revision 1.3  1998/05/07 20:03:57  rgb
++# Re-aligned text to make it more clear which options depend on which.
++#
++# Revision 1.2  1998/04/21 21:28:55  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:54  henry
++# sources moved up from linux/net/ipsec
++#
++# Revision 1.1.1.1  1998/04/08 05:35:01  henry
++# RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++#
++# Revision 0.5  1997/06/03 04:24:48  ji
++# Added ESP-3DES-MD5-96
++#
++# Revision 0.4  1997/01/15 01:32:59  ji
++# Added new transforms.
++#
++# Revision 0.3  1996/11/20 14:34:28  ji
++# Made debugging defs a configuration option.
++#
++#
+diff -durN linux-2.2.14.orig/net/ipsec/Makefile linux-2.2.14/net/ipsec/Makefile
+--- linux-2.2.14.orig/net/ipsec/Makefile       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/Makefile    Tue Feb  8 22:21:52 2000
+@@ -0,0 +1,207 @@
++# Makefile for KLIPS kernel code
++# Copyright (C) 1998, 1999  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$
++#
++# 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).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++ifndef TOPDIR
++TOPDIR  := /usr/src/linux
++endif
++
++SUB_DIRS := 
++ALL_SUB_DIRS := libfreeswan
++MOD_SUB_DIRS := 
++
++O_TARGET := ipsec.o
++O_OBJS := ipsec_init.o ipsec_xform.o ipsec_netlink.o ipsec_radij.o ipsec_tunnel.o ipsec_rcv.o
++# sysctl_net_ipsec.o 
++
++OX_OBJS := radij.o
++M_OBJS := $(O_TARGET)
++
++override CFLAGS += -Ilibfreeswan
++
++override CFLAGS += -Wall 
++#override CFLAGS += -Wconversion 
++#override CFLAGS += -Wmissing-prototypes 
++override CFLAGS += -Wpointer-arith 
++override CFLAGS += -Wcast-qual 
++#override CFLAGS += -Wmissing-declarations 
++override CFLAGS += -Wstrict-prototypes
++#override CFLAGS += -pedantic
++#override CFLAGS += -O3
++#override CFLAGS += -W
++#override CFLAGS += -Wwrite-strings 
++override CFLAGS += -Wbad-function-cast 
++
++ifeq ($(CONFIG_IPSEC_PFKEYv2),y)
++O_OBJS += pfkey_v2.o pfkey_v2_parser.o
++endif
++
++ifeq ($(CONFIG_IPSEC_ENC_DES),y)
++INCLUDE_DES = y
++endif
++
++ifeq ($(CONFIG_IPSEC_ENC_3DES),y)
++INCLUDE_DES = y
++endif
++
++ifeq ($(CONFIG_IPSEC_AUTH_HMAC_MD5),y)
++O_OBJS += ipsec_md5c.o
++endif
++
++ifeq ($(CONFIG_IPSEC_AUTH_HMAC_SHA1),y)
++O_OBJS += ipsec_sha1.o
++endif
++
++ifeq ($(INCLUDE_DES),y)
++O_OBJS += libdes/libdes.a
++endif
++
++O_OBJS += libfreeswan/libkernel.a
++
++ifeq ($(CONFIG_IPSEC),y)
++SUB_DIRS += libfreeswan
++else
++  ifeq ($(CONFIG_IPSEC),m)
++  override MOD_SUB_DIRS += libfreeswan
++  endif
++endif
++
++include $(TOPDIR)/Rules.make
++
++$(O_OBJS) $(OX_OBJS):  $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
++
++libdes/libdes.a:
++      ( cd libdes && \
++      if test " `arch | sed 's/^i[3456]/x/'`" = " x86" ; \
++      then $(MAKE) CC='$(CC)' CFLAG='$(CFLAGS)' TESTING='' x86-elf ; \
++      else $(MAKE) CC='$(CC)' CFLAG='$(CFLAGS)' libdes.a ; \
++      fi )
++
++libfreeswan/libkernel.a:
++      $(MAKE) -C libfreeswan
++
++clean:
++      -rm -f *.o
++
++tags TAGS: *.c *.h libfreeswan/*.c libfreeswan/*.h
++      find . -name '*.[ch]' |xargs etags
++      find . -name '*.[ch]' |xargs ctags
++
++tar:
++              tar -cvf /dev/f1 .
++
++#
++# $Log$
++# Revision 1.22  2000/01/21 09:44:29  rgb
++# Added compiler switches to be a lot more fussy.
++#
++# Revision 1.21  1999/11/25 23:35:20  rgb
++# Removed quotes to fix Alpha compile issues.
++#
++# Revision 1.20  1999/11/17 15:49:34  rgb
++# Changed all occurrences of ../../../lib in pathnames to libfreeswan,
++# which refers to the /usr/src/linux/net/ipsec/lib directory setup by the
++# klink target in the top-level Makefile; and libdeslite.o to
++# libdes/libdes.a.
++# Added SUB_DIRS := lib definition for the kernel libraries.
++#
++# Revision 1.19  1999/04/27 19:06:47  rgb
++# dd libs and dependancies to tags generation.
++#
++# Revision 1.18  1999/04/16 16:28:12  rgb
++# Minor bugfix to avoid including DES if only AH is used.
++#
++# Revision 1.17  1999/04/15 15:37:23  rgb
++# Forward check changes from POST1_00 branch.
++#
++# Revision 1.14.2.1  1999/03/30 17:29:17  rgb
++# Add support for pfkey.
++#
++# Revision 1.16  1999/04/11 00:28:56  henry
++# GPL boilerplate
++#
++# Revision 1.15  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.14  1999/02/18 16:50:45  henry
++# update for new DES library
++#
++# Revision 1.13  1999/02/12 21:11:45  rgb
++# Prepare for newer LIBDES (patch from P.Onion).
++#
++# Revision 1.12  1999/01/26 02:05:08  rgb
++# Remove references to INET_GET_PROTOCOL.
++# Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++# Change from transform switch to algorithm switch.
++#
++# Revision 1.11  1999/01/22 06:16:09  rgb
++# Added algorithm switch code config option.
++#
++# Revision 1.10  1998/11/08 05:31:21  henry
++# be a little fussier
++#
++# Revision 1.9  1998/11/08 05:29:41  henry
++# revisions for new libdes handling
++#
++# Revision 1.8  1998/08/12 00:05:48  rgb
++# Added new xforms to Makefile (moved des-cbc to des-old).
++#
++# Revision 1.7  1998/07/27 21:48:47  rgb
++# Add libkernel.
++#
++# Revision 1.6  1998/07/14 15:50:47  rgb
++# Add dependancies on linux config files.
++#
++# Revision 1.5  1998/07/09 17:44:06  rgb
++# Added 'clean' and 'tags' targets.
++# Added TOPDIR macro.
++# Change module back from symbol exporting to not.
++#
++# Revision 1.3  1998/06/25 19:25:04  rgb
++# Rearrange to support static linking and objects with exported symbol
++# tables.
++#
++# Revision 1.1  1998/06/18 21:27:42  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/04/15 23:18:43  rgb
++# Unfixed the ../../libdes fix to avoid messing up Henry's script.
++#
++# Revision 1.2  1998/04/14 17:50:47  rgb
++# Fixed to find the new location of libdes.
++#
++# Revision 1.1  1998/04/09 03:05:22  henry
++# sources moved up from linux/net/ipsec
++# modifications to centralize libdes code
++#
++# Revision 1.1.1.1  1998/04/08 05:35:02  henry
++# RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++#
++# Revision 0.5  1997/06/03 04:24:48  ji
++# Added ESP-3DES-MD5-96
++#
++# Revision 0.4  1997/01/15 01:32:59  ji
++# Added new transforms.
++#
++# Revision 0.3  1996/11/20 14:22:53  ji
++# *** empty log message ***
++#
+diff -durN linux-2.2.14.orig/net/ipsec/defconfig linux-2.2.14/net/ipsec/defconfig
+--- linux-2.2.14.orig/net/ipsec/defconfig      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/defconfig   Tue Feb  8 22:21:52 2000
+@@ -0,0 +1,79 @@
++#
++# RCSID $Id$
++#
++
++#
++# FreeS/WAN 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
++#
++# This must be on to talk to klips until PF_KEYv2 works.
++CONFIG_NETLINK=y
++# This must be set for 2.2.x support.
++CONFIG_NETLINK_DEV=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_IPSEC=y
++
++# To do tunnel mode IPSec, this must be enabled.
++CONFIG_IPSEC_IPIP=y
++
++# To use PF_KEYv2 (RFC2367) for sending down keying information rather
++# than netlink.  Netlink will eventually go away.
++CONFIG_IPSEC_PFKEYv2=y
++
++# To go for robustness, disable this.  To go for efficiency, enable.
++CONFIG_IPSEC_ICMP=y
++
++# To enable authentication, say 'y'.   (Highly recommended)
++CONFIG_IPSEC_AH=y
++
++# Authentication algorithm(s):
++CONFIG_IPSEC_AUTH_HMAC_MD5=y
++CONFIG_IPSEC_AUTH_HMAC_SHA1=y
++
++# To enable encryption, say 'y'.   (Highly recommended)
++CONFIG_IPSEC_ESP=y
++
++# Encryption algorithm(s):
++CONFIG_IPSEC_ENC_3DES=y
++
++# Disable insecure encryption algorithm(s):
++CONFIG_IPSEC_INSECURE=n
++CONFIG_IPSEC_ENC_DES=n
++CONFIG_IPSEC_ENC_NULL=n
++
++# To enable userspace-switchable KLIPS debugging, say 'y'.
++DEBUG_IPSEC=y
++
++#
++# $Log$
++# Revision 1.10  2000/01/11 03:09:42  rgb
++# Added a default of 'y' to PF_KEYv2 keying I/F.
++#
++# Revision 1.9  1999/05/08 21:23:12  rgb
++# Added support for 2.2.x kernels.
++#
++# Revision 1.8  1999/04/06 04:54:25  rgb
++# Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++# patch shell fixes.
++#
++#
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_ah.h linux-2.2.14/net/ipsec/ipsec_ah.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_ah.h     Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_ah.h  Tue Feb  8 22:21:52 2000
+@@ -0,0 +1,250 @@
++/*
++ * Authentication Header declarations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include "ipsec_md5h.h"
++#include "ipsec_sha1.h"
++
++#ifndef IPPROTO_AH
++#define IPPROTO_AH 51
++#endif /* IPPROTO_AH */
++
++#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 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_TDB             0x0010
++#define DB_AH_XF              0x0020
++#define DB_AH_INAU            0x0040
++#define DB_AH_REPLAY          0x0100
++
++struct ahmd5_xdata                    /* transform table data */
++{
++      __u16   amx_klen;               /* Key material length */
++      __u16   amx_alen;               /* authenticator length */
++      __u8    amx_key[AHMD5_KMAX];    /* Key material */
++};
++
++struct ahhmacmd5_edata                        /* struct for netlink interface */
++{
++      __u16   ame_klen;               /* Key material length */
++      __u16   ame_alen;               /* authenticator length */
++      __u8    ame_replayp;            /* replay protection ? */
++      __u8    ame_ooowin;             /* out-of-order window size */
++      __u16   ame_x0;                 /* filler */
++      __u8    ame_key[AHMD596_KLEN];  /* Key material */
++};
++      
++struct ahhmacsha1_edata                       /* struct for netlink interface */
++{
++      __u16   ame_klen;               /* Key material length */
++      __u16   ame_alen;               /* authenticator length */
++      __u8    ame_replayp;            /* replay protection ? */
++      __u8    ame_ooowin;             /* out-of-order window size */
++      __u16   ame_x0;                 /* filler */
++      __u8    ame_key[AHSHA196_KLEN]; /* Key material */
++};
++      
++#ifdef __KERNEL__
++
++/* General HMAC algorithm is described in RFC 2104 */
++
++#define               HMAC_IPAD       0x36
++#define               HMAC_OPAD       0x5C
++
++struct ahhmacmd5_xdata                        /* struct for xform table */
++{
++      __u16   amx_alen;               /* length of authenticator, octets  */
++      __u8    amx_replayp;            /* 1 if replay prevention active */
++      __u8    amx_ooowin;             /* out-of-order window size */
++      __u64   amx_bitmap;             /* this&next should be 8 bytes each */
++      __u32   amx_lastseq;            /* or just seq if sending!! */
++      MD5_CTX amx_octx;               /* context after H(K XOR opad) */
++      MD5_CTX amx_ictx;               /* context after H(K XOR ipad) */
++};
++
++struct ahhmacsha1_xdata                       /* struct for xform table */
++{
++      __u16   amx_alen;               /* length of authenticator, octets  */
++      __u8    amx_replayp;            /* 1 if replay prevention active */
++      __u8    amx_ooowin;             /* out-of-order window size */
++      __u64   amx_bitmap;             /* this&next should be 8 bytes each */
++      __u32   amx_lastseq;            /* or just seq if sending!! */
++      SHA1_CTX amx_octx;              /* context after H(K XOR opad) */
++      SHA1_CTX amx_ictx;              /* context after H(K XOR ipad) */
++};
++
++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) */
++};
++
++extern struct inet_protocol ah_protocol;
++
++struct options;
++
++extern int 
++ah_rcv(struct sk_buff *skb,
++       struct device *dev,
++       struct options *opt, 
++       __u32 daddr,
++       unsigned short len,
++       __u32 saddr,
++       int redo,
++       struct inet_protocol *protocol);
++
++struct ah                             /* 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 */
++};
++
++#ifdef DEBUG_IPSEC
++extern int debug_ah;
++#endif /* DEBUG_IPSEC */
++#endif /* __KERNEL__ */
++
++#ifdef DEBUG_IPSEC
++#define AHPRINTKEYS_
++#endif /* DEBUG_IPSEC */
++
++#if 0
++#if defined(__LITTLE_ENDIAN)
++static inline __u64
++htonq(__u64 q)
++{
++      register __u32 u, l;
++      u = q >> 32;
++      l = (__u32)q;
++      
++      return htonl(u) | ((__u64)htonl(l) << 32);
++}
++
++#define ntohq(_x) htonq(_x)
++
++#elif defined(__BIG_ENDIAN)
++
++#define htonq(_x) (_x)
++#define ntohq(_x) htonq(_x)
++
++#else /* __LITTLE_ENDIAN elif __BIG_ENDIAN */
++#error  "Please fix <asm/byteorder.h>"
++#endif /* __LITTLE_ENDIAN elif __BIG_ENDIAN */
++#endif /* 0 */
++
++/*
++ * $Log$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_encap.h linux-2.2.14/net/ipsec/ipsec_encap.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_encap.h  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_encap.h       Tue Feb  8 22:21:53 2000
+@@ -0,0 +1,160 @@
++/*
++ * declarations relevant to encapsulation-like operations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#define SENT_IP4      0x0008          /* data is two struct in_addr */
++
++#define SEN_HDRLEN    (2*sizeof(__u8)+sizeof(__u16))
++
++#define SEN_IP4_SRCOFF        (0)
++#define SEN_IP4_DSTOFF (sizeof (struct in_addr))
++#define SEN_IP4_OPTOFF        (2 * sizeof (struct in_addr))
++
++#define SEN_IP4_LEN   (SENT_HDRLEN + SENT_IP4_OPTOFF)
++
++#ifdef DEBUG_IPSEC
++#define DB_ER_PROCFS  0x0001
++#define DB_SP_PROCFS  0x0001
++#endif
++
++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;
++              } Sip4;
++      } Sen;
++};
++
++#define sen_ip_src    Sen.Sip4.Src
++#define sen_ip_dst    Sen.Sip4.Dst
++
++#ifndef AF_ENCAP
++#define AF_ENCAP 26
++#endif /* AF_ENCAP */
++
++/*
++ * 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.
++ */
++
++#ifdef __KERNEL__
++/*
++ * 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;
++};
++
++/*
++ * 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;
++      struct sa_id er_said;
++      struct sockaddr_encap er_eaddr;
++      struct sockaddr_encap er_emask;
++};
++
++#define er_dst er_said.dst
++#define er_spi er_said.spi
++#define er_proto er_said.proto
++#ifdef DEBUG_IPSEC
++extern int debug_eroute;
++extern int debug_spi;
++#endif
++
++#ifdef NETDEV_23
++#define device net_device
++#define dev_get __dev_get_by_name
++#endif /* NETDEV_23 */
++#endif /* __KERNEL__ */
++
++/*
++ * $Log$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_esp.h linux-2.2.14/net/ipsec/ipsec_esp.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_esp.h    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_esp.h Tue Feb  8 22:21:53 2000
+@@ -0,0 +1,309 @@
++/*
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include "ipsec_md5h.h"
++#include "ipsec_sha1.h"
++
++#ifndef IPPROTO_ESP
++#define IPPROTO_ESP 50
++#endif /* IPPROTO_ESP */
++
++#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 DB_ES_PKTRX   0x0001
++#define DB_ES_PKTRX2  0x0002
++#define DB_ES_TDB     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
++
++struct espdesold_xdata
++{
++      int     edx_ivlen;              /* 4 or 8 */
++      union
++      {
++              __u8    Iv[8];          /* that's enough space */
++              __u32   Ivl[2];
++              __u64   Ivq;
++      }Iu;
++#define edx_iv        Iu.Iv
++#define edx_ivl Iu.Ivl
++#define edx_ivq Iu.Ivq
++      union
++      {
++              __u8 Rk[8];
++              __u32 Eks[16][2];
++      }Xu;
++#define edx_rk        Xu.Rk
++#define edx_eks       Xu.Eks
++};
++
++struct espblkrply_edata
++{
++      __u16   eme_klen;               /* encryption key length */
++      __u16   ame_klen;               /* authentication key length */
++      __u16   eme_flags;              /* see below */
++      __u16   eme_ooowin;             /* out-of-order window size */
++#if 1
++      __u16   eme_ivlen;              /* IV length */
++      __u16   filler;
++      union
++      {
++              __u8    Iv[8];          /* that's enough space */
++              __u32   Ivl[2];
++              __u64   Ivq;
++      }Iu;
++#define eme_iv        Iu.Iv
++#define eme_ivl Iu.Ivl
++#define eme_ivq Iu.Ivq
++#endif
++      __u8    eme_key[EMT_ESPDES_KMAX]; /* the encryption raw key */
++      __u8    ame_key[AH_AMAX];       /* the authentication raw key */
++};
++
++#ifdef __KERNEL__
++struct espdesmd5_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks[16][2];        /* the key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++      MD5_CTX edmx_ictx;              /* derived from HMAC_key */
++      MD5_CTX edmx_octx;              /* ditto */
++};
++
++struct esp3desmd5_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks1[16][2];       /* the first key schedule */
++      __u32   edmx_eks2[16][2];       /* the second key schedule */
++      __u32   edmx_eks3[16][2];       /* the third key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++      MD5_CTX edmx_ictx;              /* derived from HMAC_key */
++      MD5_CTX edmx_octx;              /* ditto */
++};
++
++struct espnullmd5_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      MD5_CTX edmx_ictx;              /* derived from HMAC_key */
++      MD5_CTX edmx_octx;              /* ditto */
++};
++
++struct espdessha1_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks[16][2];        /* the key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++      SHA1_CTX edmx_ictx;             /* derived from HMAC_key */
++      SHA1_CTX edmx_octx;             /* ditto */
++};
++
++struct esp3dessha1_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks1[16][2];       /* the first key schedule */
++      __u32   edmx_eks2[16][2];       /* the second key schedule */
++      __u32   edmx_eks3[16][2];       /* the third key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++      SHA1_CTX edmx_ictx;             /* derived from HMAC_key */
++      SHA1_CTX edmx_octx;             /* ditto */
++};
++
++struct espnullsha1_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      SHA1_CTX edmx_ictx;             /* derived from HMAC_key */
++      SHA1_CTX edmx_octx;             /* ditto */
++};
++
++struct espdes_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks[16][2];        /* the key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++};
++
++struct esp3des_xdata
++{
++      __u8    edmx_flags;             /* same as before */
++      __u8    edmx_ooowin;            /* out-of-order window size */
++      __u16   edmx_ivlen;             /* IV length */
++      __u32   edmx_bitmap;            /* this&next should be 4 bytes each */
++      __u32   edmx_lastseq;           /* in host order */
++      __u32   edmx_eks1[16][2];       /* the first key schedule */
++      __u32   edmx_eks2[16][2];       /* the second key schedule */
++      __u32   edmx_eks3[16][2];       /* the third key schedule */
++      __u32   edmx_iv[2];             /* constant IV */
++};
++
++struct des_eks {
++      __u32   eks[16][2];     /* the key schedule */
++};
++
++extern struct inet_protocol esp_protocol;
++
++struct options;
++
++extern int
++esp_rcv(struct sk_buff *skb,
++      struct device *dev,
++      struct options *opt, 
++      __u32 daddr,
++      unsigned short len,
++      __u32 saddr,
++      int redo,
++      struct inet_protocol *protocol);
++
++struct esp
++{
++      __u32   esp_spi;                /* Security Parameters Index */
++        __u32   esp_rpl;                /* Replay counter */
++      __u8    esp_iv[8];              /* iv */
++};
++
++#ifdef DEBUG_IPSEC
++extern int debug_esp;
++#endif /* DEBUG_IPSEC */
++#endif /* __KERNEL__ */
++
++#ifdef DEBUG_IPSEC
++#define ESPPRINTKEYS_
++#endif /* DEBUG_IPSEC */
++
++/*
++ * $Log$
++ * Revision 1.11  2000/01/10 16:36:20  rgb
++ * Ditch last of EME option flags, including initiator.
++ *
++ * Revision 1.10  1999/12/07 18:16:22  rgb
++ * Fixed comments at end of #endif lines.
++ *
++ * Revision 1.9  1999/04/11 00:28:57  henry
++ * GPL boilerplate
++ *
++ * Revision 1.8  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.7  1999/01/26 02:06:00  rgb
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ *
++ * Revision 1.6  1999/01/22 15:22:05  rgb
++ * Re-enable IV in the espblkrply_edata structure to avoid breaking pluto
++ * until pluto can be fixed properly.
++ *
++ * Revision 1.5  1999/01/22 06:18:16  rgb
++ * Updated macro comments.
++ * Added key schedule types to support algorithm switch code.
++ *
++ * Revision 1.4  1998/08/12 00:07:32  rgb
++ * Added data structures for new xforms: null, {,3}dessha1.
++ *
++ * Revision 1.3  1998/07/14 15:57:01  rgb
++ * Add #ifdef __KERNEL__ to protect kernel-only structures.
++ *
++ * 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:45  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.6  1998/06/05 02:28:08  rgb
++ * Minor comment fix.
++ *
++ * Revision 1.5  1998/05/27 22:34:00  rgb
++ * Changed structures to accomodate key separation.
++ *
++ * 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:20  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:06:00  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.5  1997/06/03 04:24:48  ji
++ * Added ESP-3DES-MD5-96 transform.
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Added definitions for new ESP 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_init.c linux-2.2.14/net/ipsec/ipsec_init.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_init.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_init.c        Tue Feb  8 22:21:53 2000
+@@ -0,0 +1,1112 @@
++/*
++ * Initialization code, and /proc file system interface code.
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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.
++ */
++
++char ipsec_init_c_version[] = "RCSID $Id$";
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <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 */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#endif /* NET_21 */
++#include <asm/checksum.h>
++#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 "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++#include "ipsec_tunnel.h"
++
++#include "version.c"
++
++#include "ipsec_rcv.h"
++#include "ipsec_ah.h"
++#include "ipsec_esp.h"
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#endif
++
++#ifdef DEBUG_IPSEC
++int debug_eroute = 0;
++int debug_spi = 0;
++#endif /* DEBUG_IPSEC */
++
++#ifdef CONFIG_PROC_FS
++unsigned int ipsec_spi_next = 0x1000;
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_eroute_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++      struct wsbuf w = {buffer, length, offset, 0, 0, 0, 0};
++      unsigned long flags; /* save irq state for spinlock */
++
++#ifdef DEBUG_IPSEC
++      if (debug_radij & DB_RJ_DUMPTREES)
++        rj_dumptrees();                       /* XXXXXXXXX */
++#endif /* DEBUG_IPSEC */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_eroute_get_info: buffer=0x%p,"
++                  " *start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      spin_lock_irqsave(&eroute_lock, flags);
++
++      rj_walktree(rnh, ipsec_rj_walker_procprint, &w);
++/*    rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */
++
++      spin_unlock_irqrestore(&eroute_lock, flags);
++
++      *start = buffer + (offset - w.begin);   /* Start of wanted data */
++      w.len -= (offset - w.begin);                    /* Start slop */
++      if (w.len > length)
++              w.len = length;
++      return w.len;
++}
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_spi_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef  PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++      int len = 0;
++      off_t pos = 0, begin = 0;
++      int i;
++      struct tdb *tdbp;
++      char sa[SATOA_BUF];
++      char buf_s[ADDRTOA_BUF], buf_d[ADDRTOA_BUF];
++      size_t sa_len;
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_spi_get_info: buffer=0x%p,"
++                  "*start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++      
++      spin_lock_irqsave(&tdb_lock, flags);
++      
++      for (i = 0; i < TDB_HASHMOD; i++) {
++              for (tdbp = tdbh[i]; tdbp; tdbp = tdbp->tdb_hnext) {
++                      sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                      len += sprintf(buffer + len, "%s ", sa);
++#if 1
++                      len += sprintf(buffer + len, "%s%s%s", TDB_XFORM_NAME(tdbp));
++#else
++                      switch(tdbp->tdb_proto) {
++                      case IPPROTO_AH:
++                              len += sprintf(buffer + len, "AH");
++                              break;
++                      case IPPROTO_ESP:
++                              len += sprintf(buffer + len, "ESP");
++                              break;
++                      case IPPROTO_IPIP:
++                              len += sprintf(buffer + len, "IPIP");
++                              break;
++#if CONFIG_IPCOMP /* don't get your hopes up just yet... */
++                      case IPPROTO_COMP:
++                              len += sprintf(buffer + len, "COMP");
++                              break;
++#endif /* CONFIG_IPCOMP */
++                      default:
++                              len += sprintf(buffer + len, "UNKNOWN_proto");
++                      }
++
++#if 0
++                      len += sprintf(buffer + len, "_proto");
++#endif
++
++                      if(tdbp->tdb_encalg) {
++                              len += sprintf(buffer + len, "_");
++                              switch(tdbp->tdb_encalg) {
++                              case ESP_DES:
++                                      len += sprintf(buffer + len, "DES");
++                                      break;
++                              case ESP_3DES:
++                                      len += sprintf(buffer + len, "3DES");
++                                      break;
++                              case ESP_NULL:
++                                      len += sprintf(buffer + len, "NULL_encr");
++                                      break;
++                              default:
++                                      len += sprintf(buffer + len, "UNKNOWN_encr");
++                              }
++#if 0                         
++                              len += sprintf(buffer + len, "_encrypt");
++#endif
++                      }
++
++                      if(tdbp->tdb_encalg || tdbp->tdb_authalg) {
++                              len += sprintf(buffer + len, "_");
++                              switch(tdbp->tdb_authalg) {
++                              case AH_NONE:
++                                      len += sprintf(buffer + len, "NO_auth");
++                                      break;
++                              case AH_MD5:
++                                      len += sprintf(buffer + len, "HMAC_MD5");
++                                      break;
++                              case AH_SHA:
++                                      len += sprintf(buffer + len, "HMAC_SHA1");
++                                      break;
++                              default:
++                                      len += sprintf(buffer + len, "UNKNOWN_auth");
++                              }
++#if 0                         
++                              len += sprintf(buffer + len, "_auth");
++#endif
++                      }
++#endif
++
++                      len += sprintf(buffer + len, ": dir=%s",
++                                     (tdbp->tdb_flags & EMT_INBOUND) ?
++                                     "in" : "out");
++                      if(tdbp->tdb_iv_bits) {
++                              int j;
++                              len += sprintf(buffer + len, " ivlen=%dbits iv=0x",
++                                             tdbp->tdb_iv_bits);
++                              for(j = 0; j < tdbp->tdb_iv_bits / 8; j++) {
++                                      len += sprintf(buffer + len, "%02x",
++                                                     (__u32)((__u8*)(tdbp->tdb_iv))[j]);
++                              }
++                      }
++                      if(tdbp->tdb_encalg || tdbp->tdb_authalg) {
++                              if(tdbp->tdb_replaywin) {
++                                      len += sprintf(buffer + len, " ooowin=%d",
++                                                     tdbp->tdb_replaywin);
++                              }
++                              if(tdbp->tdb_replaywin_errs) {
++                                      len += sprintf(buffer + len, " ooo_errs=%d",
++                                                     tdbp->tdb_replaywin_errs);
++                              }
++                              if(tdbp->tdb_replaywin_lastseq) {
++                                       len += sprintf(buffer + len, " seq=%d",
++                                                    tdbp->tdb_replaywin_lastseq);
++                              }
++                              if(tdbp->tdb_replaywin_bitmap) {
++                                      len += sprintf(buffer + len, " bit=0x%Lx",
++                                                     tdbp->tdb_replaywin_bitmap);
++                              }
++                              if(tdbp->tdb_replaywin_maxdiff) {
++                                      len += sprintf(buffer + len, " max_seq_diff=%d",
++                                                     tdbp->tdb_replaywin_maxdiff);
++                              }
++                      }
++                      if(tdbp->tdb_flags & ~EMT_INBOUND) {
++                              len += sprintf(buffer + len, " flags=0x%x",
++                                             tdbp->tdb_flags & ~EMT_INBOUND);
++                              len += sprintf(buffer + len, "<");
++                              /* flag printing goes here */
++                              len += sprintf(buffer + len, ">");
++                      }
++                      if(tdbp->tdb_auth_bits) {
++                              len += sprintf(buffer + len, " alen=%d",
++                                             tdbp->tdb_auth_bits);
++                      }
++                      if(tdbp->tdb_key_bits_a) {
++                              len += sprintf(buffer + len, " aklen=%d",
++                                             tdbp->tdb_key_bits_a);
++                      }
++                      if(tdbp->tdb_auth_errs) {
++                              len += sprintf(buffer + len, " auth_errs=%d",
++                                             tdbp->tdb_auth_errs);
++                      }
++                      if(tdbp->tdb_key_bits_e) {
++                              len += sprintf(buffer + len, " eklen=%d",
++                                             tdbp->tdb_key_bits_e);
++                      }
++                      if(tdbp->tdb_encsize_errs) {
++                              len += sprintf(buffer + len, " encr_size_errs=%d",
++                                             tdbp->tdb_encsize_errs);
++                      }
++                      if(tdbp->tdb_encpad_errs) {
++                              len += sprintf(buffer + len, " encr_pad_errs=%d",
++                                             tdbp->tdb_encpad_errs);
++                      }
++                      
++                      if((tdbp->tdb_proto == IPPROTO_IPIP) && tdbp->tdb_addr_s && tdbp->tdb_addr_d) {
++                              addrtoa(((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr,
++                                      0, buf_s, sizeof(buf_s));
++                              addrtoa(((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr,
++                                      0, buf_d, sizeof(buf_d));
++                              len += sprintf(buffer + len, " %s -> %s",
++                                             buf_s, buf_d);
++                      }
++
++#if 0
++                      len += sprintf(buffer + len, " lifetimes(current,soft,hard)=");
++#else
++                      len += sprintf(buffer + len, " life(c,s,h)=");
++#endif
++                      if(tdbp->tdb_lifetime_allocations_c > 1 || 
++                         tdbp->tdb_lifetime_allocations_s ||
++                         tdbp->tdb_lifetime_allocations_h) {
++                              len += sprintf(buffer + len, "alloc(%d,%d,%d)",
++                                             tdbp->tdb_lifetime_allocations_c,
++                                             tdbp->tdb_lifetime_allocations_s,
++                                             tdbp->tdb_lifetime_allocations_h);
++                      }
++                      if(tdbp->tdb_lifetime_bytes_c ||
++                         tdbp->tdb_lifetime_bytes_s ||
++                         tdbp->tdb_lifetime_bytes_h) {
++                              len += sprintf(buffer + len, "bytes(%Ld,%Ld,%Ld)",
++                                             tdbp->tdb_lifetime_bytes_c,
++                                             tdbp->tdb_lifetime_bytes_s,
++                                             tdbp->tdb_lifetime_bytes_h);
++                      }
++                      if(tdbp->tdb_lifetime_addtime_c ||
++                         tdbp->tdb_lifetime_addtime_s ||
++                         tdbp->tdb_lifetime_addtime_h) {
++                              len += sprintf(buffer + len, "add(%Ld,%Ld,%Ld)",
++                                             tdbp->tdb_lifetime_addtime_c,
++                                             tdbp->tdb_lifetime_addtime_s,
++                                             tdbp->tdb_lifetime_addtime_h);
++                      }
++                      if(tdbp->tdb_lifetime_usetime_c ||
++                         tdbp->tdb_lifetime_usetime_s ||
++                         tdbp->tdb_lifetime_usetime_h) {
++                              len += sprintf(buffer + len, "use(%Ld,%Ld,%Ld)",
++                                             tdbp->tdb_lifetime_usetime_c,
++                                             tdbp->tdb_lifetime_usetime_s,
++                                             tdbp->tdb_lifetime_usetime_h);
++                      }
++                      if(tdbp->tdb_lifetime_packets_c ||
++                         tdbp->tdb_lifetime_packets_s ||
++                         tdbp->tdb_lifetime_packets_h) {
++                              len += sprintf(buffer + len, "packets(%Ld,%Ld,%Ld)",
++                                             tdbp->tdb_lifetime_packets_c,
++                                             tdbp->tdb_lifetime_packets_s,
++                                             tdbp->tdb_lifetime_packets_h);
++                      }
++
++                      if(tdbp->tdb_lifetime_usetime_c) {
++                              len += sprintf(buffer + len, " idle=%Ld",
++                                             jiffies / HZ - tdbp->tdb_lifetime_usetime_l);
++                      }
++
++                      len += sprintf(buffer + len, "\n");
++
++                      pos = begin + len;
++                      if(pos < offset) {
++                              len = 0;
++                              begin = pos;
++                      }
++                      if (pos > offset + length) {
++                              goto done_spi_i;
++                      }
++              }
++      }
++
++ done_spi_i:  
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_spigrp_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++      int len = 0;
++      off_t pos = 0, begin = 0;
++      int i;
++      struct tdb *tdbp, *tdbp2;
++      char sa[SATOA_BUF];
++      size_t sa_len;
++
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_spigrp_get_info: buffer=0x%p,"
++                  " *start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++      
++      for (i = 0; i < TDB_HASHMOD; i++) {
++              for (tdbp = tdbh[i]; tdbp; tdbp = tdbp->tdb_hnext)
++              {
++                      if(!tdbp->tdb_inext)
++                      {
++                              tdbp2 = tdbp;
++                              while(tdbp2) {
++                                      sa_len = satoa(tdbp2->tdb_said, 0, sa, SATOA_BUF);
++                                      len += sprintf(buffer + len, "%s ",
++                                                     sa);
++                                      tdbp2 = tdbp2->tdb_onext;
++                              }
++                              len += sprintf(buffer + len, "\n");
++                              pos = begin + len;
++                              if(pos < offset) {
++                                      len = 0;
++                                      begin = pos;
++                              }
++                              if (pos > offset + length) {
++                                      goto done_spigrp_i;
++                              }
++                      }
++              }
++      }
++
++ done_spigrp_i:       
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_tncfg_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++      int len = 0;
++      off_t pos = 0, begin = 0;
++      int i;
++      char name[9];
++      struct device *dev, *privdev;
++      struct ipsecpriv *priv;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_tncfg_get_info: buffer=0x%p,"
++                  "*start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              sprintf(name, "ipsec%d", i);
++              dev = dev_get(name);
++              if(dev) {
++                      priv = (struct ipsecpriv *)(dev->priv);
++                      len += sprintf(buffer + len, "%s",
++                                     dev->name);
++                      if(priv) {
++                              privdev = (struct device *)(priv->dev);
++                              len += sprintf(buffer + len, " -> %s",
++                                             privdev ? privdev->name : "NULL");
++                              len += sprintf(buffer + len, " mtu=%d -> %d",
++                                             /* priv */ dev->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 += sprintf(buffer + len, "\n");
++
++                      pos = begin + len;
++                      if(pos < offset) {
++                              len = 0;
++                              begin = pos;
++                      }
++                      else if (pos > offset + length) {
++                              break;
++                      }
++              }
++      }
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++}
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_spi_get_new(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++
++      int len = 0;
++      off_t pos = 0, begin = 0;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_spi_get_new: buffer=0x%p,"
++                  "*start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      len += sprintf(buffer + len, "0x%x\n", ipsec_spi_next++);
++
++      pos = begin + len;
++      if(pos < offset) {
++              len = 0;
++              begin = pos;
++      }
++      else if (pos > offset + length) {
++              goto done_spinew;
++      }
++      
++ done_spinew: 
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++
++}
++
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_version_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++
++      int len = 0;
++      off_t begin = 0;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_version_get_info: buffer=0x%p,"
++                  "*start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      len += sprintf(buffer + len, "FreeS/WAN version: %s\n", freeswan_version);
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_init CVS version %s\n",
++                  ipsec_init_c_version);
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++
++}
++
++#ifdef DEBUG_IPSEC
++#ifndef PROC_FS_2325
++static
++#endif /* PROC_FS_2325 */
++int
++ipsec_klipsdebug_get_info(char *buffer, char **start, off_t offset, int length
++#ifndef PROC_NO_DUMMY
++, int dummy
++#endif /* !PROC_NO_DUMMY */
++)
++{
++
++      int len = 0;
++      off_t begin = 0;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
++                  "klips_debug:ipsec_klipsdebug_get_info: buffer=0x%p,"
++                  "*start=0x%x, offset=%d, length=%d\n",
++                  buffer, (u_int)*start, (int)offset, length);
++
++      len += sprintf(buffer + len, "debug_tunnel=%08x.\n", debug_tunnel);
++      len += sprintf(buffer + len, "debug_netlink=%08x.\n", debug_netlink);
++      len += sprintf(buffer + len, "debug_xform=%08x.\n", debug_xform);
++      len += sprintf(buffer + len, "debug_eroute=%08x.\n", debug_eroute);
++      len += sprintf(buffer + len, "debug_spi=%08x.\n", debug_spi);
++      len += sprintf(buffer + len, "debug_radij=%08x.\n", debug_radij);
++      len += sprintf(buffer + len, "debug_esp=%08x.\n", debug_esp);
++      len += sprintf(buffer + len, "debug_ah=%08x.\n", debug_ah);
++      len += sprintf(buffer + len, "debug_rcv=%08x.\n", debug_rcv);
++#ifdef CONFIG_IPSEC_PFKEYv2
++      len += sprintf(buffer + len, "debug_pfkey=%08x.\n", debug_pfkey);
++#endif
++
++      *start = buffer + (offset - begin);     /* Start of wanted data */
++      len -= (offset - begin);                        /* Start slop */
++      if (len > length)
++              len = length;
++      return len;
++
++}
++#endif /* DEBUG_IPSEC */
++
++#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_spinew =
++{
++      0,
++      12, "ipsec_spinew",
++      S_IFREG | S_IRUGO, 1, 0, 0, 0,
++      &proc_net_inode_operations,
++      ipsec_spi_get_new,
++      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 DEBUG_IPSEC
++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 /* DEBUG_IPSEC */
++#endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++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={
++      ipsec_device_event,
++      NULL,
++      0
++};
++
++/* void */
++int
++ipsec_init(void)
++{
++      int error = 0;
++
++#ifdef CONFIG_PROC_FS
++#  ifndef PROC_FS_2325
++#    ifdef PROC_FS_21
++      proc_register(proc_net, &ipsec_eroute);
++      proc_register(proc_net, &ipsec_spi);
++      proc_register(proc_net, &ipsec_spigrp);
++      proc_register(proc_net, &ipsec_tncfg);
++      proc_register(proc_net, &ipsec_spinew);
++      proc_register(proc_net, &ipsec_version);
++#      ifdef DEBUG_IPSEC
++      proc_register(proc_net, &ipsec_klipsdebug);
++#      endif /* DEBUG_IPSEC */
++#    else /* PROC_FS_21 */
++      proc_register_dynamic(&proc_net, &ipsec_eroute);
++      proc_register_dynamic(&proc_net, &ipsec_spi);
++      proc_register_dynamic(&proc_net, &ipsec_spigrp);
++      proc_register_dynamic(&proc_net, &ipsec_tncfg);
++      proc_register_dynamic(&proc_net, &ipsec_spinew);
++      proc_register_dynamic(&proc_net, &ipsec_version);
++#      ifdef DEBUG_IPSEC
++      proc_register_dynamic(&proc_net, &ipsec_klipsdebug);
++#      endif /* DEBUG_IPSEC */
++#    endif /* PROC_FS_21 */
++#  else /* !PROC_FS_2325 */
++      proc_net_create ("ipsec_eroute", 0, ipsec_eroute_get_info);
++      proc_net_create ("ipsec_spi", 0, ipsec_spi_get_info);
++      proc_net_create ("ipsec_spigrp", 0, ipsec_spigrp_get_info);
++      proc_net_create ("ipsec_tncfg", 0, ipsec_tncfg_get_info);
++      proc_net_create ("ipsec_spinew", 0, ipsec_spi_get_new);
++      proc_net_create ("ipsec_version", 0, ipsec_version_get_info);
++#    ifdef DEBUG_IPSEC
++      proc_net_create ("ipsec_klipsdebug", 0, ipsec_klipsdebug_get_info);
++#    endif /* DEBUG_IPSEC */
++#  endif /* !PROC_FS_2325 */
++#endif          /* CONFIG_PROC_FS */
++
++      printk("klips_debug:ipsec_init: ipsec module loading. freeswan version: %s\n",
++             freeswan_version);
++      KLIPS_PRINT(1, "klips_debug:ipsec_init: ipsec_init version: %s\n",
++                  ipsec_init_c_version);
++      KLIPS_PRINT(1, "klips_debug:ipsec_init: ipsec_tunnel version: %s\n",
++                  ipsec_tunnel_c_version);
++      KLIPS_PRINT(1, "klips_debug:ipsec_init: ipsec_netlink version: %s\n",
++                  ipsec_netlink_c_version);
++
++#ifndef SPINLOCK
++      /* spin_lock_init( */ tdb_lock.lock = 0; /* ); */
++      /* spin_lock_init( */ eroute_lock.lock = 0; /* ); */
++#endif /* !SPINLOCK */
++
++      error |= ipsec_tdbinit();
++      error |= ipsec_radijinit();
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++      error |= pfkey_init();
++#endif
++
++      (void)netlink_attach(NETLINK_IPSEC, ipsec_callback);
++      register_netdevice_notifier(&ipsec_dev_notifier);
++
++#ifdef CONFIG_IPSEC_ESP
++      inet_add_protocol(&esp_protocol);
++#endif /* CONFIG_IPSEC_ESP */
++
++#ifdef CONFIG_IPSEC_AH
++      inet_add_protocol(&ah_protocol);
++#endif /* CONFIG_IPSEC_AH */
++
++      error |= ipsec_tunnel_init_devices();
++
++      return error;
++}     
++
++
++/* void */
++int
++ipsec_cleanup(void)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: calling ipsec_tunnel_cleanup_devices.\n");
++      error |= ipsec_tunnel_cleanup_devices();
++
++#ifdef CONFIG_IPSEC_AH
++      if ( inet_del_protocol(&ah_protocol) < 0 )
++              printk(KERN_INFO "klips_debug:ipsec_cleanup:ah close: can't remove protocol\n");
++#endif /* CONFIG_IPSEC_AH */
++#ifdef CONFIG_IPSEC_ESP
++      if ( inet_del_protocol(&esp_protocol) < 0 )
++              printk(KERN_INFO "klips_debug:ipsec_cleanup:esp close: can't remove protocol\n");
++#endif /* CONFIG_IPSEC_ESP */
++
++      unregister_netdevice_notifier(&ipsec_dev_notifier);
++
++      netlink_detach(NETLINK_IPSEC);
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: calling ipsec_tdbcleanup.\n");
++      error |= ipsec_tdbcleanup(0);
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: calling ipsec_radijcleanup.\n");
++      error |= ipsec_radijcleanup();
++      
++#ifdef CONFIG_IPSEC_PFKEYv2
++      KLIPS_PRINT(debug_pfkey, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:ipsec_cleanup: calling pfkey_cleanup.\n");
++      error |= pfkey_cleanup();
++#endif
++
++#ifdef CONFIG_PROC_FS
++#  ifndef PROC_FS_2325
++#    ifdef DEBUG_IPSEC
++      if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: cannot unregister /proc/net/ipsec_klipsdebug\n");
++#    endif /* DEBUG_IPSEC */
++      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_spinew.low_ino) != 0)
++              printk("klips_debug:ipsec_cleanup: cannot unregister /proc/net/ipsec_spinew\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");
++#  else /* !PROC_FS_2325 */
++#    ifdef DEBUG_IPSEC
++      proc_net_remove ("ipsec_klipsdebug");
++#    endif /* DEBUG_IPSEC */
++      proc_net_remove ("ipsec_eroute");
++      proc_net_remove ("ipsec_spi");
++      proc_net_remove ("ipsec_spigrp");
++      proc_net_remove ("ipsec_tncfg");
++      proc_net_remove ("ipsec_spinew");
++      proc_net_remove ("ipsec_version");
++#  endif /* !PROC_FS_2325 */
++#endif          /* CONFIG_PROC_FS */
++
++      return error;
++}
++
++#ifdef MODULE
++int
++init_module(void)
++{
++      int error = 0;
++
++      error |= ipsec_init();
++
++      return error;
++}
++
++int
++cleanup_module(void)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
++                  "klips_debug:cleanup_module: calling ipsec_cleanup.\n");
++
++      error |= ipsec_cleanup();
++
++      KLIPS_PRINT(1, "klips_debug:cleanup_module: ipsec module unloaded.\n");
++
++      return error;
++}
++#endif /* MODULE */
++
++/*
++ * $Log$
++ * Revision 1.44  2000/01/22 23:19:20  rgb
++ * Simplified code to use existing macro TDB_XFORM_NAME().
++ *
++ * Revision 1.43  2000/01/21 06:14:04  rgb
++ * Print individual stats only if non-zero.
++ * Removed 'bits' from each keylength for brevity.
++ * Shortened lifetimes legend for brevity.
++ * Changed wording from 'last_used' to the clearer 'idle'.
++ *
++ * Revision 1.42  1999/12/31 14:57:19  rgb
++ * MB fix for new dummy-less proc_get_info in 2.3.35.
++ *
++ * Revision 1.41  1999/11/23 23:04:03  rgb
++ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.40  1999/11/18 18:47:01  rgb
++ * Added dynamic proc registration for 2.3.25+.
++ * Changed all device registrations for static linking to
++ * dynamic to reduce the number and size of patches.
++ * Changed all protocol registrations for static linking to
++ * dynamic to reduce the number and size of patches.
++ *
++ * Revision 1.39  1999/11/18 04:12:07  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ * Added Marc Boucher's 2.3.25 proc patches.
++ * Converted all PROC_FS entries to dynamic to reduce kernel patching.
++ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
++ *
++ * Revision 1.38  1999/11/17 15:53:38  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.37  1999/10/16 04:23:06  rgb
++ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
++ * authentication errors, encryption size errors, encryption padding
++ * errors, and time since last packet.
++ *
++ * Revision 1.36  1999/10/16 00:30:47  rgb
++ * Added SA lifetime counting.
++ *
++ * Revision 1.35  1999/10/15 22:14:00  rgb
++ * Clean out cruft.
++ *
++ * Revision 1.34  1999/10/03 18:46:28  rgb
++ * Spinlock fixes for 2.0.xx and 2.3.xx.
++ *
++ * Revision 1.33  1999/10/01 17:08:10  rgb
++ * Disable spinlock init.
++ *
++ * Revision 1.32  1999/10/01 16:22:24  rgb
++ * Switch from assignment init. to functional init. of spinlocks.
++ *
++ * Revision 1.31  1999/10/01 15:44:52  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.30  1999/10/01 00:00:16  rgb
++ * Added eroute structure locking.
++ * Added tdb structure locking.
++ * Minor formatting changes.
++ * Add call to initialize tdb hash table.
++ *
++ * Revision 1.29  1999/09/23 20:22:40  rgb
++ * Enable, tidy and fix network notifier code.
++ *
++ * Revision 1.28  1999/09/18 11:39:56  rgb
++ * Start to add (disabled) netdevice notifier code.
++ *
++ * Revision 1.27  1999/08/28 08:24:47  rgb
++ * Add compiler directives to compile cleanly without debugging.
++ *
++ * Revision 1.26  1999/08/06 16:03:22  rgb
++ * Correct error messages on failure to unload /proc entries.
++ *
++ * Revision 1.25  1999/08/03 17:07:25  rgb
++ * Report device MTU, not private MTU.
++ *
++ * Revision 1.24  1999/05/25 22:24:37  rgb
++ * /PROC/NET/ipsec* init problem fix.
++ *
++ * Revision 1.23  1999/05/25 02:16:38  rgb
++ * Make modular proc_fs entries dynamic and fix for 2.2.x.
++ *
++ * Revision 1.22  1999/05/09 03:25:35  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.21  1999/05/05 22:02:30  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.20  1999/04/29 15:15:50  rgb
++ * Fix undetected iv_len reporting bug.
++ * Add sanity checking for null pointer to private data space.
++ * Add return values to init and cleanup functions.
++ *
++ * Revision 1.19  1999/04/27 19:24:44  rgb
++ * Added /proc/net/ipsec_klipsdebug support for reading the current debug
++ * settings.
++ * Instrument module load/init/unload.
++ *
++ * Revision 1.18  1999/04/15 15:37:24  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.15.2.3  1999/04/13 20:29:19  rgb
++ * /proc/net/ipsec_* cleanup.
++ *
++ * Revision 1.15.2.2  1999/04/02 04:28:23  rgb
++ * /proc/net/ipsec_* formatting enhancements.
++ *
++ * Revision 1.15.2.1  1999/03/30 17:08:33  rgb
++ * Add pfkey initialisation.
++ *
++ * Revision 1.17  1999/04/11 00:28:57  henry
++ * GPL boilerplate
++ *
++ * Revision 1.16  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.15  1999/02/24 20:15:07  rgb
++ * Update output format.
++ *
++ * Revision 1.14  1999/02/17 16:49:39  rgb
++ * Convert DEBUG_IPSEC to KLIPS_PRINT
++ * Ditch NET_IPIP dependancy.
++ *
++ * Revision 1.13  1999/01/26 02:06:37  rgb
++ * Remove ah/esp switching on include files.
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ * Removed dead code.
++ * Remove references to INET_GET_PROTOCOL.
++ *
++ * Revision 1.12  1999/01/22 06:19:18  rgb
++ * Cruft clean-out.
++ * 64-bit clean-up.
++ * Added algorithm switch code.
++ *
++ * Revision 1.11  1998/12/01 05:54:53  rgb
++ * Cleanup and order debug version output.
++ *
++ * Revision 1.10  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.9  1998/11/10 05:35:13  rgb
++ * Print direction in/out flag from /proc/net/ipsec_spi.
++ *
++ * Revision 1.8  1998/10/27 13:48:10  rgb
++ * Cleaned up /proc/net/ipsec_* filesystem for easy parsing by scripts.
++ * Fixed less(1) truncated output bug.
++ * Code clean-up.
++ *
++ * Revision 1.7  1998/10/22 06:43:16  rgb
++ * Convert to use satoa for printk.
++ *
++ * Revision 1.6  1998/10/19 14:24:35  rgb
++ * Added inclusion of freeswan.h.
++ *
++ * Revision 1.5  1998/10/09 04:43:35  rgb
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ *
++ * Revision 1.4  1998/07/27 21:50:22  rgb
++ * Not necessary to traverse mask tree for /proc/net/ipsec_eroute.
++ *
++ * Revision 1.3  1998/06/25 19:51:20  rgb
++ * Clean up #endif comments.
++ * Shift debugging comment control for procfs to debug_tunnel.
++ * Make proc_dir_entries visible to rest of kernel for static link.
++ * Replace hardwired fileperms with macros.
++ * Use macros for procfs inode numbers.
++ * Rearrange initialisations between ipsec_init and module_init as appropriate
++ * for static loading.
++ *
++ * Revision 1.2  1998/06/23 02:55:43  rgb
++ * Slightly quieted init-time messages.
++ * Re-introduced inet_add_protocol after it mysteriously disappeared...
++ * Check for and warn of absence of IPIP protocol on install of module.
++ * Move tdbcleanup to ipsec_xform.c.
++ *
++ * Revision 1.10  1998/06/18 21:29:04  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
++ * build scripts happier in presence of symbolic links
++ *
++ * Revision 1.9  1998/06/14 23:49:40  rgb
++ * Clarify version reporting on module loading.
++ *
++ * Revision 1.8  1998/06/11 05:54:23  rgb
++ * Added /proc/net/ipsec_version to report freeswan and transform versions.
++ * Added /proc/net/ipsec_spinew to generate new and unique spi's..
++ * Fixed /proc/net/ipsec_tncfg bug.
++ *
++ * Revision 1.7  1998/05/25 20:23:13  rgb
++ * proc_register changed to dynamic registration to avoid arbitrary inode
++ * numbers.
++ *
++ * Implement memory recovery from tdb and eroute tables.
++ *
++ * Revision 1.6  1998/05/21 13:08:58  rgb
++ * Rewrote procinfo subroutines to avoid *bad things* when more that 3k of
++ * information is available for printout.
++ *
++ * Revision 1.5  1998/05/18 21:29:48  rgb
++ * Cleaned up /proc/net/ipsec_* output, including a title line, algorithm
++ * names instead of numbers, standard format for numerical output base,
++ * whitespace for legibility, and the names themselves for consistency.
++ *
++ * Added /proc/net/ipsec_spigrp and /proc/net/ipsec_tncfg.
++ *
++ * Revision 1.4  1998/04/30 15:42:24  rgb
++ * Silencing attach for normal operations with #ifdef IPSEC_DEBUG.
++ *
++ * Revision 1.3  1998/04/21 21:28:58  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:22  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:06:05  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
++ * No changes.
++ *
++ * Revision 0.3  1996/11/20 14:39:04  ji
++ * Fixed problem with node names of /proc/net entries.
++ * Other minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_ipe4.h linux-2.2.14/net/ipsec/ipsec_ipe4.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_ipe4.h   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_ipe4.h        Sun Apr 11 02:28:57 1999
+@@ -0,0 +1,59 @@
++/*
++ * IP-in-IP Header declarations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++/* 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$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_md5c.c linux-2.2.14/net/ipsec/ipsec_md5c.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_md5c.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_md5c.c        Mon Dec 13 14:59:12 1999
+@@ -0,0 +1,430 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++ * 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 "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 MD5Init (context)
++MD5_CTX *context;                                        /* context */
++{
++  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 MD5Update (context, input, inputLen)
++MD5_CTX *context;                                        /* context */
++unsigned char *input;                                /* input block */
++__u32 inputLen;                     /* length of input block */
++{
++  __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 MD5Final (digest, context)
++unsigned char digest[16];                         /* message digest */
++MD5_CTX *context;                                       /* context */
++{
++  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);
++  MD5Update (context, PADDING, padLen);
++
++  /* Append length (before padding) */
++  MD5Update (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
++
++/*
++ * $Log$
++ * Revision 1.4  1999/12/13 13:59:12  rgb
++ * Quick fix to argument size to Update bugs.
++ *
++ * Revision 1.3  1999/05/21 18:09:28  henry
++ * unnecessary <memory.h> include causes trouble in 2.2
++ *
++ * Revision 1.2  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.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:02  rgb
++ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
++ * verified.
++ *
++ * Revision 1.1  1998/04/09 03:06:08  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.3  1996/11/20 14:48:53  ji
++ * Release update only.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_md5h.h linux-2.2.14/net/ipsec/ipsec_md5h.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_md5h.h   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_md5h.h        Mon Dec 13 14:59:13 1999
+@@ -0,0 +1,129 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++ * 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 MD5Init PROTO_LIST ((MD5_CTX *));
++void MD5Update PROTO_LIST
++  ((MD5_CTX *, unsigned char *, __u32));
++void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
++ 
++#endif /* _IPSEC_MD5H_H_ */
++
++/*
++ * $Log$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_netlink.c linux-2.2.14/net/ipsec/ipsec_netlink.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_netlink.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_netlink.c     Tue Feb  8 22:21:53 2000
+@@ -0,0 +1,657 @@
++/*
++ * IPSEC <> netlink interface
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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.
++ */
++
++char ipsec_netlink_c_version[] = "RCSID $Id$";
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <freeswan.h>
++#ifdef SPINLOCK
++#ifdef SPINLOCK_23
++#include <linux/spinlock.h> /* *lock* */
++#else /* 23_SPINLOCK */
++#include <asm/spinlock.h> /* *lock* */
++#endif /* 23_SPINLOCK */
++#endif /* SPINLOCK */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#define ip_chk_addr inet_addr_type
++#define IS_MYADDR RTN_LOCAL
++#endif
++#include <asm/checksum.h>
++#include <net/ip.h>
++#ifdef NETLINK_SOCK
++#include <linux/netlink.h>
++#else
++#include <net/netlink.h>
++#endif
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++
++#include "ipsec_rcv.h"
++#include "ipsec_ah.h"
++#include "ipsec_esp.h"
++
++#ifdef DEBUG_IPSEC
++#include "ipsec_tunnel.h"
++#endif
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#endif
++
++#ifdef DEBUG_IPSEC
++int debug_netlink = 0;
++#endif
++
++#define SENDERR(_x) do { len = -(_x); goto errlab; } while (0)
++
++int 
++#ifdef NETLINK_SOCK
++ipsec_callback(int proto, struct sk_buff *skb)
++#else /* NETLINK_SOCK */
++ipsec_callback(struct sk_buff *skb)
++#endif /* NETLINK_SOCK */
++{
++      /*
++       * this happens when we write to /dev/ipsec (c 36 10)
++       */
++      int len = skb->len;
++      u_char *dat = (u_char *)skb->data;
++      struct encap_msghdr *em = (struct encap_msghdr *)dat;
++      struct tdb *tdbp, *tprev;
++      int i, nspis, error = 0;
++      unsigned long flags; /* save irq state for spinlock */
++#ifdef DEBUG_IPSEC
++      struct eroute *eret;
++      char sa[SATOA_BUF];
++
++
++      satoa(em->em_said, 0, sa, SATOA_BUF);
++
++      if(debug_netlink) {
++              printk("klips_debug:ipsec_callback: skb=0x%p skblen=%ld em_magic=%d em_type=%d\n",
++                     skb, (unsigned long int)skb->len, em->em_magic, em->em_type);
++              switch(em->em_type) {
++              case EMT_SETDEBUG:
++                      printk("klips_debug:ipsec_callback: set ipsec_debug level\n");
++                      break;
++#if 0
++              case EMT_GETDEBUG:
++                      printk("klips_debug:ipsec_callback: get ipsec_debug level\n");
++                      break;
++#endif
++              case EMT_DELEROUTE:
++              case EMT_CLREROUTE:
++              case EMT_CLRSPIS:
++                      break;
++              default:
++                      printk("klips_debug:ipsec_callback: called for SA:%s\n", sa);
++              }
++      }
++#endif        
++      /*      em = (struct encap_msghdr *)dat; */
++      if (em->em_magic != EM_MAGIC) {
++              printk("klips_debug:ipsec_callback: bad magic=%d failed, should be %d\n",
++                     em->em_magic,
++                     EM_MAGIC);
++              SENDERR(EINVAL);
++      }
++      switch (em->em_type) {
++      case EMT_SETDEBUG:
++#ifdef DEBUG_IPSEC
++              if(em->em_db_nl >> (sizeof(em->em_db_nl) * 8 - 1)) {
++                      em->em_db_nl &= ~(1 << (sizeof(em->em_db_nl) * 8 -1));
++                      debug_tunnel  |= em->em_db_tn;
++                      debug_netlink |= em->em_db_nl;
++                      debug_xform   |= em->em_db_xf;
++                      debug_eroute  |= em->em_db_er;
++                      debug_spi     |= em->em_db_sp;
++                      debug_radij   |= em->em_db_rj;
++                      debug_esp     |= em->em_db_es;
++                      debug_ah      |= em->em_db_ah;
++                      debug_rcv     |= em->em_db_rx;
++#ifdef CONFIG_IPSEC_PFKEYv2
++                      debug_pfkey   |= em->em_db_ky;
++#endif
++                      if(debug_netlink)
++                              printk("klips_debug:ipsec_callback: set\n");
++              } else {
++                      if(debug_netlink)
++                              printk("klips_debug:ipsec_callback: unset\n");
++                      debug_tunnel  &= em->em_db_tn;
++                      debug_netlink &= em->em_db_nl;
++                      debug_xform   &= em->em_db_xf;
++                      debug_eroute  &= em->em_db_er;
++                      debug_spi     &= em->em_db_sp;
++                      debug_radij   &= em->em_db_rj;
++                      debug_esp     &= em->em_db_es;
++                      debug_ah      &= em->em_db_ah;
++                      debug_rcv     &= em->em_db_rx;
++#ifdef CONFIG_IPSEC_PFKEYv2
++                      debug_pfkey   &= em->em_db_ky;
++#endif
++              }
++#else
++              printk("klips_debug:ipsec_callback: debugging not enabled\n");
++              SENDERR(EINVAL);
++#endif        
++              break;
++
++#if 0
++      case EMT_GETDEBUG:
++#ifdef DEBUG_IPSEC
++              if(debug_netlink)
++                      printk("klips_debug:ipsec_callback: get\n");
++              em->em_db_tn = debug_tunnel;
++              em->em_db_nl = debug_netlink;
++              em->em_db_xf = debug_xform;
++              em->em_db_er = debug_eroute;
++              em->em_db_sp = debug_spi;
++              em->em_db_rj = debug_radij;
++              em->em_db_es = debug_esp;
++              em->em_db_ah = debug_ah;
++              em->em_db_rx = debug_rcv;
++#else
++              printk("klips_debug:ipsec_callback: debugging not enabled\n");
++              SENDERR(EINVAL);
++#endif        
++              break;
++
++#endif
++      case EMT_SETEROUTE:
++              if ((error = ipsec_makeroute(&(em->em_eaddr), &(em->em_emask), em->em_ersaid)))
++                      SENDERR(-error);
++              break;
++
++      case EMT_RPLACEROUTE:
++              if ((error = ipsec_breakroute(&(em->em_eaddr), &(em->em_emask))) == EINVAL) {
++                              SENDERR(-error);
++              }
++              if ((error = ipsec_makeroute(&(em->em_eaddr), &(em->em_emask), em->em_ersaid)))
++                      SENDERR(-error);
++              break;
++
++      case EMT_DELEROUTE:
++              if ((error = ipsec_breakroute(&(em->em_eaddr), &(em->em_emask))))
++                      SENDERR(-error);
++              break;
++
++      case EMT_CLREROUTE:
++              if ((error = ipsec_cleareroutes()))
++                      SENDERR(-error);
++              break;
++
++#ifdef DEBUG_IPSEC
++      case EMT_TESTROUTE:
++                    
++              printk("klips_debug:ipsec_callback: testroute: trying to locate 0x%08x->0x%08x", (u_int)em->em_eaddr.sen_ip_src.s_addr, (u_int)em->em_eaddr.sen_ip_dst.s_addr);
++
++              eret = ipsec_findroute(&(em->em_eaddr));
++              
++              if (eret == NULL) {
++                      printk(" not found\n");
++              } else {
++                      printk(" via SA: %s\n", sa);
++              }
++              break;
++#endif
++      case EMT_SETSPI:
++              if (em->em_if >= 5)     /* XXX -- why 5? */
++                      SENDERR(ENODEV);
++              
++              tdbp = gettdb(&(em->em_said));
++              if (tdbp == NULL) {
++                      tdbp = (struct tdb *)kmalloc(sizeof (*tdbp), GFP_ATOMIC);
++
++                      if (tdbp == NULL)
++                              SENDERR(ENOBUFS);
++                      
++                      memset((caddr_t)tdbp, 0, sizeof(*tdbp));
++                      
++                      tdbp->tdb_said = em->em_said;
++                      tdbp->tdb_flags = em->em_flags;
++                      
++                      if(ip_chk_addr((unsigned long)em->em_said.dst.s_addr) == IS_MYADDR) {
++                              tdbp->tdb_flags |= EMT_INBOUND;
++                      }
++                      KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
++                                  "klips_debug:ipsec_callback: existing Tunnel Descriptor Block not found (this\n"
++                                  "klips_debug:                is good) for SA: %s, %s-bound, allocating.\n",
++                                  sa, (tdbp->tdb_flags & EMT_INBOUND) ? "in" : "out");
++
++/* XXX                tdbp->tdb_rcvif = &(enc_softc[em->em_if].enc_if);*/
++                      tdbp->tdb_rcvif = NULL;
++              } else {
++                      KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
++                                  "klips_debug:ipsec_callback: EMT_SETSPI found an old Tunnel Descriptor Block\n"
++                                  "klips_debug:                for SA: %s, delete it first.\n", sa);
++                      SENDERR(EEXIST);
++              }
++              
++              if ((error = tdb_init(tdbp, em))) {
++                      KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
++                                  "klips_debug:ipsec_callback: EMT_SETSPI not successful for SA: %s, deleting.\n", sa);
++                      ipsec_tdbwipe(tdbp);
++                      
++                      SENDERR(-error);
++              }
++
++              tdbp->tdb_lifetime_addtime_c = jiffies/HZ;
++              tdbp->tdb_state = 1;
++              if(!tdbp->tdb_lifetime_allocations_c) {
++                      tdbp->tdb_lifetime_allocations_c += 1;
++              }
++
++              puttdb(tdbp);
++              KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
++                          "klips_debug:ipsec_callback: EMT_SETSPI successful for SA: %s\n", sa);
++              break;
++              
++      case EMT_DELSPI:
++              if (em->em_if >= 5)     /* XXX -- why 5? */
++                      SENDERR(ENODEV);
++              
++              spin_lock_irqsave(&tdb_lock, flags);
++              
++              tdbp = gettdb(&(em->em_said));
++              if (tdbp == NULL) {
++                      KLIPS_PRINT(debug_netlink & DB_NL_TDBCB,
++                                  "klips_debug:ipsec_callback: "
++                                  "EMT_DELSPI Tunnel Descriptor Block not found for SA:\n"
++                                  "klips_debug:                %s, could not delete.\n", sa);
++                      spin_unlock_irqrestore(&tdb_lock, flags);
++                      SENDERR(ENXIO);  /* XXX -- wrong error message... */
++              } else {
++                      if((error = deltdbchain(tdbp))) {
++                              spin_unlock_irqrestore(&tdb_lock, flags);
++                              SENDERR(-error);
++                      }
++              }
++              spin_unlock_irqrestore(&tdb_lock, flags);
++
++              break;
++              
++      case EMT_GRPSPIS:
++              nspis = (len - EMT_GRPSPIS_FLEN) / sizeof(em->em_rel[0]);
++              if ((nspis * (sizeof(em->em_rel[0]))) != (len - EMT_GRPSPIS_FLEN)) {
++                      printk("klips_debug:ipsec_callback: EMT_GRPSPI message size incorrect, expected nspis(%d)*%d, got %d.\n",
++                             nspis,
++                             sizeof(em->em_rel[0]),
++                             (len - EMT_GRPSPIS_FLEN));
++                      SENDERR(EINVAL);
++                      break;
++              }
++              
++              spin_lock_irqsave(&tdb_lock, flags);
++
++              for (i = 0; i < nspis; i++) {
++                      KLIPS_PRINT(debug_netlink,
++                                  "klips_debug:ipsec_callback: EMT_GRPSPI for SA(%d)\n"
++                                  "klips_debug:                %s,\n", i, sa);
++                      if ((tdbp = gettdb(&(em->em_rel[i].emr_said))) == NULL) {
++                              KLIPS_PRINT(debug_netlink,
++                                          "klips_debug:ipsec_callback: "
++                                          "EMT_GRPSPI Tunnel Descriptor Block not found for SA:\n"
++                                          "klips_debug:                %s, could not group.\n", sa);
++                              spin_unlock_irqrestore(&tdb_lock, flags);
++                              SENDERR(ENXIO);
++                      } else {
++                              if(tdbp->tdb_inext || tdbp->tdb_onext) {
++                                      KLIPS_PRINT(debug_netlink,
++                                                  "klips_debug:ipsec_callback: "
++                                                  "EMT_GRPSPI Tunnel Descriptor Block already grouped\n"
++                                                  "klips_debug:                for SA: %s, can't regroup.\n", sa);
++                                      spin_unlock_irqrestore(&tdb_lock, flags);
++                                      SENDERR(EBUSY);
++                              }
++                              em->em_rel[i].emr_tdb = tdbp;
++                      }
++              }
++              tprev = em->em_rel[0].emr_tdb;
++              tprev->tdb_inext = NULL;
++              for (i = 1; i < nspis; i++) {
++                      tdbp = em->em_rel[i].emr_tdb;
++                      tprev->tdb_onext = tdbp;
++                      tdbp->tdb_inext = tprev;
++                      tprev = tdbp;
++              }
++              tprev->tdb_onext = NULL;
++
++              spin_unlock_irqrestore(&tdb_lock, flags);
++
++              error = 0;
++              break;
++              
++      case EMT_UNGRPSPIS:
++              if (len != (8 + (sizeof(struct sa_id) + sizeof(struct tdb *)) /* 12 */) ) {
++                      printk("klips_debug:ipsec_callback: "
++                             "EMT_UNGRPSPIS message size incorrect, expected %d, got %d.\n",
++                             8 + (sizeof(struct sa_id) + sizeof(struct tdb *)),
++                                  len);
++                      SENDERR(EINVAL);
++                      break;
++              }
++              
++              spin_lock_irqsave(&tdb_lock, flags);
++
++              if ((tdbp = gettdb(&(em->em_rel[0].emr_said))) == NULL) {
++                      KLIPS_PRINT(debug_netlink,
++                                  "klips_debug:ipsec_callback: "
++                                  "EMT_UGRPSPI Tunnel Descriptor Block not found for SA:\n"
++                                  "klips_debug:                %s, could not ungroup.\n", sa);
++                      spin_unlock_irqrestore(&tdb_lock, flags);
++                      SENDERR(ENXIO);
++              }
++              while(tdbp->tdb_onext) {
++                      tdbp = tdbp->tdb_onext;
++              }
++              while(tdbp->tdb_inext) {
++                      tprev = tdbp;
++                      tdbp = tdbp->tdb_inext;
++                      tprev->tdb_inext = NULL;
++                      tdbp->tdb_onext = NULL;
++              }
++
++              spin_unlock_irqrestore(&tdb_lock, flags);
++
++              break;
++              
++      case EMT_CLRSPIS:
++              KLIPS_PRINT(debug_netlink,
++                          "klips_debug:ipsec_callback: spi clear called.\n");
++              if (em->em_if >= 5)     /* XXX -- why 5? */
++                      SENDERR(ENODEV);
++              ipsec_tdbcleanup(0);
++              break;
++      default:
++              KLIPS_PRINT(debug_netlink,
++                          "klips_debug:ipsec_callback: unknown message type\n");
++              SENDERR(EINVAL);
++      }
++ errlab:
++#ifdef NET_21
++      kfree_skb(skb);
++#else /* NET_21 */
++      kfree_skb(skb, FREE_WRITE);
++#endif /* NET_21 */
++      return len;
++}
++
++/*
++ * $Log$
++ * Revision 1.42  2000/01/21 06:14:27  rgb
++ * Moved debug message for expected output on set or clear.
++ *
++ * Revision 1.41  1999/12/01 22:14:37  rgb
++ * Added debugging message for bad netlink magic.
++ * Initialise tdb_sastate to MATURE (1).
++ * Added UNGRPSPIS bad length debugging message.
++ *
++ * Revision 1.40  1999/11/23 23:06:25  rgb
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.39  1999/11/18 04:09:18  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.38  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.37  1999/10/26 13:58:32  rgb
++ * Put spinlock flags variable declaration outside the debug compiler
++ * directive to enable compilation with debug shut off.
++ *
++ * Revision 1.36  1999/10/16 18:24:22  rgb
++ * Initialize lifetime_addtime_c and lifetime_allocations_c.
++ * Clean-up unused cruft.
++ *
++ * Revision 1.35  1999/10/08 18:37:34  rgb
++ * Fix end-of-line spacing to sate whining PHMs.
++ *
++ * Revision 1.34  1999/10/03 18:49:11  rgb
++ * Spinlock fixes for 2.0.xx and 2.3.xx.
++ *
++ * Revision 1.33  1999/10/01 15:44:53  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.32  1999/10/01 00:00:53  rgb
++ * Fix for proper netlink debugging operation.
++ * Added tdb structure locking.
++ * Minor formatting changes.
++ *
++ * Revision 1.31  1999/05/25 21:21:43  rgb
++ * Fix deltdbchain() error return code checking.
++ *
++ * Revision 1.30  1999/05/09 03:25:36  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.29  1999/05/08 21:23:27  rgb
++ * Simplify satoa() calling.
++ * Fix error return reporting.
++ * Add casting to silence the 2.2.x compile.
++ *
++ * Revision 1.28  1999/05/05 22:02:31  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.27  1999/04/29 15:16:24  rgb
++ * Add pfkey support to debugging.
++ * Change gettdb parameter to a pointer to reduce stack loading and
++ * facilitate
++ * parameter sanity checking.
++ * Add IS_MYADDR support obviating the necessity of doing this in user
++ * space.
++ * Fix undetected bug by moving puttdb in SETSPI until after initialisation
++ * to
++ * prevent tdb usage before it is ready and to save work if it does not
++ * initialise.
++ * Clean up deltdb/wipe code.
++ * Fix undetected bug of returning error as positive value.
++ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
++ *
++ * Revision 1.26  1999/04/16 15:39:35  rgb
++ * Fix already fixed unbalanced #endif.
++ *
++ * Revision 1.25  1999/04/15 15:37:24  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.21.2.1  1999/04/13 20:30:26  rgb
++ * Add experimental 'getdebug'.
++ *
++ * Revision 1.24  1999/04/11 00:28:58  henry
++ * GPL boilerplate
++ *
++ * Revision 1.23  1999/04/07 17:44:21  rgb
++ * Fix ipsec_callback memory leak, skb not freed after use.
++ *
++ * Revision 1.22  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.21  1999/02/17 16:50:11  rgb
++ * Consolidate satoa()s for space and speed efficiency.
++ * Convert DEBUG_IPSEC to KLIPS_PRINT
++ * Clean out unused cruft.
++ *
++ * Revision 1.20  1999/01/28 23:20:49  rgb
++ * Replace hard-coded numbers in macros and code with meaningful values
++ * automatically generated from sizeof() and offsetof() to further the
++ * goal of platform independance.
++ *
++ * Revision 1.19  1999/01/26 02:07:07  rgb
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ * Remove ah/esp switching on include files.
++ * Removed dead code.
++ *
++ * Revision 1.18  1999/01/22 06:20:36  rgb
++ * Cruft clean-out.
++ * 64-bit clean-up.
++ * Added algorithm switch code.
++ *
++ * Revision 1.17  1998/12/02 03:09:39  rgb
++ * Clean up debug printing conditionals to compile with debugging off.
++ *
++ * Revision 1.16  1998/12/01 05:56:57  rgb
++ * Add support for debug printing of version info.
++ * Fail on unknown error for breakroute in replace command.
++ *
++ * Revision 1.15  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.14  1998/11/10 05:36:14  rgb
++ * Clean up debug output.
++ * Add direction to spi setup debug code.
++ * Add support for SA direction flag.
++ *
++ * Revision 1.13  1998/10/31 06:51:56  rgb
++ * Get zeroize to return something useful.
++ * Clean up code to isolate 'spi --add/del' memory leak.
++ * Fixed up comments in #endif directives.
++ *
++ * Revision 1.12  1998/10/27 00:35:02  rgb
++ * Supressed debug output during normal operation.
++ *
++ * Revision 1.11  1998/10/25 02:40:21  rgb
++ * Selective debug printing, depending upon called service.
++ * Institute more precise error return codes from eroute commands.
++ * Fix bug in size of stucture passed in from user space for grpspi command.
++ *
++ * Revision 1.10  1998/10/22 06:44:58  rgb
++ * Convert to use satoa for printk.
++ * Moved break; in 'set debug level code to avoid undetected bug.
++ * Fixed run-on error message to fit 80 columns.
++ *
++ * Revision 1.9  1998/10/19 14:44:28  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.8  1998/10/09 04:29:51  rgb
++ * Added support for '-replace' option to eroute.
++ * Fixed spiungroup bug.
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ *
++ * Revision 1.7  1998/08/12 00:10:06  rgb
++ * Fixed minor error return code syntax.
++ *
++ * Revision 1.6  1998/07/29 20:22:57  rgb
++ * Cosmetic cleanup.
++ *
++ * Revision 1.5  1998/07/27 21:53:11  rgb
++ * Check for proper return code from eroute clear command.
++ * Use appropriate error return codes from kernel.
++ * Add an option to clear the SA table.
++ *
++ * Revision 1.4  1998/07/14 18:02:40  rgb
++ * Add a command to clear the eroute table.
++ * Clean up some error codes.
++ *
++ * Revision 1.3  1998/06/25 19:52:33  rgb
++ * Code cosmetic changes only.
++ *
++ * Revision 1.2  1998/06/23 02:57:58  rgb
++ * Clean up after an error condition in setspi.
++ *
++ * Revision 1.9  1998/06/18 21:29:06  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
++ * build scripts happier in presence of symbolic links
++ *
++ * Revision 1.8  1998/06/08 17:57:15  rgb
++ * Very minor spacing change.
++ *
++ * Revision 1.7  1998/05/18 21:46:45  rgb
++ * Clean up for numerical consistency of output.
++ *
++ * Added debugging switch output.
++ *
++ * SETSPI will refuse to overwrite a previous SA.  This is to make it
++ * consistent with the eroute command.
++ *
++ * spidel now deletes entire chain of spi's.
++ *
++ * spigrp can now ungroup a set of spi's.
++ *
++ * spigrp will not regroup a previously grouped spi.
++ *
++ * Key data is properly cleaned up, ie. zeroed.
++ *
++ * Revision 1.6  1998/05/07 20:36:27  rgb
++ * Fixed case where debugging not enabled that caused ipsec_netlink.c to
++ * not compile.
++ *
++ * Revision 1.5  1998/05/06 03:34:21  rgb
++ * Updated debugging output statements.
++ *
++ * Revision 1.4  1998/04/23 21:03:59  rgb
++ * Completed kernel development for userspace access to klips kernel debugging
++ * switches.
++ * Added detail to the kernel error message when trying to group non-existant
++ * spi's.
++ *
++ * Revision 1.3  1998/04/21 21:29:06  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:23  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:06:08  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
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_netlink.h linux-2.2.14/net/ipsec/ipsec_netlink.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_netlink.h        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_netlink.h     Wed Dec  8 21:31:32 1999
+@@ -0,0 +1,305 @@
++/*
++ * IPSEC <> netlink interface
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include <linux/stddef.h>
++
++#ifndef NETLINK_IPSEC
++#define NETLINK_IPSEC          10      /* IPSEC */ 
++#endif /* !NETLINK_IPSEC */
++
++#define EM_MAXRELSPIS 4               /* at most five chained xforms */
++#define EM_MAGIC      0x5377616e      /* "Swan" */
++
++#define EMT_IFADDR    1       /* set enc if addr */
++#define EMT_SETSPI    2       /* Set SPI properties */
++#define EMT_DELSPI    3       /* Delete an SPI */
++#define EMT_GRPSPIS   4       /* Group SPIs (output order)  */
++#define EMT_SETEROUTE 5       /* set an extended route */
++#define EMT_DELEROUTE 6       /* del an extended route */
++#define EMT_TESTROUTE 7       /* try to find route, print to console */
++#define EMT_SETDEBUG  8       /* set debug level if active */
++#define EMT_UNGRPSPIS 9       /* UnGroup SPIs (output order)  */
++#define EMT_CLREROUTE 10      /* clear the extended route table */
++#define EMT_CLRSPIS   11      /* clear the spi table */
++#define EMT_RPLACEROUTE       12      /* set an extended route */
++#define EMT_GETDEBUG  13      /* get debug level if active */
++
++#ifdef DEBUG_IPSEC
++#define DB_NL_TDBCB   0x0001
++#endif
++
++/* em_flags constants */
++#define EMT_INBOUND   0x01    /* SA direction, 1=inbound */
++
++struct encap_msghdr
++{
++      __u32   em_magic;               /* EM_MAGIC */
++#if 0
++      __u16   em_msglen;              /* message length */
++#endif
++      __u8    em_msglen;              /* message length */
++      __u8    em_flags;               /* message flags */
++      __u8    em_version;             /* for future expansion */
++      __u8    em_type;                /* message type */
++      union
++      {
++              __u8    C;              /* Free-text */
++              
++              struct 
++              {
++                      struct sa_id Said; /* SA ID */
++                      struct sockaddr_encap Eaddr;
++                      struct sockaddr_encap Emask;
++              } Ert;
++
++              struct
++              {
++                      struct in_addr Ia;
++                      __u8    Ifn;
++                      __u8  xxx[3];   /* makes life a lot easier */
++              } Ifa;
++
++              struct
++              {
++                      struct sa_id Said; /* SA ID */
++                      int If;         /* enc i/f for input */
++                      int Alg;        /* Algorithm to use */
++
++                        /* The following union is a surrogate for
++                         * algorithm-specific data.  To insure
++                         * proper alignment, worst-case fields
++                         * should be included.  It would be even
++                         * better to include the types that will
++                         * actually be used, but they may not be
++                         * defined for each use of this header.
++                         * The actual length is expected to be longer
++                         * than is declared here.  References are normally
++                         * made using the em_dat macro, as if it were a
++                         * field name.
++                         */
++                        union { /* Data */
++                                __u8 Dat[1];
++                                __u64 Datq[1];  /* maximal alignment (?) */
++                        } u;
++              } Xfm;
++              
++              struct
++              {
++                      struct sa_id emr_said; /* SA ID */
++                      struct tdb * emr_tdb; /* used internally! */
++                      
++              } Rel[EM_MAXRELSPIS];
++              
++#ifdef DEBUG_IPSEC
++              struct
++              {
++                      int debug_tunnel;
++                      int debug_netlink;
++                      int debug_xform;
++                      int debug_eroute;
++                      int debug_spi;
++                      int debug_radij;
++                      int debug_esp;
++                      int debug_ah;
++                      int debug_rcv;
++#ifdef CONFIG_IPSEC_PFKEYv2
++                      int debug_pfkey;
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++              } Dbg;
++#endif /* DEBUG_IPSEC */
++      } Eu;
++};
++
++#define EM_MINLEN     offsetof(struct encap_msghdr, Eu)
++#define EMT_SETSPI_FLEN       offsetof(struct encap_msghdr, em_dat)
++#define EMT_GRPSPIS_FLEN offsetof(struct encap_msghdr, Eu.Rel)
++#define EMT_SETDEBUG_FLEN (offsetof(struct encap_msghdr, Eu.Dbg + \
++                      sizeof(((struct encap_msghdr*)0)->Eu.Dbg)))
++
++#define em_c  Eu.C
++#define em_eaddr Eu.Ert.Eaddr
++#define em_emask Eu.Ert.Emask
++#define em_ersaid Eu.Ert.Said
++#define em_erdst Eu.Ert.Said.dst
++#define em_erspi Eu.Ert.Said.spi
++#define em_erproto Eu.Ert.Said.proto
++
++#define em_ifa        Eu.Ifa.Ia
++#define em_ifn        Eu.Ifa.Ifn
++
++#define em_said       Eu.Xfm.Said
++#define em_spi        Eu.Xfm.Said.spi
++#define em_dst        Eu.Xfm.Said.dst
++#define em_proto      Eu.Xfm.Said.proto
++#define em_if Eu.Xfm.If
++#define em_alg        Eu.Xfm.Alg
++#define em_dat        Eu.Xfm.u.Dat
++
++#define em_rel        Eu.Rel
++#define emr_dst emr_said.dst
++#define emr_spi emr_said.spi
++#define emr_proto emr_said.proto
++
++#ifdef DEBUG_IPSEC
++#define em_db_tn Eu.Dbg.debug_tunnel
++#define em_db_nl Eu.Dbg.debug_netlink
++#define em_db_xf Eu.Dbg.debug_xform
++#define em_db_er Eu.Dbg.debug_eroute
++#define em_db_sp Eu.Dbg.debug_spi
++#define em_db_rj Eu.Dbg.debug_radij
++#define em_db_es Eu.Dbg.debug_esp
++#define em_db_ah Eu.Dbg.debug_ah
++#define em_db_rx Eu.Dbg.debug_rcv
++#ifdef CONFIG_IPSEC_PFKEYv2
++#define em_db_ky Eu.Dbg.debug_pfkey
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++#endif /* DEBUG_IPSEC */
++
++#ifdef __KERNEL__
++extern char ipsec_netlink_c_version[];
++#ifndef KERNEL_VERSION
++#  include <linux/version.h>
++#endif
++#ifdef NETLINK_SOCK
++extern int ipsec_callback(int proto, struct sk_buff *skb);
++#else /* NETLINK_SOCK */
++extern int ipsec_callback(struct sk_buff *skb);
++#endif /* NETLINK_SOCK */
++extern void ipsec_print_ip(struct iphdr *ip);
++
++#ifdef DEBUG_IPSEC
++      #define KLIPS_PRINT(flag, format, args...) \
++              ((flag) ? printk(KERN_INFO format , ## args) : 0)
++      #define KLIPS_IP_PRINT(flag, ip) \
++              ((flag) ? ipsec_print_ip(ip) : 0)
++#else
++      #define KLIPS_PRINT(flag, format, args...) do ; while(0)
++      #define KLIPS_IP_PRINT(flag, ip) do ; while(0)
++#endif
++
++#ifdef DEBUG_IPSEC
++extern int debug_netlink;
++#endif /* DEBUG_IPSEC */
++#endif /* __KERNEL__ */
++
++/*
++ * $Log$
++ * Revision 1.22  1999/12/08 20:31:32  rgb
++ * Moved IPPROTO_COMP to lib/freeswan.h to simplify userspace includes.
++ *
++ * Revision 1.21  1999/11/18 18:47:41  rgb
++ * Added "#define NETLINK_IPSEC" in case kernel was not compiled with it.
++ *
++ * Revision 1.20  1999/11/18 04:09:18  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.19  1999/08/28 08:27:05  rgb
++ * Add a temporary kludge for 2.0.37-38 to compile even if one patch failed.
++ *
++ * Revision 1.18  1999/08/03 17:09:33  rgb
++ * Tidy up debug output, use KERN_INFO macro in printk's.
++ *
++ * Revision 1.17  1999/05/25 01:45:37  rgb
++ * Fix version macros for 2.0.x as a module.
++ *
++ * Revision 1.16  1999/05/05 22:02:31  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.15  1999/04/29 15:16:55  rgb
++ * Add pfkey support to debugging.
++ *
++ * Revision 1.14  1999/04/15 15:37:24  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.13  1999/04/11 00:28:58  henry
++ * GPL boilerplate
++ *
++ * Revision 1.12  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.11  1999/02/12 21:13:17  rgb
++ * Moved KLIPS_PRINT into a more accessible place.
++ *
++ * Revision 1.10  1999/01/28 23:20:49  rgb
++ * Replace hard-coded numbers in macros and code with meaningful values
++ * automatically generated from sizeof() and offsetof() to further the
++ * goal of platform independance.
++ *
++ * Revision 1.9  1999/01/22 06:21:23  rgb
++ * Added algorithm switch code.
++ * Cruft clean-out.
++ * 64-bit clean-up.
++ *
++ * Revision 1.8  1998/12/01 05:57:42  rgb
++ * Add support for printing debug version info.
++ *
++ * Revision 1.7  1998/11/10 05:37:35  rgb
++ * Add support for SA direction flag.
++ *
++ * Revision 1.6  1998/10/25 02:40:45  rgb
++ * Fix bug in size of stucture passed in from user space for grpspi command.
++ *
++ * Revision 1.5  1998/10/19 14:44:29  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.4  1998/10/09 04:30:11  rgb
++ * Added support for '-replace' option to eroute.
++ *
++ * Revision 1.3  1998/07/27 21:54:22  rgb
++ * Rearrange structures for consistent alignment within a union.
++ * Add an option for clearing SA table.
++ *
++ * Revision 1.2  1998/07/14 18:05:51  rgb
++ * Added #ifdef __KERNEL__ directives to restrict scope of header.
++ *
++ * 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.4  1998/05/18 21:48:24  rgb
++ * Added switch for ungrouping spi's.
++ *
++ * Revision 1.3  1998/04/23 21:01:50  rgb
++ * Added a macro for userspace access to klips kernel debugging switches.
++ *
++ * 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:09  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:39:04  ji
++ * Minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_radij.c linux-2.2.14/net/ipsec/ipsec_radij.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_radij.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_radij.c       Tue Feb  8 22:21:54 2000
+@@ -0,0 +1,498 @@
++/*
++ * Interface between the IPSEC code and the radix (radij) tree code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <freeswan.h>
++#ifdef SPINLOCK
++#ifdef SPINLOCK_23
++#include <linux/spinlock.h> /* *lock* */
++#else /* 23_SPINLOCK */
++#include <asm/spinlock.h> /* *lock* */
++#endif /* 23_SPINLOCK */
++#endif /* SPINLOCK */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#endif
++#include <asm/checksum.h>
++#include <net/ip.h>
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++
++#ifdef DEBUG_IPSEC
++int debug_radij = 0;
++#endif
++
++struct radij_node_head *rnh = 0;
++#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) == 0) /* 16 is bit offset of sen_type */
++              return -1;
++      return 0;
++}
++
++int
++ipsec_radijcleanup(void)
++{
++      int error;
++      unsigned long flags; /* save irq state for spinlock */
++
++      spin_lock_irqsave(&eroute_lock, flags);
++
++      error = radijcleanup();
++
++      spin_unlock_irqrestore(&eroute_lock, flags);
++
++      return error;
++}
++
++int
++ipsec_cleareroutes(void)
++{
++      int error;
++      unsigned long flags; /* save irq state for spinlock */
++
++      spin_lock_irqsave(&eroute_lock, flags);
++
++      error = radijcleartree();
++
++      spin_unlock_irqrestore(&eroute_lock, flags);
++
++      return error;
++}
++
++int
++ipsec_breakroute(struct sockaddr_encap *eaddr, struct sockaddr_encap *emask)
++{
++      struct radij_node *rn;
++      int error;
++      unsigned long flags; /* save irq state for spinlock */
++#ifdef DEBUG_IPSEC
++      char buf1[64], buf2[64];
++      
++      if (debug_eroute) {
++              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));
++              printk("klips_debug:ipsec_breakroute: attempting to delete eroute for %s->%s\n",
++                             buf1, buf2);
++      }
++#endif
++
++      spin_lock_irqsave(&eroute_lock, flags);
++
++      if ((error = rj_delete(eaddr, emask, rnh, &rn)) != 0) {
++              spin_unlock_irqrestore(&eroute_lock, flags);
++              KLIPS_PRINT(debug_eroute, "klips_debug:ipsec_breakroute: node not found, eroute delete failed.\n");
++              return error;
++      }
++
++      spin_unlock_irqrestore(&eroute_lock, flags);
++      
++      if (rn->rj_flags & (RJF_ACTIVE | RJF_ROOT))
++              panic ("ipsec_callback RMT_DELEROUTE root or active node\n");
++      
++      memset((caddr_t)rn, 0, sizeof (struct eroute));
++      kfree_s(rn, sizeof(struct eroute));
++      
++      return 0;
++}
++
++int
++ipsec_makeroute(struct sockaddr_encap *eaddr, struct sockaddr_encap *emask, struct sa_id said)
++{
++      struct eroute *retrt;
++      int error;
++      char sa[SATOA_BUF];
++      size_t sa_len;
++      unsigned long flags; /* save irq state for spinlock */
++#ifdef DEBUG_IPSEC
++      char buf1[64], buf2[64];
++      
++      if (debug_eroute) {
++              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 = satoa(said, 0, sa, SATOA_BUF);
++              printk("klips_debug:ipsec_makeroute: attempting to insert eroute for %s->%s, SA: %s\n",
++                     buf1, buf2, sa);
++      }
++#endif
++
++      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;
++      rd_key((&(retrt->er_rjt))) = &(retrt->er_eaddr);
++      
++      spin_lock_irqsave(&eroute_lock, flags);
++
++      error = rj_addroute(&(retrt->er_eaddr), &(retrt->er_emask), 
++                       rnh, retrt->er_rjt.rd_nodes);
++
++      spin_unlock_irqrestore(&eroute_lock, flags);
++      
++      if(error) {
++              sa_len = satoa(said, 0, sa, SATOA_BUF);
++              printk("klips_debug:ipsec_makeroute: rj_addroute not able to insert eroute for SA:%s\n", sa);
++              kfree(retrt); /* XXX -- should we? */
++              return error;
++      }
++      KLIPS_PRINT(debug_eroute,
++                  "klips_debug:ipsec_makeroute: succeeded, I think...\n");
++      return 0;
++}
++
++struct eroute *
++ipsec_findroute(struct sockaddr_encap *eaddr)
++{
++      struct radij_node *rn;
++#ifdef DEBUG_IPSEC
++      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));
++              printk("klips_debug:ipsec_findroute: %s->%s\n",
++                     buf1, buf2);
++      }
++#endif
++      rn = rj_match((caddr_t)eaddr, rnh);
++      return (struct eroute *)rn;
++}
++              
++#ifdef CONFIG_PROC_FS
++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[64], buf2[64];
++      char sa[SATOA_BUF];
++      size_t sa_len;
++      struct sockaddr_encap *key, *mask;
++      
++      KLIPS_PRINT(debug_radij,
++                  "klips_debug:ipsec_rj_walker_procprint: rn=%p, w0=%p\n",
++                  rn, w0);
++      if (rn == NULL) {
++              return 120;
++      }
++      
++      if (rn->rj_b >= 0) {
++              return 0;
++      }
++      
++      key = rd_key(rd);
++      mask = rd_mask(rd);
++      
++      if ((key == 0) || (mask == 0)) {
++              return 0;
++      }
++      
++      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));
++      sa_len = satoa(ro->er_said, 0, sa, SATOA_BUF);
++      w->len += sprintf(w->buffer + w->len,
++                        "%-18s -> %-18s => %s\n",
++                        buf1, buf2, sa);
++      
++      w->pos = w->begin + w->len;
++      if(w->pos < w->offset) {
++              w->len = 0;
++              w->begin = w->pos;
++      }
++      if (w->pos > w->offset + w->length) {
++              return -ENOBUFS;
++      }
++      return 0;
++}
++#endif          /* CONFIG_PROC_FS */
++
++int
++ipsec_rj_walker_delete(struct radij_node *rn, void *w0)
++{
++      struct rjtentry *rd = (struct rjtentry *)rn;
++      struct radij_node *rn2;
++      int error;
++      struct sockaddr_encap *key, *mask;
++#ifdef DEBUG_IPSEC
++      char buf1[64] = { 0 }, buf2[64] = { 0 };
++#endif
++
++      if (rn == NULL) {
++              return 120;
++      }
++      
++      key = rd_key(rd);
++      mask = rd_mask(rd);
++      
++      if(!key || !mask) {
++              return -1;
++      }
++#ifdef DEBUG_IPSEC
++      if(debug_radij) {
++              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));
++              printk("klips_debug:ipsec_rj_walker_delete: deleting: %s -> %s\n",
++                     buf1, buf2);
++      }
++#endif /* DEBUG_IPSEC */
++
++      if((error = rj_delete(key, mask, rnh, &rn2))) {
++              if(debug_radij) {
++                      printk("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");
++      }
++      memset((caddr_t)rn, 0, sizeof (struct eroute));
++      kfree_s(rn, sizeof(struct eroute));
++      
++      return 0;
++}
++
++/*
++ * $Log$
++ * Revision 1.36  2000/01/21 06:14:46  rgb
++ * Added debugging text to ipsec_rj_walker_delete().
++ * Set return code to negative for consistency.
++ *
++ * Revision 1.35  1999/11/23 23:05:24  rgb
++ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
++ *
++ * Revision 1.34  1999/11/18 04:13:56  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
++ *
++ * Revision 1.33  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.32  1999/10/26 13:58:33  rgb
++ * Put spinlock flags variable declaration outside the debug compiler
++ * directive to enable compilation with debug shut off.
++ *
++ * Revision 1.31  1999/10/15 22:13:29  rgb
++ * Clean out cruft.
++ * Align /proc/net/ipsec_eroute output for easier readability.
++ * Fix double linefeed in radij debug output.
++ * Fix double locking bug that locks up 2.0.36 but not 2.0.38.
++ *
++ * Revision 1.30  1999/10/08 18:37:33  rgb
++ * Fix end-of-line spacing to sate whining PHMs.
++ *
++ * Revision 1.29  1999/10/03 18:52:45  rgb
++ * Spinlock support for 2.0.xx.
++ * Dumb return code spin_unlock fix.
++ *
++ * Revision 1.28  1999/10/01 16:22:24  rgb
++ * Switch from assignment init. to functional init. of spinlocks.
++ *
++ * Revision 1.27  1999/10/01 15:44:53  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.26  1999/10/01 00:01:23  rgb
++ * Added eroute structure locking.
++ *
++ * Revision 1.25  1999/06/10 16:07:30  rgb
++ * Silence delete eroute on no debug.
++ *
++ * Revision 1.24  1999/05/09 03:25:36  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.23  1999/05/05 22:02:31  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.22  1999/04/29 15:17:23  rgb
++ * Add return values to init and cleanup functions.
++ * Add sanity checking for null pointer arguments.
++ *
++ * Revision 1.21  1999/04/11 00:28:58  henry
++ * GPL boilerplate
++ *
++ * Revision 1.20  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.19  1999/02/17 16:50:35  rgb
++ * Clean out unused cruft.
++ * Consolidate for space and speed efficiency.
++ * Convert DEBUG_IPSEC to KLIPS_PRINT
++ *
++ * Revision 1.18  1999/01/22 06:22:06  rgb
++ * Cruft clean-out.
++ * 64-bit clean-up.
++ *
++ * Revision 1.17  1998/12/02 03:09:39  rgb
++ * Clean up debug printing conditionals to compile with debugging off.
++ *
++ * Revision 1.16  1998/12/01 13:49:39  rgb
++ * Wrap version info printing in debug switches.
++ *
++ * Revision 1.15  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.14  1998/10/31 06:48:17  rgb
++ * Fixed up comments in #endif directives.
++ *
++ * Revision 1.13  1998/10/27 13:48:09  rgb
++ * Cleaned up /proc/net/ipsec_* filesystem for easy parsing by scripts.
++ * Fixed less(1) truncated output bug.
++ * Code clean-up.
++ *
++ * Revision 1.12  1998/10/25 02:41:36  rgb
++ * Change return type on ipsec_breakroute and ipsec_makeroute and add an
++ * argument to be able to transmit more infomation about errors.
++ * Fix cut-and-paste debug statement identifier.
++ *
++ * Revision 1.11  1998/10/22 06:45:39  rgb
++ * Cleaned up cruft.
++ * Convert to use satoa for printk.
++ *
++ * Revision 1.10  1998/10/19 14:44:28  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.9  1998/10/09 04:30:52  rgb
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ * Deleted old commented out cruft.
++ *
++ * Revision 1.8  1998/08/06 17:24:23  rgb
++ * Fix addrtoa return code bug from stale manpage advice preventing packets
++ * from being erouted.
++ *
++ * Revision 1.7  1998/08/06 07:44:59  rgb
++ * Fixed /proc/net/ipsec_eroute subnettoa and addrtoa return value bug that
++ * ended up in nothing being printed.
++ *
++ * Revision 1.6  1998/08/05 22:16:41  rgb
++ * Cleanup to prevent cosmetic errors (ie. debug output) from being fatal.
++ *
++ * Revision 1.5  1998/07/29 20:38:44  rgb
++ * Debug and fix subnettoa and addrtoa output.
++ *
++ * Revision 1.4  1998/07/28 00:02:39  rgb
++ * Converting to exclusive use of addrtoa.
++ * Fix eroute delete.
++ *
++ * Revision 1.3  1998/07/14 18:21:26  rgb
++ * Add function to clear the eroute table.
++ *
++ * Revision 1.2  1998/06/23 02:59:14  rgb
++ * Added debugging output to eroute add/delete routines.
++ *
++ * Revision 1.9  1998/06/18 21:29:06  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
++ * build scripts happier in presence of symbolic links
++ *
++ * Revision 1.8  1998/06/05 02:32:26  rgb
++ * Fix spi ntoh kernel debug output.
++ *
++ * Revision 1.7  1998/05/25 20:30:37  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.6  1998/05/21 13:08:57  rgb
++ * Rewrote procinfo subroutines to avoid *bad things* when more that 3k of
++ * information is available for printout.
++ *
++ * Revision 1.5  1998/05/18 21:35:55  rgb
++ * Clean up output for numerical consistency and readability.  Zero freed
++ * eroute memory.
++ *
++ * Revision 1.4  1998/04/21 21:28:58  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.3  1998/04/14 17:30:39  rgb
++ * Fix up compiling errors for radij tree memory reclamation.
++ *
++ * Revision 1.2  1998/04/12 22:03:23  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:06:10  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:39:04  ji
++ * Minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_radij.h linux-2.2.14/net/ipsec/ipsec_radij.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_radij.h  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_radij.h       Wed Nov 17 16:53:39 1999
+@@ -0,0 +1,145 @@
++/*
++ * Definitions relevant to the IPSEC <> radij tree interfacing
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include <freeswan.h>
++
++int ipsec_walk(char *);
++
++int ipsec_rj_walker_procprint(struct radij_node *, void *);
++int ipsec_rj_walker_delete(struct radij_node *, void *);
++
++struct wsbuf
++{
++      char *buffer;
++      int length;
++      off_t offset;
++      int len;
++      int prev_len;
++      off_t begin;
++      off_t pos;
++};
++
++#if 0
++struct eroute * ipsec_makeroute(struct sockaddr_encap *ea, struct sockaddr_encap *em, struct sa_id);
++#endif
++int ipsec_makeroute(struct sockaddr_encap *ea, struct sockaddr_encap *em, struct sa_id);
++
++#if 0
++struct eroute * ipsec_breakroute(struct sockaddr_encap *ea, struct sockaddr_encap *em);
++#endif
++int ipsec_breakroute(struct sockaddr_encap *ea, struct sockaddr_encap *em);
++
++int ipsec_radijinit(void);
++int ipsec_cleareroutes(void);
++int ipsec_radijcleanup(void);
++
++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 DEBUG_IPSEC
++
++extern int debug_radij;
++void rj_dumptrees(void);
++
++#define DB_RJ_DUMPTREES       0x0001
++#define DB_RJ_FINDROUTE 0x0002
++
++#endif
++
++/*
++ * $Log$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_rcv.c linux-2.2.14/net/ipsec/ipsec_rcv.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_rcv.c    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_rcv.c Tue Feb  8 22:21:54 2000
+@@ -0,0 +1,1593 @@
++/*
++ * receive code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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.
++ */
++
++char ipsec_rcv_c_version[] = "RCSID $Id$";
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#define __NO_VERSION__
++#include <linux/module.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <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 */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#define proto_priv cb
++#endif /* NET21 */
++#include <asm/checksum.h>
++#include <net/ip.h>
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++#include "ipsec_tunnel.h"
++#include "ipsec_rcv.h"
++#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
++#include "ipsec_ah.h"
++#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
++#ifdef CONFIG_IPSEC_ESP
++#include "ipsec_esp.h"
++#endif /* !CONFIG_IPSEC_ESP */
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#endif
++
++#if 0
++#define INBOUND_POLICY_CHECK
++#endif
++
++#ifdef DEBUG_IPSEC
++int debug_ah = 0;
++int debug_esp = 0;
++int debug_rcv = 0;
++#endif
++
++#ifdef CONFIG_IPSEC_ESP
++extern void des_cbc_encrypt(caddr_t, caddr_t, int, caddr_t, caddr_t, int);
++extern void des_ede3_cbc_encrypt(caddr_t, caddr_t, int, caddr_t, caddr_t, caddr_t, caddr_t, int);
++#endif /* !CONFIG_IPSEC_ESP */
++#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
++__u32 zeroes[AH_AMAX];
++#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
++
++/*
++ * 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.
++ */
++
++static int
++ipsec_checkreplaywindow(struct tdb*tdbp, __u32 seq)
++{
++      __u32 diff;
++      
++      if (tdbp->tdb_replaywin == 0)   /* replay shut off */
++              return 1;
++      if (seq == 0) 
++              return 0;               /* first == 0 or wrapped */
++
++      /* new larger sequence number */
++      if (seq > tdbp->tdb_replaywin_lastseq) {
++              diff = seq - tdbp->tdb_replaywin_lastseq;
++
++              /* In win, set bit for this pkt */
++              if (diff < tdbp->tdb_replaywin)
++                      tdbp->tdb_replaywin_bitmap =
++                              (tdbp->tdb_replaywin_bitmap << diff) | 1;
++              else
++                      /* This packet has way larger seq num */
++                      tdbp->tdb_replaywin_bitmap = 1;
++
++              if(seq - tdbp->tdb_replaywin_lastseq - 1 > tdbp->tdb_replaywin_maxdiff) {
++                      tdbp->tdb_replaywin_maxdiff = seq - tdbp->tdb_replaywin_lastseq - 1;
++              }
++              tdbp->tdb_replaywin_lastseq = seq;
++              return 1;               /* larger is good */
++      }
++      diff = tdbp->tdb_replaywin_lastseq - seq;
++
++      /* too old or wrapped */ /* if wrapped, kill off SA? */
++      if (diff >= tdbp->tdb_replaywin) {
++/*
++              if(seq < 0.25*max && tdbp->tdb_replaywin_lastseq > 0.75*max) {
++                      deltdbchain(tdbp);
++              }
++*/    
++              return 0;
++      }
++      /* this packet already seen */
++      if (tdbp->tdb_replaywin_bitmap & (1 << diff))
++              return 0;
++      tdbp->tdb_replaywin_bitmap |= (1 << diff);      /* mark as seen */
++      return 1;                       /* out of order but good */
++}
++
++int
++#ifdef NET_21
++ipsec_rcv(struct sk_buff *skb, unsigned short xlen)
++#else /* NET_21 */
++ipsec_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, 
++              __u32 daddr, unsigned short xlen, __u32 saddr,
++                                   int redo, struct inet_protocol *protocol)
++#endif /* NET_21 */
++{
++#ifdef NET_21
++#ifdef DEBUG_IPSEC
++      struct device *dev = skb->dev;
++#endif /* DEBUG_IPSEC */
++#endif /* NET_21 */
++      unsigned char protoc;
++      struct iphdr *ipp;
++#ifdef CONFIG_IPSEC_ESP
++      struct esp *espp = NULL;
++      int esphlen = 0, authlen = 0;
++      __u32 iv[2];
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++      struct ah *ahp = NULL;
++      int ahhlen = 0;
++      struct iphdr ipo;
++#endif /* CONFIG_IPSEC_AH */
++#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
++      union {
++              MD5_CTX         md5;
++              SHA1_CTX        sha1;
++      } tctx;
++      __u8 hash[AH_AMAX];
++      unsigned char *authenticator = NULL;
++#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
++
++      int hard_header_len;
++      int iphlen;
++      unsigned char *dat;
++      struct tdb *tdbp;
++      struct sa_id said;
++      struct enet_statistics *stats = NULL;           /* This device's statistics */
++      struct device *ipsecdev = NULL, *prvdev;
++      struct ipsecpriv *prv;
++      char name[9];
++      char sa[SATOA_BUF];
++      size_t sa_len;
++      char ipaddr_txt[ADDRTOA_BUF];
++      int i;
++      struct in_addr ipaddr;
++      __u8 next_header = 0;
++      __u8 proto;
++      
++      int pad = 0, ilen, padlen, len, replay = 0;
++      __u8 *idat;
++      unsigned long tdb_flags; /* save irq state for tdb spinlock */
++#ifdef INBOUND_POLICY_CHECK
++      struct tdb* tdbprev = NULL;
++      struct tdb* tdbnext = NULL;
++#ifdef INBOUND_POLICY_CHECK_
++      unsigned long eroute_flags; /* save irq state for eroute spinlock */
++      struct sockaddr_encap matcher;  /* eroute search key */
++      struct eroute *er;
++      struct tdb* policy_tdb = NULL;
++      struct sa_id policy_said;
++      struct sockaddr_encap policy_eaddr;
++      struct sockaddr_encap policy_emask;
++#endif /* INBOUND_POLICY_CHECK */
++#endif /* INBOUND_POLICY_CHECK */
++
++      /* Don't unlink in the middle of a turnaround */
++      MOD_INC_USE_COUNT;
++      
++      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;
++      }
++              
++      /* dev->hard_header_len is unreliable and should not be used */
++      hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
++      if((hard_header_len < 0) || (hard_header_len > skb_headroom(skb)))
++              hard_header_len = 0;
++
++#ifdef NET_21
++      /* 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) < 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",
++                             hard_header_len, skb_headroom(skb));
++                      goto rcvleave;
++              }
++              skb_push(skb, hard_header_len);
++              if ((skb = skb_cow(skb, skb_headroom(skb))) == NULL) {
++                      goto rcvleave;
++              }
++              if(skb->len < 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",
++                             hard_header_len, skb->len);
++                      goto rcvleave;
++              }
++              skb_pull(skb, hard_header_len);
++      }
++      
++#endif /* NET_21 */
++              
++      KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: Info -- ");
++      KLIPS_PRINT(debug_rcv && skb->dev, "sdb->dev=%s ",
++                  skb->dev->name ? skb->dev->name : "NULL");
++      KLIPS_PRINT(debug_rcv && dev, "dev=%s ",
++                  dev->name ? dev->name : "NULL");
++      KLIPS_PRINT(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");
++
++#ifdef NET_21
++      protoc = ((struct iphdr *)skb->data)->protocol;
++#else /* NET_21 */
++      if(protocol) {
++              protoc = protocol->protocol;
++      } else {
++              KLIPS_PRINT(debug_rcv & DB_RX_TDB,
++                          "klips_debug:ipsec_rcv: "
++                          "protocol arg is NULL, this is odd, using value in packet.\n");
++              protoc = ((struct iphdr *)skb->data)->protocol;
++      }
++#endif /* NET_21 */
++
++      if( (protoc != IPPROTO_AH) &&
++          (protoc != IPPROTO_ESP) ) {
++              KLIPS_PRINT(debug_rcv & DB_RX_TDB,
++                          "klips_debug:ipsec_rcv: Why the hell is someone "
++                          "passing me a non-ipsec packet? -- dropped.\n");
++              goto rcvleave;
++      }
++
++      if(skb->dev) {
++              for(i = 0; i < IPSEC_NUM_IF; i++) {
++                      sprintf(name, "ipsec%d", i);
++                      if(!strcmp(name, skb->dev->name)) {
++                              prv = (struct ipsecpriv *)(skb->dev->priv);
++                              if(prv) {
++                                      stats = (struct enet_statistics *) &(prv->mystats);
++                              }
++                              ipsecdev = skb->dev;
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: Info -- pkt "
++                                          "already proc'ed a group of ipsec headers, "
++                                          "processing next group of ipsec headers.\n");
++                              break;
++                      }
++                      if((ipsecdev = dev_get(name)) == NULL) {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_error:ipsec_rcv: device %s does "
++                                          "not exist\n", name);
++                      }
++                      prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL;
++                      prvdev = prv ? (struct device *)(prv->dev) : NULL;
++                      
++                      KLIPS_PRINT(debug_rcv && prvdev, 
++                                  "klips_debug:ipsec_rcv: physical device"
++                                  " for device %s is %s\n",
++                                  name, prvdev->name);
++                      if(prvdev && skb->dev &&
++                         !strcmp(prvdev->name, skb->dev->name)) {
++                              stats = prv ? ((struct enet_statistics *) &(prv->mystats)) : NULL;
++                              skb->dev = ipsecdev;
++                              if(stats) {
++                                      stats->rx_packets++;
++                              }
++                              break;
++                      }
++              }
++      } else {
++              KLIPS_PRINT(debug_rcv, 
++                          "klips_debug:ipsec_rcv: device supplied"
++                          " with skb is NULL\n");
++      }
++                      
++      if(!stats) {
++              ipsecdev = NULL;
++      }
++      KLIPS_PRINT((debug_rcv && !stats),
++                  "klips_error:ipsec_rcv: packet received from physical "
++                  "I/F (%s) not connected to ipsec I/F.  Cannot record "
++                  "stats.\n"
++                  "klips_error          May not have SA for decoding.  "
++                  "Is IPSEC traffic expected on this I/F?  "
++                  "Check routing.\n",
++                  skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL");
++
++#ifdef DEBUG_IPSEC
++      if (debug_rcv) {
++              struct timeval tv;
++              do_gettimeofday(&tv);
++              printk("klips_debug:ipsec_rcv: ts=%02ld.%04ld %s packet received,"
++                     " dev = %s\n", 
++                     (unsigned long int)tv.tv_sec % 60,
++                     (unsigned long int)tv.tv_usec / 100,
++                     protoc == IPPROTO_AH ? "AH" : "ESP",
++                     ipsecdev ? ipsecdev->name : "NULL");
++      }
++#endif /* DEBUG_IPSEC */
++
++      /* begin decapsulating loop here */
++      do {
++#ifdef CONFIG_IPSEC_ESP
++              espp = NULL;
++              esphlen = 0;
++              authlen = 0;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++              ahp = NULL;
++              ahhlen = 0;
++#endif /* CONFIG_IPSEC_AH */
++
++              len = skb->len;
++              dat = skb->data;
++              ipp = (struct iphdr *)skb->data;
++              proto = ipp->protocol;
++              ipaddr.s_addr = ipp->saddr;
++              addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++              
++              KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv: old\n");
++              KLIPS_IP_PRINT(debug_rcv, ipp);
++              
++              iphlen = ipp->ihl << 2;
++              ipp->check = 0;                 /* we know the sum is good */
++              
++#ifdef CONFIG_IPSEC_ESP
++              if ((proto == IPPROTO_ESP) && ((len - 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 - iphlen, ipaddr_txt);       /* XXX this will need to be 8 for IPv6 */
++                      if(stats) {
++                              stats->rx_errors++;
++                      }
++                      goto rcvleave;
++              }
++#endif /* !CONFIG_IPSEC_ESP */
++              
++              /*
++               * Find tunnel control block and (indirectly) call the appropriate
++               * tranform routine. The resulting sk_buf is a valid
++               * IP packet ready to go through input processing.
++               */
++              
++              said.dst.s_addr = ipp->daddr;
++              switch(proto) {
++#ifdef CONFIG_IPSEC_ESP
++              case IPPROTO_ESP:
++                      espp = (struct esp *)(skb->data + iphlen);
++                      said.spi = espp->esp_spi;
++                      break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++              case IPPROTO_AH:
++                      ahp = (struct ah *)(skb->data + iphlen);
++                      said.spi = ahp->ah_spi;
++                      break;
++#endif /* CONFIG_IPSEC_AH */
++              default:
++                      if(stats) {
++                              stats->rx_errors++;
++                      }
++                      goto rcvleave;
++              }
++              said.proto = proto;
++              
++#ifdef CONFIG_IPSEC_AH
++              if(proto == IPPROTO_AH) {
++                      ahhlen = (ahp->ah_hl << 2) +
++                              ((caddr_t)&(ahp->ah_rpl) - (caddr_t)ahp);
++                      next_header = ahp->ah_nh;
++                      if (ahhlen != sizeof(struct ah)) {
++                              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                                          "klips_debug:ipsec_rcv: bad "
++                                          "authenticator length %d, expected "
++                                          "%d from %s\n",
++                                          ahhlen - ((caddr_t)(ahp->ah_data) -
++                                                    (caddr_t)ahp),
++                                          AHHMAC_HASHLEN,
++                                          ipaddr_txt);
++                              if(stats) {
++                                      stats->rx_errors++;
++                              }
++                              goto rcvleave;
++                      }
++                      
++              }
++#endif /* CONFIG_IPSEC_AH */
++              
++              sa_len = satoa(said, 0, sa, SATOA_BUF);
++
++              /*
++               * The spinlock is to prevent any other process from accessing or deleting
++               * the structure while we are using and updating it.
++               */
++              spin_lock_irqsave(&tdb_lock, tdb_flags);
++
++              tdbp = gettdb(&said);
++              sa_len = satoa(said, 0, sa, SATOA_BUF);
++              if (tdbp == NULL) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: no Tunnel Descriptor "
++                                  "Block for SA:%s: incoming packet with no SA "
++                                  "dropped\n", sa);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++#ifdef INBOUND_POLICY_CHECK
++              if(tdbnext) {
++                      if(tdbnext != tdbp) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "unexpected SA:%s: does not agree with tdb->inext policy, "
++                                          "dropped\n", sa);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              goto rcvleave;
++                      } else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "SA:%s grouping from previous SA is OK.\n", sa);
++                      }
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s First SA in group.\n", sa);
++              }
++
++#if 0
++              if(tdbp->tdb_onext) {
++                      if(tdbprev != tdbp->tdb_onext) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "unexpected SA:%s: does not agree with tdb->onext policy, "
++                                          "dropped\n", sa);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              goto rcvleave;
++                      } else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "SA:%s grouping to previous SA is OK.\n", sa);
++                      }
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s No previous backlink in group.\n", sa);
++              }
++#endif
++#endif /* INBOUND_POLICY_CHECK */
++              
++#ifdef CONFIG_IPSEC_PFKEYv2
++              /* If it is in larval state, drop the packet, we cannot process yet. */
++              if(tdbp->tdb_state == SADB_SASTATE_LARVAL) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "TDB in larval state, cannot be used yet, "
++                                  "dropping packet.\n");
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              
++              if(tdbp->tdb_state == SADB_SASTATE_DEAD) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "TDB in dead state, cannot be used any more, "
++                                  "dropping packet.\n");
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              
++              if(tdbp->tdb_lifetime_bytes_s &&
++                 (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_s)) {
++                      tdbp->tdb_state = SADB_SASTATE_DYING;
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "soft bytes lifetime of SA:%s has been reached, "
++                                  "SA expiring, soft expire message sent up, "
++                                  "incoming packet still processed.\n", sa);
++                      /* pfkey_expire(tdbp) */;
++              }
++              if(tdbp->tdb_lifetime_bytes_h &&
++                 (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_h)) {
++                      /* pfkey_expire(tdbp) */;
++                      deltdbchain(tdbp);
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "hard bytes lifetime of SA:%s has been reached, "
++                                  "SA expired, incoming packet dropped.\n", sa);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              
++              if(tdbp->tdb_lifetime_addtime_s &&
++                 ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c >
++                  tdbp->tdb_lifetime_addtime_s)) {
++                      tdbp->tdb_state = SADB_SASTATE_DYING;
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "soft addtime lifetime of SA:%s has been reached, "
++                                  "SA expiring, soft expire message sent up, "
++                                  "incoming packet still processed.\n", sa);
++                      /* pfkey_expire(tdbp) */;
++              }
++              if(tdbp->tdb_lifetime_addtime_h &&
++                 ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c >
++                  tdbp->tdb_lifetime_addtime_h)) {
++                      /* pfkey_expire(tdbp) */;
++                      deltdbchain(tdbp);
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "hard addtime lifetime of SA:%s has been reached, "
++                                  "SA expired, incoming packet dropped.\n", sa);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              
++              if(tdbp->tdb_lifetime_usetime_s &&
++                 ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c >
++                  tdbp->tdb_lifetime_usetime_s)) {
++                      tdbp->tdb_state = SADB_SASTATE_DYING;
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "soft usetime lifetime of SA:%s has been reached, "
++                                  "SA expiring, soft expire message sent up, "
++                                  "incoming packet still processed.\n", sa);
++                      /* pfkey_expire(tdbp) */;
++              }
++              if(tdbp->tdb_lifetime_usetime_h &&
++                 ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c >
++                  tdbp->tdb_lifetime_usetime_h)) {
++                      /* pfkey_expire(tdbp) */;
++                      deltdbchain(tdbp);
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "hard usetime lifetime of SA:%s has been reached, "
++                                  "SA expired, incoming packet dropped.\n", sa);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++              
++              if(tdbp->tdb_lifetime_packets_s &&
++                 (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_s)) {
++                      tdbp->tdb_state = SADB_SASTATE_DYING;
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "soft packets lifetime of SA:%s has been reached, "
++                                  "SA expiring, soft expire message sent up, "
++                                  "incoming packet still processed.\n", sa);
++                      /* pfkey_expire(tdbp) */;
++              }
++              if(tdbp->tdb_lifetime_packets_h &&
++                 (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_h)) {
++                      /* pfkey_expire(tdbp) */;
++                      deltdbchain(tdbp);
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "hard packets lifetime of SA:%s has been reached, "
++                                  "SA expired, incoming packet dropped.\n", sa);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++              
++              /* authenticate, if required */
++              idat = dat + iphlen;
++              switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++              case AH_MD5:
++                      authlen = AHHMAC_HASHLEN;
++                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++              case AH_SHA:
++                      authlen = AHHMAC_HASHLEN;
++                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++              case AH_NONE:
++                      authlen = 0;
++                      break;
++              default:
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      if(stats) {
++                              stats->rx_errors++;
++                      }
++                      tdbp->tdb_alg_errs += 1;
++                      goto rcvleave;
++              }
++              ilen = len - iphlen - authlen;
++              
++#ifdef CONFIG_IPSEC_ESP
++              KLIPS_PRINT(proto == IPPROTO_ESP && debug_rcv, 
++                          "klips_debug:ipsec_rcv: packet from %s received with"
++                          " seq=%ld (iv)=0x%08lx%08lx iplen=%d esplen=%d sa=%s\n",
++                          ipaddr_txt,
++                          ntohl(espp->esp_rpl),
++                          ntohl(*((__u32 *)(espp->esp_iv)    )),
++                          ntohl(*((__u32 *)(espp->esp_iv) + 1)),
++                          len, ilen, sa);
++#endif /* !CONFIG_IPSEC_ESP */
++              
++              switch(proto) {
++#ifdef CONFIG_IPSEC_ESP
++              case IPPROTO_ESP:
++                      replay = ntohl(espp->esp_rpl);
++                      authenticator = &(dat[len - authlen]);
++                      break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++              case IPPROTO_AH:
++                      replay = ntohl(ahp->ah_rpl);
++                      authenticator = ahp->ah_data;
++                      break;
++#endif /* CONFIG_IPSEC_AH */
++              }
++
++              /* If the sequence number == 0, expire SA, it had rolled */
++              if(tdbp->tdb_replaywin && !replay /* !tdbp->tdb_replaywin_lastseq */) {
++                      deltdbchain(tdbp);
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "replay window counter rolled, expiring SA.\n");
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              }
++
++              if (!ipsec_checkreplaywindow(tdbp, replay)) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
++                                  "klips_debug:ipsec_rcv: duplicate frame from %s,"
++                                  " packet dropped\n",
++                                  ipaddr_txt);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      tdbp->tdb_replaywin_errs += 1;
++                      goto rcvleave;
++              }
++              
++              /*
++               * verify authenticator
++               */
++              
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: encalg = %d, authalg = %d.\n",
++                          tdbp->tdb_encalg, tdbp->tdb_authalg);
++              
++              if(tdbp->tdb_authalg) {
++                      switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                      case AH_MD5:
++                              tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;
++                              if(proto == IPPROTO_ESP) {
++                                      MD5Update(&tctx.md5, (caddr_t)espp, ilen);
++#ifdef CONFIG_IPSEC_AH
++                              } else {
++                                      ipo = *ipp;
++                                      ipo.tos = 0;    /* mutable RFC 2402 3.3.3.1.1.1 */
++                                      ipo.frag_off = 0;
++                                      ipo.ttl = 0;
++                                      ipo.check = 0;
++                                      
++                                      MD5Update(&tctx.md5, (caddr_t)&ipo,
++                                                sizeof(struct iphdr));
++                                      MD5Update(&tctx.md5, (caddr_t)ahp,
++                                                ahhlen - AHHMAC_HASHLEN);
++                                      MD5Update(&tctx.md5, (caddr_t)zeroes,
++                                                AHHMAC_HASHLEN);
++                                      MD5Update(&tctx.md5,
++                                                (caddr_t)dat + iphlen + ahhlen,
++                                                len - iphlen - ahhlen);
++#endif /* CONFIG_IPSEC_AH */
++                              }
++                              MD5Final(hash, &tctx.md5);
++                              tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx;
++                              MD5Update(&tctx.md5, hash, AHMD596_ALEN);
++                              MD5Final(hash, &tctx.md5);
++                              break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                      case AH_SHA:
++                              tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->ictx;
++                              if(proto == IPPROTO_ESP) {
++                                      SHA1Update(&tctx.sha1, (caddr_t)espp, ilen);
++#ifdef CONFIG_IPSEC_AH
++                              } else {
++                                      ipo = *ipp;
++                                      ipo.tos = 0;
++                                      ipo.frag_off = 0;
++                                      ipo.ttl = 0;
++                                      ipo.check = 0;
++                                      
++                                      SHA1Update(&tctx.sha1, (caddr_t)&ipo,
++                                                 sizeof(struct iphdr));
++                                      SHA1Update(&tctx.sha1, (caddr_t)ahp,
++                                                 ahhlen - AHHMAC_HASHLEN);
++                                      SHA1Update(&tctx.sha1, (caddr_t)zeroes,
++                                                 AHHMAC_HASHLEN);
++                                      SHA1Update(&tctx.sha1,
++                                                 (caddr_t)dat + iphlen + ahhlen,
++                                                 len - iphlen - ahhlen);
++#endif /* CONFIG_IPSEC_AH */
++                              }
++                              SHA1Final(hash, &tctx.sha1);
++                              tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->octx;
++                              SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++                              SHA1Final(hash, &tctx.sha1);
++                              break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                      case AH_NONE:
++                              break;
++                      }
++              
++                      if(!authenticator) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              tdbp->tdb_auth_errs += 1;
++                              goto rcvleave;
++                      }
++
++                      if (memcmp(hash, authenticator, authlen)) {
++                              KLIPS_PRINT(debug_rcv & DB_RX_INAU,
++                                          "klips_debug:ipsec_rcv: auth failed on incoming "
++                                          "packet from %s: hash=%08x%08x%08x "
++                                          "auth=%08x%08x%08x, dropped\n", ipaddr_txt,
++                                          *(__u32*)&hash[0],
++                                          *(__u32*)&hash[4],
++                                          *(__u32*)&hash[8],
++                                          *(__u32*)authenticator,
++                                          *((__u32*)authenticator) + 1,
++                                          *((__u32*)authenticator) + 2);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              tdbp->tdb_auth_errs += 1;
++                              goto rcvleave;
++                      } else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: authentication successful.\n");
++                      }
++                      
++                      memset((caddr_t)&tctx, 0, sizeof(tctx));
++                      memset(hash, 0, sizeof(hash));
++              }
++
++              switch(proto) {
++#ifdef CONFIG_IPSEC_ESP
++              case IPPROTO_ESP:
++                      switch(tdbp->tdb_encalg) {
++                      case ESP_DES:
++                      case ESP_3DES:
++                              iv[0] = *((__u32 *)(espp->esp_iv)    );
++                              iv[1] = *((__u32 *)(espp->esp_iv) + 1);
++                              esphlen = sizeof(struct esp);
++                              break;
++                      case ESP_NULL:
++                              esphlen = offsetof(struct esp, esp_iv);
++                              break;
++                      default:
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              if(stats) {
++                                      stats->rx_errors++;
++                              }
++                              tdbp->tdb_alg_errs += 1;
++                              goto rcvleave;
++                      }
++                      idat += esphlen;
++                      ilen -= esphlen;
++                      
++                      switch(tdbp->tdb_encalg) {
++                      case ESP_DES:
++                              if ((ilen) % 8) {
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      printk("klips_error:ipsec_rcv: got packet with esplen = %d from "
++                                             "%s -- should be on 8 octet boundary, packet dropped\n",
++                                             ilen, ipaddr_txt);
++                                      if(stats) {
++                                              stats->rx_errors++;
++                                      }
++                                      tdbp->tdb_encsize_errs += 1;
++                                      goto rcvleave;
++                              }
++                              des_cbc_encrypt(idat, idat, ilen,
++                                              tdbp->tdb_key_e,
++                                              (caddr_t)iv, 0);
++                              break;
++                      case ESP_3DES:
++                              if ((ilen) % 8) {
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      printk("klips_error:ipsec_rcv: got packet with esplen = %d from "
++                                             "%s -- should be on 8 octet boundary, packet dropped\n",
++                                             ilen, ipaddr_txt);
++                                      if(stats) {
++                                              stats->rx_errors++;
++                                      }
++                                      tdbp->tdb_encsize_errs += 1;
++                                      goto rcvleave;
++                              }
++                              des_ede3_cbc_encrypt(idat, idat, ilen,
++                                                   tdbp->tdb_key_e,
++                                                   tdbp->tdb_key_e + sizeof(struct des_eks),
++                                                   tdbp->tdb_key_e + 2 * sizeof(struct des_eks),
++                                                   (caddr_t)iv, 0);
++                              break;
++                      case ESP_NULL:
++                              break;
++                      }
++                      next_header = idat[ilen - 1];
++                      padlen = idat[ilen - 2];
++                      pad = padlen + 2 + authlen;
++#ifdef DEBUG_IPSEC
++                      if(debug_rcv & DB_RX_IPAD) {
++                              printk("klips_debug:ipsec_rcv: padlen=%d, contents: ",
++                                     padlen);
++                              
++                              for (i = 1; i <= padlen; i++) {
++                                      printk(" %d:%d", i,
++                                             idat[ilen - 2 - padlen + i - 1]);
++                                      if(i != idat[ilen - 2 - padlen + i - 1]) {
++                                              printk("\nklips_debug:ipsec_rcv: warning, decrypted packet from %s has bad padding\n",
++                                                     ipaddr_txt);
++                                              printk("\nklips_debug:ipsec_rcv: ...may be bad decryption -- not dropped\n");
++                                              tdbp->tdb_encpad_errs += 1;
++                                      } 
++                              }
++                              printk("\n");
++                              
++                              printk("klips_debug:ipsec_rcv: packet decrypted from "
++                                     "%s: next_header = %d, padding = %d\n",
++                                     ipaddr_txt,
++                                     next_header,
++                                     pad - 2 - authlen);
++                      }
++#endif
++                      
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++              case IPPROTO_AH:
++                      break;
++#endif /* CONFIG_IPSEC_AH */
++              }
++             
++              tdbp->tdb_lifetime_bytes_c += len;
++              if(!tdbp->tdb_lifetime_usetime_c) {
++                      tdbp->tdb_lifetime_usetime_c = jiffies / HZ;
++              }
++              tdbp->tdb_lifetime_usetime_l = jiffies / HZ;
++              tdbp->tdb_lifetime_packets_c += 1;
++              
++              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++
++              /*
++               *      Discard the original IP header
++               */
++              
++              KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                          "klips_debug:ipsec_rcv: proto = %d, protoc = %d, "
++                          "len = %d.\n",
++                          proto, protoc, len);
++
++              ipp->protocol = next_header;
++              
++              switch(proto) {
++#ifdef CONFIG_IPSEC_ESP
++              case IPPROTO_ESP:
++                      ipp->tot_len = htons(ntohs(ipp->tot_len) - (esphlen + pad));
++                      memmove((void *)(skb->data + esphlen),
++                              (void *)(skb->data), iphlen);
++                      if(skb->len < esphlen) {
++                              printk(KERN_WARNING "klips_error:ipsec_rcv: "
++                                     "tried to skb_pull esphlen=%d, %d available.  "
++                                     "This should never happen, please report.\n",
++                                     esphlen, (int)(skb->len));
++                              goto rcvleave;
++                      }
++                      skb_pull(skb, esphlen);
++              break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++              case IPPROTO_AH:
++                      ipp->tot_len = htons(ntohs(ipp->tot_len) - ahhlen);
++                      memmove((void *)(skb->data + ahhlen),
++                              (void *)(skb->data), iphlen);
++                      if(skb->len < esphlen) {
++                              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));
++                              goto rcvleave;
++                      }
++                      skb_pull(skb, ahhlen);
++                      break;
++#endif /* CONFIG_IPSEC_AH */
++              }
++
++#ifdef CONFIG_IPSEC_ESP
++              if(proto == IPPROTO_ESP) {
++                      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                                  "klips_debug:ipsec_rcv: trimming to %d.\n",
++                                  len - esphlen - pad);
++                      skb_trim(skb, len - esphlen - pad);
++              }
++#endif /* !CONFIG_IPSEC_ESP */
++              
++              /*
++               *      Adjust pointers
++               */
++              
++              len = skb->len;
++              dat = skb->data;
++              
++#ifdef NET_21
++/*            skb->h.ipiph=(struct iphdr *)skb->data; */
++              skb->nh.raw = skb->data;
++              skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
++              
++              memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++#else /* NET_21 */
++              skb->h.iph=(struct iphdr *)skb->data;
++              skb->ip_hdr=(struct iphdr *)skb->data;
++              memset(skb->proto_priv, 0, sizeof(struct options));
++#endif /* NET_21 */
++              
++              ipp = (struct iphdr *)dat;
++              ipp->check = 0;
++              ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2);
++              
++              KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                          "klips_debug:ipsec_rcv: new\n");
++              KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
++              
++              skb->protocol = htons(ETH_P_IP);
++              skb->ip_summed = 0;
++
++#ifdef INBOUND_POLICY_CHECK
++              tdbprev = tdbp;
++              tdbnext = tdbp->tdb_inext;
++              if(tdbnext) {
++                      if(tdbnext->tdb_onext != tdbp) {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "SA:%s, backpolicy does not agree with fwdpolicy.\n", sa);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              goto rcvleave;
++                      } else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "SA:%s, backpolicy agrees with fwdpolicy.\n", sa);
++                      }
++                      if(!((ipp->protocol == IPPROTO_ESP ) ||
++                           (ipp->protocol == IPPROTO_AH  ) ||
++                           (ipp->protocol == IPPROTO_IPIP)
++#ifdef CONFIG_IPSEC_IPCOMP
++                           || (ipp->protocol == IPPROTO_COMP)
++#endif /* CONFIG_IPSEC_IPCOMP */
++                              )) {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "packet with incomplete policy dropped, SA:%s.\n", sa);
++                              if(stats) {
++                                      stats->rx_dropped++;
++                              }
++                              goto rcvleave;
++                      } else {
++                              KLIPS_PRINT(debug_rcv,
++                                          "klips_debug:ipsec_rcv: "
++                                          "SA:%s, Another IPSEC header to process.\n", sa);
++                      }
++              } else {
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "No tdb_inext from this SA:%s.\n", sa);
++              }
++#endif /* INBOUND_POLICY_CHECK */
++      } while((ipp->protocol == IPPROTO_ESP) ||
++              (ipp->protocol == IPPROTO_AH )
++#ifdef CONFIG_IPSEC_IPCOMP
++              || (ipp->protocol == IPPROTO_COMP)
++#endif /* CONFIG_IPSEC_IPCOMP */
++              );
++      /* end decapsulation loop here */
++      
++#ifdef INBOUND_POLICY_CHECK_eroute
++      /*
++       * First things first -- look us up in the erouting tables.
++       */
++      matcher.sen_len = sizeof (struct sockaddr_encap);
++      matcher.sen_family = AF_ENCAP;
++      matcher.sen_type = SENT_IP4;
++      if(ipp->protocol == IPPROTO_IPIP) {
++              struct iphdr *ipp2;
++
++              ipp2 = (struct iphdr*) (((char*)ipp) + (ipp->ihl << 2));
++              matcher.sen_ip_src.s_addr = ipp2->saddr;
++              matcher.sen_ip_dst.s_addr = ipp2->daddr;
++      } else {
++              matcher.sen_ip_src.s_addr = ipp->saddr;
++              matcher.sen_ip_dst.s_addr = ipp->daddr;
++      }
++      
++      /*
++       * The spinlock is to prevent any other process from accessing or deleting
++       * the eroute while we are using and updating it.
++       */
++      spin_lock_irqsave(&eroute_lock, eroute_flags);
++      
++      er = ipsec_findroute(&matcher);
++      if(er) {
++              policy_said = er->er_said;
++              policy_eaddr = er->er_eaddr;
++              policy_emask = er->er_emask;
++      }
++      
++      spin_unlock_irqrestore(&eroute_lock, eroute_flags);
++
++      if(er) {
++              if(tdbnext) {
++                      tdbprev = tdbnext;
++                      tdbnext = tdbp->tdb_inext;
++              }
++              
++              /*
++               * The spinlock is to prevent any other process from accessing or deleting
++               * the tdb while we are using and updating it.
++               */
++              spin_lock_irqsave(&tdb_lock, tdb_flags);
++
++              policy_tdb = gettdb(&policy_said);
++              if (policy_tdb == NULL) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "no Tunnel Descriptor Block for SA%s: "
++                                  "incoming packet with no policy SA, dropped.\n", sa);
++                      goto rcvleave;
++              }
++              
++              sa_len = satoa(policy_said, 0, sa, SATOA_BUF);
++
++              KLIPS_PRINT(debug_rcv,
++                          "klips_debug:ipsec_rcv: "
++                          "found policy Tunnel Descriptor Block -- SA:%s\n", sa);
++              while(1) {
++                      if(policy_tdb->tdb_inext) {
++                              policy_tdb = policy_tdb->tdb_inext;
++                      } else {
++                              break;
++                      }
++              }
++              if(policy_tdb != tdbp) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  " Tunnel Descriptor Block for SA%s: "
++                                  "incoming packet with different policy SA, dropped.\n", sa);
++                      goto rcvleave;
++              }
++
++              tdbp->tdb_lifetime_bytes_c += len;
++              if(!tdbp->tdb_lifetime_usetime_c) {
++                      tdbp->tdb_lifetime_usetime_c = jiffies / HZ;
++              }
++              tdbp->tdb_lifetime_usetime_l = jiffies / HZ;
++              tdbp->tdb_lifetime_packets_c += 1;
++              
++              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++      }
++#endif /* INBOUND_POLICY_CHECK */
++#ifdef INBOUND_POLICY_CHECK
++
++      if(tdbnext) {
++              sa_len = satoa(tdbnext->tdb_said, 0, sa, SATOA_BUF);
++
++              if(ipp->saddr != ((struct sockaddr_in*)(tdbnext->tdb_addr_s))->sin_addr.s_addr) {
++                      ipaddr.s_addr = ipp->saddr;
++                      addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, src=%s of pkt does not agree with IPIP policy.\n",
++                                  sa, ipaddr_txt);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              } else {
++                      ipaddr.s_addr = ipp->saddr;
++                      addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, src=%s of pkt agrees with IPIP policy.\n",
++                                  sa, ipaddr_txt);
++              }
++              if(ipp->daddr != ((struct sockaddr_in*)(tdbnext->tdb_addr_d))->sin_addr.s_addr) {
++                      ipaddr.s_addr = ipp->daddr;
++                      addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, dst=%s of pkt does not agree with IPIP policy.\n",
++                                  sa, ipaddr_txt);
++                      if(stats) {
++                              stats->rx_dropped++;
++                      }
++                      goto rcvleave;
++              } else {
++                      ipaddr.s_addr = ipp->daddr;
++                      addrtoa(ipaddr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_rcv,
++                                  "klips_debug:ipsec_rcv: "
++                                  "SA:%s, dst=%s of pkt agree with IPIP policy.\n",
++                                  sa, ipaddr_txt);
++              }
++              
++              tdbnext->tdb_lifetime_bytes_c += len;
++              if(!tdbnext->tdb_lifetime_usetime_c) {
++                      tdbnext->tdb_lifetime_usetime_c = jiffies / HZ;
++              }
++              tdbnext->tdb_lifetime_usetime_l = jiffies / HZ;
++              tdbnext->tdb_lifetime_packets_c += 1;
++      }
++              
++#endif /* INBOUND_POLICY_CHECK */
++
++      if(ipp->protocol == IPPROTO_IPIP) {
++              if(skb->len < iphlen) {
++                      printk(KERN_WARNING "klips_debug:ipsec_rcv: "
++                             "tried to skb_pull iphlen=%d, %d available.  "
++                             "This should never happen, please report.\n",
++                             iphlen, (int)(skb->len));
++                      goto rcvleave;
++              }
++              skb_pull(skb, iphlen);
++
++#ifdef NET_21
++              ipp = (struct iphdr *)skb->nh.raw = skb->data;
++              skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
++              
++              memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++#else /* NET_21 */
++              ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data;
++
++              memset(skb->proto_priv, 0, sizeof(struct options));
++#endif /* NET_21 */
++
++              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);
++      }
++
++#ifdef NET_21
++      if(stats) {
++              stats->rx_bytes += skb->len;
++      }
++      if(skb->dst) {
++              dst_release(skb->dst);
++              skb->dst = NULL;
++      }
++      skb->pkt_type = PACKET_HOST;
++      if(hard_header_len &&
++         (skb->mac.raw != (skb->data - hard_header_len)) &&
++         (hard_header_len <= skb_headroom(skb))) {
++              /* copy back original MAC header */
++              memmove(skb->data - hard_header_len, skb->mac.raw, hard_header_len);
++              skb->mac.raw = skb->data - hard_header_len;
++      }
++#endif /* NET_21 */
++      KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
++                  "klips_debug:ipsec_rcv: netif_rx() called.\n");
++      netif_rx(skb);
++
++      MOD_DEC_USE_COUNT;
++      return(0);
++      
++ rcvleave:
++      if(skb) {
++#ifdef NET_21
++                kfree_skb(skb);
++#else /* NET_21 */
++                kfree_skb(skb, FREE_WRITE);
++#endif /* NET_21 */
++      }
++
++      MOD_DEC_USE_COUNT;
++      return(0);
++}
++
++struct inet_protocol ah_protocol =
++{
++      ipsec_rcv,                              /* AH handler */
++      NULL,                           /* TUNNEL error control */
++      0,                              /* next */
++      IPPROTO_AH,                     /* protocol ID */
++      0,                              /* copy */
++      NULL,                           /* data */
++      "AH"                            /* name */
++};
++
++struct inet_protocol esp_protocol = 
++{
++      ipsec_rcv,                      /* ESP handler          */
++      NULL,                           /* TUNNEL error control */
++      0,                              /* next */
++      IPPROTO_ESP,                    /* protocol ID */
++      0,                              /* copy */
++      NULL,                           /* data */
++      "ESP"                           /* name */
++};
++
++/*
++ * $Log$
++ * Revision 1.42  2000/01/26 10:04:04  rgb
++ * Fixed inbound policy checking on transport mode bug.
++ * Fixed noisy 2.0 printk arguments.
++ *
++ * Revision 1.41  2000/01/24 20:58:02  rgb
++ * Improve debugging/reporting support for (disabled) inbound
++ * policy checking.
++ *
++ * Revision 1.40  2000/01/22 23:20:10  rgb
++ * Fixed up inboud policy checking code.
++ * Cleaned out unused crud.
++ *
++ * Revision 1.39  2000/01/21 06:15:29  rgb
++ * Added sanity checks on skb_push(), skb_pull() to prevent panics.
++ * Fixed cut-and-paste debug_tunnel to debug_rcv.
++ * Added inbound policy checking code, disabled.
++ * Simplified output code by updating ipp to post-IPIP decapsulation.
++ *
++ * Revision 1.38  1999/12/22 05:08:36  rgb
++ * Checked for null skb, skb->dev, skb->data, skb->dev->name, dev->name,
++ * protocol and take appropriate action for sanity.
++ * Set ipsecdev to NULL if device could not be determined.
++ * Fixed NULL stats access bug if device could not be determined.
++ *
++ * Revision 1.37  1999/12/14 20:07:59  rgb
++ * Added a default switch case to catch bogus encalg values.
++ *
++ * Revision 1.36  1999/12/07 18:57:57  rgb
++ * Fix PFKEY symbol compile error (SADB_*) without pfkey enabled.
++ *
++ * Revision 1.35  1999/12/01 22:15:35  rgb
++ * Add checks for LARVAL and DEAD SAs.
++ * Change state of SA from MATURE to DYING when a soft lifetime is
++ * reached and print debug warning.
++ *
++ * Revision 1.34  1999/11/23 23:04:03  rgb
++ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.33  1999/11/19 01:10:06  rgb
++ * Enable protocol handler structures for static linking.
++ *
++ * Revision 1.32  1999/11/18 04:09:19  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.31  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.30  1999/10/26 15:09:07  rgb
++ * Used debug compiler directives to shut up compiler for decl/assign
++ * statement.
++ *
++ * Revision 1.29  1999/10/16 18:25:37  rgb
++ * Moved SA lifetime expiry checks before packet processing.
++ * Expire SA on replay counter rollover.
++ *
++ * Revision 1.28  1999/10/16 04:23:07  rgb
++ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
++ * authentication errors, encryption size errors, encryption padding
++ * errors, and time since last packet.
++ *
++ * Revision 1.27  1999/10/16 00:30:47  rgb
++ * Added SA lifetime counting.
++ *
++ * Revision 1.26  1999/10/15 22:14:37  rgb
++ * Add debugging.
++ *
++ * Revision 1.25  1999/10/08 18:37:34  rgb
++ * Fix end-of-line spacing to sate whining PHMs.
++ *
++ * Revision 1.24  1999/10/03 18:54:51  rgb
++ * Spinlock support for 2.3.xx.
++ * Don't forget to undo spinlocks on error!
++ *
++ * Revision 1.23  1999/10/01 15:44:53  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.22  1999/10/01 00:01:54  rgb
++ * Added tdb structure locking.
++ *
++ * Revision 1.21  1999/09/18 11:42:12  rgb
++ * Add Marc Boucher's tcpdump cloned packet fix.
++ *
++ * Revision 1.20  1999/09/17 23:50:25  rgb
++ * Add Marc Boucher's hard_header_len patches.
++ *
++ * Revision 1.19  1999/09/10 05:31:36  henry
++ * tentative fix for 2.0.38-crash bug (move chunk of new code into 2.2 #ifdef)
++ *
++ * Revision 1.18  1999/08/28 08:28:06  rgb
++ * Delete redundant sanity check.
++ *
++ * Revision 1.17  1999/08/28 02:00:58  rgb
++ * Add an extra sanity check for null skbs.
++ *
++ * Revision 1.16  1999/08/27 05:21:38  rgb
++ * Clean up skb->data/raw/nh/h manipulation.
++ * Add Marc Boucher's mods to aid tcpdump.
++ *
++ * Revision 1.15  1999/08/25 14:22:40  rgb
++ * Require 4-octet boundary check only for ESP.
++ *
++ * Revision 1.14  1999/08/11 08:36:44  rgb
++ * Add compiler directives to allow configuring out AH, ESP or transforms.
++ *
++ * Revision 1.13  1999/08/03 17:10:49  rgb
++ * Cosmetic fixes and clarification to debug output.
++ *
++ * Revision 1.12  1999/05/09 03:25:36  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.11  1999/05/08 21:23:57  rgb
++ * Add casting to silence the 2.2.x compile.
++ *
++ * Revision 1.10  1999/05/05 22:02:31  rgb
++ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
++ *
++ * Revision 1.9  1999/04/29 15:18:01  rgb
++ * hange debugging to respond only to debug_rcv.
++ * Change gettdb parameter to a pointer to reduce stack loading and
++ * facilitate parameter sanity checking.
++ *
++ * Revision 1.8  1999/04/15 15:37:24  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.4.2.2  1999/04/13 20:32:45  rgb
++ * Move null skb sanity check.
++ * Silence debug a bit more when off.
++ * Use stats more effectively.
++ *
++ * Revision 1.4.2.1  1999/03/30 17:10:32  rgb
++ * Update AH+ESP bugfix.
++ *
++ * Revision 1.7  1999/04/11 00:28:59  henry
++ * GPL boilerplate
++ *
++ * Revision 1.6  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.5  1999/03/17 15:39:23  rgb
++ * Code clean-up.
++ * Bundling bug fix.
++ * ESP_NULL esphlen and IV bug fix.
++ *
++ * Revision 1.4  1999/02/17 16:51:02  rgb
++ * Ditch NET_IPIP dependancy.
++ * Decapsulate recursively for an entire bundle.
++ *
++ * Revision 1.3  1999/02/12 21:22:47  rgb
++ * Convert debugging printks to KLIPS_PRINT macro.
++ * Clean-up cruft.
++ * Process IPIP tunnels internally.
++ *
++ * Revision 1.2  1999/01/26 02:07:36  rgb
++ * Clean up debug code when switched off.
++ * Remove references to INET_GET_PROTOCOL.
++ *
++ * Revision 1.1  1999/01/21 20:29:11  rgb
++ * Converted from transform switching to algorithm switching.
++ *
++ *
++ * Id: ipsec_esp.c,v 1.16 1998/12/02 03:08:11 rgb Exp $
++ *
++ * Log: ipsec_esp.c,v $
++ * Revision 1.16  1998/12/02 03:08:11  rgb
++ * Fix incoming I/F bug in AH and clean up inconsistencies in the I/F
++ * discovery routine in both AH and ESP.
++ *
++ * Revision 1.15  1998/11/30 13:22:51  rgb
++ * Rationalised all the klips kernel file headers.  They are much shorter
++ * now and won't conflict under RH5.2.
++ *
++ * Revision 1.14  1998/11/10 05:55:37  rgb
++ * Add even more detail to 'wrong I/F' debug statement.
++ *
++ * Revision 1.13  1998/11/10 05:01:30  rgb
++ * Clean up debug output to be quiet when disabled.
++ * Add more detail to 'wrong I/F' debug statement.
++ *
++ * Revision 1.12  1998/10/31 06:39:32  rgb
++ * Fixed up comments in #endif directives.
++ * Tidied up debug printk output.
++ * Convert to addrtoa and satoa where possible.
++ *
++ * Revision 1.11  1998/10/27 00:49:30  rgb
++ * AH+ESP bundling bug has been squished.
++ * Cosmetic brace fixing in code.
++ * Newlines added before calls to ipsec_print_ip.
++ * Fix debug output function ID's.
++ *
++ * Revision 1.10  1998/10/22 06:37:22  rgb
++ * Fixed run-on error message to fit 80 columns.
++ *
++ * Revision 1.9  1998/10/20 02:41:04  rgb
++ * Fixed a replay window size sanity test bug.
++ *
++ * Revision 1.8  1998/10/19 18:55:27  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ * \n bugfix to printk debug message.
++ *
++ * Revision 1.7  1998/10/09 04:23:03  rgb
++ * Fixed possible DoS caused by invalid transform called from an ESP
++ * packet.  This should not be a problem when protocol is added to the SA.
++ * Sanity check added for null xf_input routine.  Sanity check added for null
++ * socket buffer returned from xf_input routine.
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ *
++ * Revision 1.6  1998/07/14 15:56:04  rgb
++ * Set sdb->dev to virtual ipsec I/F.
++ *
++ * Revision 1.5  1998/06/30 18:07:46  rgb
++ * Change for ah/esp_protocol stuct visible only if module.
++ *
++ * Revision 1.4  1998/06/30 00:12:46  rgb
++ * Clean up a module compile error.
++ *
++ * Revision 1.3  1998/06/25 19:28:06  rgb
++ * Readjust premature unloading of module on packet receipt.
++ * Make protocol structure abailable to rest of kernel.
++ * Use macro for protocol number.
++ *
++ * Revision 1.2  1998/06/23 02:49:34  rgb
++ * Fix minor #include bug that prevented compiling without debugging.
++ * Added code to check for presence of IPIP protocol if an incoming packet
++ * is IPIP encapped.
++ *
++ * 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.9  1998/06/14 23:48:42  rgb
++ * Fix I/F name comparison oops bug.
++ *
++ * Revision 1.8  1998/06/11 07:20:04  rgb
++ * Stats fixed for rx_packets.
++ *
++ * Revision 1.7  1998/06/11 05:53:34  rgb
++ * Added stats for rx error and good packet reporting.
++ *
++ * Revision 1.6  1998/06/05 02:27:28  rgb
++ * Add rx_errors stats.
++ * Fix DoS bug:  skb's not being freed on dropped packets.
++ *
++ * Revision 1.5  1998/05/27 21:21:29  rgb
++ * Fix DoS potential bug.  skb was not being freed if the packet was bad.
++ *
++ * Revision 1.4  1998/05/18 22:31:37  rgb
++ * Minor change in debug output and comments.
++ *
++ * Revision 1.3  1998/04/21 21:29:02  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:19  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:59  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
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_rcv.h linux-2.2.14/net/ipsec/ipsec_rcv.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_rcv.h    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_rcv.h Thu Nov 18 05:09:19 1999
+@@ -0,0 +1,150 @@
++/*
++ * 
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#define DB_RX_PKTRX   0x0001
++#define DB_RX_PKTRX2  0x0002
++#define DB_RX_DMP     0x0004
++#define DB_RX_TDB     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__
++#include <linux/module.h>
++#include <linux/config.h>     /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++#include <freeswan.h>
++
++extern int
++ipsec_rcv(struct sk_buff *skb,
++#ifdef NET_21
++        unsigned short xlen);
++#else /* NET_21 */
++        struct device *dev,
++        struct options *opt, 
++        __u32 daddr,
++        unsigned short len,
++        __u32 saddr,
++        int redo,
++        struct inet_protocol *protocol);
++#endif /* NET_21 */
++
++#ifdef DEBUG_IPSEC
++extern int debug_rcv;
++#endif
++#endif __KERNEL__
++
++/*
++ * $Log$
++ * Revision 1.8  1999/11/18 04:09:19  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.7  1999/05/25 01:45:37  rgb
++ * Fix version macros for 2.0.x as a module.
++ *
++ * Revision 1.6  1999/05/08 21:24:27  rgb
++ * Add includes for 2.2.x include into net/ipv4/protocol.c
++ *
++ * Revision 1.5  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.4  1999/04/11 00:28:59  henry
++ * GPL boilerplate
++ *
++ * 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  1999/01/22 20:06:59  rgb
++ * Fixed cut-and-paste error from ipsec_esp.h.
++ *
++ * Revision 1.1  1999/01/21 20:29:12  rgb
++ * Converted from transform switching to algorithm switching.
++ *
++ * Log: ipsec_esp.h,v 
++ * Revision 1.4  1998/08/12 00:07:32  rgb
++ * Added data structures for new xforms: null, {,3}dessha1.
++ *
++ * Revision 1.3  1998/07/14 15:57:01  rgb
++ * Add #ifdef __KERNEL__ to protect kernel-only structures.
++ *
++ * 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:45  henry
++ * move sources from klips/src to klips/net/ipsec, to keep stupid
++ * kernel-build scripts happier in the presence of symlinks
++ *
++ * Revision 1.6  1998/06/05 02:28:08  rgb
++ * Minor comment fix.
++ *
++ * Revision 1.5  1998/05/27 22:34:00  rgb
++ * Changed structures to accomodate key separation.
++ *
++ * 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:20  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:06:00  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.5  1997/06/03 04:24:48  ji
++ * Added ESP-3DES-MD5-96 transform.
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Added definitions for new ESP 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.
++ *
++ *
++ */
++
++
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_sha1.c linux-2.2.14/net/ipsec/ipsec_sha1.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_sha1.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_sha1.c        Mon Dec 13 14:59:13 1999
+@@ -0,0 +1,201 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++ * 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 "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(SHA1_CTX* context)
++{
++    /* 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(SHA1_CTX* context, unsigned char* data, __u32 len)
++{
++__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], SHA1_CTX* context)
++{
++__u32 i, j;
++unsigned char finalcount[8];
++
++    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
++}
++
++
++/*
++ * $Log$
++ * Revision 1.5  1999/12/13 13:59:13  rgb
++ * Quick fix to argument size to Update bugs.
++ *
++ * Revision 1.4  1999/04/11 00:29:00  henry
++ * GPL boilerplate
++ *
++ * 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  1999/01/22 06:55:50  rgb
++ * 64-bit clean-up.
++ *
++ * 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:04  rgb
++ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
++ * verified.
++ *
++ * Revision 1.1  1998/04/09 03:06:11  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.4  1997/01/15 01:28:15  ji
++ * New transform
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_sha1.h linux-2.2.14/net/ipsec/ipsec_sha1.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_sha1.h   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_sha1.h        Mon Dec 13 14:59:13 1999
+@@ -0,0 +1,68 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++ * 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(SHA1_CTX *context);
++void SHA1Update(SHA1_CTX *context, unsigned char *data, __u32 len);
++void SHA1Final(unsigned char digest[20], SHA1_CTX *context);
++
++ 
++#endif /* _IPSEC_SHA1_H_ */
++
++/*
++ * $Log$
++ * 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
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_tunnel.c linux-2.2.14/net/ipsec/ipsec_tunnel.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_tunnel.c Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_tunnel.c      Tue Feb  8 22:21:55 2000
+@@ -0,0 +1,2789 @@
++/*
++ * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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.
++ */
++
++char ipsec_tunnel_c_version[] = "RCSID $Id$";
++
++#define __NO_VERSION__
++#include <linux/module.h>
++#include <linux/config.h>     /* for CONFIG_IP_FORWARD */
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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/tcp.h>         /* struct tcphdr */
++#include <linux/udp.h>         /* struct udphdr */
++#include <linux/skbuff.h>
++#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 */
++#ifdef NET_21
++#define MSS_HACK_             /* experimental */
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#include <net/dst.h>
++#undef dev_kfree_skb
++#define dev_kfree_skb(a,b) kfree_skb(a)
++#define proto_priv cb
++#define PHYSDEV_TYPE
++#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))
++#else /* NET_21 */
++#define DEV_QUEUE_XMIT(skb, device, pri) {\
++      dev_queue_xmit(skb, device, pri); \
++}
++#define ICMP_SEND(skb_in, type, code, info, dev) \
++      icmp_send(skb_in, type, code, info, dev)
++#endif /* NET_21 */
++#include <asm/checksum.h>
++#include <net/icmp.h>         /* icmp_send() */
++#include <net/ip.h>
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++#include "ipsec_tunnel.h"
++#include "ipsec_ipe4.h"
++#include "ipsec_ah.h"
++#include "ipsec_esp.h"
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++
++
++#include <net/ip.h>
++#include <linux/if_arp.h>
++#ifdef MSS_HACK
++#include <net/tcp.h>          /* TCP options */
++#endif        /* MSS_HACK */
++extern void des_cbc_encrypt(caddr_t, caddr_t, int, caddr_t, caddr_t, int);
++extern void des_ede3_cbc_encrypt(caddr_t, caddr_t, int, caddr_t, caddr_t, caddr_t, caddr_t, int);
++static __u32 zeroes[64];
++
++#ifdef DEBUG_IPSEC
++int debug_tunnel = 0;
++#endif /* DEBUG_IPSEC */
++
++#ifdef DEBUG_IPSEC_
++DEBUG_NO_STATIC void
++dmp(char *s, caddr_t bb, int len)
++{
++      int i;
++      unsigned char *b = bb;
++  
++      if (debug_tunnel) {
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_:at %s, len=%d:", s, len);
++              for (i=0; i < len; i++) {
++                      if(!(i%16)){
++                              printk("\nklips_debug:  ");
++                      }
++                      printk(" %02x", *b++);
++              }
++              printk("\n");
++      }
++}
++#else
++#define dmp(_x, _y, _z) 
++#endif
++
++#ifndef SKB_COPY_EXPAND
++/*
++ *    This is mostly skbuff.c:skb_copy().
++ */
++struct sk_buff *
++skb_copy_expand(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,
++                  KERN_INFO "klips_debug:skb_copy_expand: "
++                  "head=%p data=%p tail=%p end=%p end-head=%d\n",
++                  skb->head,
++                  skb->data,
++                  skb->tail,
++                  skb->end,
++                  skb->end - skb->head);
++
++      if(n==NULL)
++              return NULL;
++
++      /*
++       *      Shift between the two data areas in bytes
++       */
++       
++      /* offset=n->head-skb->head; */ /* moved down a few lines */
++
++      /* 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));
++              dev_kfree_skb(n, FREE_WRITE);
++              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->protocol=skb->protocol;
++      n->dst=dst_clone(skb->dst);
++      if(skb->nh.raw)
++              n->nh.raw=skb->nh.raw+offset;
++      n->is_clone=0;
++      atomic_set(&n->users, 1);
++      n->destructor = NULL;
++      n->security=skb->security;
++#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->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));
++      n->used=skb->used;
++      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 DEBUG_IPSEC
++void
++ipsec_print_ip(struct iphdr *ip)
++{
++      char buf[ADDRTOA_BUF];
++
++      printk(KERN_INFO "klips_debug:   IP:");
++      printk(" ihl:%d", ip->ihl*4);
++      printk(" ver:%d", ip->version);
++      printk(" tos:%d", ip->tos);
++      printk(" tlen:%d", ntohs(ip->tot_len));
++      printk(" id:%d", ip->id);
++      printk(" frag_off:%d", ip->frag_off);
++      printk(" ttl:%d", ip->ttl);
++      printk(" proto:%d", ip->protocol);
++      printk(" chk:%d", ip->check);
++      addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
++      printk(" saddr:%s", buf);
++      addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
++      printk(" daddr:%s", buf);
++      printk("\n");
++
++#if 0
++      {
++              __u8 *c;
++              int i;
++              
++              c = ((__u8*)ip) + ip->ihl*4;
++              for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++, c++) {
++                      if(!(i % 16)) {
++                              printk(KERN_INFO "klips_debug:   contents:");
++                      }
++                      printk("%02x ", *c);
++                      if(!((i + 1) % 16)) {
++                              printk("\n");
++                      }
++              }
++              if(i % 16) {
++                      printk("\n");
++              }
++      }
++#endif
++}
++#endif /* DEBUG_IPSEC */
++
++#ifdef REAL_LOCKING_P
++/*
++ *    Locking
++ */
++ 
++DEBUG_NO_STATIC int
++ipsec_tunnel_lock(struct ipsecpriv *prv)
++{
++      unsigned long flags;
++      save_flags(flags);
++      cli();
++      /*
++       *      Lock in an interrupt may fail
++       */
++      if(prv->locked && in_interrupt()) {
++              restore_flags(flags);
++              return 0;
++      }
++      while(prv->locked)
++              sleep_on(&prv->wait_queue);
++      prv->locked=1;
++      restore_flags(flags);
++      return 1;
++}
++
++DEBUG_NO_STATIC void
++ipsec_tunnel_unlock(struct ipsecpriv *prv)
++{
++      prv->locked=0;
++      wake_up(&prv->wait_queue);
++}
++#endif /* REAL_LOCKING_P */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_open(struct 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;
++      
++      MOD_INC_USE_COUNT;
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_close(struct device *dev)
++{
++      MOD_DEC_USE_COUNT;
++      return 0;
++}
++
++#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 */
++                                                        
++/*
++ *    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 device *dev)
++{
++      struct ipsecpriv *prv;          /* Our device' private space */
++      struct sk_buff *oskb = NULL;    /* Original skb pointer */
++      struct enet_statistics *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     max_headroom = 0;       /* The extra header space needed */
++      int     max_tailroom = 0;       /* The extra stuffing needed */
++      int     ll_headroom;            /* The extra link layer hard_header space needed */
++      int     tot_headroom = 0;       /* The total header space needed */
++      int     tot_tailroom = 0;       /* The totalstuffing needed */
++      __u8    *saved_header = NULL;   /* saved copy of the hard header */
++      int i;
++
++      struct sockaddr_encap matcher;  /* eroute search key */
++      struct eroute *er;
++      struct tdb *tdbp, *tdbq;        /* Tunnel Descriptor Block pointers */
++      char sa[SATOA_BUF];
++      size_t sa_len;
++      int hard_header_stripped = 0;   /* has the hard header been removed yet? */
++      int hard_header_len = 0;
++      struct device *physdev;
++/*    struct device *virtdev; */
++      short physmtu;
++      short mtudiff;
++#ifdef NET_21
++      struct rtable *rt = NULL;
++#endif /* NET_21 */
++      unsigned long eroute_flags; /* save irq state for spinlock */
++      struct sa_id outgoing_said;
++
++      /*
++       *      Return if there is nothing to do.  (Does this ever happen?) XXX
++       */
++      if (skb == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          KERN_INFO "klips_error:tunnel: "
++                          "Nothing to do!\n" );
++              goto cleanup;
++      }
++      if (dev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          KERN_INFO "klips_error:tunnel: "
++                          "No device associated with skb!\n" );
++              goto cleanup;
++      }
++
++      prv = dev->priv;
++      if (prv == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          KERN_INFO "klips_error:tunnel: "
++                          "Device has no private structure!\n" );
++              goto cleanup;
++      }
++
++      physdev = prv->dev;
++      if (physdev == NULL) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          KERN_INFO "klips_error:tunnel: "
++                          "Device is not attached to physical device!\n" );
++              goto cleanup;
++      }
++
++      physmtu = physdev->mtu;
++
++      stats = (struct enet_statistics *) &(prv->mystats);
++
++#ifdef NET_21
++      /* 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)) {
++              if ((skb = skb_cow(skb, skb_headroom(skb))) == NULL) {
++                      goto cleanup;
++              }
++      }
++#endif /* NET_21 */
++
++#ifdef NET_21
++      iph = skb->nh.iph;
++#else /* NET_21 */
++      iph = skb->ip_hdr;
++#endif /* NET_21 */
++
++      /* physdev->hard_header_len is unreliable and should not be used */
++      hard_header_len = (unsigned char *)iph - skb->data;
++
++      if(hard_header_len < 0) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          KERN_INFO "klips_error:tunnel: "
++                          "Negative hard_header_len (%d)?!\n", hard_header_len);
++              stats->tx_dropped++;
++              goto cleanup;
++      }
++
++      if(hard_header_len == 0) { /* no hard header present */
++              hard_header_stripped = 1;
++      }
++
++#ifdef DEBUG_IPSEC
++      if (debug_tunnel & DB_TN_XMIT) {
++              int i;
++              char c;
++              
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_start_xmit: "
++                     ">>> skb->len=%ld hard_header_len:%d",
++                     (unsigned long int)skb->len, hard_header_len);
++              c = ' ';
++              for (i=0; i < hard_header_len; i++) {
++                      printk("%c%02x", c, skb->data[i]);
++                      c = ':';
++              }
++              printk(" \n");
++      }
++#endif /* DEBUG_IPSEC */
++
++      KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, iph);
++
++      /*
++       * Sanity checks
++       */
++
++      if ((iph->ihl << 2) != sizeof (struct iphdr)) {
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_start_xmit: "
++                     "cannot process IP header options yet.  "
++                     "May be mal-formed packet.\n"); /* XXX */
++              KLIPS_IP_PRINT(1, iph);
++              stats->tx_dropped++;
++              goto cleanup;
++      }
++      
++#ifndef NET_21
++      /* TTL decrement code (on the way out!) borrowed from ip_forward.c */
++      {
++              unsigned long checksum = iph->check;
++              iph->ttl--;
++      /*
++       *      Re-compute the IP header checksum.
++       *      This is efficient. We know what has happened to the header
++       *      and can thus adjust the checksum as Phil Karn does in KA9Q
++       *      except we do this in "network byte order".
++       */
++              checksum += htons(0x0100);
++              /* carry overflow? */
++              checksum += checksum >> 16;
++              iph->check = checksum;
++      }
++      if (iph->ttl <= 0) {
++              /* Tell the sender its packet died... */
++              ICMP_SEND(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, physdev);
++
++              KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_tunnel_start_xmit: "
++                          "TTL=0, too many hops!\n");
++              stats->tx_dropped++;
++              goto cleanup;
++      }
++#endif /* !NET_21 */
++
++      /*
++       * Quick cheat for now...are we udp/500? If so, let it through
++       * without interference since it is most likely an IKE packet.
++       */
++      if(iph->protocol == IPPROTO_UDP) {
++              struct udphdr *udph = (struct udphdr*)((caddr_t)iph + (iph->ihl << 2));
++              if(ntohs(udph->dest) == 500) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "udp/500 IKE packet, sending unprocessed, "
++                                  "calling dev_queue_xmit\n"); 
++                      DEV_QUEUE_XMIT(skb, physdev, SOPRI_NORMAL);
++                              /* does this need to be freed? */
++                      skb = NULL;
++                      goto cleanup;
++              }
++      }
++
++      /*
++       * First things first -- look us up in the erouting tables.
++       */
++      matcher.sen_len = sizeof (struct sockaddr_encap);
++      matcher.sen_family = AF_ENCAP;
++      matcher.sen_type = SENT_IP4;
++      matcher.sen_ip_src.s_addr = iph->saddr;
++      matcher.sen_ip_dst.s_addr = iph->daddr;
++
++      /*
++       * The spinlock is to prevent any other process from accessing or deleting
++       * the eroute while we are using and updating it.
++       */
++      spin_lock_irqsave(&eroute_lock, eroute_flags);
++      
++      er = ipsec_findroute(&matcher);
++      if(er) {
++              outgoing_said = er->er_said;
++      }
++
++      spin_unlock_irqrestore(&eroute_lock, eroute_flags);
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_tunnel_start_xmit: "
++                  "Original head/tailroom: %d, %d\n",
++                  skb_headroom(skb), skb_tailroom(skb));
++
++      innersrc = iph->saddr;
++      /* start encapsulation loop here XXX */
++      do {
++              unsigned long tdb_flags; /* save irq state for spinlock */
++
++              newdst = orgdst = iph->daddr;
++              newsrc = orgsrc = iph->saddr;
++              orgedst = outgoing_said.dst.s_addr;
++              iphlen = iph->ihl << 2;
++              pyldsz = ntohs(iph->tot_len) - iphlen;
++              max_headroom = max_tailroom = 0;
++              
++              if (er == NULL) {
++#if ROUTE_WITH_NO_EROUTE
++#ifdef DEBUG_IPSEC
++                      if (debug_tunnel & DB_TN_XMIT) {
++                              struct timeval tv;
++                              do_gettimeofday(&tv);
++                              printk(KERN_INFO "klips_debug:ipsec_tunnel_start_xmit: "
++                                     "no eroute!: ts=%02d.%04d calling dev_queue_xmit\n", 
++                                     tv.tv_sec % 60, tv.tv_usec / 100);
++                      }
++#endif /* DEBUG_IPSEC */
++                      DEV_QUEUE_XMIT(skb, physdev, SOPRI_NORMAL);
++                      skb = NULL;
++#else /* ROUTE_WITH_NO_EROUTE */
++#ifdef DEBUG_IPSEC
++                      if (debug_tunnel & DB_TN_XMIT) {
++                              struct timeval tv;
++                              do_gettimeofday(&tv);
++                              printk(KERN_INFO "klips_debug:ipsec_tunnel_start_xmit: "
++                                     "no eroute!: ts=%02ld.%04ld, dropping.\n", 
++                                     (unsigned long int)tv.tv_sec % 60,
++                                     (unsigned long int)tv.tv_usec / 100);
++                      }
++#endif /* DEBUG_IPSEC */
++                      stats->tx_dropped++;
++#endif /* ROUTE_WITH_NO_EROUTE */
++                      goto cleanup;
++              }
++              
++              /*
++                If the packet matches an eroute with an SA.proto of IP
++                tunnelling and 
++                an SA.spi of '0', then forward the packet unprotected.
++                XXX -- This should eventually go into an SPD. 
++              */
++              if((outgoing_said.proto == IPPROTO_IPIP) && (outgoing_said.spi == 0)) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "passthrough eroute, packet sent.\n");
++                      DEV_QUEUE_XMIT(skb, physdev, SOPRI_NORMAL);
++                              /* does this need to be freed? */
++                      skb = NULL;
++                      goto cleanup;
++              }
++              
++              /*
++               * The spinlock is to prevent any other process from accessing or deleting
++               * the tdb while we are using and updating it.
++               */
++              spin_lock_irqsave(&tdb_lock, tdb_flags);
++
++              tdbp = gettdb(&outgoing_said);
++              sa_len = satoa(outgoing_said, 0, sa, SATOA_BUF);
++
++              if (tdbp == NULL) {
++                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "no Tunnel Descriptor Block for SA%s: "
++                                  "outgoing packet with no SA, dropped.\n", sa);
++                      stats->tx_dropped++;
++                      goto cleanup;
++              }
++              
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "found Tunnel Descriptor Block -- SA:<%s%s%s> %s\n",
++                          TDB_XFORM_NAME(tdbp), sa);
++              
++              /*
++               * How much headroom do we need to be able to apply
++               * all the grouped transforms?
++               */
++              tdbq = tdbp;    /* save the head of the tdb chain */
++              while (tdbp)    {
++                      sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++                      /* If it is in larval state, drop the packet, we cannot process yet. */
++                      if(tdbp->tdb_state == SADB_SASTATE_LARVAL) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "TDB in larval state for SA:<%s%s%s> %s, "
++                                          "cannot be used yet, dropping packet.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++
++                      if(tdbp->tdb_state == SADB_SASTATE_DEAD) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "TDB in dead state for SA:<%s%s%s> %s, "
++                                          "can no longer be used, dropping packet.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++
++                      /* If the replay window counter == -1, expire SA, it will roll */
++                      if(tdbp->tdb_replaywin && tdbp->tdb_replaywin_lastseq == -1) {
++                              /* pfkey_expire(tdbp) */;
++                              deltdbchain(tdbp);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "replay window counter rolled for SA:<%s%s%s> %s, "
++                                          "packet dropped, expiring SA.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++                      /* If any of the lifetime counters have overflowed, expire the SA(s). */
++                      if(tdbp->tdb_lifetime_bytes_s &&
++                         (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_s)) {
++                              /* pfkey_expire(tdbp) */;
++                              tdbp->tdb_state = SADB_SASTATE_DYING;
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "soft bytes lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expiring, soft expire message sent up, "
++                                          "outgoing packet still processed.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                      }
++                      if(tdbp->tdb_lifetime_bytes_h &&
++                         (tdbp->tdb_lifetime_bytes_c > tdbp->tdb_lifetime_bytes_h)) {
++                              /* pfkey_expire(tdbp) */;
++                              deltdbchain(tdbp);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "hard bytes lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expired, outgoing packet dropped.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++
++                      if(tdbp->tdb_lifetime_addtime_s &&
++                         ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c >
++                          tdbp->tdb_lifetime_addtime_s)) {
++                              /* pfkey_expire(tdbp) */;
++                              tdbp->tdb_state = SADB_SASTATE_DYING;
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "soft addtime lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expiring, soft expire message sent up, "
++                                          "outgoing packet still processed.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                      }
++                      if(tdbp->tdb_lifetime_addtime_h &&
++                         ((jiffies / HZ) - tdbp->tdb_lifetime_addtime_c >
++                          tdbp->tdb_lifetime_addtime_h)) {
++                              /* pfkey_expire(tdbp) */;
++                              deltdbchain(tdbp);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "hard addtime lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expired, outgoing packet dropped.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++
++                      if(tdbp->tdb_lifetime_usetime_s &&
++                         ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c >
++                          tdbp->tdb_lifetime_usetime_s)) {
++                              /* pfkey_expire(tdbp) */;
++                              tdbp->tdb_state = SADB_SASTATE_DYING;
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "soft usetime lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expiring, soft expire message sent up, "
++                                          "outgoing packet still processed.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                      }
++                      if(tdbp->tdb_lifetime_usetime_h &&
++                         ((jiffies / HZ) - tdbp->tdb_lifetime_usetime_c >
++                          tdbp->tdb_lifetime_usetime_h)) {
++                              /* pfkey_expire(tdbp) */;
++                              deltdbchain(tdbp);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "hard usetime lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expired, outgoing packet dropped.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++
++                      if(tdbp->tdb_lifetime_packets_s &&
++                         (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_s)) {
++                              /* pfkey_expire(tdbp) */;
++                              tdbp->tdb_state = SADB_SASTATE_DYING;
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "soft packets lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expiring, soft expire message sent up, "
++                                          "outgoing packet still processed.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                      }
++                      if(tdbp->tdb_lifetime_packets_h &&
++                         (tdbp->tdb_lifetime_packets_c > tdbp->tdb_lifetime_packets_h)) {
++                              /* pfkey_expire(tdbp) */;
++                              deltdbchain(tdbp);
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "hard packets lifetime of SA:<%s%s%s> %s has been reached, "
++                                          "SA expired, outgoing packet dropped.\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++#endif /* CONFIG_IPSEC_PFKEYv2 */
++
++                      headroom = tailroom = 0;
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "calling room for <%s%s%s>, SA:%s\n", 
++                                  TDB_XFORM_NAME(tdbp), sa);
++                      switch(tdbp->tdb_said.proto) {
++#ifdef CONFIG_IPSEC_AH
++                      case IPPROTO_AH:
++                              headroom += sizeof(struct ah);
++                              break;
++#endif /* CONFIG_IPSEC_AH */
++#ifdef CONFIG_IPSEC_ESP
++                      case IPPROTO_ESP:
++                              switch(tdbp->tdb_encalg) {
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case ESP_DES:
++                                      headroom += sizeof(struct esp);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case ESP_3DES:
++                                      headroom += sizeof(struct esp);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_3DES */
++#ifdef CONFIG_IPSEC_ENC_NULL
++                              case ESP_NULL:
++                                      headroom += offsetof(struct esp, esp_iv);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                              switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              case AH_MD5:
++                                      tailroom += AHHMAC_HASHLEN;
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              case AH_SHA:
++                                      tailroom += AHHMAC_HASHLEN;
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                              case AH_NONE:
++                                      break;
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }                       
++                              tailroom += ((8 - ((pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
++                              break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_IPIP
++                      case IPPROTO_IPIP:
++                              headroom += sizeof(struct iphdr);
++                              break;
++#endif /* !CONFIG_IPSEC_IPIP */
++                      default:
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      tdbp = tdbp->tdb_onext;
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "Required head/tailroom: %d,%d\n", 
++                                  headroom, tailroom);
++                      max_headroom += headroom;
++                      max_tailroom += tailroom;
++                      pyldsz += (headroom + tailroom);
++              }
++              tdbp = tdbq;    /* restore the head of the tdb chain */
++              
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "existing head/tailroom: %d, %d"
++                          " before applying xforms with %d, %d head/tailroom.\n",
++                          skb_headroom(skb), skb_tailroom(skb),
++                          max_headroom, max_tailroom);
++              
++              tot_headroom += max_headroom;
++              tot_tailroom += max_tailroom;
++              
++              mtudiff = prv->mtu + tot_headroom + tot_tailroom - physmtu;
++
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_tunnel_start_xmit: mtu:%d physmtu:%d "
++                          "tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
++                          prv->mtu, physmtu,
++                          tot_headroom, tot_tailroom, mtudiff, ntohs(iph->tot_len));
++              if(mtudiff > 0) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_info:ipsec_tunnel_start_xmit: "
++                                  "dev %s mtu of %d decreased by %d\n",
++                                  dev->name,
++                                  prv->mtu,
++                                  prv->mtu - (physmtu - tot_headroom - tot_tailroom));
++                      prv->mtu = physmtu - (tot_headroom + tot_tailroom + 7); /* add some slop? */
++#ifdef NET_21
++#if 0
++                      skb->dst->pmtu = prv->mtu; /* RGB */
++#endif /* 0 */
++#else /* NET_21 */
++#if 0
++                      dev->mtu = prv->mtu; /* RGB */
++#endif /* 0 */
++#endif /* NET_21 */
++              }
++              
++#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 (iph->protocol == IPPROTO_TCP 
++                  && outgoing_said.proto != IPPROTO_IPIP) {
++                      struct tcphdr *tcph = skb->h.th;
++                      if (tcph->syn && !tcph->ack) {
++                              if(!ipsec_adjust_mss(skb, tcph, prv->mtu)) {
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      printk(KERN_WARNING "klips: "
++                                             "ipsec_adjust_mss() failed\n");
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                      }
++              }
++#endif /* MSS_HACK */
++              /* spin_unlock_irqrestore(&eroute_lock, eroute_flags); */
++              
++              if(!hard_header_stripped) {
++                      if((saved_header = kmalloc(hard_header_len, GFP_ATOMIC)) == NULL) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              printk(KERN_WARNING "klips_debug:ipsec_tunnel_start_xmit: Failed, "
++                                     "tried to allocate %d bytes for temp hard_header.\n", 
++                                     hard_header_len);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      for (i = 0; i < hard_header_len; i++) {
++                              saved_header[i] = skb->data[i];
++                      }
++                      if(skb->len < hard_header_len) {
++                              printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                                     "tried to skb_pull hhlen=%d, %d available.  "
++                                     "This should never happen, please report.\n",
++                                     hard_header_len, (int)(skb->len));
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      skb_pull(skb, hard_header_len);
++                      hard_header_stripped = 1;
++                      
++/*                    iph = (struct iphdr *) (skb->data); */
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "head/tailroom: %d, %d after hard_header stripped.\n",
++                                  skb_headroom(skb), skb_tailroom(skb));
++                      KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, iph);
++              } else {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "hard header already stripped.\n");
++              }
++              
++              ll_headroom = (hard_header_len + 15) & ~15;
++
++              if ((skb_headroom(skb) >= max_headroom + 2 * ll_headroom) && 
++                  (skb_tailroom(skb) >= max_tailroom)
++#ifndef NET_21
++                      && skb->free
++#endif /* !NET_21 */
++                      ) {
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "data fits in existing skb\n");
++              } else {
++                      struct sk_buff* tskb = skb;
++
++                      if(!oskb) {
++                              oskb = skb;
++                      }
++
++                      tskb = skb_copy_expand(skb,
++                      /* The reason for 2 * link layer length here still baffles me...RGB */
++                                             max_headroom + 2 * ll_headroom,
++                                             max_tailroom,
++                                             GFP_ATOMIC);
++#ifdef NET_21
++                      if(tskb && skb->sk) {
++                              skb_set_owner_w(tskb, skb->sk);
++                      }
++#endif /* NET_21 */
++                      if(!(skb == oskb) ) {
++                              dev_kfree_skb(skb, FREE_WRITE);
++                      }
++                      skb = tskb;
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "head/tailroom: %d, %d after allocation\n",
++                                  skb_headroom(skb), skb_tailroom(skb));
++                      if (!skb) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              printk(KERN_WARNING "klips_debug:ipsec_tunnel_start_xmit: Failed, "
++                                     "tried to allocate %d head and %d tailroom\n", 
++                                     max_headroom, max_tailroom);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++              }
++              
++              /*
++               * Apply grouped transforms to packet
++               */
++              while (tdbp) {
++#ifdef CONFIG_IPSEC_ESP
++                      struct esp *espp;
++                      __u32 iv[2];
++                      unsigned char *idat, *pad;
++                      int authlen = 0, padlen = 0, i;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++                      struct iphdr ipo;
++                      struct ah *ahp;
++#endif /* CONFIG_IPSEC_AH */
++                      union {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              MD5_CTX md5;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              SHA1_CTX sha1;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                      } tctx;
++                      __u8 hash[AH_AMAX];
++                      int headroom = 0, tailroom = 0, ilen = 0, len = 0;
++                      unsigned char *dat;
++                      
++                      iphlen = iph->ihl << 2;
++                      pyldsz = ntohs(iph->tot_len) - iphlen;
++                      sa_len = satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                      KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "calling output for <%s%s%s>, SA:%s\n", 
++                                  /* tdbp->tdb_xform->xf_name */
++                                  TDB_XFORM_NAME(tdbp), sa);
++                      
++                      switch(tdbp->tdb_said.proto) {
++#ifdef CONFIG_IPSEC_AH
++                      case IPPROTO_AH:
++                              headroom += sizeof(struct ah);
++                              break;
++#endif /* CONFIG_IPSEC_AH */
++#ifdef CONFIG_IPSEC_ESP
++                      case IPPROTO_ESP:
++                              switch(tdbp->tdb_encalg) {
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case ESP_DES:
++                                      headroom += sizeof(struct esp);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case ESP_3DES:
++                                      headroom += sizeof(struct esp);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_3DES */
++#ifdef CONFIG_IPSEC_ENC_NULL
++                              case ESP_NULL:
++                                      headroom += offsetof(struct esp, esp_iv);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                              switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              case AH_MD5:
++                                      authlen = AHHMAC_HASHLEN;
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              case AH_SHA:
++                                      authlen = AHHMAC_HASHLEN;
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                              case AH_NONE:
++                                      break;
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }               
++                              tailroom += ((8 - ((pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
++                              tailroom += authlen;
++                              break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_IPIP
++                      case IPPROTO_IPIP:
++                              headroom += sizeof(struct iphdr);
++                              break;
++#endif /* !CONFIG_IPSEC_IPIP */
++                      default:
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "pushing %d bytes, putting %d, proto %d.\n", 
++                                  headroom, tailroom, tdbp->tdb_said.proto);
++                      if(skb_headroom(skb) < headroom) {
++                              printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                                     "tried to skb_push headroom=%d, %d available.  "
++                                     "This should never happen, please report.\n",
++                                     headroom, skb_headroom(skb));
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      dat = skb_push(skb, headroom);
++                      ilen = skb->len - tailroom;
++                      if(skb_tailroom(skb) < tailroom) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                                     "tried to skb_put %d, %d available.  "
++                                     "This should never happen, please report.\n",
++                                     tailroom, skb_tailroom(skb));
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      skb_put(skb, tailroom);
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "head/tailroom: %d, %d before xform.\n",
++                                  skb_headroom(skb), skb_tailroom(skb));
++                      len = skb->len;
++                      if(len > 0xfff0) {
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                                     "tot_len (%d) > 65520.  "
++                                     "This should never happen, please report.\n",
++                                     len);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      memmove((void *)dat, (void *)(dat + headroom), iphlen);
++                      iph = (struct iphdr *)dat;
++                      iph->tot_len = htons(skb->len);
++                      
++                      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "packet contents before xform:\n");
++                      KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, iph);
++                      
++                      switch(tdbp->tdb_said.proto) {
++#ifdef CONFIG_IPSEC_ESP
++                      case IPPROTO_ESP:
++                              espp = (struct esp *)(dat + iphlen);
++                              espp->esp_spi = tdbp->tdb_spi;
++                              espp->esp_rpl = htonl(++(tdbp->tdb_replaywin_lastseq));
++                              
++                              switch(tdbp->tdb_encalg) {
++#if defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES)
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case ESP_DES:
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case ESP_3DES:
++#endif /* CONFIG_IPSEC_ENC_3DES */
++                                      iv[0] = *((__u32*)&(espp->esp_iv)    ) =
++                                              ((__u32*)(tdbp->tdb_iv))[0];
++                                      iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
++                                              ((__u32*)(tdbp->tdb_iv))[1];
++                                      break;
++#endif /* defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES) */
++#ifdef CONFIG_IPSEC_ENC_NULL
++                              case ESP_NULL:
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                              
++                              idat = dat + iphlen + headroom;
++                              ilen = len - (iphlen + headroom + authlen);
++                              
++                              /* Self-describing padding */
++                              pad = &dat[len - tailroom];
++                              padlen = tailroom - 2 - authlen;
++                              for (i = 0; i < padlen; i++) {
++                                      pad[i] = i + 1; 
++                              }
++                              dat[len - authlen - 2] = padlen;
++                              
++                              dat[len - authlen - 1] = iph->protocol;
++                              iph->protocol = IPPROTO_ESP;
++                              
++                              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                          "klips_debug:ipsec_tunnel_start_xmit: "
++                                          "before <%s%s%s>, SA:%s:\n",
++                                          TDB_XFORM_NAME(tdbp), sa);
++                              KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, iph);
++                              
++                              switch(tdbp->tdb_encalg) {
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case ESP_DES:
++                                      des_cbc_encrypt(idat, idat, ilen,
++                                                      (caddr_t)tdbp->tdb_key_e,
++                                                      (caddr_t)iv, 1);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case ESP_3DES:
++                                      des_ede3_cbc_encrypt(idat, idat, ilen,
++                                                           (caddr_t)(&((struct des_eks*)(tdbp->tdb_key_e))[0]),
++                                                           (caddr_t)(&((struct des_eks*)(tdbp->tdb_key_e))[1]),
++                                                           (caddr_t)(&((struct des_eks*)(tdbp->tdb_key_e))[2]),
++                                                           (caddr_t)iv, 1);
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_3DES */
++#ifdef CONFIG_IPSEC_ENC_NULL
++                              case ESP_NULL:
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                              
++                              switch(tdbp->tdb_encalg) {
++#if defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES)
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case ESP_DES:
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case ESP_3DES:
++#endif /* CONFIG_IPSEC_ENC_3DES */
++                                      /* XXX update IV with the last 8 octets of the encryption */
++                                      ((__u32*)(tdbp->tdb_iv))[0] =
++                                              ((__u32 *)(idat))[(ilen >> 2) - 2];
++                                      ((__u32*)(tdbp->tdb_iv))[1] =
++                                              ((__u32 *)(idat))[(ilen >> 2) - 1];
++                                      break;
++#endif /* defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES) */
++#ifdef CONFIG_IPSEC_ENC_NULL
++                              case ESP_NULL:
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++                              
++                              switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              case AH_MD5:
++                                      dmp("espp", (char*)espp, len - iphlen - authlen);
++                                      tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;
++                                      dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, (caddr_t)espp, len - iphlen - authlen);
++                                      dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Final(hash, &tctx.md5);
++                                      dmp("ictx hash", (char*)&hash, sizeof(hash));
++                                      tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx;
++                                      dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, hash, AHMD596_ALEN);
++                                      dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Final(hash, &tctx.md5);
++                                      dmp("octx hash", (char*)&hash, sizeof(hash));
++                                      memcpy(&(dat[len - authlen]), hash, authlen);
++
++                                      /* paranoid */
++                                      memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
++                                      memset((caddr_t)hash, 0, sizeof(*hash));
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              case AH_SHA:
++                                      tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->ictx;
++                                      SHA1Update(&tctx.sha1, (caddr_t)espp, len - iphlen - authlen);
++                                      SHA1Final(hash, &tctx.sha1);
++                                      tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->octx;
++                                      SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
++                                      SHA1Final(hash, &tctx.sha1);
++                                      memcpy(&(dat[len - authlen]), hash, authlen);
++                                      
++                                      /* paranoid */
++                                      memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
++                                      memset((caddr_t)hash, 0, sizeof(*hash));
++                                      break;
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                              case AH_NONE:
++                                      break;
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++#ifdef NET_21
++                              skb->h.raw = (unsigned char*)espp;
++#endif /* NET_21 */
++                              break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_AH
++                      case IPPROTO_AH:
++                              ahp = (struct ah *)(dat + iphlen);
++                              ahp->ah_spi = tdbp->tdb_spi;
++                              ahp->ah_rpl = htonl(++(tdbp->tdb_replaywin_lastseq));
++                              ahp->ah_rv = 0;
++                              ahp->ah_nh = iph->protocol;
++                              ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
++                              iph->protocol = IPPROTO_AH;
++                              dmp("ahp", (char*)ahp, sizeof(*ahp));
++                              
++                              ipo = *iph;
++                              ipo.tos = 0;
++                              ipo.frag_off = 0;
++                              ipo.ttl = 0;
++                              ipo.check = 0;
++                              dmp("ipo", (char*)&ipo, sizeof(ipo));
++                              
++                              switch(tdbp->tdb_authalg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              case AH_MD5:
++                                      tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;
++                                      dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
++                                      dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
++                                      dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++                                      dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5,  dat + iphlen + headroom, len - iphlen - headroom);
++                                      dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Final(hash, &tctx.md5);
++                                      dmp("ictx hash", (char*)&hash, sizeof(hash));
++                                      tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx;
++                                      dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Update(&tctx.md5, hash, AHMD596_ALEN);
++                                      dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
++                                      MD5Final(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_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              case AH_SHA:
++                                      tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_key_a))->ictx;
++                                      SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
++                                      SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
++                                      SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
++                                      SHA1Update(&tctx.sha1,  dat + iphlen + headroom, len - iphlen - headroom);
++                                      SHA1Final(hash, &tctx.sha1);
++                                      tctx.sha1 = ((struct sha1_ctx*)(tdbp->tdb_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_IPSEC_AUTH_HMAC_SHA1 */
++                              default:
++                                      spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                                      stats->tx_errors++;
++                                      goto cleanup;
++                              }
++#ifdef NET_21
++                              skb->h.raw = (unsigned char*)ahp;
++#endif /* NET_21 */
++                              break;
++#endif /* CONFIG_IPSEC_AH */
++#ifdef CONFIG_IPSEC_IPIP
++                      case IPPROTO_IPIP:
++                              iph->version  = 4; /* const should be used here */
++#ifdef NET_21
++                              iph->tos      = skb->nh.iph->tos; /* XXX is this right? */
++#else /* NET_21 */
++                              iph->tos      = skb->ip_hdr->tos; /* XXX is this right? */
++#endif /* NET_21 */
++                              iph->ttl      = 64; /* ip_statistics.IpDefaultTTL; */
++                              iph->frag_off = 0;
++                              iph->saddr    = ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr.s_addr;
++                              iph->daddr    = ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr.s_addr;
++                              iph->protocol = IPPROTO_IPIP;
++                              iph->ihl      = sizeof(struct iphdr) >> 2 /* 5 */;
++#ifdef IP_SELECT_IDENT
++                              /* XXX use of skb->dst below is a questionable substitute
++                                 for &rt->u.dst which is only available later-on */
++                              ip_select_ident(iph, skb->dst);
++#else
++                              iph->id       = htons(ip_id_count++);   /* Race condition here? */
++#endif
++
++                              newdst = (__u32)iph->daddr;
++                              newsrc = (__u32)iph->saddr;
++              
++#ifdef NET_21
++                              skb->h.ipiph = skb->nh.iph;
++#endif /* NET_21 */
++                              break;
++#endif /* !CONFIG_IPSEC_IPIP */
++                      default:
++                              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++                              stats->tx_errors++;
++                              goto cleanup;
++                      }
++                      
++#ifdef NET_21
++                      skb->nh.raw = skb->data;
++#else /* NET_21 */
++                      skb->ip_hdr = skb->h.iph = (struct iphdr *) skb->data;
++#endif /* NET_21 */
++                      iph->check = 0;
++                      iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++                      
++                      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                                  "klips_debug:ipsec_tunnel_start_xmit: "
++                                  "after <%s%s%s>, SA:%s:\n",
++                                  TDB_XFORM_NAME(tdbp), sa);
++                      KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, iph);
++                      
++                      tdbp->tdb_lifetime_bytes_c += len;
++                      if(!tdbp->tdb_lifetime_usetime_c) {
++                              tdbp->tdb_lifetime_usetime_c = jiffies / HZ;
++                      }
++                      tdbp->tdb_lifetime_usetime_l = jiffies / HZ;
++                      tdbp->tdb_lifetime_packets_c += 1;
++
++                      tdbp = tdbp->tdb_onext;
++                      
++              }
++              /* end encapsulation loop here XXX */
++
++              spin_unlock_irqrestore(&tdb_lock, tdb_flags);
++
++              matcher.sen_ip_src.s_addr = iph->saddr;
++              matcher.sen_ip_dst.s_addr = iph->daddr;
++              spin_lock_irqsave(&eroute_lock, eroute_flags);
++              er = ipsec_findroute(&matcher);
++              if(er) {
++                      outgoing_said = er->er_said;
++              }
++              spin_unlock_irqrestore(&eroute_lock, eroute_flags);
++              KLIPS_PRINT(/* ((orgdst != newdst) || (orgsrc != newsrc)) */
++                      (orgedst != outgoing_said.dst.s_addr) &&
++                      outgoing_said.dst.s_addr &&
++                      er &&
++                      (debug_tunnel & DB_TN_XMIT),
++                      "klips_debug:ipsec_tunnel_start_xmit: We are recursing here.\n");
++      } while(/*((orgdst != newdst) || (orgsrc != newsrc))*/
++              (orgedst != outgoing_said.dst.s_addr) &&
++              outgoing_said.dst.s_addr &&
++              er);
++      
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_tunnel_start_xmit: "
++                  "After recursive xforms -- head/tailroom: %d, %d\n",
++                  skb_headroom(skb), skb_tailroom(skb));
++
++#if CONFIG_IPSEC_ICMP
++      if((innersrc != newsrc) && (ntohs(iph->tot_len) > physmtu)) {
++              ICMP_SEND(oskb ? oskb : skb,
++                        ICMP_DEST_UNREACH,
++                        ICMP_FRAG_NEEDED,
++                        prv->mtu,
++                        physdev);
++              KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "IPSEC tunnel mode packet is larger than MTU, ICMP sent.\n");
++      }
++#endif /* CONFIG_IPSEC_ICMP */
++
++      if(saved_header) {
++              if(skb_headroom(skb) < hard_header_len) {
++                      printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                             "tried to skb_push hhlen=%d, %d available.  "
++                             "This should never happen, please report.\n",
++                             hard_header_len, skb_headroom(skb));
++                      stats->tx_errors++;
++                      goto cleanup;
++              }
++              skb_push(skb, hard_header_len);
++              for (i = 0; i < hard_header_len; i++) {
++                      skb->data[i] = saved_header[i];
++              }
++      }
++      KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
++                  "klips_debug:ipsec_tunnel_start_xmit: "
++                  "With hard_header, final head/tailroom: %d, %d\n",
++                  skb_headroom(skb), skb_tailroom(skb));
++#ifdef DEBUG_IPSEC
++      if (debug_tunnel & DB_TN_CROUT) {
++              struct timeval tv;
++              do_gettimeofday(&tv);
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_start_xmit: "
++                     "ts=%02ld.%04ld calling dev_queue_xmit\n", 
++                     (unsigned long int)tv.tv_sec % 60,
++                     (unsigned long int)tv.tv_usec / 100);
++      }
++#endif /* DEBUG_IPSEC */
++
++#ifdef NET_21
++      /* new route/dst cache code from James Morris */
++      skb->dev = physdev;
++      /*skb_orphan(skb);*/
++      if(ip_route_output(&rt,
++                         skb->nh.iph->daddr,
++                         skb->nh.iph->saddr,
++                         RT_TOS(skb->nh.iph->tos),
++                         physdev->iflink)) {
++              stats->tx_errors++;
++              goto cleanup;
++      }
++      if(dev == rt->u.dst.dev) {
++              ip_rt_put(rt);
++              /* This is recursion, drop it. */
++              stats->tx_errors++;
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n", dev->name);
++              goto cleanup;
++      }
++      dst_release(skb->dst);
++      skb->dst = &rt->u.dst;
++      stats->tx_bytes += skb->len;
++      if(skb->len < skb->nh.raw - skb->data) {
++              printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
++                     "tried to __skb_pull nh-data=%d, %d available.  "
++                     "This should never happen, please report.\n",
++                     skb->nh.raw - skb->data, skb->len);
++              stats->tx_errors++;
++              goto cleanup;
++      }
++      __skb_pull(skb, skb->nh.raw - skb->data);
++      /* if(skb->len > skb->dst->pmtu) */
++      KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                  "klips_debug:ipsec_tunnel_start_xmit: "
++                  "...done, calling ip_send()\n");
++      ip_send(skb);
++#else /* NET_21 */
++      skb->arp = 1;
++      if(ntohs(iph->tot_len) > physmtu)
++      {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "calling ip_fragment()\n");
++              ip_fragment(NULL, skb, physdev, 0);
++              dev_kfree_skb(skb, FREE_WRITE);
++      } else {
++              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
++                          "klips_debug:ipsec_tunnel_start_xmit: "
++                          "...done, calling dev_queue_xmit()\n");
++              dev_queue_xmit(skb, physdev, SOPRI_NORMAL);
++      }
++#endif /* NET_21 */
++      stats->tx_packets++;
++
++      skb = NULL;
++ cleanup:
++      dev->tbusy = 0;
++      if(saved_header)
++              kfree_s(saved_header, hard_header_len);
++      if(skb) {
++              dev_kfree_skb(skb, FREE_WRITE);
++      }
++      if(oskb)
++              dev_kfree_skb(oskb, FREE_WRITE);
++      return 0;
++}
++
++DEBUG_NO_STATIC struct enet_statistics *
++ipsec_tunnel_get_stats(struct 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 device *dev,
++      unsigned short type, void *daddr, void *saddr, unsigned len)
++{
++      struct ipsecpriv *prv = dev->priv;
++      struct device *tmp;
++      int ret;
++
++      if(!prv->hard_header) {
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "klips_debug:ipsec_tunnel_hard_header: "
++                          "physical device has been detached, packet dropped "
++                          "0x%p->0x%p len=%d type=%d dev=%s->NULL ",
++                          saddr, daddr, len, type, dev->name);
++#ifdef NET_21
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08lx->%08lx\n",
++                          ntohl(skb->nh.iph->saddr), ntohl(skb->nh.iph->daddr) );
++#else /* NET_21 */
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08lx->%08lx\n",
++                          ntohl(skb->ip_hdr->saddr), ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++              return -ENODEV;
++      }
++
++#define da ((struct device *)(prv->dev))->dev_addr
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel_hard_header: "
++                  "Revectored 0x%p->0x%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_PRINT(debug_tunnel & DB_TN_REVEC,
++                              "ip=%08lx->%08lx\n",
++                  ntohl(skb->nh.iph->saddr), ntohl(skb->nh.iph->daddr) );
++#else /* NET_21 */
++                  KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                              "ip=%08lx->%08lx\n",
++                  ntohl(skb->ip_hdr->saddr), ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++      tmp = skb->dev;
++      skb->dev = prv->dev;
++      ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
++      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 device *dev,
++                      unsigned long raddr, struct sk_buff *skb)
++#endif /* NET_21 */
++{
++      struct ipsecpriv *prv = skb->dev->priv;
++      struct device *tmp;
++      int ret;
++      
++      if(!prv->rebuild_header) {
++              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=%08lx->%08lx\n",
++                          ntohl(skb->nh.iph->saddr), ntohl(skb->nh.iph->daddr) );
++#else /* NET_21 */
++              KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                          "ip=%08lx->%08lx\n",
++                          ntohl(skb->ip_hdr->saddr), ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++              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=%08lx->%08lx\n",
++                  ntohl(skb->nh.iph->saddr), ntohl(skb->nh.iph->daddr) );
++#else /* NET_21 */
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "ip=%08lx->%08lx\n",
++                  ntohl(skb->ip_hdr->saddr), ntohl(skb->ip_hdr->daddr) );
++#endif /* NET_21 */
++      tmp = skb->dev;
++      skb->dev = prv->dev;
++      
++#ifdef NET_21
++      ret = prv->rebuild_header(skb);
++#else /* NET_21 */
++      ret = prv->rebuild_header(buff, prv->dev, raddr, skb);
++#endif /* NET_21 */
++      skb->dev = tmp;
++      return ret;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_set_mac_address(struct device *dev, void *addr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      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=%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 device *dev,
++                               unsigned short htype, __u32 daddr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      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);
++              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, struct device *dev, unsigned char *  haddr)
++{
++      struct ipsecpriv *prv = dev->priv;
++      
++      if(!prv->header_cache_update) {
++              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");
++      prv->header_cache_update(hh, prv->dev, haddr);
++      return;
++}
++
++/*
++ * We call the attach routine to attach another device.
++ */
++
++#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: "
++                  "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 device *dev, struct neigh_parms *p)
++{
++      KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
++                  "klips_debug:ipsec_tunnel: "
++                  "ipsec_tunnel_neigh_setup_dev\n");
++
++        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 */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_attach(struct device *tndev, struct ipsecpriv *prv, struct device *dev)
++{
++        int i;
++
++      prv->dev = dev;
++      prv->hard_start_xmit = dev->hard_start_xmit;
++      prv->get_stats = dev->get_stats;
++
++      if (dev->hard_header) {
++              prv->hard_header = dev->hard_header;
++              tndev->hard_header = ipsec_tunnel_hard_header;
++      } else
++              tndev->hard_header = NULL;
++      
++      if (dev->rebuild_header) {
++              prv->rebuild_header = dev->rebuild_header;
++              tndev->rebuild_header = ipsec_tunnel_rebuild_header;
++      } else
++              tndev->rebuild_header = NULL;
++      
++      if (dev->set_mac_address) {
++              prv->set_mac_address = dev->set_mac_address;
++              tndev->set_mac_address = ipsec_tunnel_set_mac_address;
++      } else
++              tndev->set_mac_address = NULL;
++      
++#ifndef NET_21
++      if (dev->header_cache_bind) {
++              prv->header_cache_bind = dev->header_cache_bind;
++              tndev->header_cache_bind = ipsec_tunnel_cache_bind;
++      } else
++              tndev->header_cache_bind = NULL;
++#endif /* !NET_21 */
++
++      if (dev->header_cache_update) {
++              prv->header_cache_update = dev->header_cache_update;
++              tndev->header_cache_update = ipsec_tunnel_cache_update;
++      } else
++              tndev->header_cache_update = NULL;
++
++      tndev->hard_header_len = dev->hard_header_len;
++
++#ifdef NET_21
++/*    prv->neigh_setup        = dev->neigh_setup; */
++      dev->neigh_setup        = ipsec_tunnel_neigh_setup_dev;
++#endif /* NET_21 */
++      tndev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
++      prv->mtu = dev->mtu;
++
++#ifdef PHYSDEV_TYPE
++      tndev->type = dev->type /* ARPHRD_TUNNEL */;    /* initially */
++#endif /*  PHYSDEV_TYPE */
++
++      tndev->addr_len = dev->addr_len;
++      for (i=0; i<tndev->addr_len; i++) {
++              tndev->dev_addr[i] = dev->dev_addr[i];
++      }
++      if(debug_tunnel & DB_TN_INIT) {
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_attach: "
++                     "physical device %s being attached has HW address: %2x",
++                     dev->name, dev->dev_addr[0]);
++              for (i=1; i < dev->addr_len; i++) {
++                      printk(":%02x", dev->dev_addr[i]);
++              }
++              printk("\n");
++      }
++
++      return 0;
++}
++
++/*
++ * We call the detach routine to detach the ipsec tunnel from another device.
++ */
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_detach(struct device *dev, struct ipsecpriv *prv)
++{
++        int i;
++
++      if(debug_tunnel & DB_TN_INIT) {
++              printk(KERN_INFO "klips_debug:ipsec_tunnel_detach: "
++                     "physical device %s being detached from virtual device %s\n",
++                     prv->dev->name, dev->name);
++      }
++
++      prv->dev = NULL;
++      prv->hard_start_xmit = NULL;
++      prv->get_stats = NULL;
++
++      prv->hard_header = NULL;
++      dev->hard_header = NULL;
++      
++      prv->rebuild_header = NULL;
++      dev->rebuild_header = NULL;
++      
++      prv->set_mac_address = NULL;
++      dev->set_mac_address = NULL;
++      
++#ifndef NET_21
++      prv->header_cache_bind = NULL;
++      dev->header_cache_bind = NULL;
++#endif /* !NET_21 */
++
++      prv->header_cache_update = NULL;
++      dev->header_cache_update = NULL;
++
++#ifdef NET_21
++/*    prv->neigh_setup        = NULL; */
++      dev->neigh_setup        = NULL;
++#endif /* NET_21 */
++      dev->hard_header_len = 0;
++      dev->mtu = 0;
++      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 = 0;
++#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 device *ipsecdev = NULL, *prvdev;
++      struct ipsecpriv *prv;
++      char name[9];
++      int ret;
++
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_clear: called.\n");
++
++      for(i = 0; i < IPSEC_NUM_IF; i++) {
++              sprintf(name, "ipsec%d", i);
++              if((ipsecdev = dev_get(name)) != NULL) {
++                      if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
++                              prvdev = (struct 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",
++                                                  name, prvdev->name);
++                                      if((ret = ipsec_tunnel_detach(ipsecdev, prv))) {
++                                              KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                                          "klips_debug:ipsec_tunnel_clear: "
++                                                          "error %d detatching device %s from device %s.\n",
++                                                          ret, name, prvdev->name);
++                                              return ret;
++                                      }
++                              }
++                      }
++              }
++      }
++      return 0;
++}
++
++DEBUG_NO_STATIC int
++ipsec_tunnel_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
++{
++      struct ipsectunnelconf *cf = (struct ipsectunnelconf *)&ifr->ifr_data;
++      struct ipsecpriv *prv = dev->priv;
++      struct device *them; /* physical device */
++#ifdef CONFIG_IP_ALIAS
++      char *colon;
++      char realphysname[IFNAMSIZ];
++#endif /* CONFIG_IP_ALIAS */
++      
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_ioctl: "
++                  "tncfg service call #%d\n", cmd);
++      switch (cmd) {
++      /* attach a virtual ipsec? device to a physical device */
++      case IPSEC_SET_DEV:
++#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 = dev_get(realphysname);
++#else /* CONFIG_IP_ALIAS */
++              them = 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 requested is null\n");
++
++                      return -ENXIO;
++              }
++              
++              if (prv->dev)
++                      return -EBUSY;
++              return ipsec_tunnel_attach(dev, dev->priv, them);
++
++      case IPSEC_DEL_DEV:
++              if (! prv->dev)
++                      return -ENODEV;
++              return ipsec_tunnel_detach(dev, dev->priv);
++             
++      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();
++
++      default:
++              return -EOPNOTSUPP;
++      }
++}
++
++int
++ipsec_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
++{
++      struct device *dev = ptr;
++      struct device *ipsec_dev;
++      struct ipsecpriv *priv;
++      char name[9];
++      int i;
++
++      /* check for loopback devices */
++      if (dev->flags & IFF_LOOPBACK)
++              return(NOTIFY_DONE);
++
++      switch (event) 
++      {
++              case NETDEV_DOWN:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "ipsec_device_event: NETDEV_DOWN...\n");
++                      /* find the attached physical device and detach it. */
++                      for(i = 0; i < IPSEC_NUM_IF; i++) {
++                              sprintf(name, "ipsec%d", i);
++                              ipsec_dev = dev_get(name);
++                              if(ipsec_dev) {
++                                      priv = (struct ipsecpriv *)(ipsec_dev->priv);
++                                      if(priv) {
++                                              ;
++                                              if(((struct device *)(priv->dev)) == dev) {
++                                                      dev_close(ipsec_dev);
++                                                      /* return */ ipsec_tunnel_detach(ipsec_dev, priv);
++                                                      return NOTIFY_DONE;
++                                                      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,
++                                  "ipsec_device_event: NETDEV_UP...\n");
++                      /* Only handle ethernet ports */
++                      if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
++                              return NOTIFY_DONE;
++
++                      break;
++#ifdef NET_21
++              case NETDEV_UNREGISTER:
++                      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                                  "ipsec_device_event: NETDEV_UNREGISTER...\n");
++
++                      break;
++#endif /* NET_21 */
++      }
++      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 device *dev)
++{
++      int i;
++
++      printk(KERN_INFO "klips_debug:ipsec_tunnel_init: "
++             "initialisation of device: %s\n",
++             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(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;
++      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;
++
++#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_TUNNEL; /* 0 */ /* ARPHRD_ETHER; */ /* initially */
++      dev->tx_queue_len       = 10;           /* Small queue */
++      memset(dev->broadcast,0xFF, ETH_ALEN);  /* what if this is not attached to ethernet? */
++
++      /* New-style flags. */
++      dev->flags              = IFF_NOARP /* 0 */ /* Petr Novak */;
++#ifdef NET_21
++      dev_init_buffers(dev);
++#else /* NET_21 */
++      dev->family             = AF_INET;
++      dev->pa_addr            = 0;
++      dev->pa_brdaddr         = 0;
++      dev->pa_mask            = 0;
++      dev->pa_alen            = 4;
++#endif /* NET_21 */
++
++      /* 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 device *dev)
++{
++      ipsec_tunnel_init(dev); 
++      return 0;
++}
++
++static struct device dev_ipsec3 = 
++{
++      "ipsec3\0   ",          /* name */
++      0,                      /* recv memory end */
++      0,                      /* recv memory start */
++      0,                      /* memory end */
++      0,                      /* memory start */
++      0x0,                    /* base I/O address */
++      0,                      /* IRQ */
++      0, 0, 0,                /* flags */
++      NULL,                   /* next device */
++      ipsec_tunnel_probe      /* setup */
++};
++
++static struct device dev_ipsec2 = 
++{
++      "ipsec2\0   ",          /* name */
++      0,                      /* recv memory end */
++      0,                      /* recv memory start */
++      0,                      /* memory end */
++      0,                      /* memory start */
++      0x0,                    /* base I/O address */
++      0,                      /* IRQ */
++      0, 0, 0,                /* flags */
++      NULL,                   /* next device */
++      ipsec_tunnel_probe      /* setup */
++};
++
++static struct device dev_ipsec1 = 
++{
++      "ipsec1\0   ",          /* name */
++      0,                      /* recv memory end */
++      0,                      /* recv memory start */
++      0,                      /* memory end */
++      0,                      /* memory start */
++      0x0,                    /* base I/O address */
++      0,                      /* IRQ */
++      0, 0, 0,                /* flags */
++      NULL,                   /* next device */
++      ipsec_tunnel_probe      /* setup */
++};
++
++static struct device dev_ipsec0 = 
++{
++      "ipsec0\0   ",          /* name */
++      0,                      /* recv memory end */
++      0,                      /* recv memory start */
++      0,                      /* memory end */
++      0,                      /* memory start */
++      0x0,                    /* base I/O address */
++      0,                      /* IRQ */
++      0, 0, 0,                /* flags */
++      NULL,                   /* next device */
++      ipsec_tunnel_probe      /* setup */
++};
++
++int 
++ipsec_tunnel_init_devices(void)
++{
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "registering device %s\n",
++                  dev_ipsec0.name);
++      if (register_netdev(&dev_ipsec0) != 0)
++              return -EIO;
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "registering device %s\n",
++                  dev_ipsec1.name);
++      if (register_netdev(&dev_ipsec1) != 0)
++              return -EIO;
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "registering device %s\n",
++                  dev_ipsec2.name);
++      if (register_netdev(&dev_ipsec2) != 0)
++              return -EIO;
++      KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
++                  "klips_debug:ipsec_tunnel_init_devices: "
++                  "registering device %s\n",
++                  dev_ipsec3.name);
++      if (register_netdev(&dev_ipsec3) != 0)
++              return -EIO;
++      return 0;
++}
++
++/* void */
++int
++ipsec_tunnel_cleanup_devices(void)
++{
++      int error = 0;
++
++      unregister_netdev(&dev_ipsec0);
++      unregister_netdev(&dev_ipsec1);
++      unregister_netdev(&dev_ipsec2);
++      unregister_netdev(&dev_ipsec3);
++      kfree_s(dev_ipsec0.priv,sizeof(struct ipsecpriv));
++      kfree_s(dev_ipsec1.priv,sizeof(struct ipsecpriv));
++      kfree_s(dev_ipsec2.priv,sizeof(struct ipsecpriv));
++      kfree_s(dev_ipsec3.priv,sizeof(struct ipsecpriv));
++      dev_ipsec0.priv=NULL;
++      dev_ipsec1.priv=NULL;
++      dev_ipsec2.priv=NULL;
++      dev_ipsec3.priv=NULL;
++
++      return error;
++}
++
++/*
++ * $Log$
++ * Revision 1.100  2000/01/26 10:04:57  rgb
++ * Fixed noisy 2.0 printk arguments.
++ *
++ * Revision 1.99  2000/01/21 06:16:25  rgb
++ * Added sanity checks on skb_push(), skb_pull() to prevent panics.
++ * Switched to AF_ENCAP macro.
++ * Shortened debug output per packet and re-arranging debug_tunnel
++ * bitmap flags, while retaining necessary information to avoid
++ * trampling the kernel print ring buffer.
++ * Reformatted recursion switch code.
++ * Changed all references to tdb_proto to tdb_said.proto for clarity.
++ *
++ * Revision 1.98  2000/01/13 08:09:31  rgb
++ * Shuffled debug_tunnel switches to focus output.
++ * Fixed outgoing recursion bug, limiting to recursing only if the remote
++ * SG changes and if it is valid, ie. not passthrough.
++ * Clarified a number of debug messages.
++ *
++ * Revision 1.97  2000/01/10 16:37:16  rgb
++ * MB support for new ip_select_ident() upon disappearance of
++ * ip_id_count in 2.3.36+.
++ *
++ * Revision 1.96  1999/12/31 14:59:08  rgb
++ * MB fix to use new skb_copy_expand in kernel 2.3.35.
++ *
++ * Revision 1.95  1999/12/29 21:15:44  rgb
++ * Fix tncfg to aliased device bug.
++ *
++ * Revision 1.94  1999/12/22 04:26:06  rgb
++ * Converted all 'static' functions to 'DEBUG_NO_STATIC' to enable
++ * debugging by providing external labels to all functions with debugging
++ * turned on.
++ *
++ * Revision 1.93  1999/12/13 13:30:14  rgb
++ * Changed MTU reports and HW address reporting back to debug only.
++ *
++ * Revision 1.92  1999/12/07 18:57:56  rgb
++ * Fix PFKEY symbol compile error (SADB_*) without pfkey enabled.
++ *
++ * Revision 1.91  1999/12/01 22:15:36  rgb
++ * Add checks for LARVAL and DEAD SAs.
++ * Change state of SA from MATURE to DYING when a soft lifetime is
++ * reached and print debug warning.
++ *
++ * Revision 1.90  1999/11/23 23:04:04  rgb
++ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.89  1999/11/18 18:50:59  rgb
++ * Changed all device registrations for static linking to
++ * dynamic to reduce the number and size of patches.
++ *
++ * Revision 1.88  1999/11/18 04:09:19  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.87  1999/11/17 15:53:40  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.86  1999/10/16 18:25:37  rgb
++ * Moved SA lifetime expiry checks before packet processing.
++ * Expire SA on replay counter rollover.
++ *
++ * Revision 1.85  1999/10/16 04:24:31  rgb
++ * Add stats for time since last packet.
++ *
++ * Revision 1.84  1999/10/16 00:30:47  rgb
++ * Added SA lifetime counting.
++ *
++ * Revision 1.83  1999/10/15 22:15:57  rgb
++ * Clean out cruft.
++ * Add debugging.
++ *
++ * Revision 1.82  1999/10/08 18:26:19  rgb
++ * Fix 2.0.3x outgoing fragmented packet memory leak.
++ *
++ * Revision 1.81  1999/10/05 02:38:54  rgb
++ * Lower the default mtu of virtual devices to 16260.
++ *
++ * Revision 1.80  1999/10/03 18:56:41  rgb
++ * Spinlock support for 2.3.xx.
++ * Don't forget to undo spinlocks on error!
++ * Check for valid eroute before copying the structure.
++ *
++ * Revision 1.79  1999/10/01 15:44:53  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.78  1999/10/01 00:02:43  rgb
++ * Added tdb structure locking.
++ * Added eroute structure locking.
++ *
++ * Revision 1.77  1999/09/30 02:52:29  rgb
++ * Add Marc Boucher's Copy-On-Write code (same as ipsec_rcv.c).
++ *
++ * Revision 1.76  1999/09/25 19:31:27  rgb
++ * Refine MSS hack to affect SYN, but not SYN+ACK packets.
++ *
++ * Revision 1.75  1999/09/24 22:52:38  rgb
++ * Fix two things broken in 2.0.38 by trying to fix network notifiers.
++ *
++ * Revision 1.74  1999/09/24 00:30:37  rgb
++ * Add test for changed source as well as destination to check for
++ * recursion.
++ *
++ * Revision 1.73  1999/09/23 20:52:24  rgb
++ * Add James Morris' MSS hack patch, disabled.
++ *
++ * Revision 1.72  1999/09/23 20:22:40  rgb
++ * Enable, tidy and fix network notifier code.
++ *
++ * Revision 1.71  1999/09/23 18:09:05  rgb
++ * Clean up 2.2.x fragmenting traces.
++ * Disable dev->type switching, forcing ARPHRD_TUNNEL.
++ *
++ * Revision 1.70  1999/09/22 14:14:24  rgb
++ * Add sanity checks for revectored calls to prevent calling a downed I/F.
++ *
++ * Revision 1.69  1999/09/21 15:00:57  rgb
++ * Add Marc Boucher's packet size check.
++ * Flesh out network device notifier code.
++ *
++ * Revision 1.68  1999/09/18 11:39:57  rgb
++ * Start to add (disabled) netdevice notifier code.
++ *
++ * Revision 1.67  1999/09/17 23:44:40  rgb
++ * Add a comment warning potential code hackers to stay away from mac.raw.
++ *
++ * Revision 1.66  1999/09/17 18:04:02  rgb
++ * Add fix for unpredictable hard_header_len for ISDN folks (thanks MB).
++ * Ditch TTL decrement in 2.2 (MB).
++ *
++ * Revision 1.65  1999/09/15 23:15:35  henry
++ * Marc Boucher's PPP fixes
++ *
++ * Revision 1.64  1999/09/07 13:40:53  rgb
++ * Ditch unreliable references to skb->mac.raw.
++ *
++ * Revision 1.63  1999/08/28 11:33:09  rgb
++ * Check for null skb->mac pointer.
++ *
++ * Revision 1.62  1999/08/28 02:02:30  rgb
++ * Add Marc Boucher's fix for properly dealing with skb->sk.
++ *
++ * Revision 1.61  1999/08/27 05:23:05  rgb
++ * Clean up skb->data/raw/nh/h manipulation.
++ * Add Marc Boucher's mods to aid tcpdump.
++ * Add sanity checks to skb->raw/nh/h pointer copies in skb_copy_expand.
++ * Re-order hard_header stripping -- might be able to remove it...
++ *
++ * Revision 1.60  1999/08/26 20:01:02  rgb
++ * Tidy up compiler directives and macros.
++ * Re-enable ICMP for tunnels where inner_dst !=  outer_dst.
++ * Remove unnecessary skb->dev = physdev assignment affecting 2.2.x.
++ *
++ * Revision 1.59  1999/08/25 15:44:41  rgb
++ * Clean up from 2.2.x instrumenting for compilation under 2.0.36.
++ *
++ * Revision 1.58  1999/08/25 15:00:54  rgb
++ * Add dst cache code for 2.2.xx.
++ * Add sanity check for skb packet header pointers.
++ * Add/modify debugging instrumentation to *_start_xmit, *_hard_header and
++ * *_rebuild_header.
++ * Add neigh_* cache code.
++ * Change dev->type back to ARPHRD_TUNNEL.
++ *
++ * Revision 1.57  1999/08/17 21:50:23  rgb
++ * Fixed minor debug output bugs.
++ * Regrouped error recovery exit code.
++ * Added compiler directives to remove unwanted code and symbols.
++ * Shut off ICMP messages: to be refined to only send ICMP to remote systems.
++ * Add debugging code for output function addresses.
++ * Fix minor bug in (possibly unused) header_cache_bind function.
++ * Add device neighbour caching code.
++ * Change dev->type from ARPHRD_TUNNEL to physdev->type.
++ *
++ * Revision 1.56  1999/08/03 17:22:56  rgb
++ * Debug output clarification using KERN_* macros.  Other inactive changes
++ * added.
++ *
++ * Revision 1.55  1999/08/03 16:58:46  rgb
++ * Fix skb_copy_expand size bug.  Was getting incorrect size.
++ *
++ * Revision 1.54  1999/07/14 19:32:38  rgb
++ * Fix oversize packet crash and ssh stalling in 2.2.x kernels.
++ *
++ * Revision 1.53  1999/06/10 15:44:02  rgb
++ * Minor reformatting and clean-up.
++ *
++ * Revision 1.52  1999/05/09 03:25:36  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.51  1999/05/08 21:24:59  rgb
++ * Add casting to silence the 2.2.x compile.
++ *
++ * Revision 1.50  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.49  1999/04/29 15:18:52  rgb
++ * Change gettdb parameter to a pointer to reduce stack loading and
++ * facilitate parameter sanity checking.
++ * Fix undetected bug that might have tried to access a null pointer.
++ * Eliminate unnessessary usage of tdb_xform member to further switch
++ * away from the transform switch to the algorithm switch.
++ * Add return values to init and cleanup functions.
++ *
++ * Revision 1.48  1999/04/16 15:38:00  rgb
++ * Minor rearrangement of freeing code to avoid memory leaks with impossible or
++ * rare situations.
++ *
++ * Revision 1.47  1999/04/15 15:37:25  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.32.2.4  1999/04/13 21:00:18  rgb
++ * Ditch 'things I wish I had known before...'.
++ *
++ * Revision 1.32.2.3  1999/04/13 20:34:38  rgb
++ * Free skb after fragmentation.
++ * Use stats more effectively.
++ * Add I/F to mtu notch-down reporting.
++ *
++ * Revision 1.32.2.2  1999/04/02 04:26:14  rgb
++ * Backcheck from HEAD, pre1.0.
++ *
++ * Revision 1.46  1999/04/11 00:29:00  henry
++ * GPL boilerplate
++ *
++ * Revision 1.45  1999/04/07 15:42:01  rgb
++ * Fix mtu/ping bug AGAIN!
++ *
++ * Revision 1.44  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.43  1999/04/04 03:57:07  rgb
++ * ip_fragment() doesn't free the supplied skb.  Freed.
++ *
++ * Revision 1.42  1999/04/01 23:27:15  rgb
++ * Preload size of virtual mtu.
++ *
++ * Revision 1.41  1999/04/01 09:31:23  rgb
++ * Invert meaning of ICMP PMTUD config option and clarify.
++ * Code clean-up.
++ *
++ * Revision 1.40  1999/04/01 04:37:17  rgb
++ * SSH stalling bug fix.
++ *
++ * Revision 1.39  1999/03/31 23:44:28  rgb
++ * Don't send ICMP on DF and frag_off.
++ *
++ * Revision 1.38  1999/03/31 15:20:10  rgb
++ * Quiet down debugging.
++ *
++ * Revision 1.37  1999/03/31 08:30:31  rgb
++ * Add switch to shut off ICMP PMTUD packets.
++ *
++ * Revision 1.36  1999/03/31 05:44:47  rgb
++ * Keep PMTU reduction private.
++ *
++ * Revision 1.35  1999/03/27 15:13:02  rgb
++ * PMTU/fragmentation bug fix.
++ *
++ * Revision 1.34  1999/03/17 21:19:26  rgb
++ * Fix kmalloc nonatomic bug.
++ *
++ * Revision 1.33  1999/03/17 15:38:42  rgb
++ * Code clean-up.
++ * ESP_NULL IV bug fix.
++ *
++ * Revision 1.32  1999/03/01 20:44:25  rgb
++ * Code clean-up.
++ * Memory leak bug fix.
++ *
++ * Revision 1.31  1999/02/27 00:02:09  rgb
++ * Tune to report the MTU reduction once, rather than after every recursion
++ * through the encapsulating code, preventing tcp stream stalling.
++ *
++ * Revision 1.30  1999/02/24 20:21:01  rgb
++ * Reformat debug printk's.
++ * Fix recursive encapsulation, dynamic MTU bugs and add debugging code.
++ * Clean-up.
++ *
++ * Revision 1.29  1999/02/22 17:08:14  rgb
++ * Fix recursive encapsulation code.
++ *
++ * Revision 1.28  1999/02/19 18:27:02  rgb
++ * Improve DF, fragmentation and PMTU behaviour and add dynamic MTU discovery.
++ *
++ * Revision 1.27  1999/02/17 16:51:37  rgb
++ * Clean out unused cruft.
++ * Temporarily tone down volume of debug output.
++ * Temporarily shut off fragment rejection.
++ * Disabled temporary failed recursive encapsulation loop.
++ *
++ * Revision 1.26  1999/02/12 21:21:26  rgb
++ * Move KLIPS_PRINT to ipsec_netlink.h for accessibility.
++ *
++ * Revision 1.25  1999/02/11 19:38:27  rgb
++ * More clean-up.
++ * Add sanity checking for skb_copy_expand() to prevent kernel panics on
++ * skb_put() values out of range.
++ * Fix head/tailroom calculation causing skb_put() out-of-range values.
++ * Fix return values to prevent 'nonatomic alloc_skb' warnings.
++ * Allocate new skb iff needed.
++ * Added more debug statements.
++ * Make headroom depend on structure, not hard-coded values.
++ *
++ * Revision 1.24  1999/02/10 23:20:33  rgb
++ * Shut up annoying 'statement has no effect' compiler warnings with
++ * debugging compiled out.
++ *
++ * Revision 1.23  1999/02/10 22:36:30  rgb
++ * Clean-up obsolete, unused and messy code.
++ * Converted most IPSEC_DEBUG statements to KLIPS_PRINT macros.
++ * Rename ipsec_tunnel_do_xmit to ipsec_tunnel_start_xmit and eliminated
++ * original ipsec_tunnel_start_xmit.
++ * Send all packet with different inner and outer destinations directly to
++ * the attached physical device, rather than back through ip_forward,
++ * preventing disappearing routes problems.
++ * Do sanity checking before investing too much CPU in allocating new
++ * structures.
++ * Fail on IP header options: We cannot process them yet.
++ * Add some helpful comments.
++ * Use virtual device for parameters instead of physical device.
++ *
++ * Revision 1.22  1999/02/10 03:03:02  rgb
++ * Duh.  Fixed the TTL bug: forgot to update the checksum.
++ *
++ * Revision 1.21  1999/02/09 23:17:53  rgb
++ * Add structure members to ipsec_print_ip debug function.
++ * Temporarily fix TTL bug preventing tunnel mode from functioning.
++ *
++ * Revision 1.20  1999/02/09 00:14:25  rgb
++ * Add KLIPSPRINT macro.  (Not used yet, though.)
++ * Delete old ip_tunnel code (BADCODE).
++ * Decrement TTL in outgoing packet.
++ * Set TTL on new IPIP_TUNNEL to default, not existing packet TTL.
++ * Delete ethernet only feature and fix hard-coded hard_header_len.
++ *
++ * Revision 1.19  1999/01/29 17:56:22  rgb
++ * 64-bit re-fix submitted by Peter Onion.
++ *
++ * Revision 1.18  1999/01/28 22:43:24  rgb
++ * Fixed bug in ipsec_print_ip that caused an OOPS, found by P.Onion.
++ *
++ * Revision 1.17  1999/01/26 02:08:16  rgb
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ * Removed dead code.
++ *
++ * Revision 1.16  1999/01/22 06:25:26  rgb
++ * Cruft clean-out.
++ * Added algorithm switch code.
++ * 64-bit clean-up.
++ * Passthrough on IPIP protocol, spi 0x0 fix.
++ * Enhanced debugging.
++ *
++ * Revision 1.15  1998/12/01 13:22:04  rgb
++ * Added support for debug printing of version info.
++ *
++ * Revision 1.14  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.13  1998/11/17 21:13:52  rgb
++ * Put IKE port bypass debug output in user-switched debug statements.
++ *
++ * Revision 1.12  1998/11/13 13:20:25  rgb
++ * Fixed ntohs bug in udp/500 hole for IKE.
++ *
++ * Revision 1.11  1998/11/10 08:01:19  rgb
++ * Kill tcp/500 hole,  keep udp/500 hole.
++ *
++ * Revision 1.10  1998/11/09 21:29:26  rgb
++ * If no eroute is found, discard packet and incr. tx_error.
++ *
++ * Revision 1.9  1998/10/31 06:50:00  rgb
++ * Add tcp/udp/500 bypass.
++ * Fixed up comments in #endif directives.
++ *
++ * Revision 1.8  1998/10/27 00:34:31  rgb
++ * Reformat debug output of IP headers.
++ * Newlines added before calls to ipsec_print_ip.
++ *
++ * Revision 1.7  1998/10/19 14:44:28  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.6  1998/10/09 04:31:35  rgb
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ *
++ * Revision 1.5  1998/08/28 03:09:51  rgb
++ * Prevent kernel log spam with default route through ipsec.
++ *
++ * Revision 1.4  1998/08/05 22:23:09  rgb
++ * Change setdev return code to ENXIO for a non-existant physical device.
++ *
++ * Revision 1.3  1998/07/29 20:41:11  rgb
++ * Add ipsec_tunnel_clear to clear all tunnel attachments.
++ *
++ * Revision 1.2  1998/06/25 20:00:33  rgb
++ * Clean up #endif comments.
++ * Rename dev_ipsec to dev_ipsec0 for consistency.
++ * Document ipsec device fields.
++ * Make ipsec_tunnel_probe visible from rest of kernel for static linking.
++ * Get debugging report for *every* ipsec device initialisation.
++ * Comment out redundant code.
++ *
++ * 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.8  1998/06/14 23:49:40  rgb
++ * Clarify version reporting on module loading.
++ *
++ * Revision 1.7  1998/05/27 23:19:20  rgb
++ * Added version reporting.
++ *
++ * Revision 1.6  1998/05/18 21:56:23  rgb
++ * Clean up for numerical consistency of output and cleaning up debug code.
++ *
++ * Revision 1.5  1998/05/12 02:44:23  rgb
++ * Clarifying 'no e-route to host' message.
++ *
++ * Revision 1.4  1998/04/30 15:34:35  rgb
++ * Enclosed most remaining debugging statements in #ifdef's to make it quieter.
++ *
++ * Revision 1.3  1998/04/21 21:28:54  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:24  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:06:12  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.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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_tunnel.h linux-2.2.14/net/ipsec/ipsec_tunnel.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_tunnel.h Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_tunnel.h      Fri Nov 19 02:12:15 1999
+@@ -0,0 +1,194 @@
++/*
++ * IPSEC tunneling code
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++/*
++ * 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
++{
++      __u32   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)
++
++#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 device *dev;
++      struct wait_queue *wait_queue;
++      char locked;
++      int  (*hard_start_xmit) (struct sk_buff *skb,
++              struct device *dev);
++      int  (*hard_header) (struct sk_buff *skb,
++              struct 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 device *dev,
++                      unsigned long raddr, struct sk_buff *skb);
++#endif /* NET_21 */
++      int  (*set_mac_address)(struct device *dev, void *addr);
++#ifndef NET_21
++      void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,
++                               unsigned short htype, __u32 daddr);
++#endif /* !NET_21 */
++      void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
++      struct enet_statistics *(*get_stats)(struct device *dev);
++      struct enet_statistics mystats;
++      int mtu;        /* What is the desired MTU? */
++};
++
++#define IPSEC_NUM_IF  4
++
++extern char ipsec_tunnel_c_version[];
++
++int ipsec_tunnel_init_devices(void);
++
++/* void */ int ipsec_tunnel_cleanup_devices(void);
++
++extern /* void */ int ipsec_init(void);
++
++#ifdef DEBUG_IPSEC
++extern int debug_tunnel;
++#endif /* DEBUG_IPSEC */
++#endif /* __KERNEL__ */
++
++#ifdef DEBUG_IPSEC
++#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
++#endif /* DEBUG_IPSEC */
++
++/*
++ * $Log$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_xform.c linux-2.2.14/net/ipsec/ipsec_xform.c
+--- linux-2.2.14.orig/net/ipsec/ipsec_xform.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_xform.c       Tue Feb  8 22:21:55 2000
+@@ -0,0 +1,1172 @@
++/*
++ * Common routines for IPSEC transformations.
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#endif
++#include <asm/checksum.h>
++#include <net/ip.h>
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++#include "ipsec_ipe4.h"
++#include "ipsec_ah.h"
++#include "ipsec_esp.h"
++
++#ifdef CONFIG_IPSEC_PFKEYv2
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#endif
++
++#ifdef DEBUG_IPSEC
++int debug_xform = 0;
++#endif
++
++#define SENDERR(_x) do { len = -(_x); goto errlab; } while (0)
++
++extern int des_set_key(caddr_t, caddr_t);
++
++struct xformsw xformsw[] = {
++{ XF_IP4,             0,              "IPv4_Encapsulation"},
++{ XF_AHHMACMD5,               XFT_AUTH,       "HMAC_MD5_Authentication"},
++{ XF_AHHMACSHA1,      XFT_AUTH,       "HMAC_SHA-1_Authentication"},
++{ XF_ESPDES,          XFT_CONF,       "DES_Encryption"},
++{ XF_ESPDESMD596,     XFT_CONF,       "DES-MD5-96_Encryption"},
++{ XF_ESPDESSHA196,    XFT_CONF,       "DES-SHA1-96_Encryption"},
++{ XF_ESP3DES,         XFT_CONF,       "3DES_Encryption"},
++{ XF_ESP3DESMD596,    XFT_CONF,       "3DES-MD5-96_Encryption"},
++{ XF_ESP3DESSHA196,   XFT_CONF,       "3DES-SHA1-96_Encryption"},
++{ XF_ESPNULLMD596,    XFT_CONF,       "NULL-MD5-96_ESP_*Plaintext*"},
++{ XF_ESPNULLSHA196,   XFT_CONF,       "NULL-SHA1-96_ESP_*Plaintext*"},
++};
++
++struct tdb *tdbh[TDB_HASHMOD];
++#ifdef SPINLOCK
++spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
++#else /* SPINLOCK */
++spinlock_t tdb_lock;
++#endif /* SPINLOCK */
++struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];
++
++int
++ipsec_tdbinit(void)
++{
++      int i;
++
++      for(i = 1; i < TDB_HASHMOD; i++) {
++              tdbh[i] = NULL;
++      }
++      return 0;
++}
++
++struct tdb *
++gettdb(struct sa_id *said)
++{
++      int hashval;
++      struct tdb *tdbp;
++        char sa[SATOA_BUF];
++
++      if(!said) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:gettdb: null pointer passed in!\n");
++              return NULL;
++      }
++
++      satoa(*said, 0, sa, SATOA_BUF);
++
++      hashval = (said->spi+said->dst.s_addr+said->proto) % TDB_HASHMOD;
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:gettdb: linked entry in tdb table for hash=%d of SA:%s requested.\n",
++                  hashval, sa);
++
++      if(!(tdbp = tdbh[hashval])) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:gettdb: no entries in tdb table for hash=%d of SA:%s.\n",
++                          hashval, sa);
++              return NULL;
++      }
++
++      for (; tdbp; tdbp = tdbp->tdb_hnext) {
++              if ((tdbp->tdb_said.spi == said->spi) &&
++                  (tdbp->tdb_said.dst.s_addr == said->dst.s_addr) &&
++                  (tdbp->tdb_said.proto == said->proto)) {
++                      return tdbp;
++              }
++      }
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:gettdb: no entry in linked list for hash=%d of SA:%s.\n",
++                  hashval, sa);
++      return NULL;
++}
++
++/* void */
++int
++puttdb(struct tdb *tdbp)
++{
++      int error = 0;
++      unsigned int hashval;
++      unsigned long flags; /* save irq state for spinlock */
++
++      if(!tdbp) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:puttdb: null pointer passed in!\n");
++              return -ENODATA;
++      }
++      hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr + tdbp->tdb_proto) % TDB_HASHMOD);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++      
++      tdbp->tdb_hnext = tdbh[hashval];
++      tdbh[hashval] = tdbp;
++      
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      return error;
++}
++
++/* This tdb better be locked before it is handed in, or races might
++ * happen */
++
++/* void */
++int
++deltdb(struct tdb *tdbp)
++{
++      unsigned int hashval;
++      struct tdb *tdbtp;
++        char sa[SATOA_BUF];
++
++      if(!tdbp) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:deltdb: null pointer passed in!\n");
++              return -ENODATA;
++      }
++      
++      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++      if(tdbp->tdb_inext || tdbp->tdb_onext) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:deltdb: SA:%s still linked!\n",
++                          sa);
++              return -EMLINK;
++      }
++      
++      hashval = ((tdbp->tdb_spi + tdbp->tdb_dst.s_addr + tdbp->tdb_proto) % TDB_HASHMOD);
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:deltdb: deleting SA:%s, hashval=%d.\n",
++                  sa, hashval);
++      if(!tdbh[hashval]) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:deltdb: no entries in tdb table for hash=%d of SA:%s.\n",
++                          hashval, sa);
++              return -ENOENT;
++      }
++      
++      if (tdbp == tdbh[hashval]) {
++              tdbh[hashval] = tdbh[hashval]->tdb_hnext;
++              tdbp->tdb_hnext = NULL;
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:deltdb: successfully deleted first tdb in chain.\n");
++              return 0;
++      } else {
++              for (tdbtp = tdbh[hashval]; tdbtp; tdbtp = tdbtp->tdb_hnext) {
++                      if (tdbtp->tdb_hnext == tdbp) {
++                              tdbtp->tdb_hnext = tdbp->tdb_hnext;
++                              tdbp->tdb_hnext = NULL;
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:deltdb: successfully "
++                                          "deleted link in tdb chain.\n");
++                              return 0;
++                      }
++              }
++      }
++      
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:deltdb: no entries in linked list for hash=%d of SA:%s.\n",
++                  hashval, sa);
++      return -ENOENT;
++}
++
++/* This tdb better be locked before it is handed in, or races might
++ * happen */
++
++int
++deltdbchain(struct tdb *tdbp)
++{
++      struct tdb *tdbdel;
++      int error = 0;
++        char sa[SATOA_BUF];
++
++      if(!tdbp) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:deltdbchain: null pointer passed in!\n");
++              return -ENODATA;
++      }
++
++      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:deltdbchain: passed SA:%s\n", sa);
++      while(tdbp->tdb_onext) {
++              tdbp = tdbp->tdb_onext;
++      }
++
++      while(tdbp) {
++              /* XXX send a pfkey message up to advise of deleted TDB */
++              satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++              KLIPS_PRINT(debug_xform,
++                          "klips_debug:deltdbchain: unlinking and delting SA:%s", sa);
++              tdbdel = tdbp;
++              tdbp = tdbp->tdb_inext;
++              if(tdbp) {
++                      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                      KLIPS_PRINT(debug_xform,
++                                  ", inext=%s", sa);
++                      tdbdel->tdb_inext = NULL;
++                      tdbp->tdb_onext = NULL;
++              }
++              KLIPS_PRINT(debug_xform,
++                          ".\n");
++              if((error = deltdb(tdbdel))) {
++                      KLIPS_PRINT(debug_xform,
++                                  "klips_debug:deltdbchain: "
++                                  "deltdb returned error %d.\n", -error);
++                      return error;
++              }
++              if((error = ipsec_tdbwipe(tdbdel))) {
++                      KLIPS_PRINT(debug_xform,
++                                  "klips_debug:deltdbchain: "
++                                  "ipsec_tdbwipe returned error %d.\n", -error);
++                      return error;
++              }
++      }
++      return error;
++}
++
++int
++tdb_init(struct tdb *tdbp, struct encap_msghdr *em)
++{
++      int alg;
++      struct xformsw *xsp;
++      int len;
++        int i;
++#if defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES)
++        int error;
++#endif /* CONFIG_IPSEC_ENC_{,3}DES */
++
++        char sa[SATOA_BUF];
++        size_t sa_len;
++
++      if(!tdbp || !em) {
++              KLIPS_PRINT(debug_xform,
++                          "klips_error:tdb_init: null pointer passed in!\n");
++              SENDERR(ENODATA);
++      }
++
++      sa_len = satoa(em->em_said, 0, sa, SATOA_BUF);
++
++        KLIPS_PRINT(debug_esp,
++                  "klips_debug:tdb_init: (algo_switch defined) called for SA:%s\n", sa);
++      alg = em->em_alg;
++      
++      for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++) {
++              if (xsp->xf_type == alg) {
++                      KLIPS_PRINT(debug_netlink,
++                                  "klips_debug:tdb_init: called with tdbp=0x%p, xsp=0x%p, em=0x%p\n",
++                                  tdbp, xsp, em);
++                      KLIPS_PRINT(debug_netlink,
++                                  "klips_debug:tdb_init: calling init routine of %s\n",
++                                  xsp->xf_name);
++                      tdbp->tdb_xform = xsp;
++                      tdbp->tdb_replaywin_lastseq = 0;
++                      tdbp->tdb_replaywin_bitmap = 0;
++                      /* check size of message here XXX */
++                      switch(alg) {
++#ifdef CONFIG_IPSEC_IPIP
++                      case XF_IP4: {
++                              struct ipe4_xdata *xd;
++                              xd = (struct ipe4_xdata *)(em->em_dat);
++
++                              tdbp->tdb_authalg = AH_NONE;
++                              tdbp->tdb_encalg = ESP_NONE;
++                              
++                              if((tdbp->tdb_addr_s = (struct sockaddr*)
++                                 kmalloc((tdbp->tdb_addr_s_size = sizeof(struct sockaddr_in)),
++                                         GFP_ATOMIC)) == NULL) {
++                                      SENDERR(ENOMEM);
++                              }
++                              if((tdbp->tdb_addr_d = (struct sockaddr*)
++                                 kmalloc((tdbp->tdb_addr_d_size = sizeof(struct sockaddr_in)),
++                                         GFP_ATOMIC)) == NULL) {
++                                      SENDERR(ENOMEM);
++                              }
++                              
++                              /* might want to use a different structure here, or set sin_family and sin_port */
++                              ((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr = xd->i4_src;
++                              ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr = xd->i4_dst;
++                      }
++                              break;
++#endif /* !CONFIG_IPSEC_IPIP */
++
++#ifdef CONFIG_IPSEC_AH
++
++# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                      case XF_AHHMACMD5: {
++                              struct ahhmacmd5_edata *ed;
++                              unsigned char kb[AHMD596_BLKLEN];
++                              MD5_CTX *ictx;
++                              MD5_CTX *octx;
++
++                              ed = (struct ahhmacmd5_edata *)em->em_dat;
++
++                              tdbp->tdb_authalg = AH_MD5;
++                              tdbp->tdb_encalg = ESP_NONE;
++                              
++                              if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahhmacmd5_edata))
++                                      SENDERR(EINVAL);
++                              
++                              if (ed->ame_klen != AHMD596_KLEN) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: incorrect key size: %d"
++                                                  "-- must be %d octets (bytes)\n",
++                                                  ed->ame_klen, AHMD596_KLEN);
++                                      SENDERR(EINVAL);
++                              }
++                              
++                              if (ed->ame_alen != AHMD596_ALEN) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: authenticator size: %d"
++                                                  " -- must be %d octets (bytes)\n",
++                                                  ed->ame_alen, AHMD596_ALEN);
++                                      SENDERR(EINVAL);
++                              }
++                              
++                              KLIPS_PRINT(debug_ah,
++                                          "klips_debug:tdb_init: hmac md5-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                          ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+3)));
++                              
++                              tdbp->tdb_key_bits_a = ed->ame_klen;
++                              tdbp->tdb_auth_bits = ed->ame_alen * 8;
++                              
++                              if(ed->ame_ooowin > 64) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: replay window size: %d"
++                                                  " -- must be 0 <= size <= 64\n",
++                                                  ed->ame_ooowin);
++                                      SENDERR(EINVAL);
++                              }
++                              tdbp->tdb_replaywin = ed->ame_ooowin;
++                              tdbp->tdb_replaywin_lastseq = tdbp->tdb_replaywin_bitmap = 0;
++                              
++                              if((tdbp->tdb_key_a = (caddr_t)
++                                  kmalloc((tdbp->tdb_key_a_size = sizeof(struct md5_ctx)),
++                                          GFP_ATOMIC)) == NULL) {
++                                      SENDERR(ENOMEM);
++                              }
++
++                              for (i = 0; i < ed->ame_klen; i++) {
++                                      kb[i] = ed->ame_key[i] ^ HMAC_IPAD;
++                              }
++                              for (; i < AHMD596_BLKLEN; i++) {
++                                      kb[i] = HMAC_IPAD;
++                              }
++
++                              ictx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->ictx);
++                              MD5Init(ictx);
++                              MD5Update(ictx, kb, AHMD596_BLKLEN);
++
++                              for (i = 0; i < AHMD596_BLKLEN; i++)
++                                      kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++
++                              octx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->octx);
++                              MD5Init(octx);
++                              MD5Update(octx, kb, AHMD596_BLKLEN);
++                              
++                              KLIPS_PRINT(debug_ah,
++                                          "klips_debug:tdb_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] );
++                              
++                              /* zero key buffer -- paranoid */
++                              memset(kb, 0, sizeof(kb));
++                              memset((caddr_t)&(ed->ame_key), 0, ed->ame_klen);
++                      }
++                              break;
++# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                      case XF_AHHMACSHA1: {
++                              struct ahhmacsha1_edata *ed;
++                              unsigned char kb[AHSHA196_BLKLEN];
++                              SHA1_CTX *ictx;
++                              SHA1_CTX *octx;
++
++                              ed = (struct ahhmacsha1_edata *)em->em_dat;
++                              
++                              tdbp->tdb_authalg = AH_SHA;
++                              tdbp->tdb_encalg = ESP_NONE;
++                              
++                              if (em->em_msglen - EMT_SETSPI_FLEN > sizeof (struct ahhmacsha1_edata))
++                                      SENDERR(EINVAL);
++                              
++                              if (ed->ame_klen != AHSHA196_KLEN) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: incorrect key size: %d"
++                                                  "-- must be %d octets (bytes)\n",
++                                                  ed->ame_klen, AHSHA196_KLEN);
++                                      SENDERR(EINVAL);
++                              }
++                              
++                              if (ed->ame_alen != AHSHA196_ALEN) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: authenticator size: %d"
++                                                  " -- must be %d octets (bytes)\n",
++                                                  ed->ame_alen, AHSHA196_ALEN);
++                                      SENDERR(EINVAL);
++                              }
++                              
++                              KLIPS_PRINT(debug_ah,
++                                          "klips_debug:tdb_init: hmac sha1-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                          ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                          ntohl(*(((__u32 *)ed->ame_key)+3)));
++                              
++                              tdbp->tdb_key_bits_a = ed->ame_klen;
++                              tdbp->tdb_auth_bits = ed->ame_alen * 8;
++                              
++                              if(ed->ame_ooowin > 64) {
++                                      KLIPS_PRINT(debug_ah,
++                                                  "klips_debug:tdb_init: replay window size: %d"
++                                                  " -- must be 0 <= size <= 64\n",
++                                                  ed->ame_ooowin);
++                                      SENDERR(EINVAL);
++                              }
++                              tdbp->tdb_replaywin = ed->ame_ooowin;
++                              tdbp->tdb_replaywin_lastseq = tdbp->tdb_replaywin_bitmap = 0;
++                              
++                              if((tdbp->tdb_key_a = (caddr_t)
++                                  kmalloc((tdbp->tdb_key_a_size = (__u16)sizeof(struct sha1_ctx)),
++                                          GFP_ATOMIC)) == NULL) {
++                                      SENDERR(ENOMEM);
++                              }
++
++                              for (i = 0; i < ed->ame_klen; i++)
++                                      kb[i] = ed->ame_key[i] ^ HMAC_IPAD;
++                              for (; i < AHSHA196_BLKLEN; i++)
++                                      kb[i] = HMAC_IPAD;
++
++                              ictx = &(((struct sha1_ctx*)(tdbp->tdb_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*)(tdbp->tdb_key_a))->octx);
++                              SHA1Init(octx);
++                              SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                              
++                              KLIPS_PRINT(debug_ah,
++                                          "klips_debug:tdb_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] );
++                              
++                              /* zero key buffer -- paranoid */
++                              memset(kb, 0, sizeof(kb));
++                              memset((caddr_t)&(ed->ame_key), 0, ed->ame_klen);
++                      }
++                              break;
++# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++
++#endif /* CONFIG_IPSEC_AH */
++
++#ifdef CONFIG_IPSEC_ESP
++#ifdef CONFIG_IPSEC_ENC_DES
++                      case XF_ESPDES:
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                      case XF_ESPDESMD596:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                      case XF_ESPDESSHA196:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                      case XF_ESP3DES:
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                      case XF_ESP3DESMD596:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                      case XF_ESP3DESSHA196:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++#endif /* CONFIG_IPSEC_ENC_3DES */
++#ifdef CONFIG_IPSEC_ENC_NULL
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                      case XF_ESPNULLMD596:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                      case XF_ESPNULLSHA196:
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++#endif /* CONFIG_IPSEC_ENC_NULL */
++                      {
++                              struct espblkrply_edata *ed;
++                              unsigned char kb[AHMD596_BLKLEN];
++                              ed = (struct espblkrply_edata *)em->em_dat;
++
++                              if(ed->eme_ooowin > 64) {
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_init: replay window size: %d"
++                                                  "-- must be 0 <= size <= 64\n",
++                                                  ed->eme_ooowin);
++                                      SENDERR(EINVAL);
++                              }
++                              tdbp->tdb_replaywin = ed->eme_ooowin;
++
++                              switch(alg) {
++                              case XF_ESPDES:
++                              case XF_ESP3DES:
++                              case XF_ESPDESMD596:
++                              case XF_ESP3DESMD596:
++                              case XF_ESPDESSHA196:
++                              case XF_ESP3DESSHA196:
++                                      if((tdbp->tdb_iv = (caddr_t)
++                                         kmalloc((tdbp->tdb_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) {
++                                              SENDERR(ENOMEM);
++                                      }
++                                      get_random_bytes((void *)tdbp->tdb_iv, EMT_ESPDES_IV_SZ);
++                                      break;
++                              default:
++                              }
++
++                              switch(alg) {
++#ifdef CONFIG_IPSEC_ENC_DES
++                              case XF_ESPDES:
++                              case XF_ESPDESMD596:
++                              case XF_ESPDESSHA196:
++                                      tdbp->tdb_encalg = ESP_DES;
++                              
++                                      if (ed->eme_klen != EMT_ESPDES_KEY_SZ) {
++                                              KLIPS_PRINT(debug_esp,
++                                                          "klips_debug:tdb_init: incorrect encryption "
++                                                          "key size: %d -- must be %d octets (bytes)\n",
++                                                          ed->eme_klen, EMT_ESPDES_KEY_SZ);
++                                              SENDERR(EINVAL);
++                                      }
++
++                                      tdbp->tdb_key_bits_e = ed->eme_klen;
++
++                                      if((tdbp->tdb_key_e = (caddr_t)
++                                         kmalloc((tdbp->tdb_key_e_size = sizeof(struct des_eks)),
++                                                 GFP_ATOMIC)) == NULL) {
++                                              SENDERR(ENOMEM);
++                                      }
++#if 0
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_init: des key 1 is 0x%08lx%08lx\n",
++                                                  ntohl(*((__u32 *)ed->eme_key)),
++                                                  ntohl(*((__u32 *)ed->eme_key + 1)));
++#endif
++                                      error = des_set_key((caddr_t)(ed->eme_key), (caddr_t)(tdbp->tdb_key_e));
++                                      if (error == -1)
++                                              printk("klips_debug:tdb_init: parity error in des key\n");
++                                      else if (error == -2)
++                                              printk("klips_debug:tdb_init: illegal weak des key\n");
++                                      if (error) {
++                                              memset(tdbp->tdb_key_e, 0, sizeof (struct des_eks));
++                                              kfree_s(tdbp->tdb_key_e, sizeof(struct des_eks));
++                                              SENDERR(EINVAL);
++                                      }
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_DES */
++#ifdef CONFIG_IPSEC_ENC_3DES
++                              case XF_ESP3DES:
++                              case XF_ESP3DESMD596:
++                              case XF_ESP3DESSHA196:
++                                      tdbp->tdb_encalg = ESP_3DES;
++                              
++                                      if (ed->eme_klen != EMT_ESP3DES_KEY_SZ) {
++                                              KLIPS_PRINT(debug_esp,
++                                                          "klips_debug:tdb_init: incorrect encryption "
++                                                          "key size: %d -- must be %d octets (bytes)\n",
++                                                          ed->eme_klen, EMT_ESP3DES_KEY_SZ);
++                                              SENDERR(EINVAL);
++                                      }
++
++                                      tdbp->tdb_key_bits_e = ed->eme_klen;
++
++                                      if((tdbp->tdb_key_e = (caddr_t)
++                                         kmalloc((tdbp->tdb_key_e_size = 3 * sizeof(struct des_eks)),
++                                                 GFP_ATOMIC)) == NULL) {
++                                              SENDERR(ENOMEM);
++                                      }
++
++                                      for(i = 0; i < 3; i++) {
++#if 0
++                                              KLIPS_PRINT(debug_esp,
++                                                          "klips_debug:tdb_init: 3des key %d/3 is 0x%08lx%08lx\n",
++                                                          i + 1,
++                                                          ntohl(*((__u32 *)ed->eme_key + i * 2)),
++                                                          ntohl(*((__u32 *)ed->eme_key + i * 2 + 1)));
++#endif
++                                              error = des_set_key((caddr_t)(ed->eme_key) + EMT_ESPDES_KEY_SZ * i,
++                                                                  (caddr_t)&((struct des_eks*)(tdbp->tdb_key_e))[i]);
++                                              if (error == -1)
++                                                      printk("klips_debug:tdb_init: parity error in des key %d/3\n", i + 1);
++                                              else if (error == -2)
++                                                      printk("klips_debug:tdb_init: illegal weak des key %d/3\n", i + 1);
++                                              if (error) {
++                                                      memset(tdbp->tdb_key_e, 0, 3 * sizeof(struct des_eks));
++                                                      kfree_s(tdbp->tdb_key_e, 3 * sizeof(struct des_eks));
++                                                      SENDERR(EINVAL);
++                                              }
++                                      }
++
++                                      break;
++#endif /* CONFIG_IPSEC_ENC_3DES */
++                              default:
++                                      tdbp->tdb_encalg = ESP_NULL;
++                              }
++
++                              switch(alg) {
++#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++                              case XF_ESPDESMD596:
++                              case XF_ESP3DESMD596:
++                              case XF_ESPNULLMD596:
++                              {
++                                      MD5_CTX *ictx;
++                                      MD5_CTX *octx;
++
++                                      tdbp->tdb_authalg = AH_MD5;
++                              
++                                      if (ed->ame_klen != AHMD596_KLEN) {
++                                              KLIPS_PRINT(debug_esp,
++                                                          "klips_debug:tdb_init: incorrect authorisation "
++                                                          " key size: %d -- must be %d octets (bytes)\n",
++                                                          ed->ame_klen, AHMD596_KLEN);
++                                              SENDERR(EINVAL);
++                                      }
++
++                                      tdbp->tdb_key_bits_a = ed->ame_klen;
++                                      tdbp->tdb_auth_bits = ed->ame_klen * 8;
++                      
++
++                                      if((tdbp->tdb_key_a = (caddr_t)
++                                         kmalloc((tdbp->tdb_key_a_size = sizeof(struct md5_ctx)),
++                                                 GFP_ATOMIC)) == NULL) {
++                                              SENDERR(ENOMEM);
++                                      }
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_init: hmac md5-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                                  ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+3)));
++                                      
++                                      for (i=0; i< AHMD596_KLEN; i++)
++                                              kb[i] = (*(((unsigned char *)(ed->ame_key)) + i)) ^ HMAC_IPAD;
++                                      /*
++                                       * HMAC_key is now contained in the first 128 bits of kb.
++                                       * Pad with zeroes and XOR with HMAC_IPAD to create the inner context
++                                       */
++                                      for (; i<AHMD596_BLKLEN; i++) {
++                                              kb[i] = HMAC_IPAD;
++                                      }
++
++                                      ictx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->ictx);
++                                      MD5Init(ictx);
++                                      MD5Update(ictx, kb, AHMD596_BLKLEN);
++                                      
++                                      for (i=0; i<AHMD596_BLKLEN; i++) {
++                                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                                      }
++                                      
++                                      octx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->octx);
++                                      MD5Init(octx);
++                                      MD5Update(octx, kb, AHMD596_BLKLEN);
++                                      
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_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] );
++
++                                      memset(kb, 0, sizeof(kb)); /* paranoid */
++                                      memset((caddr_t)&(ed->eme_key), 0, ed->eme_klen);
++                                      memset((caddr_t)&(ed->ame_key), 0, ed->ame_klen);
++                                      break;
++                              }
++#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++                              case XF_ESPNULLSHA196:
++                              case XF_ESPDESSHA196:
++                              case XF_ESP3DESSHA196:
++                              {
++                                      SHA1_CTX *ictx;
++                                      SHA1_CTX *octx;
++
++                                      tdbp->tdb_authalg = AH_SHA;
++                              
++                                      if (ed->ame_klen != AHSHA196_KLEN) {
++                                              KLIPS_PRINT(debug_esp,
++                                                          "klips_debug:tdb_init: incorrect authorisation "
++                                                          " key size: %d -- must be %d octets (bytes)\n",
++                                                          ed->ame_klen, AHSHA196_KLEN);
++                                              SENDERR(EINVAL);
++                                      }
++
++                                      tdbp->tdb_key_bits_a = ed->ame_klen;
++                                      tdbp->tdb_auth_bits = ed->ame_klen * 8;
++
++                                      if((tdbp->tdb_key_a = (caddr_t)
++                                         kmalloc((tdbp->tdb_key_a_size = sizeof(struct sha1_ctx)),
++                                                 GFP_ATOMIC)) == NULL) {
++                                              SENDERR(ENOMEM);
++                                      }
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_init: hmac sha1-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                                  ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                                  ntohl(*(((__u32 *)ed->ame_key)+3)));
++
++                                      for (i=0; i< AHSHA196_KLEN; i++)
++                                              kb[i] = (*(((unsigned char *)(ed->ame_key)) + i)) ^ HMAC_IPAD;
++                                      /*
++                                       * HMAC_key is now contained in the first 128 bits of kb.
++                                       * Pad with zeroes and XOR with HMAC_IPAD to create the inner context
++                                       */
++                                      for (; i<AHSHA196_BLKLEN; i++)
++                                              kb[i] = HMAC_IPAD;
++                                      
++                                      ictx = &(((struct sha1_ctx*)(tdbp->tdb_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*)(tdbp->tdb_key_a))->octx);
++                                      SHA1Init(octx);
++                                      SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                              
++                                      KLIPS_PRINT(debug_esp,
++                                                  "klips_debug:tdb_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] );
++                                      
++                                      memset(kb, 0, sizeof(kb)); /* paranoid */
++                                      memset((caddr_t)&(ed->eme_key), 0, ed->eme_klen);
++                                      memset((caddr_t)&(ed->ame_key), 0, ed->ame_klen);
++                                      break;
++                              }
++#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++                              case XF_ESPDES:
++                              case XF_ESP3DES:
++                                      tdbp->tdb_authalg = AH_NONE;
++                                      break;
++                              default:
++                              }
++                      }
++                              break;
++#endif /* !CONFIG_IPSEC_ESP */
++                      default:
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:tdb_init: alg=%d not configured\n", alg);
++                              SENDERR(ESOCKTNOSUPPORT);
++                      }
++                      SENDERR(0);
++              }
++      }
++      KLIPS_PRINT(debug_xform & DB_XF_INIT,
++                  "klips_debug:tdb_init: unregistered algorithm %d requested\n"
++                  "klips_debug:   trying to setup SA:%s\n", alg, sa);
++      SENDERR(EINVAL);
++errlab:
++      return len;
++}
++
++int 
++ipsec_tdbcleanup(__u8 proto)
++{
++      int i;
++      int error = 0;
++      struct tdb *tdbp, **tdbprev, *tdbdel;
++        char sa[SATOA_BUF];
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_xform,
++                  "klips_debug:ipsec_tdbcleanup: cleaning up proto=%d.\n", proto);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++
++      for (i = 0; i < TDB_HASHMOD; i++) {
++              tdbprev = &(tdbh[i]);
++              tdbp = tdbh[i];
++              for(; tdbp;) {
++                      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                      KLIPS_PRINT(debug_xform,
++                                  "klips_debug:ipsec_tdbcleanup: checking SA:%s, hash=%d",
++                                  sa, i);
++                      tdbdel = tdbp;
++                      tdbp = tdbdel->tdb_hnext;
++                      if(tdbp) {
++                              satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                              KLIPS_PRINT(debug_xform,
++                                          ", hnext=%s", sa);
++                      }
++                      if(*tdbprev) {
++                              satoa((*tdbprev)->tdb_said, 0, sa, SATOA_BUF);
++                              KLIPS_PRINT(debug_xform,
++                                          ", *tdbprev=%s", sa);
++                              if((*tdbprev)->tdb_hnext) {
++                                      satoa((*tdbprev)->tdb_hnext->tdb_said, 0, sa, SATOA_BUF);
++                                      KLIPS_PRINT(debug_xform,
++                                                  ", *tdbprev->tdb_hnext=%s", sa);
++                              }
++                      }
++                      KLIPS_PRINT(debug_xform,
++                                  ".\n");
++                      if(!proto || (proto == tdbdel->tdb_proto)) {
++                              satoa(tdbdel->tdb_said, 0, sa, SATOA_BUF);
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_tdbcleanup: deleting SA chain:%s.\n",
++                                          sa);
++                              /* *tdbprev = tdbdel->tdb_hnext; */
++                              if((error = deltdbchain(tdbdel))) {
++                                      goto errlab;
++                              }
++                              tdbprev = &(tdbh[i]);
++                              tdbp = tdbh[i];
++
++                              KLIPS_PRINT(debug_xform,
++                                          "klips_debug:ipsec_tdbcleanup: deleted SA chain:%s", sa);
++                              if(tdbp) {
++                                      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++                                      KLIPS_PRINT(debug_xform,
++                                                  ", tdbh[%d]=%s", i, sa);
++                              }
++                              if(*tdbprev) {
++                                      satoa((*tdbprev)->tdb_said, 0, sa, SATOA_BUF);
++                                      KLIPS_PRINT(debug_xform,
++                                                  ", *tdbprev=%s", sa);
++                                      if((*tdbprev)->tdb_hnext) {
++                                              satoa((*tdbprev)->tdb_hnext->tdb_said, 0, sa, SATOA_BUF);
++                                              KLIPS_PRINT(debug_xform,
++                                                          ", *tdbprev->tdb_hnext=%s", sa);
++                                      }
++                              }
++                              KLIPS_PRINT(debug_xform,
++                                          ".\n");
++                      } else {
++                              tdbprev = &tdbdel;
++                      }
++              }
++      }
++ errlab:
++
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      return(-error);
++}
++
++int
++ipsec_tdbwipe(struct tdb *tdbp)
++{
++      if(!tdbp) {
++              return -1;
++      }
++
++      if(tdbp->tdb_addr_s) {
++              memset((caddr_t)(tdbp->tdb_addr_s), 0, tdbp->tdb_addr_s_size);
++              kfree_s(tdbp->tdb_addr_s, tdbp->tdb_addr_s_size);
++      }
++      tdbp->tdb_addr_s = NULL;
++
++      if(tdbp->tdb_addr_d) {
++              memset((caddr_t)(tdbp->tdb_addr_d), 0, tdbp->tdb_addr_d_size);
++              kfree_s(tdbp->tdb_addr_d, tdbp->tdb_addr_d_size);
++      }
++      tdbp->tdb_addr_d = NULL;
++
++      if(tdbp->tdb_addr_p) {
++              memset((caddr_t)(tdbp->tdb_addr_p), 0, tdbp->tdb_addr_p_size);
++              kfree_s(tdbp->tdb_addr_p, tdbp->tdb_addr_p_size);
++      }
++      tdbp->tdb_addr_p = NULL;
++
++      if(tdbp->tdb_key_a) {
++              memset((caddr_t)(tdbp->tdb_key_a), 0, tdbp->tdb_key_a_size);
++              kfree_s(tdbp->tdb_key_a, tdbp->tdb_key_a_size);
++      }
++      tdbp->tdb_key_a = NULL;
++
++      if(tdbp->tdb_key_e) {
++              memset((caddr_t)(tdbp->tdb_key_e), 0, tdbp->tdb_key_e_size);
++              kfree_s(tdbp->tdb_key_e, tdbp->tdb_key_e_size);
++      }
++      tdbp->tdb_key_e = NULL;
++
++      if(tdbp->tdb_iv) {
++              memset((caddr_t)(tdbp->tdb_iv), 0, tdbp->tdb_iv_size);
++              kfree_s(tdbp->tdb_iv, tdbp->tdb_iv_size);
++      }
++      tdbp->tdb_iv = NULL;
++
++      memset((caddr_t)tdbp, 0, sizeof(*tdbp));
++      kfree_s(tdbp, sizeof(*tdbp));
++      tdbp = NULL;
++
++      return 0;
++}
++
++/*
++ * $Log$
++ * Revision 1.36  2000/01/26 10:11:28  rgb
++ * Fixed spacing in error text causing run-in words.
++ *
++ * Revision 1.35  2000/01/21 06:17:16  rgb
++ * Tidied up compiler directive indentation for readability.
++ * Added ictx,octx vars for simplification.(kravietz)
++ * Added macros for HMAC padding magic numbers.(kravietz)
++ * Fixed missing key length reporting bug.
++ * Fixed bug in tdbwipe to return immediately on NULL tdbp passed in.
++ *
++ * Revision 1.34  1999/12/08 00:04:19  rgb
++ * Fixed SA direction overwriting bug for netlink users.
++ *
++ * Revision 1.33  1999/12/01 22:16:44  rgb
++ * Minor formatting changes in ESP MD5 initialisation.
++ *
++ * Revision 1.32  1999/11/25 09:06:36  rgb
++ * Fixed error return messages, should be returning negative numbers.
++ * Implemented SENDERR macro for propagating error codes.
++ * Added debug message and separate error code for algorithms not compiled
++ * in.
++ *
++ * Revision 1.31  1999/11/23 23:06:26  rgb
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.30  1999/11/18 04:09:20  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.29  1999/11/17 15:53:40  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.28  1999/10/18 20:04:01  rgb
++ * Clean-out unused cruft.
++ *
++ * Revision 1.27  1999/10/03 19:01:03  rgb
++ * Spinlock support for 2.3.xx and 2.0.xx kernels.
++ *
++ * Revision 1.26  1999/10/01 16:22:24  rgb
++ * Switch from assignment init. to functional init. of spinlocks.
++ *
++ * Revision 1.25  1999/10/01 15:44:54  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.24  1999/10/01 00:03:46  rgb
++ * Added tdb structure locking.
++ * Minor formatting changes.
++ * Add function to initialize tdb hash table.
++ *
++ * Revision 1.23  1999/05/25 22:42:12  rgb
++ * Add deltdbchain() debugging.
++ *
++ * Revision 1.22  1999/05/25 21:24:31  rgb
++ * Add debugging statements to deltdbchain().
++ *
++ * Revision 1.21  1999/05/25 03:51:48  rgb
++ * Refix error return code.
++ *
++ * Revision 1.20  1999/05/25 03:34:07  rgb
++ * Fix error return for flush.
++ *
++ * Revision 1.19  1999/05/09 03:25:37  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.18  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.17  1999/04/29 15:20:16  rgb
++ * Change gettdb parameter to a pointer to reduce stack loading and
++ * facilitate parameter sanity checking.
++ * Add sanity checking for null pointer arguments.
++ * Add debugging instrumentation.
++ * Add function deltdbchain() which will take care of unlinking,
++ * zeroing and deleting a chain of tdbs.
++ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
++ * tdbwipe now actually zeroes the tdb as well as any of its pointed
++ * structures.
++ *
++ * Revision 1.16  1999/04/16 15:36:29  rgb
++ * Fix cut-and-paste error causing a memory leak in IPIP TDB freeing.
++ *
++ * Revision 1.15  1999/04/11 00:29:01  henry
++ * GPL boilerplate
++ *
++ * Revision 1.14  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.13  1999/02/19 18:23:01  rgb
++ * Nix debug off compile warning.
++ *
++ * Revision 1.12  1999/02/17 16:52:16  rgb
++ * Consolidate satoa()s for space and speed efficiency.
++ * Convert DEBUG_IPSEC to KLIPS_PRINT
++ * Clean out unused cruft.
++ * Ditch NET_IPIP dependancy.
++ * Loop for 3des key setting.
++ *
++ * Revision 1.11  1999/01/26 02:09:05  rgb
++ * Remove ah/esp/IPIP switching on include files.
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ * Removed dead code.
++ * Clean up debug code when switched off.
++ * Remove references to INET_GET_PROTOCOL.
++ * Added code exclusion macros to reduce code from unused algorithms.
++ *
++ * Revision 1.10  1999/01/22 06:28:55  rgb
++ * Cruft clean-out.
++ * Put random IV generation in kernel.
++ * Added algorithm switch code.
++ * Enhanced debugging.
++ * 64-bit clean-up.
++ *
++ * Revision 1.9  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.8  1998/11/25 04:59:06  rgb
++ * Add conditionals for no IPIP tunnel code.
++ * Delete commented out code.
++ *
++ * Revision 1.7  1998/10/31 06:50:41  rgb
++ * Convert xform ASCII names to no spaces.
++ * Fixed up comments in #endif directives.
++ *
++ * Revision 1.6  1998/10/19 14:44:28  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.5  1998/10/09 04:32:19  rgb
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ *
++ * Revision 1.4  1998/08/12 00:11:31  rgb
++ * Added new xform functions to the xform table.
++ * Fixed minor debug output spelling error.
++ *
++ * Revision 1.3  1998/07/09 17:45:31  rgb
++ * Clarify algorithm not available message.
++ *
++ * Revision 1.2  1998/06/23 03:00:51  rgb
++ * Check for presence of IPIP protocol if it is setup one way (we don't
++ * know what has been set up the other way and can only assume it will be
++ * symmetrical with the exception of keys).
++ *
++ * Revision 1.1  1998/06/18 21:27:51  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/06/11 05:54:59  rgb
++ * Added transform version string pointer to xformsw initialisations.
++ *
++ * Revision 1.2  1998/04/21 21:28:57  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:02  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.5  1997/06/03 04:24:48  ji
++ * Added ESP-3DES-MD5-96
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Added new transforms.
++ *
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/ipsec_xform.h linux-2.2.14/net/ipsec/ipsec_xform.h
+--- linux-2.2.14.orig/net/ipsec/ipsec_xform.h  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/ipsec_xform.h       Tue Feb  8 22:21:55 2000
+@@ -0,0 +1,318 @@
++/*
++ * Definitions relevant to IPSEC transformations
++ * Copyright (C) 1996, 1997  John Ioannidis.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++#include <freeswan.h>
++
++#define XF_NONE                       0       /* No transform set */
++#define XF_IP4                        1       /* IP inside IP */
++#define XF_AHMD5              2       /* AH MD5 */
++#define XF_AHSHA              3       /* AH SHA */
++#define XF_ESPDESOLD          4       /* old ESP DES-CBC */
++#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_ESPDESMD5          8       /* DES, HMAC-MD-5 with 128-bits of authentication */
++#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_ESPDESMD596          11      /* DES, HMAC-MD-5 with 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_ESPDESSHA196         15      /* DES, HMAC-SHA-1 with 96-bits of authentication */
++#define XF_ESPDES             16      /* ESP DES */
++
++#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
++ */
++
++#define AH_NONE                  0
++#define AH_MD5                   2
++#define AH_SHA                   3
++#define AH_DES                   4
++
++/* IPsec ESP transform values */
++
++#define ESP_NONE               0
++#define ESP_DES_IV64             1
++#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_DES_IV32             9
++#define ESP_RC4                 10
++#define ESP_NULL                11
++
++/* 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
++
++#ifdef DEBUG_IPSEC
++#define DB_XF_INIT    0x0001
++#endif
++
++#ifdef __KERNEL__
++/* 'struct tdb' should really be 64bit aligned... XXX */
++struct tdb                            /* tunnel descriptor block */
++{
++      struct tdb      *tdb_hnext;     /* next in hash chain */
++      struct tdb      *tdb_onext;     /* next in output */
++      struct tdb      *tdb_inext;     /* next in input (prev!) */
++      struct ifnet    *tdb_rcvif;     /* related rcv encap interface */
++      struct sa_id    tdb_said;       /* SA ID */
++      __u32   tdb_seq;        /* seq num of msg that set this SA */
++      __u32   tdb_pid;        /* PID of process that set this SA */
++#if 1
++      struct xformsw  *tdb_xform;     /* transformation to use (host order)*/
++      caddr_t         tdb_xdata;      /* transformation data (opaque) */
++#endif
++      __u8            tdb_authalg;    /* auth algorithm for this SA */
++      __u8            tdb_encalg;     /* enc algorithm for this SA */
++
++      __u32           tdb_alg_errs;   /* number of algorithm errors */
++      __u32   tdb_auth_errs;  /* number of authentication errors */
++      __u32   tdb_encsize_errs;       /* number of encryption size errors */
++      __u32   tdb_encpad_errs;        /* number of encryption size errors */
++      __u32   tdb_replaywin_errs;     /* number of pkt sequence errors */
++
++      __u8            tdb_replaywin;  /* replay window size */
++      __u8            tdb_state;      /* state of SA */
++      __u32   tdb_replaywin_lastseq;  /* last pkt sequence num */
++      __u64   tdb_replaywin_bitmap;   /* bitmap of received pkts */
++      __u32   tdb_replaywin_maxdiff;  /* maximum pkt sequence difference */
++
++      __u32   tdb_flags;      /* generic xform flags */
++
++      __u32   tdb_lifetime_allocations_c;     /* see rfc2367 */
++      __u32   tdb_lifetime_allocations_s;
++      __u32   tdb_lifetime_allocations_h;
++      __u64   tdb_lifetime_bytes_c;
++      __u64   tdb_lifetime_bytes_s;
++      __u64   tdb_lifetime_bytes_h;
++      __u64   tdb_lifetime_addtime_c;
++      __u64   tdb_lifetime_addtime_s;
++      __u64   tdb_lifetime_addtime_h;
++      __u64   tdb_lifetime_usetime_c;
++      __u64   tdb_lifetime_usetime_s;
++      __u64   tdb_lifetime_usetime_h;
++      __u64   tdb_lifetime_packets_c;
++      __u64   tdb_lifetime_packets_s;
++      __u64   tdb_lifetime_packets_h;
++      __u64   tdb_lifetime_usetime_l; /* last time transform was used */
++      struct sockaddr *tdb_addr_s;    /* src sockaddr */
++      struct sockaddr *tdb_addr_d;    /* dst sockaddr */
++              struct sockaddr *tdb_addr_p;    /* proxy sockaddr */
++      __u16   tdb_addr_s_size;
++      __u16   tdb_addr_d_size;
++      __u16   tdb_addr_p_size;
++      __u16   tdb_key_bits_a; /* size of authkey in bits */
++      __u16   tdb_auth_bits;  /* size of authenticator in bits */
++      __u16   tdb_key_bits_e; /* size of enckey in bits */
++      __u16   tdb_iv_bits;    /* size of IV in bits */
++
++      __u8    tdb_iv_size;
++      __u16   tdb_key_a_size;
++      __u16   tdb_key_e_size;
++      caddr_t tdb_key_a;      /* authentication key */
++      caddr_t tdb_key_e;      /* encryption key */
++      caddr_t tdb_iv;         /* Initialisation Vector */
++      __u16   tdb_ident_type_s;       /* src identity type */
++      __u16   tdb_ident_type_d;       /* dst identity type */
++      __u64   tdb_ident_id_s; /* src identity id */
++      __u64   tdb_ident_id_d; /* dst identity id */
++      __u8    tdb_ident_len_s;        /* src identity type */
++      __u8    tdb_ident_len_d;        /* dst identity type */
++      caddr_t tdb_ident_data_s;       /* src identity data */
++      caddr_t tdb_ident_data_d;       /* dst identity data */
++#if 0
++      sens
++#endif
++};
++
++#define tdb_spi tdb_said.spi
++#define tdb_dst tdb_said.dst
++#define tdb_proto tdb_said.proto
++
++#define TDB_XFORM_NAME(x) \
++      (x)->tdb_proto == IPPROTO_AH ? "AH" : \
++      (x)->tdb_proto == IPPROTO_ESP ? "ESP" : \
++      (x)->tdb_proto == IPPROTO_IPIP ? "IPIP" : \
++      (x)->tdb_proto == IPPROTO_COMP ? "COMP" : \
++      "UNKNOWN_proto", \
++      (x)->tdb_encalg == ESP_NONE ? "" : \
++      (x)->tdb_encalg == ESP_DES ? "_DES" : \
++      (x)->tdb_encalg == ESP_3DES ? "_3DES" : \
++      (x)->tdb_encalg == ESP_NULL ? "_NULL_encr" : \
++      "UNKNOWN_encr", \
++      (x)->tdb_authalg == AH_NONE ? "" : \
++      (x)->tdb_authalg == AH_MD5 ? "_HMAC_MD5" : \
++      (x)->tdb_authalg == AH_SHA ? "_HMAC_SHA1" : \
++      "UNKNOWN_auth" \
++
++#define TDB_HASHMOD   257
++
++struct xformsw
++{
++      u_short         xf_type;        /* Unique ID of xform */
++      u_short         xf_flags;       /* secondary type reall) */
++      char            *xf_name;       /* human-readable name */
++};
++
++extern struct tdb *tdbh[TDB_HASHMOD];
++extern spinlock_t tdb_lock;
++extern struct xformsw xformsw[], *xformswNXFORMSW;
++
++extern int ipsec_tdbinit(void);
++extern struct tdb *gettdb(struct sa_id*);
++extern /* void */ int deltdb(struct tdb *);
++extern /* void */ int deltdbchain(struct tdb *);
++extern /* void */ int puttdb(struct tdb *);
++extern int tdb_init(struct tdb *, struct encap_msghdr *);
++extern int ipsec_tdbcleanup(__u8);
++extern int ipsec_tdbwipe(struct tdb *);
++
++#ifdef DEBUG_IPSEC
++extern int debug_xform;
++#endif
++#endif /* __KERNEL__ */
++
++/*
++ * $Log$
++ * Revision 1.18  2000/01/21 06:17:45  rgb
++ * Tidied up spacing.
++ *
++ * Revision 1.17  1999/11/17 15:53:40  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.16  1999/10/16 04:23:07  rgb
++ * Add stats for replaywin_errs, replaywin_max_sequence_difference,
++ * authentication errors, encryption size errors, encryption padding
++ * errors, and time since last packet.
++ *
++ * Revision 1.15  1999/10/16 00:29:11  rgb
++ * Added SA lifetime packet counting variables.
++ *
++ * Revision 1.14  1999/10/01 00:04:14  rgb
++ * Added tdb structure locking.
++ * Add function to initialize tdb hash table.
++ *
++ * Revision 1.13  1999/04/29 15:20:57  rgb
++ * dd return values to init and cleanup functions.
++ * Eliminate unnessessary usage of tdb_xform member to further switch
++ * away from the transform switch to the algorithm switch.
++ * Change gettdb parameter to a pointer to reduce stack loading and
++ * facilitate parameter sanity checking.
++ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
++ *
++ * Revision 1.12  1999/04/15 15:37:25  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.9.2.2  1999/04/13 20:35:57  rgb
++ * Fix spelling mistake in comment.
++ *
++ * Revision 1.9.2.1  1999/03/30 17:13:52  rgb
++ * Extend struct tdb to support pfkey.
++ *
++ * Revision 1.11  1999/04/11 00:29:01  henry
++ * GPL boilerplate
++ *
++ * Revision 1.10  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.9  1999/01/26 02:09:31  rgb
++ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
++ * Removed dead code.
++ *
++ * Revision 1.8  1999/01/22 06:29:35  rgb
++ * Added algorithm switch code.
++ * Cruft clean-out.
++ *
++ * Revision 1.7  1998/11/10 05:37:35  rgb
++ * Add support for SA direction flag.
++ *
++ * Revision 1.6  1998/10/19 14:44:29  rgb
++ * Added inclusion of freeswan.h.
++ * sa_id structure implemented and used: now includes protocol.
++ *
++ * Revision 1.5  1998/08/12 00:12:30  rgb
++ * Added macros for new xforms.  Added prototypes for new xforms.
++ *
++ * Revision 1.4  1998/07/28 00:04:20  rgb
++ * Add macro for clearing the SA table.
++ *
++ * Revision 1.3  1998/07/14 18:06:46  rgb
++ * Added #ifdef __KERNEL__ directives to restrict scope of header.
++ *
++ * Revision 1.2  1998/06/23 03:02:19  rgb
++ * Created a prototype for ipsec_tdbcleanup when it was moved from
++ * ipsec_init.c.
++ *
++ * Revision 1.1  1998/06/18 21:27:51  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/06/11 05:55:31  rgb
++ * Added transform version string pointer to xformsw structure definition.
++ * Added extern declarations for transform version strings.
++ *
++ * Revision 1.3  1998/05/18 22:02:54  rgb
++ * Modify the *_zeroize function prototypes to include one parameter.
++ *
++ * Revision 1.2  1998/04/21 21:29:08  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:14  henry
++ * sources moved up from linux/net/ipsec
++ *
++ * Revision 1.1.1.1  1998/04/08 05:35:06  henry
++ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
++ *
++ * Revision 0.5  1997/06/03 04:24:48  ji
++ * Added ESP-3DES-MD5-96
++ *
++ * Revision 0.4  1997/01/15 01:28:15  ji
++ * Added new transforms.
++ *
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/Makefile linux-2.2.14/net/ipsec/libdes/Makefile
+--- linux-2.2.14.orig/net/ipsec/libdes/Makefile        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/Makefile     Thu Nov 25 18:04:25 1999
+@@ -0,0 +1,250 @@
++# You must select the correct terminal control system to be used to
++# turn character echo off when reading passwords.  There a 5 systems
++# SGTTY   - the old BSD system
++# TERMIO  - most system V boxes
++# TERMIOS - SGI (ala IRIX).
++# VMS     - the DEC operating system
++# MSDOS   - we all know what it is :-)
++# read_pwd.c makes a reasonable guess at what is correct.
++
++# Targets
++# make          - twidle the options yourself :-)
++# make cc       - standard cc options
++# make gcc      - standard gcc options
++# make x86-elf  - linux-elf etc
++# make x86-out  - linux-a.out, FreeBSD etc
++# make x86-solaris
++# make x86-bdsi
++
++# If you are on a DEC Alpha, edit des.h and change the DES_LONG
++# define to 'unsigned int'.  I have seen this give a %20 speedup.
++
++OPTS0= -DLIBDES_LIT -DRAND -DTERMIO #-DNOCONST
++
++# Version 1.94 has changed the strings_to_key function so that it is
++# now compatible with MITs when the string is longer than 8 characters.
++# If you wish to keep the old version, uncomment the following line.
++# This will affect the -E/-D options on des(1).
++#OPTS1= -DOLD_STR_TO_KEY
++
++# There are 4 possible performance options
++# -DDES_PTR
++# -DDES_RISC1
++# -DDES_RISC2 (only one of DES_RISC1 and DES_RISC2)
++# -DDES_UNROLL
++# after the initial build, run 'des_opts' to see which options are best
++# for your platform.  There are some listed in options.txt
++#OPTS2= -DDES_PTR 
++#OPTS3= -DDES_RISC1 # or DES_RISC2
++#OPTS4= -DDES_UNROLL
++
++OPTS= $(OPTS0) $(OPTS1) $(OPTS2) $(OPTS3) $(OPTS4)
++
++MAKE=make -f Makefile
++#CC=cc
++#CFLAG= -O
++
++CC=gcc
++#CFLAG= -O4 -funroll-loops -fomit-frame-pointer
++CFLAG= -O3 -fomit-frame-pointer
++
++CFLAGS=$(OPTS) $(CFLAG)
++CPP=$(CC) -E
++AS=as
++
++# Assember version of des_encrypt*().
++DES_ENC=des_enc.o fcrypt_b.o          # normal C version
++#DES_ENC=asm/dx86-elf.o       asm/yx86-elf.o  # elf format x86
++#DES_ENC=asm/dx86-out.o       asm/yx86-out.o  # a.out format x86
++#DES_ENC=asm/dx86-sol.o       asm/yx86-sol.o  # solaris format x86 
++#DES_ENC=asm/dx86bsdi.o       asm/yx86basi.o  # bsdi format x86 
++
++LIBDIR=/usr/local/lib
++BINDIR=/usr/local/bin
++INCDIR=/usr/local/include
++MANDIR=/usr/local/man
++MAN1=1
++MAN3=3
++SHELL=/bin/sh
++OBJ_LIT=cbc_enc.o ecb_enc.o $(DES_ENC) fcrypt.o set_key.o
++OBJ_FULL=cbc_cksm.o $(OBJ_LIT) pcbc_enc.o \
++      xcbc_enc.o qud_cksm.o \
++      cfb64ede.o cfb64enc.o cfb_enc.o ecb3_enc.o \
++      enc_read.o enc_writ.o ofb64ede.o ofb64enc.o ofb_enc.o  \
++      rand_key.o read_pwd.o read2pwd.o rpc_enc.o  str2key.o supp.o
++
++GENERAL_LIT=COPYRIGHT INSTALL README VERSION Makefile des_crypt.man \
++      des.doc options.txt asm
++GENERAL_FULL=$(GENERAL_LIT) FILES Imakefile times vms.com KERBEROS MODES.DES \
++      des.man DES.pm DES.pod DES.xs Makefile.PL dess.cpp des3s.cpp \
++      Makefile.uni typemap t Makefile.ssl makefile.bc Makefile.lit \
++      des.org des_locl.org
++TESTING_LIT=  destest speed des_opts
++TESTING_FULL= rpw $(TESTING_LIT)
++TESTING_SRC_LIT=destest.c speed.c des_opts.c
++TESTING_SRC_FULL=rpw.c $(TESTING_SRC_LIT)
++HEADERS_LIT=des_ver.h des.h des_locl.h podd.h sk.h spr.h
++HEADERS_FULL= $(HEADERS_LIT) rpc_des.h
++LIBDES_LIT=cbc_enc.c ecb_enc.c fcrypt.c set_key.c des_enc.c fcrypt_b.c
++LIBDES_FULL= cbc_cksm.c pcbc_enc.c qud_cksm.c \
++      cfb64ede.c cfb64enc.c cfb_enc.c ecb3_enc.c \
++      enc_read.c enc_writ.c ofb64ede.c ofb64enc.c ofb_enc.c  \
++      rand_key.c rpc_enc.c  str2key.c  supp.c \
++      xcbc_enc.c $(LIBDES_LIT) read_pwd.c read2pwd.c
++
++PERL= des.pl testdes.pl doIP doPC1 doPC2 PC1 PC2 shifts.pl
++
++OBJ=  $(OBJ_LIT)
++GENERAL=$(GENERAL_LIT)
++TESTING=$(TESTING_LIT)
++TESTING_SRC=$(TESTING_SRC_LIT)
++HEADERS=$(HEADERS_LIT)
++LIBDES=       $(LIBDES_LIT)
++
++ALL=  $(GENERAL) $(TESTING_SRC) $(LIBDES) $(PERL) $(HEADERS)
++
++DLIB= libdes.a
++
++all: $(DLIB) $(TESTING)
++
++cc:
++      $(MAKE) CC=cc CFLAGS="-O $(OPTS) $(CFLAG)" all
++
++gcc:
++      $(MAKE) CC=gcc CFLAGS="-O3 -fomit-frame-pointer $(OPTS) $(CFLAG)" all
++
++x86-elf:
++      $(MAKE) DES_ENC='asm/dx86-elf.o asm/yx86-elf.o' CC='$(CC)' CFLAGS="-DELF $(OPTS) $(CFLAG)" all
++
++x86-out:
++      $(MAKE) DES_ENC='asm/dx86-out.o asm/yx86-out.o' CC='$(CC)' CFLAGS="-DOUT $(OPTS) $(CFLAG)" all
++
++x86-solaris:
++      $(MAKE) DES_ENC='asm/dx86-sol.o asm/yx86-sol.o' CC='$(CC)' CFLAGS="-DSOL $(OPTS) $(CFLAG)" all
++
++x86-bsdi:
++      $(MAKE) DES_ENC='asm/dx86bsdi.o asm/yx86bsdi.o' CC='$(CC)' CFLAGS="-DBSDI $(OPTS) $(CFLAG)" all
++
++# elf
++asm/dx86-elf.o: asm/dx86unix.cpp
++      $(CPP) -DELF asm/dx86unix.cpp | $(AS) -o asm/dx86-elf.o
++
++asm/yx86-elf.o: asm/yx86unix.cpp
++      $(CPP) -DELF asm/yx86unix.cpp | $(AS) -o asm/yx86-elf.o
++
++# solaris
++asm/dx86-sol.o: asm/dx86unix.cpp
++      $(CC) -E -DSOL asm/dx86unix.cpp | sed 's/^#.*//' > asm/dx86-sol.s
++      as -o asm/dx86-sol.o asm/dx86-sol.s
++      rm -f asm/dx86-sol.s
++
++asm/yx86-sol.o: asm/yx86unix.cpp
++      $(CC) -E -DSOL asm/yx86unix.cpp | sed 's/^#.*//' > asm/yx86-sol.s
++      as -o asm/yx86-sol.o asm/yx86-sol.s
++      rm -f asm/yx86-sol.s
++
++# a.out
++asm/dx86-out.o: asm/dx86unix.cpp
++      $(CPP) -DOUT asm/dx86unix.cpp | $(AS) -o asm/dx86-out.o
++
++asm/yx86-out.o: asm/yx86unix.cpp
++      $(CPP) -DOUT asm/yx86unix.cpp | $(AS) -o asm/yx86-out.o
++
++# bsdi
++asm/dx86bsdi.o: asm/dx86unix.cpp
++      $(CPP) -DBSDI asm/dx86unix.cpp | $(AS) -o asm/dx86bsdi.o
++
++asm/yx86bsdi.o: asm/yx86unix.cpp
++      $(CPP) -DBSDI asm/yx86unix.cpp | $(AS) -o asm/yx86bsdi.o
++
++asm/dx86unix.cpp:
++      (cd asm; perl des-586.pl cpp >dx86unix.cpp)
++
++asm/yx86unix.cpp:
++      (cd asm; perl crypt586.pl cpp >yx86unix.cpp)
++
++test: all
++      ./destest
++
++$(DLIB): $(OBJ)
++      /bin/rm -f $(DLIB)
++      ar cr $(DLIB) $(OBJ)
++      -if test -s /bin/ranlib; then /bin/ranlib $(DLIB); \
++      else if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(DLIB); \
++      else exit 0; fi; fi
++
++des_opts: des_opts.o $(DLIB)
++      $(CC) $(CFLAGS) -o des_opts des_opts.o $(DLIB)
++
++destest: destest.o $(DLIB)
++      $(CC) $(CFLAGS) -o destest destest.o $(DLIB)
++
++rpw: rpw.o $(DLIB)
++      $(CC) $(CFLAGS) -o rpw rpw.o $(DLIB)
++
++speed: speed.o $(DLIB)
++      $(CC) $(CFLAGS) -o speed speed.o $(DLIB)
++
++des: des.o $(DLIB)
++      $(CC) $(CFLAGS) -o des des.o $(DLIB)
++
++tags:
++      ctags $(TESTING_SRC) $(LIBDES)
++
++tar_lit:
++      /bin/mv Makefile Makefile.tmp
++      /bin/cp Makefile.lit Makefile
++      tar chf libdes-l.tar $(LIBDES_LIT) $(HEADERS_LIT) \
++              $(GENERAL_LIT) $(TESTING_SRC_LIT)
++      /bin/rm -f Makefile
++      /bin/mv Makefile.tmp Makefile
++
++tar:
++      tar chf libdes.tar $(ALL)
++
++shar:
++      shar $(ALL) >libdes.shar
++
++depend:
++      makedepend $(LIBDES) $(TESTING_SRC)
++
++clean:
++      /bin/rm -f *.o tags core $(TESTING) $(DLIB) .nfs* *.old *.bak asm/*.o 
++
++dclean:
++      sed -e '/^# DO NOT DELETE THIS LINE/ q' Makefile >Makefile.new
++      mv -f Makefile.new Makefile
++
++# Eric is probably going to choke when he next looks at this --tjh
++install:
++      if test $(INSTALLTOP); then \
++          echo SSL style install; \
++          cp $(DLIB) $(INSTALLTOP)/lib; \
++          if test -s /bin/ranlib; then \
++              /bin/ranlib $(INSTALLTOP)/lib/$(DLIB); \
++          else \
++              if test -s /usr/bin/ranlib; then \
++              /usr/bin/ranlib $(INSTALLTOP)/lib/$(DLIB); \
++          fi; fi; \
++          chmod 644 $(INSTALLTOP)/lib/$(DLIB); \
++          cp des.h $(INSTALLTOP)/include; \
++          chmod 644 $(INSTALLTOP)/include/des.h; \
++      else \
++          echo Standalone install; \
++          cp $(DLIB) $(LIBDIR)/$(DLIB); \
++          if test -s /bin/ranlib; then \
++            /bin/ranlib $(LIBDIR)/$(DLIB); \
++          else \
++            if test -s /usr/bin/ranlib; then \
++              /usr/bin/ranlib $(LIBDIR)/$(DLIB); \
++            fi; \
++          fi; \
++          chmod 644 $(LIBDIR)/$(DLIB); \
++          cp des_crypt.man $(MANDIR)/man$(MAN3)/des_crypt.$(MAN3); \
++          chmod 644 $(MANDIR)/man$(MAN3)/des_crypt.$(MAN3); \
++          cp des.man $(MANDIR)/man$(MAN1)/des.$(MAN1); \
++          chmod 644 $(MANDIR)/man$(MAN1)/des.$(MAN1); \
++          cp des.h $(INCDIR)/des.h; \
++          chmod 644 $(INCDIR)/des.h; \
++      fi
++# DO NOT DELETE THIS LINE -- make depend depends on it.
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/crypt586.pl linux-2.2.14/net/ipsec/libdes/asm/crypt586.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/crypt586.pl Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/crypt586.pl      Thu Feb 18 17:41:30 1999
+@@ -0,0 +1,204 @@
++#!/usr/local/bin/perl
++#
++# The inner loop instruction sequence and the IP/FP modifications are from
++# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
++# I've added the stuff needed for crypt() but I've not worried about making
++# things perfect.
++#
++
++push(@INC,"perlasm","../../perlasm");
++require "x86asm.pl";
++
++&asm_init($ARGV[0],"crypt586.pl");
++
++$L="edi";
++$R="esi";
++
++&external_label("des_SPtrans");
++&fcrypt_body("fcrypt_body");
++&asm_finish();
++
++sub fcrypt_body
++      {
++      local($name,$do_ip)=@_;
++
++      &function_begin($name,"EXTRN   _des_SPtrans:DWORD");
++
++      &comment("");
++      &comment("Load the 2 words");
++      $ks="ebp";
++
++      &xor(   $L,     $L);
++      &xor(   $R,     $R);
++      &mov($ks,&wparam(1));
++
++      &push(25); # add a variable
++
++      &set_label("start");
++      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");
++              }
++       &mov("ebx",    &swtmp(0));
++      &mov("eax",     $L);
++       &dec("ebx");
++      &mov($L,        $R);
++       &mov($R,       "eax");
++      &mov(&swtmp(0), "ebx");
++       &jnz(&label("start"));
++
++      &comment("");
++      &comment("FP");
++      &mov("edx",&wparam(0));
++
++      &FP_new($R,$L,"eax",3);
++      &mov(&DWP(0,"edx","",0),"eax");
++      &mov(&DWP(4,"edx","",0),$L);
++
++      &pop("ecx");    # remove variable
++
++      &function_end($name);
++      }
++
++sub D_ENCRYPT
++      {
++      local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
++
++      &mov(   $u,             &wparam(2));                    # 2
++      &mov(   $t,             $R);
++      &shr(   $t,             16);                            # 1
++      &mov(   $tmp2,          &wparam(3));                    # 2
++      &xor(   $t,             $R);                            # 1
++
++      &and(   $u,             $t);                            # 2
++      &and(   $t,             $tmp2);                         # 2
++
++      &mov(   $tmp1,          $u);
++      &shl(   $tmp1,          16);                            # 1
++      &mov(   $tmp2,          $t);
++      &shl(   $tmp2,          16);                            # 1
++      &xor(   $u,             $tmp1);                         # 2
++      &xor(   $t,             $tmp2);                         # 2
++      &mov(   $tmp1,          &DWP(&n2a($S*4),$ks,"",0));     # 2
++      &xor(   $u,             $tmp1);
++      &mov(   $tmp2,          &DWP(&n2a(($S+1)*4),$ks,"",0)); # 2
++      &xor(   $u,             $R);
++      &xor(   $t,             $R);
++      &xor(   $t,             $tmp2);
++
++      &and(   $u,             "0xfcfcfcfc"    );              # 2
++      &xor(   $tmp1,          $tmp1);                         # 1
++      &and(   $t,             "0xcfcfcfcf"    );              # 2
++      &xor(   $tmp2,          $tmp2); 
++      &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 ($notlast 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);
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/des-586.pl linux-2.2.14/net/ipsec/libdes/asm/des-586.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/des-586.pl  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/des-586.pl       Thu Feb 18 17:41:31 1999
+@@ -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);
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/des686.pl linux-2.2.14/net/ipsec/libdes/asm/des686.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/des686.pl   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/des686.pl        Thu Feb 18 17:41:32 1999
+@@ -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]);
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/desboth.pl linux-2.2.14/net/ipsec/libdes/asm/desboth.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/desboth.pl  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/desboth.pl       Thu Feb 18 17:41:32 1999
+@@ -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);
++      }
++
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/cbc.pl linux-2.2.14/net/ipsec/libdes/asm/perlasm/cbc.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/cbc.pl      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/perlasm/cbc.pl   Thu Feb 18 17:41:34 1999
+@@ -0,0 +1,342 @@
++#!/usr/local/bin/perl
++
++# 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;
++#
++# calls 
++# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
++#
++
++#&cbc("des_ncbc_encrypt","des_encrypt",0);
++#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
++#     1,4,5,3,5,-1);
++#&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);
++#
++# When doing a cipher that needs bigendian order,
++# for encrypt, the iv is kept in bigendian form,
++# while for decrypt, it is kept in little endian.
++sub cbc
++      {
++      local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
++      # name is the function name
++      # enc_func and dec_func and the functions to call for encrypt/decrypt
++      # swap is true if byte order needs to be reversed
++      # iv_off is parameter number for the iv 
++      # enc_off is parameter number for the encrypt/decrypt flag
++      # p1,p2,p3 are the offsets for parameters to be passed to the
++      # underlying calls.
++
++      &function_begin_B($name,"");
++      &comment("");
++
++      $in="esi";
++      $out="edi";
++      $count="ebp";
++
++      &push("ebp");
++      &push("ebx");
++      &push("esi");
++      &push("edi");
++
++      $data_off=4;
++      $data_off+=4 if ($p1 > 0);
++      $data_off+=4 if ($p2 > 0);
++      $data_off+=4 if ($p3 > 0);
++
++      &mov($count,    &wparam(2));    # length
++
++      &comment("getting iv ptr from parameter $iv_off");
++      &mov("ebx",     &wparam($iv_off));      # Get iv ptr
++
++      &mov($in,       &DWP(0,"ebx","",0));#   iv[0]
++      &mov($out,      &DWP(4,"ebx","",0));#   iv[1]
++
++      &push($out);
++      &push($in);
++      &push($out);    # used in decrypt for iv[1]
++      &push($in);     # used in decrypt for iv[0]
++
++      &mov("ebx",     "esp");         # This is the address of tin[2]
++
++      &mov($in,       &wparam(0));    # in
++      &mov($out,      &wparam(1));    # out
++
++      # We have loaded them all, how lets push things
++      &comment("getting encrypt flag from parameter $enc_off");
++      &mov("ecx",     &wparam($enc_off));     # Get enc flag
++      if ($p3 > 0)
++              {
++              &comment("get and push parameter $p3");
++              if ($enc_off != $p3)
++                      { &mov("eax",   &wparam($p3)); &push("eax"); }
++              else    { &push("ecx"); }
++              }
++      if ($p2 > 0)
++              {
++              &comment("get and push parameter $p2");
++              if ($enc_off != $p2)
++                      { &mov("eax",   &wparam($p2)); &push("eax"); }
++              else    { &push("ecx"); }
++              }
++      if ($p1 > 0)
++              {
++              &comment("get and push parameter $p1");
++              if ($enc_off != $p1)
++                      { &mov("eax",   &wparam($p1)); &push("eax"); }
++              else    { &push("ecx"); }
++              }
++      &push("ebx");           # push data/iv
++
++      &cmp("ecx",0);
++      &jz(&label("decrypt"));
++
++      &and($count,0xfffffff8);
++      &mov("eax",     &DWP($data_off,"esp","",0));    # load iv[0]
++      &mov("ebx",     &DWP($data_off+4,"esp","",0));  # load iv[1]
++
++      &jz(&label("encrypt_finish"));
++
++      #############################################################
++
++      &set_label("encrypt_loop");
++      # encrypt start 
++      # "eax" and "ebx" hold iv (or the last cipher text)
++
++      &mov("ecx",     &DWP(0,$in,"",0));      # load first 4 bytes
++      &mov("edx",     &DWP(4,$in,"",0));      # second 4 bytes
++
++      &xor("eax",     "ecx");
++      &xor("ebx",     "edx");
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP($data_off,"esp","",0),        "eax"); # put in array for call
++      &mov(&DWP($data_off+4,"esp","",0),      "ebx"); #
++
++      &call($enc_func);
++
++      &mov("eax",     &DWP($data_off,"esp","",0));
++      &mov("ebx",     &DWP($data_off+4,"esp","",0));
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP(0,$out,"",0),"eax");
++      &mov(&DWP(4,$out,"",0),"ebx");
++
++      # eax and ebx are the next iv.
++
++      &add($in,       8);
++      &add($out,      8);
++
++      &sub($count,    8);
++      &jnz(&label("encrypt_loop"));
++
++###################################################################3
++      &set_label("encrypt_finish");
++      &mov($count,    &wparam(2));    # length
++      &and($count,    7);
++      &jz(&label("finish"));
++      &xor("ecx","ecx");
++      &xor("edx","edx");
++      &mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
++      &jmp_ptr($count);
++
++&set_label("ej7");
++      &xor("edx",             "edx") if $ppro; # ppro friendly
++      &movb(&HB("edx"),       &BP(6,$in,"",0));
++      &shl("edx",8);
++&set_label("ej6");
++      &movb(&HB("edx"),       &BP(5,$in,"",0));
++&set_label("ej5");
++      &movb(&LB("edx"),       &BP(4,$in,"",0));
++&set_label("ej4");
++      &mov("ecx",             &DWP(0,$in,"",0));
++      &jmp(&label("ejend"));
++&set_label("ej3");
++      &movb(&HB("ecx"),       &BP(2,$in,"",0));
++      &xor("ecx",             "ecx") if $ppro; # ppro friendly
++      &shl("ecx",8);
++&set_label("ej2");
++      &movb(&HB("ecx"),       &BP(1,$in,"",0));
++&set_label("ej1");
++      &movb(&LB("ecx"),       &BP(0,$in,"",0));
++&set_label("ejend");
++
++      &xor("eax",     "ecx");
++      &xor("ebx",     "edx");
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP($data_off,"esp","",0),        "eax"); # put in array for call
++      &mov(&DWP($data_off+4,"esp","",0),      "ebx"); #
++
++      &call($enc_func);
++
++      &mov("eax",     &DWP($data_off,"esp","",0));
++      &mov("ebx",     &DWP($data_off+4,"esp","",0));
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP(0,$out,"",0),"eax");
++      &mov(&DWP(4,$out,"",0),"ebx");
++
++      &jmp(&label("finish"));
++
++      #############################################################
++      #############################################################
++      &set_label("decrypt",1);
++      # decrypt start 
++      &and($count,0xfffffff8);
++      # The next 2 instructions are only for if the jz is taken
++      &mov("eax",     &DWP($data_off+8,"esp","",0));  # get iv[0]
++      &mov("ebx",     &DWP($data_off+12,"esp","",0)); # get iv[1]
++      &jz(&label("decrypt_finish"));
++
++      &set_label("decrypt_loop");
++      &mov("eax",     &DWP(0,$in,"",0));      # load first 4 bytes
++      &mov("ebx",     &DWP(4,$in,"",0));      # second 4 bytes
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP($data_off,"esp","",0),        "eax"); # put back
++      &mov(&DWP($data_off+4,"esp","",0),      "ebx"); #
++
++      &call($dec_func);
++
++      &mov("eax",     &DWP($data_off,"esp","",0));    # get return
++      &mov("ebx",     &DWP($data_off+4,"esp","",0));  #
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov("ecx",     &DWP($data_off+8,"esp","",0));  # get iv[0]
++      &mov("edx",     &DWP($data_off+12,"esp","",0)); # get iv[1]
++
++      &xor("ecx",     "eax");
++      &xor("edx",     "ebx");
++
++      &mov("eax",     &DWP(0,$in,"",0));      # get old cipher text,
++      &mov("ebx",     &DWP(4,$in,"",0));      # next iv actually
++
++      &mov(&DWP(0,$out,"",0),"ecx");
++      &mov(&DWP(4,$out,"",0),"edx");
++
++      &mov(&DWP($data_off+8,"esp","",0),      "eax"); # save iv
++      &mov(&DWP($data_off+12,"esp","",0),     "ebx"); #
++
++      &add($in,       8);
++      &add($out,      8);
++
++      &sub($count,    8);
++      &jnz(&label("decrypt_loop"));
++############################ ENDIT #######################3
++      &set_label("decrypt_finish");
++      &mov($count,    &wparam(2));    # length
++      &and($count,    7);
++      &jz(&label("finish"));
++
++      &mov("eax",     &DWP(0,$in,"",0));      # load first 4 bytes
++      &mov("ebx",     &DWP(4,$in,"",0));      # second 4 bytes
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov(&DWP($data_off,"esp","",0),        "eax"); # put back
++      &mov(&DWP($data_off+4,"esp","",0),      "ebx"); #
++
++      &call($dec_func);
++
++      &mov("eax",     &DWP($data_off,"esp","",0));    # get return
++      &mov("ebx",     &DWP($data_off+4,"esp","",0));  #
++
++      &bswap("eax")   if $swap;
++      &bswap("ebx")   if $swap;
++
++      &mov("ecx",     &DWP($data_off+8,"esp","",0));  # get iv[0]
++      &mov("edx",     &DWP($data_off+12,"esp","",0)); # get iv[1]
++
++      &xor("ecx",     "eax");
++      &xor("edx",     "ebx");
++
++      # this is for when we exit
++      &mov("eax",     &DWP(0,$in,"",0));      # get old cipher text,
++      &mov("ebx",     &DWP(4,$in,"",0));      # next iv actually
++
++&set_label("dj7");
++      &rotr("edx",    16);
++      &movb(&BP(6,$out,"",0), &LB("edx"));
++      &shr("edx",16);
++&set_label("dj6");
++      &movb(&BP(5,$out,"",0), &HB("edx"));
++&set_label("dj5");
++      &movb(&BP(4,$out,"",0), &LB("edx"));
++&set_label("dj4");
++      &mov(&DWP(0,$out,"",0), "ecx");
++      &jmp(&label("djend"));
++&set_label("dj3");
++      &rotr("ecx",    16);
++      &movb(&BP(2,$out,"",0), &LB("ecx"));
++      &shl("ecx",16);
++&set_label("dj2");
++      &movb(&BP(1,$in,"",0),  &HB("ecx"));
++&set_label("dj1");
++      &movb(&BP(0,$in,"",0),  &LB("ecx"));
++&set_label("djend");
++
++      # final iv is still in eax:ebx
++      &jmp(&label("finish"));
++
++
++############################ FINISH #######################3
++      &set_label("finish",1);
++      &mov("ecx",     &wparam($iv_off));      # Get iv ptr
++
++      #################################################
++      $total=16+4;
++      $total+=4 if ($p1 > 0);
++      $total+=4 if ($p2 > 0);
++      $total+=4 if ($p3 > 0);
++      &add("esp",$total);
++
++      &mov(&DWP(0,"ecx","",0),        "eax"); # save iv
++      &mov(&DWP(4,"ecx","",0),        "ebx"); # save iv
++
++      &function_end_A($name);
++
++      &set_label("cbc_enc_jmp_table",1);
++      &data_word("0");
++      &data_word(&label("ej1"));
++      &data_word(&label("ej2"));
++      &data_word(&label("ej3"));
++      &data_word(&label("ej4"));
++      &data_word(&label("ej5"));
++      &data_word(&label("ej6"));
++      &data_word(&label("ej7"));
++      &set_label("cbc_dec_jmp_table",1);
++      &data_word("0");
++      &data_word(&label("dj1"));
++      &data_word(&label("dj2"));
++      &data_word(&label("dj3"));
++      &data_word(&label("dj4"));
++      &data_word(&label("dj5"));
++      &data_word(&label("dj6"));
++      &data_word(&label("dj7"));
++
++      &function_end_B($name);
++      
++      }
++
++1;
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/readme linux-2.2.14/net/ipsec/libdes/asm/perlasm/readme
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/readme      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/perlasm/readme   Thu Feb 18 17:41:35 1999
+@@ -0,0 +1,124 @@
++The perl scripts in this directory are my 'hack' to generate
++multiple different assembler formats via the one origional script.
++
++The way to use this library is to start with adding the path to this directory
++and then include it.
++
++push(@INC,"perlasm","../../perlasm");
++require "x86asm.pl";
++
++The first thing we do is setup the file and type of assember
++
++&asm_init($ARGV[0],$0);
++
++The first argument is the 'type'.  Currently
++'cpp', 'sol', 'a.out', 'elf' or 'win32'.
++Argument 2 is the file name.
++
++The reciprocal function is
++&asm_finish() which should be called at the end.
++
++There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
++and x86unix.pl which is the unix (gas) version.
++
++Functions of interest are:
++&external_label("des_SPtrans");       declare and external variable
++&LB(reg);                     Low byte for a register
++&HB(reg);                     High byte for a register
++&BP(off,base,index,scale)     Byte pointer addressing
++&DWP(off,base,index,scale)    Word pointer addressing
++&stack_push(num)              Basically a 'sub esp, num*4' with extra
++&stack_pop(num)                       inverse of stack_push
++&function_begin(name,extra)   Start a function with pushing of
++                              edi, esi, ebx and ebp.  extra is extra win32
++                              external info that may be required.
++&function_begin_B(name,extra) Same as norma function_begin but no pushing.
++&function_end(name)           Call at end of function.
++&function_end_A(name)         Standard pop and ret, for use inside functions
++&function_end_B(name)         Call at end but with poping or 'ret'.
++&swtmp(num)                   Address on stack temp word.
++&wparam(num)                  Parameter number num, that was push
++                              in C convention.  This all works over pushes
++                              and pops.
++&comment("hello there")               Put in a comment.
++&label("loop")                        Refer to a label, normally a jmp target.
++&set_label("loop")            Set a label at this point.
++&data_word(word)              Put in a word of data.
++
++So how does this all hold together?  Given
++
++int calc(int len, int *data)
++      {
++      int i,j=0;
++
++      for (i=0; i<len; i++)
++              {
++              j+=other(data[i]);
++              }
++      }
++
++So a very simple version of this function could be coded as
++
++      push(@INC,"perlasm","../../perlasm");
++      require "x86asm.pl";
++      
++      &asm_init($ARGV[0],"cacl.pl");
++
++      &external_label("other");
++
++      $tmp1=  "eax";
++      $j=     "edi";
++      $data=  "esi";
++      $i=     "ebp";
++
++      &comment("a simple function");
++      &function_begin("calc");
++      &mov(   $data,          &wparam(1)); # data
++      &xor(   $j,             $j);
++      &xor(   $i,             $i);
++
++      &set_label("loop");
++      &cmp(   $i,             &wparam(0));
++      &jge(   &label("end"));
++
++      &mov(   $tmp1,          &DWP(0,$data,$i,4));
++      &push(  $tmp1);
++      &call(  "other");
++      &add(   $j,             "eax");
++      &pop(   $tmp1);
++      &inc(   $i);
++      &jmp(   &label("loop"));
++
++      &set_label("end");
++      &mov(   "eax",          $j);
++
++      &function_end("calc");
++
++      &asm_finish();
++
++The above example is very very unoptimised but gives an idea of how
++things work.
++
++There is also a cbc mode function generator in cbc.pl
++
++&cbc( $name,
++      $encrypt_function_name,
++      $decrypt_function_name,
++      $true_if_byte_swap_needed,
++      $parameter_number_for_iv,
++      $parameter_number_for_encrypt_flag,
++      $first_parameter_to_pass,
++      $second_parameter_to_pass,
++      $third_parameter_to_pass);
++
++So for example, given
++void BF_encrypt(BF_LONG *data,BF_KEY *key);
++void BF_decrypt(BF_LONG *data,BF_KEY *key);
++void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
++        BF_KEY *ks, unsigned char *iv, int enc);
++
++&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
++
++&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);
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86asm.pl linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86asm.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86asm.pl   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86asm.pl        Thu Feb 18 17:41:35 1999
+@@ -0,0 +1,111 @@
++#!/usr/local/bin/perl
++
++# require 'x86asm.pl';
++# &asm_init("cpp","des-586.pl");
++# XXX
++# XXX
++# main'asm_finish
++
++sub main'asm_finish
++      {
++      &file_end();
++      &asm_finish_cpp() if $cpp;
++      print &asm_get_output();
++      }
++
++sub main'asm_init
++      {
++      ($type,$fn)=@_;
++      $filename=$fn;
++
++      $cpp=$sol=$aout=$win32=0;
++      if (    ($type eq "elf"))
++              { require "x86unix.pl"; }
++      elsif ( ($type eq "a.out"))
++              { $aout=1; require "x86unix.pl"; }
++      elsif ( ($type eq "sol"))
++              { $sol=1; require "x86unix.pl"; }
++      elsif ( ($type eq "cpp"))
++              { $cpp=1; require "x86unix.pl"; }
++      elsif ( ($type eq "win32"))
++              { $win32=1; 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);
++              }
++
++      &asm_init_output();
++
++&comment("Don't even think of reading this code");
++&comment("It was automatically generated by $filename");
++&comment("Which is a perl program used to generate the x86 assember for");
++&comment("any of elf, a.out, BSDI,Win32, or Solaris");
++&comment("eric <eay\@cryptsoft.com>");
++&comment("");
++
++      $filename =~ s/\.pl$//;
++      &file($filename);
++      }
++
++sub asm_finish_cpp
++      {
++      return unless $cpp;
++
++      local($tmp,$i);
++      foreach $i (&get_labels())
++              {
++              $tmp.="#define $i _$i\n";
++              }
++      print <<"EOF";
++/* Run the C pre-processor over this file with one of the following defined
++ * ELF - elf object files,
++ * OUT - a.out object files,
++ * BSDI - BSDI style a.out object files
++ * SOL - Solaris style elf
++ */
++
++#define TYPE(a,b)       .type   a,b
++#define SIZE(a,b)       .size   a,b
++
++#if defined(OUT) || defined(BSDI)
++$tmp
++#endif
++
++#ifdef OUT
++#define OK    1
++#define ALIGN 4
++#endif
++
++#ifdef BSDI
++#define OK              1
++#define ALIGN           4
++#undef SIZE
++#undef TYPE
++#endif
++
++#if defined(ELF) || defined(SOL)
++#define OK              1
++#define ALIGN           16
++#endif
++
++#ifndef OK
++You need to define one of
++ELF - elf systems - linux-elf, NetBSD and DG-UX
++OUT - a.out systems - linux-a.out and FreeBSD
++SOL - solaris systems, which are elf with strange comment lines
++BSDI - a.out with a very primative version of as.
++#endif
++
++/* Let the Assembler begin :-) */
++EOF
++      }
++
++1;
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86ms.pl linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86ms.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86ms.pl    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86ms.pl Thu Feb 18 17:41:35 1999
+@@ -0,0 +1,345 @@
++#!/usr/local/bin/perl
++
++package x86ms;
++
++$label="L000";
++
++%lb=( 'eax',  'al',
++      'ebx',  'bl',
++      'ecx',  'cl',
++      'edx',  'dl',
++      'ax',   'al',
++      'bx',   'bl',
++      'cx',   'cl',
++      'dx',   'dl',
++      );
++
++%hb=( 'eax',  'ah',
++      'ebx',  'bh',
++      'ecx',  'ch',
++      'edx',  'dh',
++      'ax',   'ah',
++      'bx',   'bh',
++      'cx',   'ch',
++      'dx',   'dh',
++      );
++
++sub main'asm_init_output { @out=(); }
++sub main'asm_get_output { return(@out); }
++sub main'get_labels { return(@labels); }
++sub main'external_label { push(@labels,@_); }
++
++sub main'LB
++      {
++      (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
++      return($lb{$_[0]});
++      }
++
++sub main'HB
++      {
++      (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
++      return($hb{$_[0]});
++      }
++
++sub main'BP
++      {
++      &get_mem("BYTE",@_);
++      }
++
++sub main'DWP
++      {
++      &get_mem("DWORD",@_);
++      }
++
++sub main'stack_push
++      {
++      local($num)=@_;
++      $stack+=$num*4;
++      &main'sub("esp",$num*4);
++      }
++
++sub main'stack_pop
++      {
++      local($num)=@_;
++      $stack-=$num*4;
++      &main'add("esp",$num*4);
++      }
++
++sub get_mem
++      {
++      local($size,$addr,$reg1,$reg2,$idx)=@_;
++      local($t,$post);
++      local($ret)="$size PTR ";
++
++      $addr =~ s/^\s+//;
++      if ($addr =~ /^(.+)\+(.+)$/)
++              {
++              $reg2=&conv($1);
++              $addr="_$2";
++              }
++      elsif ($addr =~ /^[_a-zA-Z]/)
++              {
++              $addr="_$addr";
++              }
++
++      $reg1="$regs{$reg1}" if defined($regs{$reg1});
++      $reg2="$regs{$reg2}" if defined($regs{$reg2});
++      if (($addr ne "") && ($addr ne 0))
++              {
++              if ($addr !~ /^-/)
++                      { $ret.=$addr; }
++              else    { $post=$addr; }
++              }
++      if ($reg2 ne "")
++              {
++              $t="";
++              $t="*$idx" if ($idx != 0);
++              $reg1="+".$reg1 if ("$reg1$post" ne "");
++              $ret.="[$reg2$t$reg1$post]";
++              }
++      else
++              {
++              $ret.="[$reg1$post]"
++              }
++      return($ret);
++      }
++
++sub main'mov  { &out2("mov",@_); }
++sub main'movb { &out2("mov",@_); }
++sub main'and  { &out2("and",@_); }
++sub main'or   { &out2("or",@_); }
++sub main'shl  { &out2("shl",@_); }
++sub main'shr  { &out2("shr",@_); }
++sub main'xor  { &out2("xor",@_); }
++sub main'xorb { &out2("xor",@_); }
++sub main'add  { &out2("add",@_); }
++sub main'adc  { &out2("adc",@_); }
++sub main'sub  { &out2("sub",@_); }
++sub main'rotl { &out2("rol",@_); }
++sub main'rotr { &out2("ror",@_); }
++sub main'exch { &out2("xchg",@_); }
++sub main'cmp  { &out2("cmp",@_); }
++sub main'lea  { &out2("lea",@_); }
++sub main'mul  { &out1("mul",@_); }
++sub main'div  { &out1("div",@_); }
++sub main'dec  { &out1("dec",@_); }
++sub main'inc  { &out1("inc",@_); }
++sub main'jmp  { &out1("jmp",@_); }
++sub main'jmp_ptr { &out1p("jmp",@_); }
++sub main'je   { &out1("je",@_); }
++sub main'jle  { &out1("jle",@_); }
++sub main'jz   { &out1("jz",@_); }
++sub main'jge  { &out1("jge",@_); }
++sub main'jl   { &out1("jl",@_); }
++sub main'jb   { &out1("jb",@_); }
++sub main'jnz  { &out1("jnz",@_); }
++sub main'jne  { &out1("jne",@_); }
++sub main'push { &out1("push",@_); $stack+=4; }
++sub main'pop  { &out1("pop",@_); $stack-=4; }
++sub main'bswap        { &out1("bswap",@_); &using486(); }
++sub main'not  { &out1("not",@_); }
++sub main'call { &out1("call",'_'.$_[0]); }
++sub main'ret  { &out0("ret"); }
++sub main'nop  { &out0("nop"); }
++
++sub out2
++      {
++      local($name,$p1,$p2)=@_;
++      local($l,$t);
++
++      push(@out,"\t$name\t");
++      $t=&conv($p1).",";
++      $l=length($t);
++      push(@out,$t);
++      $l=4-($l+9)/8;
++      push(@out,"\t" x $l);
++      push(@out,&conv($p2));
++      push(@out,"\n");
++      }
++
++sub out0
++      {
++      local($name)=@_;
++
++      push(@out,"\t$name\n");
++      }
++
++sub out1
++      {
++      local($name,$p1)=@_;
++      local($l,$t);
++
++      push(@out,"\t$name\t".&conv($p1)."\n");
++      }
++
++sub conv
++      {
++      local($p)=@_;
++
++      $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
++      return $p;
++      }
++
++sub using486
++      {
++      return if $using486;
++      $using486++;
++      grep(s/\.386/\.486/,@out);
++      }
++
++sub main'file
++      {
++      local($file)=@_;
++
++      local($tmp)=<<"EOF";
++      TITLE   $file.asm
++        .386
++.model FLAT
++EOF
++      push(@out,$tmp);
++      }
++
++sub main'function_begin
++      {
++      local($func,$extra)=@_;
++
++      push(@labels,$func);
++
++      local($tmp)=<<"EOF";
++_TEXT SEGMENT
++PUBLIC        _$func
++$extra
++_$func PROC NEAR
++      push    ebp
++      push    ebx
++      push    esi
++      push    edi
++EOF
++      push(@out,$tmp);
++      $stack=20;
++      }
++
++sub main'function_begin_B
++      {
++      local($func,$extra)=@_;
++
++      local($tmp)=<<"EOF";
++_TEXT SEGMENT
++PUBLIC        _$func
++$extra
++_$func PROC NEAR
++EOF
++      push(@out,$tmp);
++      $stack=4;
++      }
++
++sub main'function_end
++      {
++      local($func)=@_;
++
++      local($tmp)=<<"EOF";
++      pop     edi
++      pop     esi
++      pop     ebx
++      pop     ebp
++      ret
++_$func ENDP
++_TEXT ENDS
++EOF
++      push(@out,$tmp);
++      $stack=0;
++      %label=();
++      }
++
++sub main'function_end_B
++      {
++      local($func)=@_;
++
++      local($tmp)=<<"EOF";
++_$func ENDP
++_TEXT ENDS
++EOF
++      push(@out,$tmp);
++      $stack=0;
++      %label=();
++      }
++
++sub main'function_end_A
++      {
++      local($func)=@_;
++
++      local($tmp)=<<"EOF";
++      pop     edi
++      pop     esi
++      pop     ebx
++      pop     ebp
++      ret
++EOF
++      push(@out,$tmp);
++      }
++
++sub main'file_end
++      {
++      push(@out,"END\n");
++      }
++
++sub main'wparam
++      {
++      local($num)=@_;
++
++      return(&main'DWP($stack+$num*4,"esp","",0));
++      }
++
++sub main'swtmp
++      {
++      return(&main'DWP($_[0]*4,"esp","",0));
++      }
++
++# Should use swtmp, which is above esp.  Linix can trash the stack above esp
++#sub main'wtmp
++#     {
++#     local($num)=@_;
++#
++#     return(&main'DWP(-(($num+1)*4),"esp","",0));
++#     }
++
++sub main'comment
++      {
++      foreach (@_)
++              {
++              push(@out,"\t; $_\n");
++              }
++      }
++
++sub main'label
++      {
++      if (!defined($label{$_[0]}))
++              {
++              $label{$_[0]}="\$${label}${_[0]}";
++              $label++;
++              }
++      return($label{$_[0]});
++      }
++
++sub main'set_label
++      {
++      if (!defined($label{$_[0]}))
++              {
++              $label{$_[0]}="${label}${_[0]}";
++              $label++;
++              }
++      push(@out,"$label{$_[0]}:\n");
++      }
++
++sub main'data_word
++      {
++      push(@out,"\tDD\t$_[0]\n");
++      }
++
++sub out1p
++      {
++      local($name,$p1)=@_;
++      local($l,$t);
++
++      push(@out,"\t$name\t ".&conv($p1)."\n");
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86unix.pl linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86unix.pl
+--- linux-2.2.14.orig/net/ipsec/libdes/asm/perlasm/x86unix.pl  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/asm/perlasm/x86unix.pl       Thu Feb 18 17:41:36 1999
+@@ -0,0 +1,403 @@
++#!/usr/local/bin/perl
++
++package x86unix;
++
++$label="L000";
++
++$align=($main'aout)?"4":"16";
++$under=($main'aout)?"_":"";
++$com_start=($main'sol)?"/":"#";
++
++sub main'asm_init_output { @out=(); }
++sub main'asm_get_output { return(@out); }
++sub main'get_labels { return(@labels); }
++sub main'external_label { push(@labels,@_); }
++
++if ($main'cpp)
++      {
++      $align="ALIGN";
++      $under="";
++      $com_start='/*';
++      $com_end='*/';
++      }
++
++%lb=( 'eax',  '%al',
++      'ebx',  '%bl',
++      'ecx',  '%cl',
++      'edx',  '%dl',
++      'ax',   '%al',
++      'bx',   '%bl',
++      'cx',   '%cl',
++      'dx',   '%dl',
++      );
++
++%hb=( 'eax',  '%ah',
++      'ebx',  '%bh',
++      'ecx',  '%ch',
++      'edx',  '%dh',
++      'ax',   '%ah',
++      'bx',   '%bh',
++      'cx',   '%ch',
++      'dx',   '%dh',
++      );
++
++%regs=(       'eax',  '%eax',
++      'ebx',  '%ebx',
++      'ecx',  '%ecx',
++      'edx',  '%edx',
++      'esi',  '%esi',
++      'edi',  '%edi',
++      'ebp',  '%ebp',
++      'esp',  '%esp',
++      );
++
++%reg_val=(
++      'eax',  0x00,
++      'ebx',  0x03,
++      'ecx',  0x01,
++      'edx',  0x02,
++      'esi',  0x06,
++      'edi',  0x07,
++      'ebp',  0x05,
++      'esp',  0x04,
++      );
++
++sub main'LB
++      {
++      (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
++      return($lb{$_[0]});
++      }
++
++sub main'HB
++      {
++      (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
++      return($hb{$_[0]});
++      }
++
++sub main'DWP
++      {
++      local($addr,$reg1,$reg2,$idx)=@_;
++
++      $ret="";
++      $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
++      $reg1="$regs{$reg1}" if defined($regs{$reg1});
++      $reg2="$regs{$reg2}" if defined($regs{$reg2});
++      $ret.=$addr if ($addr ne "") && ($addr ne 0);
++      if ($reg2 ne "")
++              { $ret.="($reg1,$reg2,$idx)"; }
++      else
++              { $ret.="($reg1)" }
++      return($ret);
++      }
++
++sub main'BP
++      {
++      return(&main'DWP(@_));
++      }
++
++#sub main'BP
++#     {
++#     local($addr,$reg1,$reg2,$idx)=@_;
++#
++#     $ret="";
++#
++#     $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
++#     $reg1="$regs{$reg1}" if defined($regs{$reg1});
++#     $reg2="$regs{$reg2}" if defined($regs{$reg2});
++#     $ret.=$addr if ($addr ne "") && ($addr ne 0);
++#     if ($reg2 ne "")
++#             { $ret.="($reg1,$reg2,$idx)"; }
++#     else
++#             { $ret.="($reg1)" }
++#     return($ret);
++#     }
++
++sub main'mov  { &out2("movl",@_); }
++sub main'movb { &out2("movb",@_); }
++sub main'and  { &out2("andl",@_); }
++sub main'or   { &out2("orl",@_); }
++sub main'shl  { &out2("sall",@_); }
++sub main'shr  { &out2("shrl",@_); }
++sub main'xor  { &out2("xorl",@_); }
++sub main'xorb { &out2("xorb",@_); }
++sub main'add  { &out2("addl",@_); }
++sub main'adc  { &out2("adcl",@_); }
++sub main'sub  { &out2("subl",@_); }
++sub main'rotl { &out2("roll",@_); }
++sub main'rotr { &out2("rorl",@_); }
++sub main'exch { &out2("xchg",@_); }
++sub main'cmp  { &out2("cmpl",@_); }
++sub main'lea  { &out2("leal",@_); }
++sub main'mul  { &out1("mull",@_); }
++sub main'div  { &out1("divl",@_); }
++sub main'jmp  { &out1("jmp",@_); }
++sub main'jmp_ptr { &out1p("jmp",@_); }
++sub main'je   { &out1("je",@_); }
++sub main'jle  { &out1("jle",@_); }
++sub main'jne  { &out1("jne",@_); }
++sub main'jnz  { &out1("jnz",@_); }
++sub main'jz   { &out1("jz",@_); }
++sub main'jge  { &out1("jge",@_); }
++sub main'jl   { &out1("jl",@_); }
++sub main'jb   { &out1("jb",@_); }
++sub main'dec  { &out1("decl",@_); }
++sub main'inc  { &out1("incl",@_); }
++sub main'push { &out1("pushl",@_); $stack+=4; }
++sub main'pop  { &out1("popl",@_); $stack-=4; }
++sub main'bswap        { &out1("bswapl",@_); }
++sub main'not  { &out1("notl",@_); }
++sub main'call { &out1("call",$under.$_[0]); }
++sub main'ret  { &out0("ret"); }
++sub main'nop  { &out0("nop"); }
++
++sub out2
++      {
++      local($name,$p1,$p2)=@_;
++      local($l,$ll,$t);
++      local(%special)=(       "roll",0xD1C0,"rorl",0xD1C8,
++                              "rcll",0xD1D0,"rcrl",0xD1D8,
++                              "shll",0xD1E0,"shrl",0xD1E8,
++                              "sarl",0xD1F8);
++      
++      if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
++              {
++              $op=$special{$name}|$reg_val{$p1};
++              $tmp1=sprintf ".byte %d\n",($op>>8)&0xff;
++              $tmp2=sprintf ".byte %d\t",$op     &0xff;
++              push(@out,$tmp1);
++              push(@out,$tmp2);
++
++              $p2=&conv($p2);
++              $p1=&conv($p1);
++              &main'comment("$name $p2 $p1");
++              return;
++              }
++
++      push(@out,"\t$name\t");
++      $t=&conv($p2).",";
++      $l=length($t);
++      push(@out,$t);
++      $ll=4-($l+9)/8;
++      $tmp1=sprintf "\t" x $ll;
++      push(@out,$tmp1);
++      push(@out,&conv($p1)."\n");
++      }
++
++sub out1
++      {
++      local($name,$p1)=@_;
++      local($l,$t);
++
++      push(@out,"\t$name\t".&conv($p1)."\n");
++      }
++
++sub out1p
++      {
++      local($name,$p1)=@_;
++      local($l,$t);
++
++      push(@out,"\t$name\t*".&conv($p1)."\n");
++      }
++
++sub out0
++      {
++      push(@out,"\t$_[0]\n");
++      }
++
++sub conv
++      {
++      local($p)=@_;
++
++#     $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
++
++      $p=$regs{$p} if (defined($regs{$p}));
++
++      $p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
++      $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
++      return $p;
++      }
++
++sub main'file
++      {
++      local($file)=@_;
++
++      local($tmp)=<<"EOF";
++      .file   "$file.s"
++      .version        "01.01"
++gcc2_compiled.:
++EOF
++      push(@out,$tmp);
++      }
++
++sub main'function_begin
++      {
++      local($func)=@_;
++
++      $func=$under.$func;
++
++      local($tmp)=<<"EOF";
++.text
++      .align $align
++.globl $func
++EOF
++      push(@out,$tmp);
++      if ($main'cpp)
++              { $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
++      else    { $tmp=push(@out,"\t.type\t$func,\@function\n"); }
++      push(@out,"$func:\n");
++      $tmp=<<"EOF";
++      pushl   %ebp
++      pushl   %ebx
++      pushl   %esi
++      pushl   %edi
++
++EOF
++      push(@out,$tmp);
++      $stack=20;
++      }
++
++sub main'function_begin_B
++      {
++      local($func,$extra)=@_;
++
++      $func=$under.$func;
++
++      local($tmp)=<<"EOF";
++.text
++      .align $align
++.globl $func
++EOF
++      push(@out,$tmp);
++      if ($main'cpp)
++              { push(@out,"\tTYPE($func,\@function)\n"); }
++      else    { push(@out,"\t.type    $func,\@function\n"); }
++      push(@out,"$func:\n");
++      $stack=4;
++      }
++
++sub main'function_end
++      {
++      local($func)=@_;
++
++      $func=$under.$func;
++
++      local($tmp)=<<"EOF";
++      popl    %edi
++      popl    %esi
++      popl    %ebx
++      popl    %ebp
++      ret
++.${func}_end:
++EOF
++      push(@out,$tmp);
++      if ($main'cpp)
++              { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
++      else    { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
++      push(@out,".ident       \"$func\"\n");
++      $stack=0;
++      %label=();
++      }
++
++sub main'function_end_A
++      {
++      local($func)=@_;
++
++      local($tmp)=<<"EOF";
++      popl    %edi
++      popl    %esi
++      popl    %ebx
++      popl    %ebp
++      ret
++EOF
++      push(@out,$tmp);
++      }
++
++sub main'function_end_B
++      {
++      local($func)=@_;
++
++      $func=$under.$func;
++
++      push(@out,".${func}_end:\n");
++      if ($main'cpp)
++              { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
++      else    { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
++      push(@out,".ident       \"desasm.pl\"\n");
++      $stack=0;
++      %label=();
++      }
++
++sub main'wparam
++      {
++      local($num)=@_;
++
++      return(&main'DWP($stack+$num*4,"esp","",0));
++      }
++
++sub main'stack_push
++      {
++      local($num)=@_;
++      $stack+=$num*4;
++      &main'sub("esp",$num*4);
++      }
++
++sub main'stack_pop
++      {
++      local($num)=@_;
++      $stack-=$num*4;
++      &main'add("esp",$num*4);
++      }
++
++sub main'swtmp
++      {
++      return(&main'DWP($_[0]*4,"esp","",0));
++      }
++
++# Should use swtmp, which is above esp.  Linix can trash the stack above esp
++#sub main'wtmp
++#     {
++#     local($num)=@_;
++#
++#     return(&main'DWP(-($num+1)*4,"esp","",0));
++#     }
++
++sub main'comment
++      {
++      foreach (@_)
++              {
++              if (/^\s*$/)
++                      { push(@out,"\n"); }
++              else
++                      { push(@out,"\t$com_start $_ $com_end\n"); }
++              }
++      }
++
++sub main'label
++      {
++      if (!defined($label{$_[0]}))
++              {
++              $label{$_[0]}=".${label}${_[0]}";
++              $label++;
++              }
++      return($label{$_[0]});
++      }
++
++sub main'set_label
++      {
++      if (!defined($label{$_[0]}))
++              {
++              $label{$_[0]}=".${label}${_[0]}";
++              $label++;
++              }
++      push(@out,".align $align\n") if ($_[1] != 0);
++      push(@out,"$label{$_[0]}:\n");
++      }
++
++sub main'file_end
++      {
++      }
++
++sub main'data_word
++      {
++      push(@out,"\t.long $_[0]\n");
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/cbc_enc.c linux-2.2.14/net/ipsec/libdes/cbc_enc.c
+--- linux-2.2.14.orig/net/ipsec/libdes/cbc_enc.c       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/cbc_enc.c    Thu Feb 18 17:41:10 1999
+@@ -0,0 +1,135 @@
++/* 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_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;
++
++      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;
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/des.h linux-2.2.14/net/ipsec/libdes/des.h
+--- linux-2.2.14.orig/net/ipsec/libdes/des.h   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/des.h        Tue Apr  6 00:02:01 1999
+@@ -0,0 +1,307 @@
++/* 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
++
++#include <stdio.h>
++
++/* 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). */
++#ifndef DES_LONG
++/* RCSID $Id$ */
++/* This conditional for FreeS/WAN project. */
++#ifdef __alpha
++#define DES_LONG unsigned int
++#else
++#define DES_LONG unsigned long
++#endif
++#endif
++
++typedef unsigned char des_cblock[8];
++typedef struct des_ks_struct
++      {
++      union   {
++              des_cblock _;
++              /* make sure things are correct size on machines with
++               * 8 byte longs */
++              DES_LONG pad[2];
++              } ks;
++#undef _
++#define _     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);
++#ifdef PERL5
++char *des_crypt(const char *buf,const char *salt);
++#else
++/* some stupid compilers complain because I have declared char instead
++ * of const char */
++#ifdef HEADER_DES_LOCL_H
++char *crypt(const char *buf,const char *salt);
++#else
++char *crypt();
++#endif
++#endif
++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> */
++void des_cblock_print_file(des_cblock *cb, FILE *fp);
++/* 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> */
++void des_cblock_print_file();
++/* 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
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/des_enc.c linux-2.2.14/net/ipsec/libdes/des_enc.c
+--- linux-2.2.14.orig/net/ipsec/libdes/des_enc.c       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/des_enc.c    Thu Feb 18 17:41:12 1999
+@@ -0,0 +1,502 @@
++/* 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_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;
++
++      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;
++
++      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;
++
++      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 */
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/des_locl.h linux-2.2.14/net/ipsec/libdes/des_locl.h
+--- linux-2.2.14.orig/net/ipsec/libdes/des_locl.h      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/des_locl.h   Thu Feb 18 17:41:12 1999
+@@ -0,0 +1,516 @@
++/* 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 <stdio.h>
++#include <stdlib.h>
++#ifndef MSDOS
++#include <unistd.h>
++#endif
++#include "des.h"
++
++#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)
++#include <string.h>
++#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
++
++#ifdef RAND
++#define srandom(s) srand(s)
++#define random rand
++#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); \
++                              } \
++                      }
++
++#if defined(WIN32)
++#define       ROTATE(a,n)     (_lrotr(a,n))
++#else
++#define       ROTATE(a,n)     (((a)>>(n))+((a)<<(32-(n))))
++#endif
++
++/* 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 NOPROTO
++void fcrypt_body(DES_LONG *out,des_key_schedule ks,
++      DES_LONG Eswap0, DES_LONG Eswap1);
++#else
++void fcrypt_body();
++#endif
++
++#endif
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/des_opts.c linux-2.2.14/net/ipsec/libdes/des_opts.c
+--- linux-2.2.14.orig/net/ipsec/libdes/des_opts.c      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/des_opts.c   Thu Feb 18 17:41:13 1999
+@@ -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.h"
++#include "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
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/des_ver.h linux-2.2.14/net/ipsec/libdes/des_ver.h
+--- linux-2.2.14.orig/net/ipsec/libdes/des_ver.h       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/des_ver.h    Thu Feb 18 17:41:13 1999
+@@ -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 */
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/destest.c linux-2.2.14/net/ipsec/libdes/destest.c
+--- linux-2.2.14.orig/net/ipsec/libdes/destest.c       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/destest.c    Thu Feb 18 17:41:13 1999
+@@ -0,0 +1,871 @@
++/* crypto/des/destest.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.]
++ */
++
++#if defined(WIN32) || defined(WIN16) || defined(WINDOWS)
++#ifndef MSDOS
++#define MSDOS
++#endif
++#endif
++
++#include <stdio.h>
++#include <stdlib.h>
++#ifndef MSDOS
++#include <unistd.h>
++#else
++#include <io.h>
++#endif
++#include <string.h>
++#include "des.h"
++
++/* tisk tisk - the test keys don't all have odd parity :-( */
++/* test data */
++#define NUM_TESTS 34
++static unsigned char key_data[NUM_TESTS][8]={
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
++      {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10},
++      {0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57},
++      {0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E},
++      {0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86},
++      {0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E},
++      {0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6},
++      {0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE},
++      {0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6},
++      {0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE},
++      {0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16},
++      {0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F},
++      {0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46},
++      {0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E},
++      {0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76},
++      {0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07},
++      {0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F},
++      {0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7},
++      {0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF},
++      {0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6},
++      {0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF},
++      {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
++      {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
++      {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10}};
++
++static unsigned char plain_data[NUM_TESTS][8]={
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
++      {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
++      {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
++      {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42},
++      {0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA},
++      {0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72},
++      {0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A},
++      {0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2},
++      {0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A},
++      {0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2},
++      {0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A},
++      {0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02},
++      {0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A},
++      {0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32},
++      {0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA},
++      {0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62},
++      {0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2},
++      {0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA},
++      {0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92},
++      {0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A},
++      {0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2},
++      {0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
++      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
++      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
++
++static unsigned char cipher_data[NUM_TESTS][8]={
++      {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
++      {0x73,0x59,0xB2,0x16,0x3E,0x4E,0xDC,0x58},
++      {0x95,0x8E,0x6E,0x62,0x7A,0x05,0x55,0x7B},
++      {0xF4,0x03,0x79,0xAB,0x9E,0x0E,0xC5,0x33},
++      {0x17,0x66,0x8D,0xFC,0x72,0x92,0x53,0x2D},
++      {0x8A,0x5A,0xE1,0xF8,0x1A,0xB8,0xF2,0xDD},
++      {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
++      {0xED,0x39,0xD9,0x50,0xFA,0x74,0xBC,0xC4},
++      {0x69,0x0F,0x5B,0x0D,0x9A,0x26,0x93,0x9B},
++      {0x7A,0x38,0x9D,0x10,0x35,0x4B,0xD2,0x71},
++      {0x86,0x8E,0xBB,0x51,0xCA,0xB4,0x59,0x9A},
++      {0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A},
++      {0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95},
++      {0x86,0xA5,0x60,0xF1,0x0E,0xC6,0xD8,0x5B},
++      {0x0C,0xD3,0xDA,0x02,0x00,0x21,0xDC,0x09},
++      {0xEA,0x67,0x6B,0x2C,0xB7,0xDB,0x2B,0x7A},
++      {0xDF,0xD6,0x4A,0x81,0x5C,0xAF,0x1A,0x0F},
++      {0x5C,0x51,0x3C,0x9C,0x48,0x86,0xC0,0x88},
++      {0x0A,0x2A,0xEE,0xAE,0x3F,0xF4,0xAB,0x77},
++      {0xEF,0x1B,0xF0,0x3E,0x5D,0xFA,0x57,0x5A},
++      {0x88,0xBF,0x0D,0xB6,0xD7,0x0D,0xEE,0x56},
++      {0xA1,0xF9,0x91,0x55,0x41,0x02,0x0B,0x56},
++      {0x6F,0xBF,0x1C,0xAF,0xCF,0xFD,0x05,0x56},
++      {0x2F,0x22,0xE4,0x9B,0xAB,0x7C,0xA1,0xAC},
++      {0x5A,0x6B,0x61,0x2C,0xC2,0x6C,0xCE,0x4A},
++      {0x5F,0x4C,0x03,0x8E,0xD1,0x2B,0x2E,0x41},
++      {0x63,0xFA,0xC0,0xD0,0x34,0xD9,0xF7,0x93},
++      {0x61,0x7B,0x3A,0x0C,0xE8,0xF0,0x71,0x00},
++      {0xDB,0x95,0x86,0x05,0xF8,0xC8,0xC6,0x06},
++      {0xED,0xBF,0xD1,0xC6,0x6C,0x29,0xCC,0xC7},
++      {0x35,0x55,0x50,0xB2,0x15,0x0E,0x24,0x51},
++      {0xCA,0xAA,0xAF,0x4D,0xEA,0xF1,0xDB,0xAE},
++      {0xD5,0xD4,0x4F,0xF7,0x20,0x68,0x3D,0x0D},
++      {0x2A,0x2B,0xB0,0x08,0xDF,0x97,0xC2,0xF2}};
++
++static unsigned char cipher_ecb2[NUM_TESTS-1][8]={
++      {0x92,0x95,0xB5,0x9B,0xB3,0x84,0x73,0x6E},
++      {0x19,0x9E,0x9D,0x6D,0xF3,0x9A,0xA8,0x16},
++      {0x2A,0x4B,0x4D,0x24,0x52,0x43,0x84,0x27},
++      {0x35,0x84,0x3C,0x01,0x9D,0x18,0xC5,0xB6},
++      {0x4A,0x5B,0x2F,0x42,0xAA,0x77,0x19,0x25},
++      {0xA0,0x6B,0xA9,0xB8,0xCA,0x5B,0x17,0x8A},
++      {0xAB,0x9D,0xB7,0xFB,0xED,0x95,0xF2,0x74},
++      {0x3D,0x25,0x6C,0x23,0xA7,0x25,0x2F,0xD6},
++      {0xB7,0x6F,0xAB,0x4F,0xBD,0xBD,0xB7,0x67},
++      {0x8F,0x68,0x27,0xD6,0x9C,0xF4,0x1A,0x10},
++      {0x82,0x57,0xA1,0xD6,0x50,0x5E,0x81,0x85},
++      {0xA2,0x0F,0x0A,0xCD,0x80,0x89,0x7D,0xFA},
++      {0xCD,0x2A,0x53,0x3A,0xDB,0x0D,0x7E,0xF3},
++      {0xD2,0xC2,0xBE,0x27,0xE8,0x1B,0x68,0xE3},
++      {0xE9,0x24,0xCF,0x4F,0x89,0x3C,0x5B,0x0A},
++      {0xA7,0x18,0xC3,0x9F,0xFA,0x9F,0xD7,0x69},
++      {0x77,0x2C,0x79,0xB1,0xD2,0x31,0x7E,0xB1},
++      {0x49,0xAB,0x92,0x7F,0xD0,0x22,0x00,0xB7},
++      {0xCE,0x1C,0x6C,0x7D,0x85,0xE3,0x4A,0x6F},
++      {0xBE,0x91,0xD6,0xE1,0x27,0xB2,0xE9,0x87},
++      {0x70,0x28,0xAE,0x8F,0xD1,0xF5,0x74,0x1A},
++      {0xAA,0x37,0x80,0xBB,0xF3,0x22,0x1D,0xDE},
++      {0xA6,0xC4,0xD2,0x5E,0x28,0x93,0xAC,0xB3},
++      {0x22,0x07,0x81,0x5A,0xE4,0xB7,0x1A,0xAD},
++      {0xDC,0xCE,0x05,0xE7,0x07,0xBD,0xF5,0x84},
++      {0x26,0x1D,0x39,0x2C,0xB3,0xBA,0xA5,0x85},
++      {0xB4,0xF7,0x0F,0x72,0xFB,0x04,0xF0,0xDC},
++      {0x95,0xBA,0xA9,0x4E,0x87,0x36,0xF2,0x89},
++      {0xD4,0x07,0x3A,0xF1,0x5A,0x17,0x82,0x0E},
++      {0xEF,0x6F,0xAF,0xA7,0x66,0x1A,0x7E,0x89},
++      {0xC1,0x97,0xF5,0x58,0x74,0x8A,0x20,0xE7},
++      {0x43,0x34,0xCF,0xDA,0x22,0xC4,0x86,0xC8},
++      {0x08,0xD7,0xB4,0xFB,0x62,0x9D,0x08,0x85}};
++
++static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
++static unsigned char cbc2_key[8]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87};
++static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
++static unsigned char cbc_iv  [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
++static char cbc_data[40]="7654321 Now is the time for \0001";
++
++static unsigned char cbc_ok[32]={
++      0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
++      0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
++      0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
++      0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
++
++static unsigned char xcbc_ok[32]={
++      0x86,0x74,0x81,0x0D,0x61,0xA4,0xA5,0x48,
++      0xB9,0x93,0x03,0xE1,0xB8,0xBB,0xBD,0xBD,
++      0x64,0x30,0x0B,0xB9,0x06,0x65,0x81,0x76,
++      0x04,0x1D,0x77,0x62,0x17,0xCA,0x2B,0xD2,
++      };
++
++static unsigned char cbc3_ok[32]={
++      0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
++      0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
++      0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
++      0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75};
++
++static unsigned char pcbc_ok[32]={
++      0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
++      0x6d,0xec,0xb4,0x70,0xa0,0xe5,0x6b,0x15,
++      0xae,0xa6,0xbf,0x61,0xed,0x7d,0x9c,0x9f,
++      0xf7,0x17,0x46,0x3b,0x8a,0xb3,0xcc,0x88};
++
++static unsigned char cfb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
++static unsigned char cfb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
++static unsigned char cfb_buf1[40],cfb_buf2[40],cfb_tmp[8];
++static unsigned char plain[24]=
++      {
++      0x4e,0x6f,0x77,0x20,0x69,0x73,
++      0x20,0x74,0x68,0x65,0x20,0x74,
++      0x69,0x6d,0x65,0x20,0x66,0x6f,
++      0x72,0x20,0x61,0x6c,0x6c,0x20
++      };
++static unsigned char cfb_cipher8[24]= {
++      0xf3,0x1f,0xda,0x07,0x01,0x14, 0x62,0xee,0x18,0x7f,0x43,0xd8,
++      0x0a,0x7c,0xd9,0xb5,0xb0,0xd2, 0x90,0xda,0x6e,0x5b,0x9a,0x87 };
++static unsigned char cfb_cipher16[24]={
++      0xF3,0x09,0x87,0x87,0x7F,0x57, 0xF7,0x3C,0x36,0xB6,0xDB,0x70,
++      0xD8,0xD5,0x34,0x19,0xD3,0x86, 0xB2,0x23,0xB7,0xB2,0xAD,0x1B };
++static unsigned char cfb_cipher32[24]={
++      0xF3,0x09,0x62,0x49,0xA4,0xDF, 0xA4,0x9F,0x33,0xDC,0x7B,0xAD,
++      0x4C,0xC8,0x9F,0x64,0xE4,0x53, 0xE5,0xEC,0x67,0x20,0xDA,0xB6 };
++static unsigned char cfb_cipher48[24]={
++      0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x30,0xB5,0x15,0xEC,0xBB,0x85,
++      0x97,0x5A,0x13,0x8C,0x68,0x60, 0xE2,0x38,0x34,0x3C,0xDC,0x1F };
++static unsigned char cfb_cipher64[24]={
++      0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x6E,0x51,0xA6,0x9E,0x83,0x9B,
++      0x1A,0x92,0xF7,0x84,0x03,0x46, 0x71,0x33,0x89,0x8E,0xA6,0x22 };
++
++static unsigned char ofb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
++static unsigned char ofb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
++static unsigned char ofb_buf1[24],ofb_buf2[24],ofb_tmp[8];
++static unsigned char ofb_cipher[24]=
++      {
++      0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51,
++      0x35,0xf2,0x4a,0x24,0x2e,0xeb,0x3d,0x3f,
++      0x3d,0x6d,0x5b,0xe3,0x25,0x5a,0xf8,0xc3
++      };
++
++DES_LONG cbc_cksum_ret=0xB462FEF7L;
++unsigned char cbc_cksum_data[8]={0x1D,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
++
++#ifndef NOPROTO
++static char *pt(unsigned char *p);
++static int cfb_test(int bits, unsigned char *cfb_cipher);
++static int cfb64_test(unsigned char *cfb_cipher);
++static int ede_cfb64_test(unsigned char *cfb_cipher);
++#else
++static char *pt();
++static int cfb_test();
++static int cfb64_test();
++static int ede_cfb64_test();
++#endif
++
++int main(argc,argv)
++int argc;
++char *argv[];
++      {
++      int i,j,err=0;
++      des_cblock in,out,outin,iv3;
++      des_key_schedule ks,ks2,ks3;
++      unsigned char cbc_in[40];
++      unsigned char cbc_out[40];
++      DES_LONG cs;
++      unsigned char qret[4][4],cret[8];
++      DES_LONG lqret[4];
++      int num;
++      char *str;
++
++      printf("Doing ecb\n");
++      for (i=0; i<NUM_TESTS; i++)
++              {
++              if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
++                      {
++                      printf("Key error %2d:%d\n",i+1,j);
++                      err=1;
++                      }
++              memcpy(in,plain_data[i],8);
++              memset(out,0,8);
++              memset(outin,0,8);
++              des_ecb_encrypt((C_Block *)in,(C_Block *)out,ks,DES_ENCRYPT);
++              des_ecb_encrypt((C_Block *)out,(C_Block *)outin,ks,DES_DECRYPT);
++
++              if (memcmp(out,cipher_data[i],8) != 0)
++                      {
++                      printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
++                              i+1,pt(key_data[i]),pt(in),pt(cipher_data[i]),
++                              pt(out));
++                      err=1;
++                      }
++              if (memcmp(in,outin,8) != 0)
++                      {
++                      printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
++                              i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
++                      err=1;
++                      }
++              }
++
++#ifndef LIBDES_LIT
++      printf("Doing ede ecb\n");
++      for (i=0; i<(NUM_TESTS-1); i++)
++              {
++              if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
++                      {
++                      err=1;
++                      printf("Key error %2d:%d\n",i+1,j);
++                      }
++              if ((j=des_key_sched((C_Block *)(key_data[i+1]),ks2)) != 0)
++                      {
++                      printf("Key error %2d:%d\n",i+2,j);
++                      err=1;
++                      }
++              if ((j=des_key_sched((C_Block *)(key_data[i+2]),ks3)) != 0)
++                      {
++                      printf("Key error %2d:%d\n",i+3,j);
++                      err=1;
++                      }
++              memcpy(in,plain_data[i],8);
++              memset(out,0,8);
++              memset(outin,0,8);
++              des_ecb2_encrypt((C_Block *)in,(C_Block *)out,ks,ks2,
++                      DES_ENCRYPT);
++              des_ecb2_encrypt((C_Block *)out,(C_Block *)outin,ks,ks2,
++                      DES_DECRYPT);
++
++              if (memcmp(out,cipher_ecb2[i],8) != 0)
++                      {
++                      printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
++                              i+1,pt(key_data[i]),pt(in),pt(cipher_ecb2[i]),
++                              pt(out));
++                      err=1;
++                      }
++              if (memcmp(in,outin,8) != 0)
++                      {
++                      printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
++                              i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
++                      err=1;
++                      }
++              }
++#endif
++
++      printf("Doing cbc\n");
++      if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      memset(cbc_out,0,40);
++      memset(cbc_in,0,40);
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++      des_ncbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
++              (long)strlen((char *)cbc_data)+1,ks,
++              (C_Block *)iv3,DES_ENCRYPT);
++      if (memcmp(cbc_out,cbc_ok,32) != 0)
++              printf("cbc_encrypt encrypt error\n");
++
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++      des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
++              (long)strlen((char *)cbc_data)+1,ks,
++              (C_Block *)iv3,DES_DECRYPT);
++      if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)) != 0)
++              {
++              printf("cbc_encrypt decrypt error\n");
++              err=1;
++              }
++
++#ifndef LIBDES_LIT
++      printf("Doing desx cbc\n");
++      if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      memset(cbc_out,0,40);
++      memset(cbc_in,0,40);
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++      des_xcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
++              (long)strlen((char *)cbc_data)+1,ks,
++              (C_Block *)iv3,
++              (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_ENCRYPT);
++      if (memcmp(cbc_out,xcbc_ok,32) != 0)
++              {
++              printf("des_xcbc_encrypt encrypt error\n");
++              }
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++      des_xcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
++              (long)strlen((char *)cbc_data)+1,ks,
++              (C_Block *)iv3,
++              (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_DECRYPT);
++      if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)+1) != 0)
++              {
++              printf("des_xcbc_encrypt decrypt error\n");
++              err=1;
++              }
++#endif
++
++      printf("Doing ede cbc\n");
++      if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      if ((j=des_key_sched((C_Block *)cbc2_key,ks2)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      if ((j=des_key_sched((C_Block *)cbc3_key,ks3)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      memset(cbc_out,0,40);
++      memset(cbc_in,0,40);
++      i=strlen((char *)cbc_data)+1;
++      /* i=((i+7)/8)*8; */
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++
++      des_ede3_cbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
++              16L,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
++      des_ede3_cbc_encrypt((C_Block *)&(cbc_data[16]),
++              (C_Block *)&(cbc_out[16]),
++              (long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
++      if (memcmp(cbc_out,cbc3_ok,
++              (unsigned int)(strlen((char *)cbc_data)+1+7)/8*8) != 0)
++              {
++              printf("des_ede3_cbc_encrypt encrypt error\n");
++              err=1;
++              }
++
++      memcpy(iv3,cbc_iv,sizeof(cbc_iv));
++      des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
++              (long)i,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
++      if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
++              {
++              printf("des_ede3_cbc_encrypt decrypt error\n");
++              err=1;
++              }
++
++#ifndef LIBDES_LIT
++      printf("Doing pcbc\n");
++      if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
++              {
++              printf("Key error %d\n",j);
++              err=1;
++              }
++      memset(cbc_out,0,40);
++      memset(cbc_in,0,40);
++      des_pcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
++              (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_ENCRYPT);
++      if (memcmp(cbc_out,pcbc_ok,32) != 0)
++              {
++              printf("pcbc_encrypt encrypt error\n");
++              err=1;
++              }
++      des_pcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
++              (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_DECRYPT);
++      if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
++              {
++              printf("pcbc_encrypt decrypt error\n");
++              err=1;
++              }
++
++      printf("Doing ");
++      printf("cfb8 ");
++      err+=cfb_test(8,cfb_cipher8);
++      printf("cfb16 ");
++      err+=cfb_test(16,cfb_cipher16);
++      printf("cfb32 ");
++      err+=cfb_test(32,cfb_cipher32);
++      printf("cfb48 ");
++      err+=cfb_test(48,cfb_cipher48);
++      printf("cfb64 ");
++      err+=cfb_test(64,cfb_cipher64);
++
++      printf("cfb64() ");
++      err+=cfb64_test(cfb_cipher64);
++
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      for (i=0; i<sizeof(plain); i++)
++              des_cfb_encrypt(&(plain[i]),&(cfb_buf1[i]),
++                      8,(long)1,ks,(C_Block *)cfb_tmp,DES_ENCRYPT);
++      if (memcmp(cfb_cipher8,cfb_buf1,sizeof(plain)) != 0)
++              {
++              printf("cfb_encrypt small encrypt error\n");
++              err=1;
++              }
++
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      for (i=0; i<sizeof(plain); i++)
++              des_cfb_encrypt(&(cfb_buf1[i]),&(cfb_buf2[i]),
++                      8,(long)1,ks,(C_Block *)cfb_tmp,DES_DECRYPT);
++      if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
++              {
++              printf("cfb_encrypt small decrypt error\n");
++              err=1;
++              }
++
++      printf("ede_cfb64() ");
++      err+=ede_cfb64_test(cfb_cipher64);
++
++      printf("done\n");
++
++      printf("Doing ofb\n");
++      des_key_sched((C_Block *)ofb_key,ks);
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      des_ofb_encrypt(plain,ofb_buf1,64,(long)sizeof(plain)/8,ks,
++              (C_Block *)ofb_tmp);
++      if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
++              {
++              printf("ofb_encrypt encrypt error\n");
++printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
++ofb_buf1[8+0], ofb_buf1[8+1], ofb_buf1[8+2], ofb_buf1[8+3],
++ofb_buf1[8+4], ofb_buf1[8+5], ofb_buf1[8+6], ofb_buf1[8+7]);
++printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
++ofb_buf1[8+0], ofb_cipher[8+1], ofb_cipher[8+2], ofb_cipher[8+3],
++ofb_buf1[8+4], ofb_cipher[8+5], ofb_cipher[8+6], ofb_cipher[8+7]);
++              err=1;
++              }
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      des_ofb_encrypt(ofb_buf1,ofb_buf2,64,(long)sizeof(ofb_buf1)/8,ks,
++              (C_Block *)ofb_tmp);
++      if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
++              {
++              printf("ofb_encrypt decrypt error\n");
++printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
++ofb_buf2[8+0], ofb_buf2[8+1], ofb_buf2[8+2], ofb_buf2[8+3],
++ofb_buf2[8+4], ofb_buf2[8+5], ofb_buf2[8+6], ofb_buf2[8+7]);
++printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
++plain[8+0], plain[8+1], plain[8+2], plain[8+3],
++plain[8+4], plain[8+5], plain[8+6], plain[8+7]);
++              err=1;
++              }
++
++      printf("Doing ofb64\n");
++      des_key_sched((C_Block *)ofb_key,ks);
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      memset(ofb_buf1,0,sizeof(ofb_buf1));
++      memset(ofb_buf2,0,sizeof(ofb_buf1));
++      num=0;
++      for (i=0; i<sizeof(plain); i++)
++              {
++              des_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,
++                      (C_Block *)ofb_tmp,&num);
++              }
++      if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
++              {
++              printf("ofb64_encrypt encrypt error\n");
++              err=1;
++              }
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      num=0;
++      des_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
++              (C_Block *)ofb_tmp,&num);
++      if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
++              {
++              printf("ofb64_encrypt decrypt error\n");
++              err=1;
++              }
++
++      printf("Doing ede_ofb64\n");
++      des_key_sched((C_Block *)ofb_key,ks);
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      memset(ofb_buf1,0,sizeof(ofb_buf1));
++      memset(ofb_buf2,0,sizeof(ofb_buf1));
++      num=0;
++      for (i=0; i<sizeof(plain); i++)
++              {
++              des_ede3_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,ks,ks,
++                      (C_Block *)ofb_tmp,&num);
++              }
++      if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
++              {
++              printf("ede_ofb64_encrypt encrypt error\n");
++              err=1;
++              }
++      memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
++      num=0;
++      des_ede3_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
++              ks,ks,(C_Block *)ofb_tmp,&num);
++      if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
++              {
++              printf("ede_ofb64_encrypt decrypt error\n");
++              err=1;
++              }
++
++      printf("Doing cbc_cksum\n");
++      des_key_sched((C_Block *)cbc_key,ks);
++      cs=des_cbc_cksum((C_Block *)cbc_data,(C_Block *)cret,
++              (long)strlen(cbc_data),ks,(C_Block *)cbc_iv);
++      if (cs != cbc_cksum_ret)
++              {
++              printf("bad return value (%08lX), should be %08lX\n",
++                      (unsigned long)cs,(unsigned long)cbc_cksum_ret);
++              err=1;
++              }
++      if (memcmp(cret,cbc_cksum_data,8) != 0)
++              {
++              printf("bad cbc_cksum block returned\n");
++              err=1;
++              }
++
++      printf("Doing quad_cksum\n");
++      cs=quad_cksum((C_Block *)cbc_data,(C_Block *)qret,
++              (long)strlen(cbc_data),2,(C_Block *)cbc_iv);
++      for (i=0; i<4; i++)
++              {
++              lqret[i]=0;
++              memcpy(&(lqret[i]),&(qret[i][0]),4);
++              }
++      { /* Big-endian fix */
++      static DES_LONG l=1;
++      static unsigned char *c=(unsigned char *)&l;
++      DES_LONG ll;
++
++      if (!c[0])
++              {
++              ll=lqret[0]^lqret[3];
++              lqret[0]^=ll;
++              lqret[3]^=ll;
++              ll=lqret[1]^lqret[2];
++              lqret[1]^=ll;
++              lqret[2]^=ll;
++              }
++      }
++      if (cs != 0x70d7a63aL)
++              {
++              printf("quad_cksum error, ret %08lx should be 70d7a63a\n",
++                      (unsigned long)cs);
++              err=1;
++              }
++      if (lqret[0] != 0x327eba8dL)
++              {
++              printf("quad_cksum error, out[0] %08lx is not %08lx\n",
++                      (unsigned long)lqret[0],0x327eba8dL);
++              err=1;
++              }
++      if (lqret[1] != 0x201a49ccL)
++              {
++              printf("quad_cksum error, out[1] %08lx is not %08lx\n",
++                      (unsigned long)lqret[1],0x201a49ccL);
++              err=1;
++              }
++      if (lqret[2] != 0x70d7a63aL)
++              {
++              printf("quad_cksum error, out[2] %08lx is not %08lx\n",
++                      (unsigned long)lqret[2],0x70d7a63aL);
++              err=1;
++              }
++      if (lqret[3] != 0x501c2c26L)
++              {
++              printf("quad_cksum error, out[3] %08lx is not %08lx\n",
++                      (unsigned long)lqret[3],0x501c2c26L);
++              err=1;
++              }
++#endif
++
++      printf("input word alignment test");
++      for (i=0; i<4; i++)
++              {
++              printf(" %d",i);
++              des_ncbc_encrypt((C_Block *)&(cbc_out[i]),(C_Block *)cbc_in,
++                      (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
++                      DES_ENCRYPT);
++              }
++      printf("\noutput word alignment test");
++      for (i=0; i<4; i++)
++              {
++              printf(" %d",i);
++              des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)&(cbc_in[i]),
++                      (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
++                      DES_ENCRYPT);
++              }
++      printf("\n");
++      printf("fast crypt test ");
++      str=crypt("testing","ef");
++      if (strcmp("efGnQx2725bI2",str) != 0)
++              {
++              printf("fast crypt error, %s should be efGnQx2725bI2\n",str);
++              err=1;
++              }
++      str=crypt("bca76;23","yA");
++      if (strcmp("yA1Rp/1hZXIJk",str) != 0)
++              {
++              printf("fast crypt error, %s should be yA1Rp/1hZXIJk\n",str);
++              err=1;
++              }
++      printf("\n");
++      exit(err);
++      return(0);
++      }
++
++static char *pt(p)
++unsigned char *p;
++      {
++      static char bufs[10][20];
++      static int bnum=0;
++      char *ret;
++      int i;
++      static char *f="0123456789ABCDEF";
++
++      ret= &(bufs[bnum++][0]);
++      bnum%=10;
++      for (i=0; i<8; i++)
++              {
++              ret[i*2]=f[(p[i]>>4)&0xf];
++              ret[i*2+1]=f[p[i]&0xf];
++              }
++      ret[16]='\0';
++      return(ret);
++      }
++
++#ifndef LIBDES_LIT
++
++static int cfb_test(bits, cfb_cipher)
++int bits;
++unsigned char *cfb_cipher;
++      {
++      des_key_schedule ks;
++      int i,err=0;
++
++      des_key_sched((C_Block *)cfb_key,ks);
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      des_cfb_encrypt(plain,cfb_buf1,bits,(long)sizeof(plain),ks,
++              (C_Block *)cfb_tmp,DES_ENCRYPT);
++      if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("cfb_encrypt encrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf1[i])));
++              }
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      des_cfb_encrypt(cfb_buf1,cfb_buf2,bits,(long)sizeof(plain),ks,
++              (C_Block *)cfb_tmp,DES_DECRYPT);
++      if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("cfb_encrypt decrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf1[i])));
++              }
++      return(err);
++      }
++
++static int cfb64_test(cfb_cipher)
++unsigned char *cfb_cipher;
++      {
++      des_key_schedule ks;
++      int err=0,i,n;
++
++      des_key_sched((C_Block *)cfb_key,ks);
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      n=0;
++      des_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,
++              (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
++      des_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
++              (long)sizeof(plain)-12,ks,
++              (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
++      if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("cfb_encrypt encrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf1[i])));
++              }
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      n=0;
++      des_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,
++              (C_Block *)cfb_tmp,&n,DES_DECRYPT);
++      des_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
++              (long)sizeof(plain)-17,ks,
++              (C_Block *)cfb_tmp,&n,DES_DECRYPT);
++      if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("cfb_encrypt decrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf2[i])));
++              }
++      return(err);
++      }
++
++static int ede_cfb64_test(cfb_cipher)
++unsigned char *cfb_cipher;
++      {
++      des_key_schedule ks;
++      int err=0,i,n;
++
++      des_key_sched((C_Block *)cfb_key,ks);
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      n=0;
++      des_ede3_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,ks,ks,
++              (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
++      des_ede3_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
++              (long)sizeof(plain)-12,ks,ks,ks,
++              (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
++      if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("ede_cfb_encrypt encrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf1[i])));
++              }
++      memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
++      n=0;
++      des_ede3_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,ks,ks,
++              (C_Block *)cfb_tmp,&n,DES_DECRYPT);
++      des_ede3_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
++              (long)sizeof(plain)-17,ks,ks,ks,
++              (C_Block *)cfb_tmp,&n,DES_DECRYPT);
++      if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
++              {
++              err=1;
++              printf("ede_cfb_encrypt decrypt error\n");
++              for (i=0; i<24; i+=8)
++                      printf("%s\n",pt(&(cfb_buf2[i])));
++              }
++      return(err);
++      }
++
++#endif
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/ecb_enc.c linux-2.2.14/net/ipsec/libdes/ecb_enc.c
+--- linux-2.2.14.orig/net/ipsec/libdes/ecb_enc.c       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/ecb_enc.c    Tue Apr  6 00:02:01 1999
+@@ -0,0 +1,128 @@
++/* 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_locl.h"
++#include "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$ */
++/* 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];
++
++      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;
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/fcrypt.c linux-2.2.14/net/ipsec/libdes/fcrypt.c
+--- linux-2.2.14.orig/net/ipsec/libdes/fcrypt.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/fcrypt.c     Thu Feb 18 17:41:14 1999
+@@ -0,0 +1,153 @@
++/* NOCW */
++#include <stdio.h>
++
++/* This version of crypt has been developed from my MIT compatable
++ * DES library.
++ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
++ * Eric Young (eay@cryptsoft.com)
++ */
++
++/* Modification by Jens Kupferschmidt (Cu)
++ * I have included directive PARA for shared memory computers.
++ * I have included a directive LONGCRYPT to using this routine to cipher
++ * passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN
++ * definition is the maximum of lenght of password and can changed. I have
++ * defined 24.
++ */
++
++#include "des_locl.h"
++
++/* Added more values to handle illegal salt values the way normal
++ * crypt() implementations do.  The patch was sent by 
++ * Bjorn Gronvall <bg@sics.se>
++ */
++static unsigned const char con_salt[128]={
++0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
++0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
++0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
++0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
++0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
++0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
++0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
++0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
++0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
++0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
++0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
++0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
++0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
++0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
++0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
++0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
++};
++
++static unsigned const char cov_2char[64]={
++0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
++0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
++0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
++0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
++0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
++0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
++0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
++0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
++};
++
++#ifndef NOPROTO
++void fcrypt_body(DES_LONG *out,des_key_schedule ks,
++      DES_LONG Eswap0, DES_LONG Eswap1);
++
++#ifdef PERL5
++char *des_crypt(const char *buf,const char *salt);
++#else
++char *crypt(const char *buf,const char *salt);
++#endif
++#else
++void fcrypt_body();
++#ifdef PERL5
++char *des_crypt();
++#else
++char *crypt();
++#endif
++#endif
++
++#ifdef PERL5
++char *des_crypt(buf,salt)
++#else
++char *crypt(buf,salt)
++#endif
++const char *buf;
++const char *salt;
++      {
++      static char buff[14];
++
++      return(des_fcrypt(buf,salt,buff));
++      }
++
++
++char *des_fcrypt(buf,salt,ret)
++const char *buf;
++const char *salt;
++char *ret;
++      {
++      unsigned int i,j,x,y;
++      DES_LONG Eswap0,Eswap1;
++      DES_LONG out[2],ll;
++      des_cblock key;
++      des_key_schedule ks;
++      unsigned char bb[9];
++      unsigned char *b=bb;
++      unsigned char c,u;
++
++      /* eay 25/08/92
++       * If you call crypt("pwd","*") as often happens when you
++       * have * as the pwd field in /etc/passwd, the function
++       * returns *\0XXXXXXXXX
++       * The \0 makes the string look like * so the pwd "*" would
++       * crypt to "*".  This was found when replacing the crypt in
++       * our shared libraries.  People found that the disbled
++       * accounts effectivly had no passwd :-(. */
++      x=ret[0]=((salt[0] == '\0')?'A':salt[0]);
++      Eswap0=con_salt[x]<<2;
++      x=ret[1]=((salt[1] == '\0')?'A':salt[1]);
++      Eswap1=con_salt[x]<<6;
++
++/* EAY
++r=strlen(buf);
++r=(r+7)/8;
++*/
++      for (i=0; i<8; i++)
++              {
++              c= *(buf++);
++              if (!c) break;
++              key[i]=(c<<1);
++              }
++      for (; i<8; i++)
++              key[i]=0;
++
++      des_set_key((des_cblock *)(key),ks);
++      fcrypt_body(&(out[0]),ks,Eswap0,Eswap1);
++
++      ll=out[0]; l2c(ll,b);
++      ll=out[1]; l2c(ll,b);
++      y=0;
++      u=0x80;
++      bb[8]=0;
++      for (i=2; i<13; i++)
++              {
++              c=0;
++              for (j=0; j<6; j++)
++                      {
++                      c<<=1;
++                      if (bb[y] & u) c|=1;
++                      u>>=1;
++                      if (!u)
++                              {
++                              y++;
++                              u=0x80;
++                              }
++                      }
++              ret[i]=cov_2char[c];
++              }
++      ret[13]='\0';
++      return(ret);
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/fcrypt_b.c linux-2.2.14/net/ipsec/libdes/fcrypt_b.c
+--- linux-2.2.14.orig/net/ipsec/libdes/fcrypt_b.c      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/fcrypt_b.c   Thu Feb 18 17:41:14 1999
+@@ -0,0 +1,148 @@
++/* crypto/des/fcrypt_b.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 <stdio.h>
++
++/* This version of crypt has been developed from my MIT compatable
++ * DES library.
++ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
++ * Eric Young (eay@cryptsoft.com)
++ */
++
++#define DES_FCRYPT
++#include "des_locl.h"
++#undef DES_FCRYPT
++
++#undef PERM_OP
++#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
++      (b)^=(t),\
++      (a)^=((t)<<(n)))
++
++#undef HPERM_OP
++#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
++      (a)=(a)^(t)^(t>>(16-(n))))\
++
++void fcrypt_body(out, ks, Eswap0, Eswap1)
++DES_LONG *out;
++des_key_schedule ks;
++DES_LONG Eswap0;
++DES_LONG Eswap1;
++      {
++      register DES_LONG l,r,t,u;
++#ifdef DES_PTR
++      register unsigned char *des_SP=(unsigned char *)des_SPtrans;
++#endif
++      register DES_LONG *s;
++      register int j;
++      register DES_LONG E0,E1;
++
++      l=0;
++      r=0;
++
++      s=(DES_LONG *)ks;
++      E0=Eswap0;
++      E1=Eswap1;
++
++      for (j=0; j<25; j++)
++              {
++#ifdef DES_UNROLL
++              register int i;
++
++              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); /*  1 */
++                      D_ENCRYPT(r,l,i+6); /*  2 */
++                      }
++#else
++              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 */
++#endif
++
++              t=l;
++              l=r;
++              r=t;
++              }
++      l=ROTATE(l,3)&0xffffffffL;
++      r=ROTATE(r,3)&0xffffffffL;
++
++      PERM_OP(l,r,t, 1,0x55555555L);
++      PERM_OP(r,l,t, 8,0x00ff00ffL);
++      PERM_OP(l,r,t, 2,0x33333333L);
++      PERM_OP(r,l,t,16,0x0000ffffL);
++      PERM_OP(l,r,t, 4,0x0f0f0f0fL);
++
++      out[0]=r;
++      out[1]=l;
++      }
++
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/podd.h linux-2.2.14/net/ipsec/libdes/podd.h
+--- linux-2.2.14.orig/net/ipsec/libdes/podd.h  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/podd.h       Thu Feb 18 17:41:15 1999
+@@ -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};
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/set_key.c linux-2.2.14/net/ipsec/libdes/set_key.c
+--- linux-2.2.14.orig/net/ipsec/libdes/set_key.c       Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/set_key.c    Thu Feb 18 17:41:15 1999
+@@ -0,0 +1,246 @@
++/* 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_locl.h"
++#include "podd.h"
++#include "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);
++              }
++
++      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));
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/sk.h linux-2.2.14/net/ipsec/libdes/sk.h
+--- linux-2.2.14.orig/net/ipsec/libdes/sk.h    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/sk.h Thu Feb 18 17:41:16 1999
+@@ -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,
++}};
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/speed.c linux-2.2.14/net/ipsec/libdes/speed.c
+--- linux-2.2.14.orig/net/ipsec/libdes/speed.c Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/speed.c      Thu Feb 18 17:41:16 1999
+@@ -0,0 +1,329 @@
++/* crypto/des/speed.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.]
++ */
++
++/* 11-Sep-92 Andrew Daviel   Support for Silicon Graphics IRIX added */
++/* 06-Apr-92 Luke Brennan    Support for VMS and add extra signal calls */
++
++#ifndef MSDOS
++#define TIMES
++#endif
++
++#include <stdio.h>
++#ifndef MSDOS
++#include <unistd.h>
++#else
++#include <io.h>
++extern int 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.h"
++
++/* 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) || defined(_AIX)
++#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)/1e3;
++              return((ret == 0.0)?1e-6:ret);
++              }
++#endif
++      }
++
++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 a,b,c,d,e;
++#ifndef SIGALRM
++      long ca,cb,cc,cd,ce;
++#endif
++
++#ifndef TIMES
++      printf("To get the most acurate results, try to run this\n");
++      printf("program when this computer is idle.\n");
++#endif
++
++      des_set_key((C_Block *)key2,sch2);
++      des_set_key((C_Block *)key3,sch3);
++
++#ifndef SIGALRM
++      printf("First we calculate the approximate speed ...\n");
++      des_set_key((C_Block *)key,sch);
++      count=10;
++      do      {
++              long i;
++              DES_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;
++      printf("Doing set_key %ld times\n",ca);
++#define COND(d)       (count != (d))
++#define COUNT(d) (d)
++#else
++#define COND(c)       (run)
++#define COUNT(d) (count)
++      signal(SIGALRM,sig_done);
++      printf("Doing set_key for 10 seconds\n");
++      alarm(10);
++#endif
++
++      Time_F(START);
++      for (count=0,run=1; COND(ca); count++)
++              des_set_key((C_Block *)key,sch);
++      d=Time_F(STOP);
++      printf("%ld set_key's in %.2f seconds\n",count,d);
++      a=((double)COUNT(ca))/d;
++
++#ifdef SIGALRM
++      printf("Doing des_encrypt's for 10 seconds\n");
++      alarm(10);
++#else
++      printf("Doing des_encrypt %ld times\n",cb);
++#endif
++      Time_F(START);
++      for (count=0,run=1; COND(cb); count++)
++              {
++              DES_LONG data[2];
++
++              des_encrypt(data,&(sch[0]),DES_ENCRYPT);
++              }
++      d=Time_F(STOP);
++      printf("%ld des_encrypt's in %.2f second\n",count,d);
++      b=((double)COUNT(cb)*8)/d;
++
++#ifdef SIGALRM
++      printf("Doing des_cbc_encrypt on %ld byte blocks for 10 seconds\n",
++              BUFSIZE);
++      alarm(10);
++#else
++      printf("Doing des_cbc_encrypt %ld times on %ld byte blocks\n",cc,
++              BUFSIZE);
++#endif
++      Time_F(START);
++      for (count=0,run=1; COND(cc); count++)
++              des_ncbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,&(sch[0]),
++                      (C_Block *)&(key[0]),DES_ENCRYPT);
++      d=Time_F(STOP);
++      printf("%ld des_cbc_encrypt's of %ld byte blocks in %.2f second\n",
++              count,BUFSIZE,d);
++      c=((double)COUNT(cc)*BUFSIZE)/d;
++
++#ifdef SIGALRM
++      printf("Doing des_ede_cbc_encrypt on %ld byte blocks for 10 seconds\n",
++              BUFSIZE);
++      alarm(10);
++#else
++      printf("Doing des_ede_cbc_encrypt %ld times on %ld byte blocks\n",cd,
++              BUFSIZE);
++#endif
++      Time_F(START);
++      for (count=0,run=1; COND(cd); count++)
++              des_ede3_cbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,
++                      &(sch[0]),
++                      &(sch2[0]),
++                      &(sch3[0]),
++                      (C_Block *)&(key[0]),
++                      DES_ENCRYPT);
++      d=Time_F(STOP);
++      printf("%ld des_ede_cbc_encrypt's of %ld byte blocks in %.2f second\n",
++              count,BUFSIZE,d);
++      d=((double)COUNT(cd)*BUFSIZE)/d;
++
++#ifdef SIGALRM
++      printf("Doing crypt for 10 seconds\n");
++      alarm(10);
++#else
++      printf("Doing crypt %ld times\n",ce);
++#endif
++      Time_F(START);
++      for (count=0,run=1; COND(ce); count++)
++              crypt("testing1","ef");
++      e=Time_F(STOP);
++      printf("%ld crypts in %.2f second\n",count,e);
++      e=((double)COUNT(ce))/e;
++
++      printf("set_key            per sec = %12.2f (%9.3fuS)\n",a,1.0e6/a);
++      printf("DES raw ecb bytes  per sec = %12.2f (%9.3fuS)\n",b,8.0e6/b);
++      printf("DES cbc bytes      per sec = %12.2f (%9.3fuS)\n",c,8.0e6/c);
++      printf("DES ede cbc bytes  per sec = %12.2f (%9.3fuS)\n",d,8.0e6/d);
++      printf("crypt              per sec = %12.2f (%9.3fuS)\n",e,1.0e6/e);
++      exit(0);
++#if defined(LINT) || defined(MSDOS)
++      return(0);
++#endif
++      }
+diff -durN linux-2.2.14.orig/net/ipsec/libdes/spr.h linux-2.2.14/net/ipsec/libdes/spr.h
+--- linux-2.2.14.orig/net/ipsec/libdes/spr.h   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libdes/spr.h        Thu Feb 18 17:41:16 1999
+@@ -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,
++}};
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/Makefile linux-2.2.14/net/ipsec/libfreeswan/Makefile
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/Makefile   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/Makefile        Tue Feb  8 22:22:09 2000
+@@ -0,0 +1,49 @@
++# FreeS/WAN library
++# Copyright (C) 1998, 1999  Henry Spencer.
++# 
++# 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$
++
++ifndef TOPDIR
++TOPDIR  := /usr/src/linux
++endif
++
++L_TARGET := libkernel.a
++
++L_OBJS := ultoa.o addrtoa.o subnettoa.o subnetof.o goodmask.o datatoa.o \
++      rangetoa.o satoa.o pfkey_v2_parse.o pfkey_v2_build.o pfkey_v2_ext_bits.o
++
++HDRS=freeswan.h internal.h
++
++override CFLAGS += -I.
++
++override CFLAGS += -Wall 
++#override CFLAGS += -Wconversion 
++#override CFLAGS += -Wmissing-prototypes 
++override CFLAGS += -Wpointer-arith 
++override CFLAGS += -Wcast-qual 
++#override CFLAGS += -Wmissing-declarations 
++override CFLAGS += -Wstrict-prototypes
++#override CFLAGS += -pedantic
++#override CFLAGS += -O3
++#override CFLAGS += -W
++#override CFLAGS += -Wwrite-strings 
++override CFLAGS += -Wbad-function-cast 
++
++include $(TOPDIR)/Rules.make
++
++$(L_OBJS):    $(HDRS)
++
++clean:
++      rm -f $(L_TARGET) *.o try* core *.core
++      ( cd des && $(MAKE) clean )
++
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/addrtoa.c linux-2.2.14/net/ipsec/libfreeswan/addrtoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/addrtoa.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/addrtoa.c       Sun Apr 11 01:19:36 1999
+@@ -0,0 +1,68 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.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 freeswan.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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atoaddr.c linux-2.2.14/net/ipsec/libfreeswan/atoaddr.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atoaddr.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atoaddr.c       Tue Feb  8 22:22:09 2000
+@@ -0,0 +1,238 @@
++/*
++ * conversion from ASCII forms of addresses to internal ones
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/*
++ * Define NOLEADINGZEROS to interpret 032 as an error, not as 32.  There
++ * is deliberately no way to interpret it as 26 (i.e., as octal).
++ */
++
++/*
++ * Legal characters in a domain name.  Underscore technically is not,
++ * but is a common misunderstanding.
++ */
++static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
++                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
++
++static const char *try8hex(const char *, size_t, struct in_addr *);
++static const char *try8hosthex(const char *, size_t, struct in_addr *);
++static const char *trydotted(const char *, size_t, struct in_addr *);
++static const char *getbyte(const char **, const char *, int *);
++
++/*
++ - atoaddr - convert ASCII name or dotted-decimal address to binary address
++ */
++const char *                  /* NULL for success, else string literal */
++atoaddr(src, srclen, addrp)
++const char *src;
++size_t srclen;                        /* 0 means "apply strlen" */
++struct in_addr *addrp;
++{
++      struct hostent *h;
++      struct netent *ne = NULL;
++      const char *oops;
++#     define  HEXLEN  10      /* strlen("0x11223344") */
++#     ifndef ATOADDRBUF
++#     define  ATOADDRBUF      100
++#     endif
++      char namebuf[ATOADDRBUF];
++      char *p = namebuf;
++      char *q;
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (srclen == 0)
++              return "empty string";
++
++      /* might it be hex? */
++      if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
++              return try8hex(src+2, srclen-2, addrp);
++      if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
++              return try8hosthex(src+2, srclen-2, addrp);
++
++      /* try it as dotted decimal */
++      oops = trydotted(src, srclen, addrp);
++      if (oops == NULL)
++              return NULL;            /* it worked */
++      if (*oops != '?')
++              return oops;            /* it *was* probably meant as a d.q. */
++
++      /* try it as a name -- first, NUL-terminate it */
++      if (srclen > sizeof(namebuf)-1) {
++              p = (char *) MALLOC(srclen+1);
++              if (p == NULL)
++                      return "unable to allocate temporary space for name";
++      }
++      p[0] = '\0';
++      strncat(p, src, srclen);
++
++      /* next, check that it's a vaguely legal name */
++      for (q = p; *q != '\0'; q++)
++              if (!isprint(*q))
++                      return "unprintable character in name";
++      if (strspn(p, namechars) != srclen)
++              return "illegal (non-DNS-name) character in name";
++
++      /* try as host name, failing that as /etc/networks network name */
++      h = gethostbyname(p);
++      if (h == NULL)
++              ne = getnetbyname(p);
++      if (p != namebuf)
++              FREE(p);
++      if (h == NULL && ne == NULL)
++              return "name lookup failed";
++
++      if (h != NULL)
++              memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
++      else
++              addrp->s_addr = htonl(ne->n_net);
++      return NULL;
++}
++
++/*
++ - try8hosthex - try conversion as an eight-digit host-order hex number
++ */
++const char *                  /* NULL for success, else string literal */
++try8hosthex(src, srclen, addrp)
++const char *src;
++size_t srclen;                        /* should be 8 */
++struct in_addr *addrp;
++{
++      const char *oops;
++      unsigned long addr;
++
++      if (srclen != 8)
++              return "internal error, try8hex called with bad length";
++
++      oops = atoul(src, srclen, 16, &addr);
++      if (oops != NULL)
++              return oops;
++
++      addrp->s_addr = addr;
++      return NULL;
++}
++
++/*
++ - try8hex - try conversion as an eight-digit network-order hex number
++ */
++const char *                  /* NULL for success, else string literal */
++try8hex(src, srclen, addrp)
++const char *src;
++size_t srclen;                        /* should be 8 */
++struct in_addr *addrp;
++{
++      const char *oops;
++
++      oops = try8hosthex(src, srclen, addrp);
++      if (oops != NULL)
++              return oops;
++
++      addrp->s_addr = htonl(addrp->s_addr);
++      return NULL;
++}
++
++/*
++ - trydotted - try conversion as dotted decimal
++ *
++ * If the first char of a complaint is '?', that means "didn't look like
++ * dotted decimal at all".
++ */
++const char *                  /* NULL for success, else string literal */
++trydotted(src, srclen, addrp)
++const char *src;
++size_t srclen;
++struct in_addr *addrp;
++{
++      const char *stop = src + srclen;        /* just past end */
++      int byte;
++      const char *oops;
++      unsigned long addr;
++      int i;
++#     define  NBYTES  4
++#     define  BYTE    8
++
++      addr = 0;
++      for (i = 0; i < NBYTES && src < stop; i++) {
++              oops = getbyte(&src, stop, &byte);
++              if (oops != NULL) {
++                      if (*oops != '?')
++                              return oops;    /* bad number */
++                      if (i > 1)
++                              return oops+1;  /* failed number */
++                      return oops;            /* with leading '?' */
++              }
++              addr = (addr << BYTE) | byte;
++              if (i < 3 && src < stop && *src++ != '.') {
++                      if (i == 0)
++                              return "?syntax error in dotted-decimal address";
++                      else
++                              return "syntax error in dotted-decimal address";
++              }
++      }
++      addr <<= (NBYTES - i) * BYTE;
++      if (src != stop)
++              return "extra garbage on end of dotted-decimal address";
++
++      addrp->s_addr = htonl(addr);
++      return NULL;
++}
++
++/*
++ - getbyte - try to scan a byte in dotted decimal
++ * A subtlety here is that all this arithmetic on ASCII digits really is
++ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
++ * It's easier to just do it ourselves than set up for a call to atoul().
++ *
++ * If the first char of a complaint is '?', that means "didn't look like a
++ * number at all".
++ */
++const char *                  /* NULL for success, else string literal */
++getbyte(srcp, stop, retp)
++const char **srcp;            /* *srcp is updated */
++const char *stop;             /* first untouchable char */
++int *retp;                    /* return-value pointer */
++{
++      char c;
++      const char *p;
++      int no;
++
++      if (*srcp >= stop)
++              return "?empty number in dotted-decimal address";
++
++      if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
++              return "hex numbers not supported in dotted-decimal addresses";
++#ifdef NOLEADINGZEROS
++      if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
++              return "octal numbers not supported in dotted-decimal addresses";
++#endif /* NOLEADINGZEROS */
++
++      /* must be decimal, if it's numeric at all */
++      no = 0;
++      p = *srcp;
++      while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
++              no = no*10 + (c - '0');
++              p++;
++      }
++      if (p == *srcp)
++              return "?non-numeric component in dotted-decimal address";
++      *srcp = p;
++      if (no > 255)
++              return "byte overflow in dotted-decimal address";
++      *retp = no;
++      return NULL;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atoasr.c linux-2.2.14/net/ipsec/libfreeswan/atoasr.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atoasr.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atoasr.c        Tue Dec  7 06:00:51 1999
+@@ -0,0 +1,212 @@
++/*
++ * convert from ASCII form of address/subnet/range to binary
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/*
++ - atoasr - convert ASCII to address, subnet, or range
++ */
++const char *                  /* NULL for success, else string literal */
++atoasr(src, srclen, typep, addrsp)
++const char *src;
++size_t srclen;                        /* 0 means "apply strlen" */
++char *typep;                  /* return type code:  'a', 's', 'r' */
++struct in_addr addrsp[2];
++{
++      const char *punct;
++      const char *stop;
++      const char *oops;
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (srclen == 0)
++              return "empty string";
++
++      /* subnet is easy to spot */
++      punct = memchr(src, '/', srclen);
++      if (punct != NULL) {
++              *typep = 's';
++              return atosubnet(src, srclen, &addrsp[0], &addrsp[1]);
++      }
++
++      /* try for a range */
++      stop = src + srclen;
++      for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL;
++                                                                      punct++)
++              if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.')
++                      break;                  /* NOTE BREAK OUT */
++      if (punct == NULL) {
++              /* didn't find the range delimiter, must be plain address */
++              *typep = 'a';
++              return atoaddr(src, srclen, &addrsp[0]);
++      }
++
++      /* looks like a range */
++      *typep = 'r';
++      if (stop - punct > 4 && *(punct+3) == '.')
++              punct++;                /* first dot is trailing dot of name */
++      oops = atoaddr(src, punct - src, &addrsp[0]);
++      if (oops != NULL)
++              return oops;
++      oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]);
++      if (oops != NULL)
++              return oops;
++      if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr))
++              return "invalid range, begin > end";
++      return NULL;
++}
++
++
++
++#ifdef ATOASR_MAIN
++
++#include <stdio.h>
++
++void regress();
++
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++      struct in_addr a[2];
++      char buf[100];
++      const char *oops;
++      size_t n;
++      char type;
++
++      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);
++      }
++
++      oops = atoasr(argv[1], 0, &type, a);
++      if (oops != NULL) {
++              fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
++              exit(1);
++      }
++      switch (type) {
++      case 'a':
++              n = addrtoa(a[0], 0, buf, sizeof(buf));
++              break;
++      case 's':
++              n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
++              break;
++      case 'r':
++              n = rangetoa(a, 0, buf, sizeof(buf));
++              break;
++      default:
++              fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type);
++              exit(1);
++              break;
++      }
++      if (n > sizeof(buf)) {
++              fprintf(stderr, "%s: reverse conversion of ", argv[0]);
++              fprintf(stderr, "%s ", inet_ntoa(a[0]));
++              fprintf(stderr, "%s", inet_ntoa(a[1]));
++              fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
++                                              (long)n, (long)sizeof(buf));
++              exit(1);
++      }
++      printf("%s\n", buf);
++
++      exit(0);
++}
++
++struct rtab {
++      char *input;
++      char *output;                   /* NULL means error expected */
++} rtab[] = {
++      "1.2.3.0",                      "1.2.3.0",
++      "1.2.3.0/255.255.255.0",        "1.2.3.0/24",
++      "1.2.3.0...1.2.3.5",            "1.2.3.0...1.2.3.5",
++      "1.2.3.4.5",                    NULL,
++      "1.2.3.4/",                     NULL,
++      "1.2.3.4...",                   NULL,
++      "1.2.3.4....",                  NULL,
++      "localhost./32",                "127.0.0.1/32",
++      "localhost....127.0.0.3",       "127.0.0.1...127.0.0.3",
++      "127.0.0.0...localhost.",       "127.0.0.0...127.0.0.1",
++      "127.0.0.3...localhost.",       NULL,
++      NULL,                           NULL
++};
++
++void
++regress()
++{
++      struct rtab *r;
++      int status = 0;
++      struct in_addr a[2];
++      struct in_addr m;
++      char in[100];
++      char buf[100];
++      const char *oops;
++      size_t n;
++      char type;
++
++      for (r = rtab; r->input != NULL; r++) {
++              strcpy(in, r->input);
++              oops = atoasr(in, 0, &type, a);
++              if (oops != NULL && r->output == NULL)
++                      {}              /* okay, error expected */
++              else if (oops != NULL) {
++                      printf("`%s' atoasr failed: %s\n", r->input, oops);
++                      status = 1;
++              } else if (r->output == NULL) {
++                      printf("`%s' atoasr succeeded unexpectedly '%c'\n",
++                                                      r->input, type);
++                      status = 1;
++              } else {
++                      switch (type) {
++                      case 'a':
++                              n = addrtoa(a[0], 0, buf, sizeof(buf));
++                              break;
++                      case 's':
++                              n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
++                              break;
++                      case 'r':
++                              n = rangetoa(a, 0, buf, sizeof(buf));
++                              break;
++                      default:
++                              fprintf(stderr, "`%s' unknown type '%c'\n",
++                                                      r->input, type);
++                              n = 0;
++                              status = 1;
++                              break;
++                      }
++                      if (n > sizeof(buf)) {
++                              printf("`%s' '%c' reverse failed:  need %ld\n",
++                                              r->input, type, (long)n);
++                              status = 1;
++                      } else if (n > 0 && strcmp(r->output, buf) != 0) {
++                              printf("`%s' '%c' gave `%s', expected `%s'\n",
++                                      r->input, type, buf, r->output);
++                              status = 1;
++                      }
++              }
++      }
++      exit(status);
++}
++
++#endif /* ATOASR_MAIN */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atodata.c linux-2.2.14/net/ipsec/libfreeswan/atodata.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atodata.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atodata.c       Tue Dec  7 06:00:52 1999
+@@ -0,0 +1,506 @@
++/*
++ * convert from ASCII form of arbitrary data (e.g., keys) to binary
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/* converters */
++static int unhex(const char *, char *, size_t);
++static int unb64(const char *, char *, size_t);
++static int untext(const char *, char *, size_t);
++
++/* internal error codes for converters */
++#define       BADCHAR (-1)            /* invalid character */
++#define       SHORT   (-2)            /* string ended prematurely */
++#define       BADPAD  (-3)            /* bad base64 padding */
++
++/*
++ - atobytes - convert ASCII to data bytes
++ * If some of this looks slightly odd, it's because the original atodata()
++ * was written first, and this was an afterthought, and it wasn't worth
++ * redoing the code extensively.
++ */
++const char *                  /* NULL for success, else string literal */
++atobytes(src, srclen, dst, dstlen, lenp)
++const char *src;
++size_t srclen;                        /* 0 means apply strlen() */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++size_t *lenp;                 /* where to record length (NULL is nowhere) */
++{
++      size_t ingroup;         /* number of input bytes converted at once */
++      char buf[4];            /* output from conversion */
++      int nbytes;             /* size of output */
++      int (*decode)(const char *, char *, size_t);
++      char *stop;
++      int ndone;
++      int i;
++      int underscoreok;
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (dstlen == 0)
++              dst = buf;      /* point it somewhere valid */
++      stop = dst + dstlen;
++
++      /* which ASCII encoding is it? */
++      if (srclen < 2)
++              return "input too short to be valid";
++      if (*src++ != '0')
++              return "input does not begin with known prefix";
++      switch (*src++) {
++      case 'x':
++      case 'X':
++              ingroup = 2;
++              decode = unhex;
++              underscoreok = 1;
++              break;
++      case 's':
++      case 'S':
++              ingroup = 4;
++              decode = unb64;
++              underscoreok = 0;
++              break;
++      case 't':
++      case 'T':
++              ingroup = 1;
++              decode = untext;
++              underscoreok = 0;
++              break;
++      default:
++              return 0;
++              break;
++      }
++      srclen -= 2;
++
++      /* proceed */
++      ndone = 0;
++      while (srclen >= ingroup) {
++              nbytes = (*decode)(src, buf, sizeof(buf));
++              switch (nbytes) {
++              case BADCHAR:
++                      return "unknown character in input";
++                      break;
++              case SHORT:
++                      return "input ends prematurely, perhaps truncated";
++                      break;
++              case BADPAD:
++                      return "non-zero padding in base64 input";
++                      break;
++              }
++              if (nbytes <= 0)
++                      return "unknown internal error";
++              for (i = 0; i < nbytes; i++) {
++                      if (dst < stop)
++                              *dst++ = buf[i];
++                      ndone++;
++              }
++              src += ingroup;
++              srclen -= ingroup;
++              if (underscoreok && srclen > 1 && *src == '_') {
++                      /* srclen > 1 means not last character */
++                      src++;
++                      srclen--;
++              }
++      }
++      if (srclen != 0)
++              return "input ends in mid-byte, perhaps truncated";
++      if (ndone == 0)
++              return "no data bytes specified by input";
++      if (lenp != NULL)
++              *lenp = ndone;
++      return NULL;
++}
++
++/*
++ - atodata - convert ASCII to data
++ * backward-compatibility interface for atobytes
++ */
++size_t                                /* 0 for failure, true length for success */
++atodata(src, srclen, dst, dstlen)
++const char *src;
++size_t srclen;                        /* 0 means apply strlen() */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t len;
++      const char *err;
++
++      err = atobytes(src, srclen, dst, dstlen, &len);
++      if (err != NULL)
++              return 0;
++      return len;
++}
++
++/*
++ - unhex - convert two ASCII hex digits to byte
++ */
++static int            /* number of result bytes, or error code */
++unhex(src, dst, dstlen)
++const char *src;      /* known to be full length */
++char *dst;
++size_t dstlen;                /* not large enough is a failure */
++{
++      char *p;
++      unsigned byte;
++      static char hex[] = "0123456789abcdef";
++
++      if (dstlen < 1)
++              return SHORT;
++
++      p = strchr(hex, *src);
++      if (p == NULL)
++              p = strchr(hex, tolower(*src));
++      if (p == NULL)
++              return BADCHAR;
++      byte = (p - hex) << 4;
++      src++;
++
++      p = strchr(hex, *src);
++      if (p == NULL)
++              p = strchr(hex, tolower(*src));
++      if (p == NULL)
++              return BADCHAR;
++      byte |= (p - hex);
++
++      *dst = byte;
++      return 1;
++}
++
++/*
++ - unb64 - convert four ASCII base64 digits to three bytes
++ * Note that a base64 digit group is padded out with '=' if it represents
++ * less than three bytes:  one byte is dd==, two is ddd=, three is dddd.
++ */
++static int            /* number of result bytes, or error code */
++unb64(src, dst, dstlen)
++const char *src;      /* known to be full length */
++char *dst;
++size_t dstlen;
++{
++      char *p;
++      unsigned byte1;
++      unsigned byte2;
++      static char base64[] =
++      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
++
++      if (dstlen < 3)
++              return SHORT;
++
++      p = strchr(base64, *src++);
++      if (p == NULL)
++              return BADCHAR;
++      byte1 = (p - base64) << 2;      /* first six bits */
++
++      p = strchr(base64, *src++);
++      if (p == NULL)
++              return BADCHAR;
++      byte2 = p - base64;             /* next six:  two plus four */
++      *dst++ = byte1 | (byte2 >> 4);
++      byte1 = (byte2 & 0xf) << 4;
++
++      p = strchr(base64, *src++);
++      if (p == NULL) {
++              if (*(src-1) == '=' && *src == '=') {
++                      if (byte1 != 0)         /* bad padding */
++                              return BADPAD;
++                      return 1;
++              }
++              return BADCHAR;
++      }
++      byte2 = p - base64;             /* next six:  four plus two */
++      *dst++ = byte1 | (byte2 >> 2);
++      byte1 = (byte2 & 0x3) << 6;
++
++      p = strchr(base64, *src++);
++      if (p == NULL) {
++              if (*(src-1) == '=') {
++                      if (byte1 != 0)         /* bad padding */
++                              return BADPAD;
++                      return 2;
++              }
++              return BADCHAR;
++      }
++      byte2 = p - base64;             /* last six */
++      *dst++ = byte1 | byte2;
++      return 3;
++}
++
++/*
++ - untext - convert one ASCII character to byte
++ */
++static int            /* number of result bytes, or error code */
++untext(src, dst, dstlen)
++const char *src;      /* known to be full length */
++char *dst;
++size_t dstlen;                /* not large enough is a failure */
++{
++      if (dstlen < 1)
++              return SHORT;
++
++      *dst = *src;
++      return 1;
++}
++
++
++
++#ifdef ATODATA_MAIN
++
++#include <stdio.h>
++
++void regress();
++void hexout();
++
++/*
++ - main - convert first argument to hex, or run regression
++ */
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++#     ifndef ATODATABUF
++#     define  ATODATABUF      1024
++#     endif
++      char buf[ATODATABUF];
++      char buf2[ATODATABUF];
++      size_t n;
++      size_t i;
++      char *p = buf;
++      char *p2 = buf2;
++      char *pgm = argv[0];
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
++              exit(2);
++      }
++
++      if (strcmp(argv[1], "-r") == 0) {
++              regress(pgm);   /* should not return */
++              fprintf(stderr, "%s: regress() returned?!?\n", pgm);
++              exit(1);
++      }
++
++      n = atodata(argv[1], 0, buf, sizeof(buf));
++      if (n == 0) {
++              fprintf(stderr, "%s: atodata reports error in `%s'\n", pgm,
++                                                              argv[1]);
++              exit(1);
++      }
++
++      if (n > sizeof(buf)) {
++              p = (char *)malloc((size_t)n);
++              if (p == NULL) {
++                      fprintf(stderr,
++                              "%s: unable to malloc %d bytes for result\n",
++                              pgm, n);
++                      exit(1);
++              }
++              n = atodata(argv[1], 0, p, n);
++              if (n == 0) {
++                      fprintf(stderr, "%s: error in atodata retry?!?\n", pgm);
++                      exit(1);
++              }
++      }
++
++      hexout(p, n, stdout);
++      printf("\n");
++
++      i = datatoa(buf, n, 'h', buf2, sizeof(buf2));
++      if (i == 0) {
++              fprintf(stderr, "%s: datatoa reports error in `%s'\n", pgm,
++                                                              argv[1]);
++              exit(1);
++      }
++
++      if (i > sizeof(buf2)) {
++              p2 = (char *)malloc((size_t)i);
++              if (p == NULL) {
++                      fprintf(stderr,
++                              "%s: unable to malloc %d bytes for result\n",
++                              pgm, i);
++                      exit(1);
++              }
++              i = datatoa(buf, n, 'h', p2, i);
++              if (i == 0) {
++                      fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
++                      exit(1);
++              }
++      }
++
++      printf("%s\n", p2);
++
++      exit(0);
++}
++
++/*
++ - hexout - output an arbitrary-length string in hex
++ */
++void
++hexout(s, len, f)
++const char *s;
++size_t len;
++FILE *f;
++{
++      size_t i;
++
++      fprintf(f, "0x");
++      for (i = 0; i < len; i++)
++              fprintf(f, "%02x", (unsigned char)s[i]);
++}
++
++struct artab {
++      char *ascii;            /* NULL for end */
++      char *data;             /* NULL for error expected */
++} atodatatab[] = {
++      "",             NULL,
++      "0",            NULL,
++      "0x",           NULL,
++      "0xa",          NULL,
++      "0xab",         "\xab",
++      "0xabc",        NULL,
++      "0xabcd",       "\xab\xcd",
++      "0x0123456789", "\x01\x23\x45\x67\x89",
++      "0x01x",        NULL,
++      "0xabcdef",     "\xab\xcd\xef",
++      "0xABCDEF",     "\xab\xcd\xef",
++      "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f",
++      "0XaBc0_eEd8",  "\xab\xc0\xee\xd8",
++      "0XaBc0_",      NULL,
++      "0X_aBc0",      NULL,
++      "0Xa_Bc0",      NULL,
++      "0s",           NULL,
++      "0sA",          NULL,
++      "0sBA",         NULL,
++      "0sCBA",        NULL,
++      "0sDCBA",       "\x0c\x20\x40",
++      "0SDCBA",       "\x0c\x20\x40",
++      "0sDA==",       "\x0c",
++      "0sDC==",       NULL,
++      "0sDCA=",       "\x0c\x20",
++      "0sDCB=",       NULL,
++      "0sDCAZ",       "\x0c\x20\x19",
++      "0sDCAa",       "\x0c\x20\x1a",
++      "0sDCAz",       "\x0c\x20\x33",
++      "0sDCA0",       "\x0c\x20\x34",
++      "0sDCA9",       "\x0c\x20\x3d",
++      "0sDCA+",       "\x0c\x20\x3e",
++      "0sDCA/",       "\x0c\x20\x3f",
++      "0sAbraCadabra+",       "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe",
++      "0t",           NULL,
++      "0tabc_xyz",    "abc_xyz",
++      NULL,           NULL,
++};
++
++struct drtab {
++      char *data;     /* NULL for end */
++      char format;
++      char *ascii;    /* NULL for error expected */
++} datatoatab[] = {
++      "",                     'x',    "0x",
++      "",                     'X',    NULL,
++      "",                     's',    NULL,
++      "0",                    'x',    "0x30",
++      "\xab\xcd",             'x',    "0xabcd",
++      "\x01\x23\x45\x67\x89", 'x',    "0x0123456789",
++      "\xab\xcd\xef",         'x',    "0xabcdef",
++      "\xab\xc0\xee\xd8\x1f", 'x',    "0xabc0eed81f",
++      "\x01\x02",             'h',    "0x0102",
++      "\x01\x02\x03\x04\x05\x06",     'h',    "0x01020304_0506",
++      NULL,                   'x',    NULL,
++};
++
++/*
++ - regress - regression-test atodata()
++ */
++void                  /* should not return at all, in fact */
++regress(pgm)
++char *pgm;
++{
++      struct artab *r;
++      struct drtab *dr;
++      char buf[100];
++      size_t n;
++      int status = 0;
++
++      for (r = atodatatab; r->ascii != NULL; r++) {
++              n = atodata(r->ascii, 0, buf, sizeof(buf));
++              if (n == 0 && r->data == NULL)
++                      {}                      /* error expected */
++              else if (n == 0) {
++                      printf("`%s' gave error, expecting %d `", r->ascii,
++                                                      strlen(r->data));
++                      hexout(r->data, strlen(r->data), stdout);
++                      printf("'\n");
++                      status = 1;
++              } else if (r->data == NULL) {
++                      printf("`%s' gave %d `", r->ascii, n);
++                      hexout(buf, n, stdout);
++                      printf("', expecting error\n");
++                      status = 1;
++              } else if (n != strlen(r->data)) {
++                      printf("length wrong in `%s': got %d `", r->ascii, n);
++                      hexout(buf, n, stdout);
++                      printf("', expecting %d `", strlen(r->data));
++                      hexout(r->data, strlen(r->data), stdout);
++                      printf("'\n");
++                      status = 1;
++              } else if (memcmp(buf, r->data, n) != 0) {
++                      printf("`%s' gave %d `", r->ascii, n);
++                      hexout(buf, n, stdout);
++                      printf("', expecting %d `", strlen(r->data));
++                      hexout(r->data, strlen(r->data), stdout);
++                      printf("'\n");
++                      status = 1;
++              }
++      }
++      for (dr = datatoatab; dr->data != NULL; dr++) {
++              n = datatoa(dr->data, strlen(dr->data), dr->format, buf,
++                                                              sizeof(buf));
++              if (n == 0 && dr->ascii == NULL)
++                      {}                      /* error expected */
++              else if (n == 0) {
++                      printf("`");
++                      hexout(dr->data, strlen(dr->data), stdout);
++                      printf("' %c gave error, expecting %d `%s'\n",
++                              dr->format, strlen(dr->ascii)+1, dr->ascii);
++                      status = 1;
++              } else if (dr->ascii == NULL) {
++                      printf("`");
++                      hexout(dr->data, strlen(dr->data), stdout);
++                      printf("' %c gave %d `%.*s', expecting error\n",
++                              dr->format, n, n, buf);
++                      status = 1;
++              } else if (n != strlen(dr->ascii)+1) {
++                      printf("length wrong in `");
++                      hexout(dr->data, strlen(dr->data), stdout);
++                      printf("': got %d `%.*s'", n, n, buf);
++                      printf(", expecting %d `%s'\n", strlen(dr->ascii)+1,
++                                                              dr->ascii);
++                      status = 1;
++              } else if (memcmp(buf, dr->ascii, n) != 0) {
++                      printf("`");
++                      hexout(dr->data, strlen(dr->data), stdout);
++                      printf("' gave %d `%.*s'", n, n, buf);
++                      printf(", expecting %d `%s'\n", strlen(dr->ascii)+1,
++                                                              dr->ascii);
++                      status = 1;
++              }
++      }
++      exit(status);
++}
++
++#endif /* ATODATA_MAIN */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atosa.c linux-2.2.14/net/ipsec/libfreeswan/atosa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atosa.c    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atosa.c Tue Feb  8 22:22:10 2000
+@@ -0,0 +1,198 @@
++/*
++ * convert from ASCII form of SA ID to binary
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++static struct satype {
++      char *prefix;
++      size_t prelen;          /* strlen(prefix) */
++      int proto;
++} satypes[] = {
++      { "ah",         2,      SA_AH   },
++      { "esp",        3,      SA_ESP  },
++      { "tun",        3,      SA_IPIP },
++      { NULL,         0,      0,      }
++};
++
++/*
++ - atosa - convert ASCII "ah507@10.0.0.1" to SA identifier
++ */
++const char *                  /* NULL for success, else string literal */
++atosa(src, srclen, sa)
++const char *src;
++size_t srclen;                        /* 0 means "apply strlen" */
++struct sa_id *sa;
++{
++      const char *at;
++      const char *addr;
++      const char *spi = NULL;
++      struct satype *sat;
++      unsigned long ul;
++      const char *oops;
++#     define  MINLEN  5       /* ah0@0 is as short as it can get */
++      static char ptname[] = PASSTHROUGHNAME;
++#     define  PTNLEN  (sizeof(ptname)-1)      /* -1 for NUL */
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (srclen == 0)
++              return "empty string";
++      if (srclen < MINLEN)
++              return "string too short to be SA specifier";
++      if (srclen == PTNLEN && memcmp(src, ptname, PTNLEN) == 0) {
++              src = PASSTHROUGHIS;
++              srclen = strlen(src);
++      }
++
++      at = memchr(src, '@', srclen);
++      if (at == NULL)
++              return "no @ in SA specifier";
++
++      for (sat = satypes; sat->prefix != NULL; sat++)
++              if (sat->prelen < srclen &&
++                              strncmp(src, sat->prefix, sat->prelen) == 0) {
++                      sa->proto = sat->proto;
++                      spi = src + sat->prelen;
++                      break;                  /* NOTE BREAK OUT */
++              }
++      if (sat->prefix == NULL)
++              return "SA specifier must begin with `ah', `esp', or `tun'";
++
++      if (spi >= at)
++              return "no SPI in SA specifier";
++      oops = atoul(spi, at - spi, 13, &ul);
++      if (oops != NULL)
++              return oops;
++      sa->spi = htonl(ul);
++
++      addr = at + 1;
++      oops = atoaddr(addr, srclen - (addr - src), &sa->dst);
++      if (oops != NULL)
++              return oops;
++
++      return NULL;
++}
++
++
++
++#ifdef ATOSA_MAIN
++
++#include <stdio.h>
++
++void regress();
++
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++      struct sa_id sa;
++      char buf[100];
++      const char *oops;
++      size_t n;
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
++              exit(2);
++      }
++
++      if (strcmp(argv[1], "-r") == 0) {
++              regress();
++              fprintf(stderr, "regress() returned?!?\n");
++              exit(1);
++      }
++
++      oops = atosa(argv[1], 0, &sa);
++      if (oops != NULL) {
++              fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
++              exit(1);
++      }
++      n = satoa(sa, 0, buf, sizeof(buf));
++      if (n > sizeof(buf)) {
++              fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
++              fprintf(stderr, "%lu@", sa.spi);
++              fprintf(stderr, "%s", inet_ntoa(sa.dst));
++              fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
++                                              (long)n, (long)sizeof(buf));
++              exit(1);
++      }
++      printf("%s\n", buf);
++
++      exit(0);
++}
++
++struct rtab {
++      char *input;
++      char *output;                   /* NULL means error expected */
++} rtab[] = {
++      "esp257@1.2.3.0",               "esp257@1.2.3.0",
++      "ah0x20@1.2.3.4",               "ah32@1.2.3.4",
++      "tun011@111.2.3.99",            "tun11@111.2.3.99",
++      "",                             NULL,
++      "_",                            NULL,
++      "ah2.2",                        NULL,
++      "goo2@1.2.3.4",                 NULL,
++      "esp9@1.2.3.4",                 "esp9@1.2.3.4",
++      "espp9@1.2.3.4",                NULL,
++      "es9@1.2.3.4",                  NULL,
++      "ah@1.2.3.4",                   NULL,
++      "esp7x7@1.2.3.4",               NULL,
++      "esp77@1.0x2.3.4",              NULL,
++      PASSTHROUGHNAME,                PASSTHROUGHNAME,
++      NULL,                           NULL
++};
++
++void
++regress()
++{
++      struct rtab *r;
++      int status = 0;
++      struct sa_id sa;
++      char in[100];
++      char buf[100];
++      const char *oops;
++      size_t n;
++
++      for (r = rtab; r->input != NULL; r++) {
++              strcpy(in, r->input);
++              oops = atosa(in, 0, &sa);
++              if (oops != NULL && r->output == NULL)
++                      {}              /* okay, error expected */
++              else if (oops != NULL) {
++                      printf("`%s' atosa failed: %s\n", r->input, oops);
++                      status = 1;
++              } else if (r->output == NULL) {
++                      printf("`%s' atosa succeeded unexpectedly\n",
++                                                              r->input);
++                      status = 1;
++              } else {
++                      n = satoa(sa, 'd', buf, sizeof(buf));
++                      if (n > sizeof(buf)) {
++                              printf("`%s' satoa failed:  need %ld\n",
++                                                      r->input, (long)n);
++                              status = 1;
++                      } else if (strcmp(r->output, buf) != 0) {
++                              printf("`%s' gave `%s', expected `%s'\n",
++                                              r->input, buf, r->output);
++                              status = 1;
++                      }
++              }
++      }
++      exit(status);
++}
++
++#endif /* ATOSA_MAIN */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atosubnet.c linux-2.2.14/net/ipsec/libfreeswan/atosubnet.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atosubnet.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atosubnet.c     Sun Apr 11 01:24:20 1999
+@@ -0,0 +1,213 @@
++/*
++ * convert from ASCII form of subnet specification to binary
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++#ifndef DEFAULTSUBNET
++#define       DEFAULTSUBNET   "%default"
++#endif
++
++/*
++ - atosubnet - convert ASCII "addr/mask" to address and mask
++ * Mask can be integer bit count.
++ */
++const char *                  /* NULL for success, else string literal */
++atosubnet(src, srclen, addrp, maskp)
++const char *src;
++size_t srclen;                        /* 0 means "apply strlen" */
++struct in_addr *addrp;
++struct in_addr *maskp;
++{
++      const char *slash;
++      const char *mask;
++      size_t mlen;
++      const char *oops;
++      unsigned long bc;
++      static char def[] = DEFAULTSUBNET;
++#     define  DEFLEN  (sizeof(def) - 1)       /* -1 for NUL */
++      static char defis[] = "0/0";
++#     define  DEFILEN (sizeof(defis) - 1)
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (srclen == 0)
++              return "empty string";
++
++      if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
++              src = defis;
++              srclen = DEFILEN;
++      }
++
++      slash = memchr(src, '/', srclen);
++      if (slash == NULL)
++              return "no / in subnet specification";
++      mask = slash + 1;
++      mlen = srclen - (mask - src);
++
++      oops = atoaddr(src, slash-src, addrp);
++      if (oops != NULL)
++              return oops;
++
++      oops = atoul(mask, mlen, 10, &bc);
++      if (oops == NULL) {
++              /* atoul succeeded, it's a bit-count mask */
++              if (bc > ABITS)
++                      return "bit-count mask too large";
++#ifdef NOLEADINGZEROS
++              if (mlen > 1 && *mask == '0')
++                      return "octal not allowed in mask";
++#endif /* NOLEADINGZEROS */
++              *maskp = bitstomask((int)bc);
++      } else {
++              oops = atoaddr(mask, mlen, maskp);
++              if (oops != NULL)
++                      return oops;
++              if (!goodmask(*maskp))
++                      return "non-contiguous mask";
++      }
++
++      addrp->s_addr &= maskp->s_addr;
++      return NULL;
++}
++
++
++
++#ifdef ATOSUBNET_MAIN
++
++#include <stdio.h>
++
++void regress();
++
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++      struct in_addr a;
++      struct in_addr m;
++      char buf[100];
++      const char *oops;
++      size_t n;
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]);
++              exit(2);
++      }
++
++      if (strcmp(argv[1], "-r") == 0) {
++              regress();
++              fprintf(stderr, "regress() returned?!?\n");
++              exit(1);
++      }
++
++      oops = atosubnet(argv[1], 0, &a, &m);
++      if (oops != NULL) {
++              fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
++              exit(1);
++      }
++      n = subnettoa(a, m, 0, buf, sizeof(buf));
++      if (n > sizeof(buf)) {
++              fprintf(stderr, "%s: reverse conversion of ", argv[0]);
++              fprintf(stderr, "%s/", inet_ntoa(a));
++              fprintf(stderr, "%s", inet_ntoa(m));
++              fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
++                                              (long)n, (long)sizeof(buf));
++              exit(1);
++      }
++      printf("%s\n", buf);
++
++      exit(0);
++}
++
++struct rtab {
++      char *input;
++      char *output;                   /* NULL means error expected */
++} rtab[] = {
++      "1.2.3.0/255.255.255.0",        "1.2.3.0/24",
++      "1.2.3.0/24",                   "1.2.3.0/24",
++      "1.2.3.1/255.255.255.240",      "1.2.3.0/28",
++      "1.2.3.1/32",                   "1.2.3.1/32",
++      "1.2.3.1/0",                    "0.0.0.0/0",
++/*    "1.2.3.1/255.255.127.0",        "1.2.3.0/255.255.127.0",        */
++      "1.2.3.1/255.255.127.0",        NULL,
++      "128.009.000.032/32",           "128.9.0.32/32",
++      "128.0x9.0.32/32",              NULL,
++      "0x80090020/32",                "128.9.0.32/32",
++      "0x800x0020/32",                NULL,
++      "128.9.0.32/0xffFF0000",        "128.9.0.0/16",
++      "128.9.0.32/0x00ffFF0000",      NULL,
++      "128.9.0.32/0xffFF",            NULL,
++      "128.9.0.32.27/32",             NULL,
++      "128.9.0k32/32",                NULL,
++      "328.9.0.32/32",                NULL,
++      "128.9..32/32",                 NULL,
++      "10/8",                         "10.0.0.0/8",
++      "10.0/8",                       "10.0.0.0/8",
++      "10.0.0/8",                     "10.0.0.0/8",
++      "10.0.1/24",                    "10.0.1.0/24",
++      "_",                            NULL,
++      "_/_",                          NULL,
++      "1.2.3.1",                      NULL,
++      "1.2.3.1/_",                    NULL,
++      "1.2.3.1/24._",                 NULL,
++      "1.2.3.1/99",                   NULL,
++      "localhost./32",                "127.0.0.1/32",
++      "%default",                     "0.0.0.0/0",
++      NULL,                           NULL
++};
++
++void
++regress()
++{
++      struct rtab *r;
++      int status = 0;
++      struct in_addr a;
++      struct in_addr m;
++      char in[100];
++      char buf[100];
++      const char *oops;
++      size_t n;
++
++      for (r = rtab; r->input != NULL; r++) {
++              strcpy(in, r->input);
++              oops = atosubnet(in, 0, &a, &m);
++              if (oops != NULL && r->output == NULL)
++                      {}              /* okay, error expected */
++              else if (oops != NULL) {
++                      printf("`%s' atosubnet failed: %s\n", r->input, oops);
++                      status = 1;
++              } else if (r->output == NULL) {
++                      printf("`%s' atosubnet succeeded unexpectedly\n",
++                                                              r->input);
++                      status = 1;
++              } else {
++                      n = subnettoa(a, m, 0, buf, sizeof(buf));
++                      if (n > sizeof(buf)) {
++                              printf("`%s' subnettoa failed:  need %ld\n",
++                                                      r->input, (long)n);
++                              status = 1;
++                      } else if (strcmp(r->output, buf) != 0) {
++                              printf("`%s' gave `%s', expected `%s'\n",
++                                              r->input, buf, r->output);
++                              status = 1;
++                      }
++              }
++      }
++      exit(status);
++}
++
++#endif /* ATOSUBNET_MAIN */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/atoul.c linux-2.2.14/net/ipsec/libfreeswan/atoul.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/atoul.c    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/atoul.c Tue Dec  7 06:00:52 1999
+@@ -0,0 +1,90 @@
++/*
++ * convert from ASCII form of unsigned long to binary
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/*
++ - atoul - convert ASCII substring to unsigned long number
++ */
++const char *                  /* NULL for success, else string literal */
++atoul(src, srclen, base, resultp)
++const char *src;
++size_t srclen;                        /* 0 means strlen(src) */
++int base;                     /* 0 means figure it out */
++unsigned long *resultp;
++{
++      const char *stop;
++      static char hex[] = "0123456789abcdef";
++      static char uchex[] = "0123456789ABCDEF";
++      int d;
++      char c;
++      char *p;
++      unsigned long r;
++      unsigned long rlimit;
++      int dlimit;
++
++      if (srclen == 0)
++              srclen = strlen(src);
++      if (srclen == 0)
++              return "empty string";
++
++      if (base == 0 || base == 13) {
++              if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x'))
++                      return atoul(src+2, srclen-2, 16, resultp);
++              if (srclen > 1 && *src == '0' && base != 13)
++                      return atoul(src+1, srclen-1, 8, resultp);
++              return atoul(src, srclen, 10, resultp);
++      }
++      if (base != 8 && base != 10 && base != 16)
++              return "unsupported number base";
++
++      r = 0;
++      stop = src + srclen;
++      if (base == 16) {
++              while (src < stop) {
++                      c = *src++;
++                      p = strchr(hex, c);
++                      if (p != NULL)
++                              d = p - hex;
++                      else {
++                              p = strchr(uchex, c);
++                              if (p == NULL)
++                                      return "non-hex-digit in hex number";
++                              d = p - uchex;
++                      }
++                      r = (r << 4) | d;
++              }
++              /* defer length check to catch invalid digits first */
++              if (srclen > sizeof(unsigned long) * 2)
++                      return "hex number too long";
++      } else {
++              rlimit = ULONG_MAX / base;
++              dlimit = (int)(ULONG_MAX - rlimit*base);
++              while (src < stop) {
++                      c = *src++;
++                      d = c - '0';
++                      if (d < 0 || d >= base)
++                              return "non-digit in number";
++                      if (r > rlimit || (r == rlimit && d > dlimit))
++                              return "unsigned-long overflow";
++                      r = r*base + d;
++              }
++      }
++
++      *resultp = r;
++      return NULL;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/datatoa.c linux-2.2.14/net/ipsec/libfreeswan/datatoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/datatoa.c  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/datatoa.c       Tue Nov 30 05:12:53 1999
+@@ -0,0 +1,106 @@
++/*
++ * convert from binary data (e.g. key) to ASCII form
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/*
++ - bytestoa - convert data bytes to ASCII
++ */
++size_t                                /* true length (with NUL) for success */
++bytestoa(src, srclen, format, dst, dstlen)
++const char *src;
++size_t srclen;
++int format;                   /* character indicating what format */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      char *stop;
++      size_t ndone;
++      unsigned c;
++      size_t nwanted;
++      int dobreaks;
++      static char hex[] = "0123456789abcdef";
++
++      switch (format) {
++      case 'x':
++              dobreaks = 0;
++              break;
++      case 0:
++      case 'h':
++              dobreaks = 1;
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      switch (dstlen) {
++      case 0:
++              dst = hex;      /* point it somewhere valid */
++              break;
++      case 1:
++              break;
++      case 2:
++              strcpy(dst, "0");
++              dst += 1;
++              break;
++      default:
++              strcpy(dst, "0x");
++              dst += 2;
++              break;
++      }
++      nwanted = 2;
++      stop = dst + dstlen;
++
++      ndone = 0;
++      while (ndone < srclen) {
++              c = (unsigned char)*src++;
++              if (dst < stop)
++                      *dst++ = hex[c>>4];
++              if (dst < stop)
++                      *dst++ = hex[c&0xf];
++              nwanted += 2;
++              ndone++;
++              if (dobreaks && ndone % 4 == 0 && ndone < srclen) {
++                      if (dst < stop)
++                              *dst++ = '_';
++                      nwanted++;
++              }
++      }
++      if (dst < stop)
++              *dst++ = '\0';
++      else if (dstlen > 0)
++              *(stop-1) = '\0';
++      nwanted++;
++
++      return nwanted;
++}
++
++/*
++ - datatoa - convert data to ASCII
++ * backward-compatibility synonym for bytestoa
++ */
++size_t                                /* true length (with NUL) for success */
++datatoa(src, srclen, format, dst, dstlen)
++const 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 bytestoa(src, srclen, format, dst, dstlen);
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/freeswan.h linux-2.2.14/net/ipsec/libfreeswan/freeswan.h
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/freeswan.h Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/freeswan.h      Tue Feb  8 22:22:10 2000
+@@ -0,0 +1,325 @@
++#ifndef _FREESWAN_H
++/*
++ * header file for FreeS/WAN library functions
++ * 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$
++ */
++#define       _FREESWAN_H     /* seen it, no need to see it again */
++
++/*
++ * FreeS/WAN library routines
++ */
++
++
++
++/*
++ * 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.
++ */
++#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
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
++#define SPINLOCK
++#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++#  define SPINLOCK_23
++#  endif
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,25)
++#define PROC_FS_2325
++#else
++#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
++#  define PROC_FS_21
++#  endif
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
++#define NETDEV_23
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
++#define NETLINK_SOCK
++#define NET_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
++
++#ifdef __KERNEL__
++
++#  include <linux/types.h>
++#  include <linux/in.h>
++#  ifndef SPINLOCK
++#    include <linux/bios32.h>
++     /* simulate spin locks */
++     typedef struct {
++       volatile char lock;
++     } spinlock_t;
++
++#    define spin_lock_init(x) { (x)->lock = 0;}
++#    define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
++                                        (x)->lock=1; save_flags(flags);\
++                                        cli();}
++#    define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
++#  endif /* !SPINLOCK */
++
++#  ifndef NET21
++#    define uint8_t __u8
++#    define uint16_t __u16 
++#    define uint32_t __u32 
++#    define uint64_t __u64 
++#  endif /* !NET21 */
++
++#ifndef IPPROTO_COMP
++#define IPPROTO_COMP 108
++#endif /* !IPPROTO_COMP */
++
++#ifdef DEBUG_IPSEC
++#define DEBUG_NO_STATIC
++#else /* DEBUG_IPSEC */
++#define DEBUG_NO_STATIC static
++#endif /* DEBUG_IPSEC */
++
++#else /* __KERNEL__ */
++
++#  include <stdio.h>
++#  include <netinet/in.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__ */
++
++/*
++ * And a synonym for a type we should try to treat as opaque.
++ */
++typedef struct in_addr ip_address;
++
++
++
++/*
++ * ASCII/binary conversions
++ */
++
++/* 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) */
++      ip_address *addr
++);
++size_t                                /* space needed for full conversion */
++addrtoa(
++      ip_address 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) */
++      ip_address *addr,
++      ip_address *mask
++);
++size_t                                /* space needed for full conversion */
++subnettoa(
++      ip_address addr,
++      ip_address 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' */
++      ip_address *addrs       /* two-element array */
++);
++size_t                                /* space needed for full conversion */
++rangetoa(
++      ip_address *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 */
++#ifdef __KERNEL__
++typedef __u32 ipsec_spi_t;
++#else
++typedef u_int32_t ipsec_spi_t;
++#endif
++struct sa_id {                        /* to identify an SA, we need: */
++        ip_address dst;               /* A. destination host */
++        ipsec_spi_t spi;      /* B. 32-bit SPI, assigned by dest. host */
++      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 */
++};
++
++/* SAs */
++const char *                  /* NULL for success, else string literal */
++atosa(
++      const char *src,
++      size_t srclen,          /* 0 means strlen(src) */
++      struct sa_id *sa
++);
++size_t                                /* space needed for full conversion */
++satoa(
++      struct sa_id sa,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++#define       SATOA_BUF       (3+ULTOA_BUF+ADDRTOA_BUF)
++
++/* 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 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 char *src,
++      size_t srclen,
++      int format,             /* character; 0 means default */
++      char *dst,
++      size_t dstlen
++);
++
++
++
++/*
++ * misc. network-address stuff
++ */
++
++/* part extraction and special addresses */
++ip_address
++subnetof(
++      ip_address addr,
++      ip_address mask
++);
++ip_address
++hostof(
++      ip_address addr,
++      ip_address mask
++);
++ip_address
++broadcastof(
++      ip_address addr,
++      ip_address mask
++);
++
++/* mask handling */
++int
++goodmask(
++      ip_address mask
++);
++int
++masktobits(
++      ip_address mask
++);
++ip_address
++bitstomask(
++      int n
++);
++
++
++/*
++ * general utilities
++ */
++
++#ifndef __KERNEL__
++/* option pickup from files (userland only because of use of FILE) */
++const char *                  /* NULL for success, else string literal */
++optionsfrom(
++      const char *filename,
++      int *argcp,             /* pointers to argc and argv */
++      char ***argvp,
++      int optind,             /* next argument */
++      FILE *errorreport       /* if non-NULL, complain there and die */
++);
++#endif
++
++
++
++#endif /* _FREESWAN_H */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/goodmask.c linux-2.2.14/net/ipsec/libfreeswan/goodmask.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/goodmask.c Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/goodmask.c      Sun Apr 11 01:24:21 1999
+@@ -0,0 +1,93 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++/*
++ - 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);
++
++      if ((((x|(x-1))+1)&x) == 0)
++              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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/internal.h linux-2.2.14/net/ipsec/libfreeswan/internal.h
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/internal.h Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/internal.h      Thu May  6 00:02:34 1999
+@@ -0,0 +1,75 @@
++/*
++ * internal definitions for use within the library; do not export!
++ * 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$
++ */
++
++#ifndef ABITS
++#define       ABITS   32      /* bits in an Internet address */
++#endif
++
++/* case-independent ASCII character equality comparison */
++#define       CIEQ(c1, c2)    ( ((c1)&~040) == ((c2)&~040) )
++
++/* syntax for passthrough SA */
++#ifndef PASSTHROUGHNAME
++#define       PASSTHROUGHNAME "%passthrough"
++#define       PASSTHROUGHIS   "tun0@0.0.0.0"
++#define       PASSTHROUGHTYPE "tun"
++#define       PASSTHROUGHSPI  0
++#define       PASSTHROUGHDST  0
++#endif
++
++/*
++ * Headers, greatly complicated by stupid and unnecessary inconsistencies
++ * between the user environment and the kernel environment.  These are done
++ * here so that this mess need exist in only one place.
++ *
++ * It may seem like a -I or two could avoid most of this, but on closer
++ * inspection it is not quite that easy.
++ */
++
++/* things that need to come from one place or the other, depending */
++#ifdef __KERNEL__
++#include <linux/types.h>
++#include <linux/socket.h>
++#include <linux/in.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#else
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <string.h>
++#include <ctype.h>
++#endif
++
++/* things that exist only in userland */
++#ifndef __KERNEL__
++
++/* You'd think this would be okay in the kernel too -- it's just a */
++/* bunch of constants -- but no, in RH5.1 it screws up other things. */
++/* (Credit:  Mike Warfield tracked this problem down.  Thanks Mike!) */
++/* Fortunately, we don't need it in the kernel subset of the library. */
++#include <limits.h>
++
++/* header files for things that should never be called in kernel */
++#include <netdb.h>
++
++/* memory allocation, currently user-only, macro-ized just in case */
++#include <stdlib.h>
++#define       MALLOC(n)       malloc(n)
++#define       FREE(p)         free(p)
++
++#endif /* __KERNEL__ */
++
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/optionsfrom.c linux-2.2.14/net/ipsec/libfreeswan/optionsfrom.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/optionsfrom.c      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/optionsfrom.c   Sun Apr 11 01:24:21 1999
+@@ -0,0 +1,301 @@
++/*
++ * pick up more options from a file, in the middle of an option scan
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++#include <stdio.h>
++
++#define       MAX     100             /* loop-detection limit */
++
++/* internal work area */
++struct work {
++#     define  LOTS    1024
++      char buf[LOTS];
++      char *line;
++      char *pending;
++};
++
++static const char *dowork(const char *, int *, char ***, int);
++static const char *getanarg(FILE *, struct work *, char **);
++static char *getline(FILE *, char *, size_t);
++
++/*
++ - optionsfrom - add some options, taken from a file, to argc/argv
++ * If errsto is non-NULL, does not return in event of error.
++ */
++const char *                  /* NULL for success, else string literal */
++optionsfrom(filename, argcp, argvp, optind, errsto)
++const char *filename;
++int *argcp;                   /* pointer to argc */
++char ***argvp;                        /* pointer to argv */
++int optind;                   /* current optind, number of next argument */
++FILE *errsto;                 /* where to report errors (NULL means return) */
++{
++      const char *e;
++      static int nuses = 0;
++
++      if (errsto != NULL) {
++              nuses++;
++              if (nuses >= MAX) {
++                      fprintf(errsto,
++                              "%s: optionsfrom called %d times, looping?\n",
++                              (*argvp)[0], nuses);
++                      exit(2);
++              }
++      } else
++              nuses = 0;
++
++      e = dowork(filename, argcp, argvp, optind);
++      if (e != NULL && errsto != NULL) {
++              fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e);
++              exit(2);
++      }
++      return e;
++}
++
++/*
++ - dowork - do all the real work of optionsfrom
++ * Does not alter the existing arguments, but does relocate and alter
++ * the argv pointer vector.
++ */
++static const char *           /* NULL for success, else string literal */
++dowork(filename, argcp, argvp, optind)
++const char *filename;
++int *argcp;                   /* pointer to argc */
++char ***argvp;                        /* pointer to argv */
++int optind;                   /* current optind, number of next argument */
++{
++      char **newargv;
++      char **tmp;
++      int newargc;
++      int next;               /* place for next argument */
++      int room;               /* how many more new arguments we can hold */
++#     define  SOME    10      /* first guess at how many we'll need */
++      FILE *f;
++      int i;
++      const char *p;
++      struct work wa;         /* for getanarg() */
++
++      f = fopen(filename, "r");
++      if (f == NULL)
++              return "unable to open file";
++
++      newargc = *argcp + SOME;
++      newargv = malloc((newargc+1) * sizeof(char *));
++      if (newargv == NULL)
++              return "unable to allocate memory";
++      memcpy(newargv, *argvp, optind * sizeof(char *));
++      room = SOME;
++      next = optind;
++
++      newargv[next] = NULL;
++      wa.pending = NULL;
++      while ((p = getanarg(f, &wa, &newargv[next])) == NULL) {
++              if (room == 0) {
++                      newargc += SOME;
++                      tmp = realloc(newargv, (newargc+1) * sizeof(char *));
++                      if (tmp == NULL) {
++                              p = "out of space for new argv";
++                              break;          /* NOTE BREAK OUT */
++                      }
++                      newargv = tmp;
++                      room += SOME;
++              }
++              next++;
++              room--;
++      }
++      if (p != NULL && !feof(f)) {    /* error of some kind */
++              for (i = optind+1; i <= next; i++)
++                      if (newargv[i] != NULL)
++                              free(newargv[i]);
++              free(newargv);
++              fclose(f);
++              return p;
++      }
++
++      fclose(f);
++      memcpy(newargv + next, *argvp + optind,
++                                      (*argcp+1-optind) * sizeof(char *));
++      *argcp += next - optind;
++      *argvp = newargv;
++      return NULL;
++}
++
++/*
++ - getanarg - get a malloced argument from the file
++ */
++static const char *           /* NULL for success, else string literal */
++getanarg(f, w, linep)
++FILE *f;
++struct work *w;
++char **linep;                 /* where to store pointer if successful */
++{
++      size_t len;
++      char *p;
++      char *endp;
++
++      while (w->pending == NULL) {    /* no pending line */
++              if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL)
++                      return "error in line read";    /* caller checks EOF */
++              if (w->line[0] != '#' &&
++                              *(w->line + strspn(w->line, " \t")) != '\0')
++                      w->pending = w->line;
++      }
++
++      if (w->pending == w->line && w->line[0] != '-') {
++              /* fresh plain line */
++              w->pending = NULL;
++              p = w->line;
++              endp = p + strlen(p);
++              if (*p == '"' && endp > p+1 && *(endp-1) == '"') {
++                      p++;
++                      endp--;
++                      *endp = '\0';
++              }
++              if (w->line == w->buf) {
++                      *linep = malloc(endp - p + 1);
++                      if (*linep == NULL)
++                              return "out of memory for new line";
++                      strcpy(*linep, p);
++              } else                  /* getline already malloced it */
++                      *linep = p;
++              return NULL;
++      }
++
++      /* chip off a piece of a pending line */
++      p = w->pending;
++      p += strspn(p, " \t");
++      endp = p + strcspn(p, " \t");
++      len = endp - p;
++      if (*endp != '\0') {
++              *endp++ = '\0';
++              endp += strspn(endp, " \t");
++      }
++      /* endp now points to next real character, or to line-end NUL */
++      *linep = malloc(len + 1);
++      if (*linep == NULL) {
++              if (w->line != w->buf)
++                      free(w->line);
++              return "out of memory for new argument";
++      }
++      strcpy(*linep, p);
++      if (*endp == '\0') {
++              w->pending = NULL;
++              if (w->line != w->buf)
++                      free(w->line);
++      } else
++              w->pending = endp;
++      return NULL;
++}
++
++/*
++ - getline - read a line from the file, trim newline off
++ */
++static char *                 /* pointer to line, NULL for eof/error */
++getline(f, buf, bufsize)
++FILE *f;
++char *buf;                    /* buffer to use, if convenient */
++size_t bufsize;                       /* size of buf */
++{
++      size_t len;
++
++      if (fgets(buf, bufsize, f) == NULL)
++              return NULL;
++      len = strlen(buf);
++
++      if (len < bufsize-1 || buf[bufsize-1] == '\n') {
++              /* it fit */
++              buf[len-1] = '\0';
++              return buf;
++      }
++
++      /* oh crud, buffer overflow */
++      /* for now, to hell with it */
++      return NULL;
++}
++
++
++
++#ifdef TEST
++
++#include <getopt.h>
++
++char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ...";
++struct option opts[] = {
++      "foo",          0,      NULL,   'f',
++      "bar",          0,      NULL,   'b',
++      "builtin",      0,      NULL,   'B',
++      "optionsfrom",  1,      NULL,   '+',
++      "help",         0,      NULL,   'h',
++      "version",      0,      NULL,   'v',
++      0,              0,      NULL,   0,
++};
++
++int
++main(argc, argv)
++int argc;
++char *argv[];
++{
++      int opt;
++      extern char *optarg;
++      extern int optind;
++      int errflg = 0;
++      const char *p;
++      int i;
++      FILE *errs = NULL;
++
++      while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
++              switch (opt) {
++              case 'f':
++              case 'b':
++                      break;
++              case 'B':
++                      errs = stderr;
++                      break;
++              case '+':       /* optionsfrom */
++                      p = optionsfrom(optarg, &argc, &argv, optind, errs);
++                      if (p != NULL) {
++                              fprintf(stderr, "%s: optionsfrom error: %s\n",
++                                                              argv[0], p);
++                              exit(1);
++                      }
++                      break;
++              case 'h':       /* help */
++                      printf("%s\n", usage);
++                      exit(0);
++                      break;
++              case 'v':       /* version */
++                      printf("1\n");
++                      exit(0);
++                      break;
++              case '?':
++              default:
++                      errflg = 1;
++                      break;
++              }
++      if (errflg) {
++              fprintf(stderr, "%s\n", usage);
++              exit(2);
++      }
++
++      for (i = 1; i < argc; i++)
++              printf("%d: `%s'\n", i, argv[i]);
++      exit(0);
++}
++
++
++#endif /* TEST */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey.h linux-2.2.14/net/ipsec/libfreeswan/pfkey.h
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey.h    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/pfkey.h Tue Feb  8 22:22:11 2000
+@@ -0,0 +1,270 @@
++/*
++ * FreeS/WAN specific PF_KEY headers
++ * Copyright (C) 1999  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$
++ */
++
++#ifndef __NET_IPSEC_PF_KEY_H
++#define __NET_IPSEC_PF_KEY_H
++#ifdef __KERNEL__
++extern void pfkey_proto_init(struct net_proto *pro);
++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);
++
++extern struct sock *pfkey_sock_list;
++struct socket_list
++{
++      struct socket *socketp;
++      struct socket_list *next;
++};
++
++extern void pfkey_list_insert_socket(struct socket*, struct socket_list*);
++extern void pfkey_list_remove_socket(struct socket*, struct socket_list*);
++extern struct socket_list *pfkey_open_sockets;
++extern struct socket_list *pfkey_registered_sockets;
++extern uint8_t sadb_satype2proto[];
++
++/* #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
++struct sockaddr_key
++{
++      uint16_t        key_family;     /* PF_KEY */
++      uint16_t        key_pad;        /* not used */
++      uint32_t        key_pid;        /* process ID */
++};
++/* #endif */ /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
++
++struct pfkey_extracted_data
++{
++      struct tdb* tdb;
++      struct tdb* tdb2;
++      struct eroute *eroute;
++};
++#endif /* __KERNEL__ */
++
++extern uint8_t satype2proto(uint8_t satype);
++extern uint8_t proto2satype(uint8_t proto);
++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)->protinfo))->key_pid
++
++#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
++#define BITS_PER_OCTET 8
++#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
++#define ALIGN(x,y) (DIVUP(x,y) * y) /* align on y boundary */
++
++#define PFKEYv2_MAX_MSGSIZE 4096
++
++/*
++ * PF_KEYv2 permitted and required extensions in and out bitmaps
++ */
++
++extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/];
++#define EXT_BITS_IN 0
++#define EXT_BITS_OUT 1
++#define EXT_BITS_PERM 0
++#define EXT_BITS_REQ 1
++
++extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
++extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
++extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
++
++extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
++                         int (*ext_parsers[])(struct sadb_ext* ),
++                         struct sadb_ext **extensions,
++                         int dir);
++
++/*
++ * 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_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);
++
++int
++pfkey_lifetime_build(struct sadb_ext **       pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           allocations,
++                   uint64_t           bytes,
++                   uint64_t           addtime,
++                   uint64_t           usetime);
++
++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,
++              char*                   key);
++
++int
++pfkey_ident_build(struct sadb_ext**   pfkey_ext,
++                uint16_t              exttype,
++                uint16_t              ident_type,
++                uint64_t              ident_id,
++                char*                 ident_string);
++
++int
++pfkey_sens_build(struct sadb_ext**    pfkey_ext,
++               uint32_t               dpd,
++               uint8_t                sens_level,
++               uint8_t                sens_len,
++               uint8_t                integ_level,
++               uint8_t                integ_len);
++
++int
++pfkey_prop_build(struct sadb_ext**    pfkey_ext,
++               uint8_t                replay);
++
++int
++pfkey_supported_build(struct sadb_ext**       pfkey_ext,
++                    uint16_t          exttype);
++
++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);
++
++int
++pfkey_msg_build(struct sadb_msg**     pfkey_msg,
++              struct sadb_ext*        extensions[],
++              int                     dir);
++
++#endif /* __NET_IPSEC_PF_KEY_H */
++
++/*
++ * $Log$
++ * Revision 1.18  2000/01/22 23:24:06  rgb
++ * Added prototypes for proto2satype(), satype2proto() and proto2name().
++ *
++ * Revision 1.17  2000/01/21 06:26:59  rgb
++ * Converted from double tdb arguments to one structure (extr)
++ * containing pointers to all temporary information structures.
++ * Added klipsdebug switching capability.
++ * Dropped unused argument to pfkey_x_satype_build().
++ *
++ * Revision 1.16  1999/12/29 21:17:41  rgb
++ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
++ * parameter for cleaner manipulation of extensions[] and to guard
++ * against potential memory leaks.
++ * Changed the I/F to pfkey_msg_free() for the same reason.
++ *
++ * Revision 1.15  1999/12/09 23:12:54  rgb
++ * Added macro for BITS_PER_OCTET.
++ * Added argument to pfkey_sa_build() to do eroutes.
++ *
++ * Revision 1.14  1999/12/08 20:33:25  rgb
++ * Changed sa_family_t to uint16_t for 2.0.xx compatibility.
++ *
++ * Revision 1.13  1999/12/07 19:53:40  rgb
++ * Removed unused first argument from extension parsers.
++ * Changed __u* types to uint* to avoid use of asm/types.h and
++ * sys/types.h in userspace code.
++ * Added function prototypes for pfkey message and extensions
++ * initialisation and cleanup.
++ *
++ * Revision 1.12  1999/12/01 22:19:38  rgb
++ * Change pfkey_sa_build to accept an SPI in network byte order.
++ *
++ * Revision 1.11  1999/11/27 11:55:26  rgb
++ * Added extern sadb_satype2proto to enable moving protocol lookup table
++ * to lib/pfkey_v2_parse.c.
++ * Delete unused, moved typedefs.
++ * Add argument to pfkey_msg_parse() for direction.
++ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
++ *
++ * Revision 1.10  1999/11/23 22:29:21  rgb
++ * This file has been moved in the distribution from klips/net/ipsec to
++ * lib.
++ * Add macros for dealing with alignment and rounding up more opaquely.
++ * The uint<n>_t type defines have been moved to freeswan.h to avoid
++ * chicken-and-egg problems.
++ * Add macros for dealing with alignment and rounding up more opaque.
++ * Added prototypes for using extention header bitmaps.
++ * Added prototypes of all the build functions.
++ *
++ * Revision 1.9  1999/11/20 21:59:48  rgb
++ * Moved socketlist type declarations and prototypes for shared use.
++ * Slightly modified scope of sockaddr_key declaration.
++ *
++ * Revision 1.8  1999/11/17 14:34:25  rgb
++ * Protect sa_family_t from being used in userspace with GLIBC<2.
++ *
++ * Revision 1.7  1999/10/27 19:40:35  rgb
++ * Add a maximum PFKEY packet size macro.
++ *
++ * Revision 1.6  1999/10/26 16:58:58  rgb
++ * Created a sockaddr_key and key_opt socket extension structures.
++ *
++ * Revision 1.5  1999/06/10 05:24:41  rgb
++ * Renamed variables to reduce confusion.
++ *
++ * Revision 1.4  1999/04/29 15:21:11  rgb
++ * Add pfkey support to debugging.
++ * Add return values to init and cleanup functions.
++ *
++ * Revision 1.3  1999/04/15 17:58:07  rgb
++ * Add RCSID labels.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_build.c linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_build.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_build.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_build.c        Tue Feb  8 22:22:11 2000
+@@ -0,0 +1,1182 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999  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$
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parser.c.
++ */
++
++char pfkey_v2_build_c_version[] = "$Id$";
++
++/*
++ * 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 <linux/malloc.h> /* kmalloc() */
++# 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;
++
++# define DEBUGGING(format,args...) \
++         ((debug_pfkey) ? printk(KERN_INFO "klips_debug:" format , ## args) : 0)
++# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
++# define FREE(obj) kfree(obj)
++#else /* __KERNEL__ */
++
++# include <sys/types.h>
++# include <linux/types.h>
++# include <linux/errno.h>
++# include <malloc.h>
++# include <string.h> /* memset */
++
++# include "../pluto/constants.h" 
++# include "../pluto/defs.h"  /* for PRINTF_LIKE */
++# include "../pluto/log.h"  /* for debugging and DBG_log */
++
++extern unsigned int debugging;  /* bits selecting what to report */
++unsigned int pfkey_lib_debug = 0;
++
++/* #define PLUTO */
++
++# ifdef PLUTO
++#  define DEBUGGING(format,args...)  { DBG_log("pfkey_lib_debug:" format, ## args);  }
++# else
++#  define DEBUGGING(format,args...)  if(pfkey_lib_debug) { printf("pfkey_lib_debug:" format, ## args); } else { ; }
++# endif
++# define MALLOC(size) malloc(size)
++# define FREE(obj) free(obj)
++#endif /* __KERNEL__ */
++
++#include <freeswan.h>
++#include <pfkeyv2.h>
++#include <pfkey.h>
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++void
++pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
++{
++      int i;
++      
++      for (i = 0; i != SADB_EXT_MAX + 1; i++) {
++              extensions[i] = NULL;
++      }
++}
++
++void
++pfkey_extensions_free(struct sadb_ext *extensions[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 != 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(
++              "pfkey_msg_hdr_build:\n");
++      DEBUGGING(
++              "pfkey_msg_hdr_build: on_entry &pfkey_ext=%p pfkey_ext=%p *pfkey_ext=%p.\n",
++              &pfkey_ext,
++              pfkey_ext,
++              *pfkey_ext);
++      /* sanity checks... */
++      if(pfkey_msg) {
++              DEBUGGING(
++                      "pfkey_msg_hdr_build:why is pfkey_msg already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(!msg_type) {
++              DEBUGGING(
++                      "pfkey_msg_hdr_build: msg type not set, must be non-zero..\n");
++              SENDERR(EINVAL);
++      }
++
++      if(msg_type > SADB_MAX) {
++              DEBUGGING(
++                      "pfkey_msg_hdr_build: msg type too large:%d.\n",
++                      msg_type);
++              SENDERR(EINVAL);
++      }
++
++      if(satype > SADB_SATYPE_MAX) {
++              DEBUGGING(
++                      "pfkey_msg_hdr_build: satype %d > max %d\n", 
++                      satype, SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_msg = (struct sadb_msg*)
++           MALLOC(sizeof(struct sadb_msg)))) {
++              DEBUGGING(
++                      "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(
++              "pfkey_msg_hdr_build: on_exit &pfkey_ext=%p pfkey_ext=%p *pfkey_ext=%p.\n",
++              &pfkey_ext,
++              pfkey_ext,
++              *pfkey_ext);
++errlab:
++      return error;
++}     
++
++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)
++{
++      int error = 0;
++      struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
++
++      DEBUGGING(
++                  "pfkey_sa_build: spi=%x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
++                  spi, /* in host order */
++                  replay_window,
++                  sa_state,
++                  auth,
++                  encrypt,
++                  flags);
++      /* sanity checks... */
++      if(pfkey_sa) {
++              DEBUGGING(
++                      "pfkey_sa_build:why is pfkey_sa already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(exttype != SADB_EXT_SA &&
++         exttype != SADB_X_EXT_SA2) {
++              DEBUGGING(
++                      "pfkey_sa_build: invalid exttype=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      if(replay_window > 64) {
++              DEBUGGING(
++                      "pfkey_sa_build: replay window size: %d"
++                      " -- must be 0 <= size <= 64\n",
++                      replay_window);
++              SENDERR(EINVAL);
++      }
++
++      if(auth > SADB_AALG_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_build: auth=%d > SADB_AALG_MAX=%d.\n",
++                      auth,
++                      SADB_AALG_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(encrypt > SADB_EALG_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_build: encrypt=%d > SADB_EALG_MAX=%d.\n",
++                      encrypt,
++                      SADB_EALG_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(sa_state > SADB_SASTATE_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_build: sa_state=%d exceeds MAX=%d.\n",
++                      sa_state,
++                      SADB_SASTATE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(sa_state == SADB_SASTATE_DEAD) {
++              DEBUGGING(
++                      "pfkey_sa_build: sa_state=%d is DEAD=%d is not allowed.\n",
++                      sa_state,
++                      SADB_SASTATE_DEAD);
++              SENDERR(EINVAL);
++      }
++      
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_sa = (struct sadb_sa*)
++           MALLOC(sizeof(struct sadb_sa)))) {
++              DEBUGGING(
++                      "pfkey_sa_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_sa, 0, sizeof(struct sadb_sa));
++      
++      pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_sa->sadb_sa_exttype = exttype;
++      pfkey_sa->sadb_sa_spi = spi;
++      pfkey_sa->sadb_sa_replay = replay_window;
++      pfkey_sa->sadb_sa_state = sa_state;
++      pfkey_sa->sadb_sa_auth = auth;
++      pfkey_sa->sadb_sa_encrypt = encrypt;
++      pfkey_sa->sadb_sa_flags = flags;
++
++errlab:
++      return error;
++}     
++
++int
++pfkey_lifetime_build(struct sadb_ext **       pfkey_ext,
++                   uint16_t           exttype,
++                   uint32_t           allocations,
++                   uint64_t           bytes,
++                   uint64_t           addtime,
++                   uint64_t           usetime)
++{
++      int error = 0;
++      struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
++
++      DEBUGGING(
++              "pfkey_lifetime_build:\n");
++      /* sanity checks... */
++      if(pfkey_lifetime) {
++              DEBUGGING(
++                      "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(
++                      "pfkey_lifetime_build: invalid exttype=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_lifetime = (struct sadb_lifetime*)
++           MALLOC(sizeof(struct sadb_lifetime)))) {
++              DEBUGGING(
++                      "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;
++
++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 *saddr;
++      char ipaddr_txt[ADDRTOA_BUF];
++      struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
++      
++      DEBUGGING(
++              "pfkey_address_build: exttype=%d proto=%d prefixlen=%d\n", exttype, proto, prefixlen);
++      /* sanity checks... */
++      if(pfkey_address) {
++              DEBUGGING(
++                      "pfkey_address_build:why is pfkey_address already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      switch(exttype) {       
++      case SADB_EXT_ADDRESS_SRC:
++      case SADB_EXT_ADDRESS_DST:
++      case SADB_EXT_ADDRESS_PROXY:
++      case SADB_X_EXT_ADDRESS_DST2:
++      case SADB_X_EXT_ADDRESS_SRC_FLOW:
++      case SADB_X_EXT_ADDRESS_DST_FLOW:
++      case SADB_X_EXT_ADDRESS_SRC_MASK:
++      case SADB_X_EXT_ADDRESS_DST_MASK:
++              break;
++      default:
++              DEBUGGING( 
++                      "pfkey_address_build: unrecognised ext_type=%d.\n", 
++                      exttype); 
++              SENDERR(EINVAL); 
++      }
++
++      switch(address->sa_family) {
++      case AF_INET:
++              DEBUGGING(
++                      "pfkey_address_build: found address family AF_INET.\n");
++              saddr_len = sizeof(struct sockaddr_in);
++              saddr = (char*)&((struct sockaddr_in*)address)->sin_addr;
++              break;
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++      case AF_INET6:
++              DEBUGGING(
++                      "pfkey_address_build: found address family AF_INET6.\n");
++              saddr_len = sizeof(struct sockaddr_in6);
++              saddr = (char*)&((struct sockaddr_in6*)address)->sin6_addr;
++              break;
++#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
++      default:
++              DEBUGGING(
++                      "pfkey_address_build: address->sa_family=%d not supported.\n",
++                      address->sa_family);
++              SENDERR(EPFNOSUPPORT);
++      }
++      
++      addrtoa(*((struct in_addr*)saddr),
++              0,
++              ipaddr_txt, sizeof(ipaddr_txt));
++      DEBUGGING(
++              "pfkey_address_build: found address=%s.\n",
++              ipaddr_txt);
++      if(prefixlen != 0) {
++              DEBUGGING(
++                      "pfkey_address_build: address prefixes not supported yet.\n");
++              SENDERR(EAFNOSUPPORT); /* not supported yet */
++      }
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_address = (struct sadb_address*)
++           MALLOC(ALIGN(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN) ))) {
++              DEBUGGING(
++                      "pfkey_lifetime_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_address,
++             0,
++             ALIGN(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
++      /* XXX check if port!=0 */
++      
++      pfkey_address_s_ska.sin_port = 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(
++              "pfkey_address_build: successful.\n");
++
++ errlab:
++      return error;
++}
++
++int
++pfkey_key_build(struct sadb_ext**     pfkey_ext,
++              uint16_t                exttype,
++              uint16_t                key_bits,
++              char*                   key)
++{
++      int error = 0;
++      struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
++
++      DEBUGGING(
++              "pfkey_key_build:\n");
++      /* sanity checks... */
++      if(pfkey_key) {
++              DEBUGGING(
++                      "pfkey_key_build:why is pfkey_key already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      if(!key_bits) {
++              DEBUGGING(
++                      "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))) {
++              DEBUGGING(
++                      "pfkey_key_build: unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_key = (struct sadb_key*)
++           MALLOC(sizeof(struct sadb_key) +
++                                  DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN))) {
++              DEBUGGING(
++                      "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,
++                char*                 ident_string)
++{
++      int error = 0;
++      struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_ident) {
++              DEBUGGING(
++                      "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))) {
++              DEBUGGING(
++                      "pfkey_ident_build: unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      if((ident_type == SADB_IDENTTYPE_RESERVED)) {
++              DEBUGGING(
++                      "pfkey_ident_build: ident_type must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(ident_type > SADB_IDENTTYPE_MAX) {
++              DEBUGGING(
++                      "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) {
++              DEBUGGING(
++                      "pfkey_ident_build: string required to allocate size of extension.\n");
++              SENDERR(EINVAL);
++      }
++      
++#if 0
++      if((ident_type == SADB_IDENTTYPE_USERFQDN) ) {
++      }
++#endif
++          
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_ident = (struct sadb_ident*)
++           MALLOC(ALIGN(sizeof(struct sadb_key) + strlen(ident_string), IPSEC_PFKEYv2_ALIGN)))) {
++              DEBUGGING(
++                      "pfkey_ident_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_ident,
++             0,
++             ALIGN(sizeof(struct sadb_ident) + strlen(ident_string),
++                   IPSEC_PFKEYv2_ALIGN));
++      
++      pfkey_ident->sadb_ident_len = DIVUP(sizeof(struct sadb_ident) + strlen(ident_string),
++                                          IPSEC_PFKEYv2_ALIGN);
++      
++      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,
++             strlen(ident_string));
++
++      /* string terminator/padding must be zero */
++      /* Which one is better, I don't know... */
++#if 0
++      for(i = strlen(ident_string);
++          i < ALIGN(sizeof(struct sadb_ident) + strlen(ident_string), IPSEC_PFKEYv2_ALIGN);
++          i++) {
++              ((char*)pfkey_ident)[i] = 0;
++      }
++#else
++      memset(((char*)pfkey_ident) + sizeof(struct sadb_ident) + strlen(ident_string),
++             0,
++             ALIGN(sizeof(struct sadb_ident) + strlen(ident_string), IPSEC_PFKEYv2_ALIGN) -
++             sizeof(struct sadb_ident) + strlen(ident_string));
++#endif
++
++errlab:
++      return error;
++}
++
++int
++pfkey_sens_build(struct sadb_ext**    pfkey_ext,
++               uint32_t               dpd,
++               uint8_t                sens_level,
++               uint8_t                sens_len,
++               uint8_t                integ_level,
++               uint8_t                integ_len)
++{
++      int error = 0;
++      struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_sens) {
++              DEBUGGING(
++                      "pfkey_sens_build:why is pfkey_sens already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "pfkey_sens_build: Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_sens = (struct sadb_sens*)
++           MALLOC(sizeof(struct sadb_sens)))) {
++              DEBUGGING(
++                      "pfkey_sens_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_sens,
++             0,
++             sizeof(struct sadb_sens));
++      
++      pfkey_sens->sadb_sens_len = sizeof(struct sadb_sens) / 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;
++
++errlab:
++      return error;
++}
++
++int
++pfkey_prop_build(struct sadb_ext**    pfkey_ext,
++               uint8_t                replay)
++{
++      int error = 0;
++      int i;
++      struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_prop) {
++              DEBUGGING(
++                      "pfkey_prop_build:why is pfkey_prop already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "pfkey_prop_build: Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_prop = (struct sadb_prop*)
++           MALLOC(sizeof(struct sadb_prop)))) {
++              DEBUGGING(
++                      "pfkey_prop_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_prop,
++             0,
++             sizeof(struct sadb_prop));
++      
++      pfkey_prop->sadb_prop_len = sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN;
++
++      pfkey_prop->sadb_prop_exttype = SADB_EXT_SUPPORTED_AUTH;
++      pfkey_prop->sadb_prop_replay = replay;
++
++      for(i=0; i<3; i++) {
++              pfkey_prop->sadb_prop_reserved[i] = 0;
++      }
++
++#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;
++#endif
++errlab:
++      return error;
++}
++
++int
++pfkey_supported_build(struct sadb_ext**       pfkey_ext,
++                    uint16_t          exttype)
++{
++      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(
++                      "pfkey_supported_build:why is pfkey_supported already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "pfkey_supported_build: Sorry, I can't build exttype=%d yet.\n",
++              (*pfkey_ext)->sadb_ext_type);
++      SENDERR(EINVAL); /* don't process these yet */
++
++      if( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
++              DEBUGGING(
++                      "pfkey_supported_build: unsupported extension type=%d.\n",
++                      exttype);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
++      for(i = 0;
++          i < pfkey_supported->sadb_supported_len -
++                  (sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN);
++          i++) {
++              /* process algo description */
++              if(!pfkey_alg->sadb_alg_reserved) {
++                      DEBUGGING(
++                              "pfkey_supported_build: alg#%d, alg_id=%d, res=%d, must be zero.\n",
++                              i,
++                              pfkey_alg->sadb_alg_id,
++                              pfkey_alg->sadb_alg_reserved);
++                      SENDERR(EINVAL);
++              }
++              pfkey_alg += sizeof(struct sadb_alg);
++      }
++      
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_supported = (struct sadb_supported*)
++           MALLOC(sizeof(struct sadb_supported)))) {
++              DEBUGGING(
++                      "pfkey_supported_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++      memset(pfkey_supported,
++             0,
++             sizeof(struct sadb_supported));
++      
++      pfkey_supported->sadb_supported_len = sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN;
++      pfkey_supported->sadb_supported_exttype = exttype;
++      pfkey_supported->sadb_supported_reserved = 0;
++
++#if 0
++  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,
++                   uint32_t           max)
++{
++      int error = 0;
++      struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
++      
++      /* sanity checks... */
++      if(pfkey_spirange) {
++              DEBUGGING(
++                      "pfkey_spirange_build:why is pfkey_spirange already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++        if(max < min) {
++              DEBUGGING(
++                      "pfkey_spirange_build: minspi=%d must be < maxspi=%d.\n",
++                      min,
++                      max);
++                SENDERR(EINVAL);
++        }
++      
++      if(min <= 255) {
++              DEBUGGING(
++                      "pfkey_spirange_build: minspi=%d must be > 255.\n",
++                      min);
++              SENDERR(EEXIST);
++      }
++      
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_spirange = (struct sadb_spirange*)
++           MALLOC(sizeof(struct sadb_spirange)))) {
++              DEBUGGING(
++                      "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(
++                      "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(
++              "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 */
++
++      if(!(*pfkey_ext = (struct sadb_ext*)
++           pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
++           MALLOC(sizeof(struct sadb_x_kmprivate)))) {
++              DEBUGGING(
++                      "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 = 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(
++              "pfkey_x_satype_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_satype) {
++              DEBUGGING(
++                      "pfkey_x_satype_build:why is pfkey_x_satype already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      if(!satype) {
++              DEBUGGING(
++                      "pfkey_x_satype_build: SA type not set, must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(satype > SADB_SATYPE_MAX) {
++              DEBUGGING(
++                      "pfkey_x_satype_build: satype %d > max %d\n", 
++                      satype, SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_satype = (struct sadb_x_satype*)
++           MALLOC(sizeof(struct sadb_x_satype)))) {
++              DEBUGGING(
++                      "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 = 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)
++{
++      int error = 0;
++      int i;
++      struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
++
++      DEBUGGING(
++              "pfkey_x_debug_build:\n");
++      /* sanity checks... */
++      if(pfkey_x_debug) {
++              DEBUGGING(
++                      "pfkey_x_debug_build:why is pfkey_x_debug already pointing to something?\n");
++              SENDERR(EINVAL);
++      }
++      
++      DEBUGGING(
++              "pfkey_x_debug_build:tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x?\n",
++              tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey);
++
++      if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_debug = (struct sadb_x_debug*)
++           MALLOC(sizeof(struct sadb_x_debug)))) {
++              DEBUGGING(
++                      "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 = 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;
++
++      for(i=0; i<4; i++) {
++              pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
++      }
++
++errlab:
++      return error;
++}
++
++#if I_DONT_THINK_THIS_WILL_BE_USEFUL
++int (*ext_default_builders[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;
++      int ext;
++      int total_size;
++      struct sadb_ext *pfkey_ext;
++      int extensions_seen = 0;
++      struct sadb_ext *extensions_check[SADB_EXT_MAX + 1];
++      
++      if(!extensions[0]) {
++              DEBUGGING(
++                      "pfkey_msg_build: extensions[0] must be specified (struct sadb_msg).\n");
++              SENDERR(EINVAL);
++      }
++
++      total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
++      for(ext = 1; ext <= SADB_EXT_MAX; ext++) {
++              if(extensions[ext]) {
++                      total_size += (extensions[ext])->sadb_ext_len;
++              }
++        }                
++
++      if(!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) {
++              DEBUGGING(
++                      "pfkey_msg_build: memory allocation failed\n");
++              SENDERR(ENOMEM);
++      }
++
++      DEBUGGING(
++              "pfkey_msg_build: pfkey_msg=%p allocated %d bytes, &(extensions[0])=%p\n",
++              *pfkey_msg,
++              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 ;
++
++      pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
++
++      for(ext = 1; ext <= 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(!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] &
++                           1<<ext)) {
++                              DEBUGGING(
++                                      "pfkey_msg_build: "
++                                      "ext type %d not permitted, exts_perm=%08x, 1<<type=%08x\n", 
++                                      ext, 
++                                      extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
++                                      1<<ext);
++                              SENDERR(EINVAL);
++                      }
++                      DEBUGGING(
++                              "pfkey_msg_build: copying %d bytes from extensions[%d]=%p to=%p\n",
++                              (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN,
++                              ext,
++                              (extensions[ext]),
++                              pfkey_ext);
++                      memcpy(pfkey_ext,
++                             extensions[ext],
++                             (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
++                      ((char*)pfkey_ext) += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
++                      /* Mark that we have seen this extension and remember the header location */
++                      extensions_seen |= ( 1 << ext );
++              }
++      }
++
++      /* check required extensions */
++      DEBUGGING(
++              "pfkey_msg_build: extensions "
++              "permitted=%08x, seen=%08x, required=%08x.\n",
++              extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
++              extensions_seen,
++              extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]);
++      
++      if((extensions_seen &
++          extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) !=
++         extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) {
++              DEBUGGING(
++                      "pfkey_msg_build: required extensions missing:%08x.\n",
++                      extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] -
++                      (extensions_seen &
++                       extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) );
++              SENDERR(EINVAL);
++      }
++      
++      if((error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir))) {
++              DEBUGGING(
++                      "pfkey_msg_build: Trouble parsing newly built pfkey message, error=%d.\n",
++                      error);
++              SENDERR(-error);
++      }
++
++errlab:
++
++      return error;
++}
++
++/*
++ * $Log$
++ * Revision 1.10  2000/01/24 21:14:35  rgb
++ * Added disabled pluto pfkey lib debug flag.
++ *
++ * Revision 1.9  2000/01/21 06:27:32  rgb
++ * Added address cases for eroute flows.
++ * Removed unused code.
++ * Dropped unused argument to pfkey_x_satype_build().
++ * Indented compiler directives for readability.
++ * Added klipsdebug switching capability.
++ * Fixed SADB_EXT_MAX bug not permitting last extension access.
++ *
++ * Revision 1.8  1999/12/29 21:17:41  rgb
++ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
++ * parameter for cleaner manipulation of extensions[] and to guard
++ * against potential memory leaks.
++ * Changed the I/F to pfkey_msg_free() for the same reason.
++ *
++ * Revision 1.7  1999/12/09 23:12:20  rgb
++ * Removed unused cruft.
++ * Added argument to pfkey_sa_build() to do eroutes.
++ * Fixed exttype check in as yet unused pfkey_lifetime_build().
++ *
++ * Revision 1.6  1999/12/07 19:54:29  rgb
++ * Removed static pluto debug flag.
++ * Added functions for pfkey message and extensions initialisation
++ * and cleanup.
++ *
++ * Revision 1.5  1999/12/01 22:20:06  rgb
++ * Changed pfkey_sa_build to accept an SPI in network byte order.
++ * Added <string.h> to quiet userspace compiler.
++ * Moved pfkey_lib_debug variable into the library.
++ * Removed SATYPE check from pfkey_msg_hdr_build so FLUSH will work.
++ * Added extension assembly debugging.
++ * Isolated assignment with brackets to be sure of scope.
++ *
++ * Revision 1.4  1999/11/27 11:57:35  rgb
++ * Added ipv6 headers.
++ * Remove over-zealous algorithm sanity checkers from pfkey_sa_build.
++ * Debugging error messages added.
++ * Fixed missing auth and encrypt assignment bug.
++ * Add argument to pfkey_msg_parse() for direction.
++ * Move parse-after-build check inside pfkey_msg_build().
++ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
++ * Add CVS log entry to bottom of file.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_ext_bits.c linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_ext_bits.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_ext_bits.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_ext_bits.c     Tue Feb  8 22:22:11 2000
+@@ -0,0 +1,682 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999  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$
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parse.c.
++ */
++
++char pfkey_v2_ext_bits_c_version[] = "$Id$";
++
++/*
++ * 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 <linux/malloc.h> /* kmalloc() */
++#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 */ 
++
++#else /* __KERNEL__ */
++
++#include <sys/types.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#endif
++
++#include <freeswan.h>
++#include <pfkeyv2.h>
++#include <pfkey.h>
++
++unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
++
++/* INBOUND EXTENSIONS */
++{
++
++/* PERMITTED */
++{
++/* SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_SPIRANGE
++,
++/* SADB_UPDATE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_ADD */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_DELETE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_ACQUIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_EXPIRE */
++0
++,
++/* SADB_FLUSH */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_X_PROMISC */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_ADDFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DEBUG */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_X_EXT_DEBUG
++},
++
++/* REQUIRED */
++{
++/* SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_SPIRANGE
++,
++/* SADB_UPDATE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++,
++/* SADB_ADD */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++/*| 1<<SADB_EXT_KEY_AUTH*/
++/*| 1<<SADB_EXT_KEY_ENCRYPT*/
++,
++/* SADB_DELETE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_ACQUIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_EXPIRE */
++0
++,
++/* SADB_FLUSH */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_X_PROMISC */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++/*| 1<<SADB_X_EXT_SATYPE2*/
++/*| 1<<SADB_X_EXT_SA2*/
++/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
++,
++/* SADB_X_ADDFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1<<SADB_EXT_RESERVED
++/*| 1<<SADB_EXT_SA*/
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DEBUG */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_X_EXT_DEBUG
++}
++
++},
++
++/* OUTBOUND EXTENSIONS */
++{
++
++/* PERMITTED */
++{
++/* SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_UPDATE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_ADD */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_DELETE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_ACQUIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++,
++/* SADB_EXPIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_FLUSH */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++,
++/* SADB_X_PROMISC */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_ADDFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DEBUG */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_X_EXT_DEBUG
++},
++
++/* REQUIRED */
++{
++/* SADB_RESERVED */
++0
++,
++/* SADB_GETSPI */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_UPDATE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_ADD */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_DELETE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_GET */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++,
++/* SADB_ACQUIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_PROPOSAL
++,
++/* SADB_REGISTER */
++1<<SADB_EXT_RESERVED
++/* | 1<<SADB_EXT_SUPPORTED_AUTH
++   | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
++,
++/* SADB_EXPIRE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++/* | 1<<SADB_EXT_LIFETIME_HARD
++   | 1<<SADB_EXT_LIFETIME_SOFT */
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_FLUSH */
++1<<SADB_EXT_RESERVED
++,
++/* SADB_DUMP */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++,
++/* SADB_X_PROMISC */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_PCHANGE */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_LIFETIME_CURRENT
++| 1<<SADB_EXT_LIFETIME_HARD
++| 1<<SADB_EXT_LIFETIME_SOFT
++| 1<<SADB_EXT_ADDRESS_SRC
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_EXT_ADDRESS_PROXY
++| 1<<SADB_EXT_KEY_AUTH
++| 1<<SADB_EXT_KEY_ENCRYPT
++| 1<<SADB_EXT_IDENTITY_SRC
++| 1<<SADB_EXT_IDENTITY_DST
++| 1<<SADB_EXT_SENSITIVITY
++| 1<<SADB_EXT_PROPOSAL
++| 1<<SADB_EXT_SUPPORTED_AUTH
++| 1<<SADB_EXT_SUPPORTED_ENCRYPT
++| 1<<SADB_EXT_SPIRANGE
++| 1<<SADB_X_EXT_KMPRIVATE
++| 1<<SADB_X_EXT_SATYPE2
++| 1<<SADB_X_EXT_SA2
++| 1<<SADB_X_EXT_ADDRESS_DST2
++,
++/* SADB_X_GRPSA */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++,
++/* SADB_X_ADDFLOW */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_EXT_SA
++| 1<<SADB_EXT_ADDRESS_DST
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DELFLOW */
++1<<SADB_EXT_RESERVED
++/*| 1<<SADB_EXT_SA*/
++| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
++| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
++| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
++| 1<<SADB_X_EXT_ADDRESS_DST_MASK
++,
++/* SADB_X_DEBUG */
++1<<SADB_EXT_RESERVED
++| 1<<SADB_X_EXT_DEBUG
++}
++}
++};
++
++/*
++ * $Log$
++ * Revision 1.4  2000/01/21 06:27:56  rgb
++ * Added address cases for eroute flows.
++ * Added comments for each message type.
++ * Added klipsdebug switching capability.
++ * Fixed GRPSA bitfields.
++ *
++ * Revision 1.3  1999/12/01 22:20:27  rgb
++ * Remove requirement for a proxy address in an incoming getspi message.
++ *
++ * Revision 1.2  1999/11/27 11:57:06  rgb
++ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
++ * Add CVS log entry to bottom of file.
++ * Cleaned out unused bits.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_parse.c linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_parse.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/pfkey_v2_parse.c   Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/pfkey_v2_parse.c        Tue Feb  8 22:22:11 2000
+@@ -0,0 +1,1127 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999  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$
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_parser.c.
++ */
++
++char pfkey_v2_parse_c_version[] = "$Id$";
++
++/*
++ * 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 <linux/malloc.h> /* kmalloc() */
++# 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;
++
++# define DEBUGGING(format,args...) \
++         ((debug_pfkey) ? printk(KERN_INFO "klips_debug:" format , ## args) : 0)
++
++
++#else /* __KERNEL__ */
++
++# include <sys/types.h>
++# include <linux/types.h>
++# include <linux/errno.h>
++
++# include "../pluto/constants.h" 
++# include "../pluto/defs.h"  /* for PRINTF_LIKE */
++# include "../pluto/log.h"  /* for debugging and DBG_log */
++
++extern unsigned int pfkey_lib_debug;  /* bits selecting what to report */
++
++/* #define PLUTO */
++
++# ifdef PLUTO
++#  define DEBUGGING(format,args...)  { DBG_log("pfkey_lib_debug:" format, ## args);  }
++# else
++#  define DEBUGGING(format,args...)  if(pfkey_lib_debug) { printf("pfkey_lib_debug:" format, ## args); } else { ; }
++# endif
++
++#endif /* __KERNEL__ */
++
++
++#include <freeswan.h>
++#include <pfkeyv2.h>
++#include <pfkey.h>
++
++#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,  SADB_SATYPE_ESP,        "ESP"  },
++      { IPPROTO_AH,   SADB_SATYPE_AH,         "AH"   },
++      { IPPROTO_IPIP, SADB_X_SATYPE_IPIP,     "IPIP" },
++#ifdef CONFIG_IPCOMP
++      { IPPROTO_COMP, SADB_X_SATYPE_COMP,     "COMP" },
++#endif /* CONFIG_IPCOMP */
++#else /* __KERNEL__ */
++      { SA_ESP,       SADB_SATYPE_ESP,        "ESP"  },
++      { SA_AH,        SADB_SATYPE_AH,         "AH"   },
++      { SA_IPIP,      SADB_X_SATYPE_IPIP,     "IPIP" },
++#ifdef CONFIG_IPCOMP
++      { SA_COMP,      SADB_X_SATYPE_COMP,     "COMP" },
++#endif /* CONFIG_IPCOMP */
++#endif /* __KERNEL__ */
++      { 0, 0 }
++};
++
++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* proto2name(uint8_t proto) {
++      int i = 0;
++
++      while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
++              i++;
++      }
++      return satype_tbl[i].name;
++}
++
++uint8_t sadb_satype2proto[] = {
++#ifdef __KERNEL__
++      0,
++      0,
++      IPPROTO_AH,
++      IPPROTO_ESP,
++      0,
++      0,
++      0,
++      0,
++      0,
++      IPPROTO_IPIP,
++      IPPROTO_COMP
++#else /* __KERNEL__ */
++      0,
++      0,
++      SA_AH,
++      SA_ESP,
++      0,
++      0,
++      0,
++      0,
++      0,
++      SA_IPIP,
++      SA_COMP
++#endif /* __KERNEL__ */
++};
++
++/* Default extension parsers taken from the KLIPS code */
++
++static int
++pfkey_sa_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
++      
++      DEBUGGING(
++              "pfkey_sa_parse:\n");
++      /* sanity checks... */
++      if(!pfkey_sa) {
++              DEBUGGING(
++                      "pfkey_sa_parse: NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_sa_parse: length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
++                      pfkey_sa->sadb_sa_len,
++                      sizeof(struct sadb_sa));
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_parse: pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n",
++                      pfkey_sa->sadb_sa_encrypt,
++                      SADB_EALG_MAX);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_parse: pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n",
++                      pfkey_sa->sadb_sa_auth,
++                      SADB_AALG_MAX);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) {
++              DEBUGGING(
++                      "pfkey_sa_parse: state=%d exceeds MAX=%d.\n",
++                      pfkey_sa->sadb_sa_state,
++                      SADB_SASTATE_MAX);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
++              DEBUGGING(
++                      "pfkey_sa_parse: state=%d is DEAD=%d.\n",
++                      pfkey_sa->sadb_sa_state,
++                      SADB_SASTATE_DEAD);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_sa->sadb_sa_replay > 64) {
++              DEBUGGING(
++                      "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 ==  SADB_EXT_SA) ||
++            (pfkey_sa->sadb_sa_exttype ==  SADB_X_EXT_SA2)))
++      {
++              DEBUGGING(
++                      "pfkey_sa_parse: unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n",
++                      pfkey_sa->sadb_sa_exttype,
++                      SADB_EXT_SA,
++                      SADB_X_EXT_SA2);
++              SENDERR(EINVAL);
++      }
++      DEBUGGING(
++              "pfkey_sa_parse: successfully found len=%d exttype=%d spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d.\n",
++              pfkey_sa->sadb_sa_len,
++              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);
++
++ errlab:
++      return error;
++}     
++
++static int
++pfkey_lifetime_parse(struct sadb_ext  *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
++
++      DEBUGGING(
++                  "pfkey_lifetime_parse:\n");
++      /* sanity checks... */
++      if(!pfkey_lifetime) {
++              DEBUGGING(
++                      "pfkey_lifetime_parse: NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_lifetime->sadb_lifetime_len !=
++         sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_lifetime_parse: length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
++                      pfkey_lifetime->sadb_lifetime_len,
++                      sizeof(struct sadb_lifetime));
++              SENDERR(EINVAL);
++      }
++
++      if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) &&
++         (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) &&
++         (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) {
++              DEBUGGING( 
++                      "pfkey_lifetime_parse: unexpected ext_type=%d.\n", 
++                      pfkey_lifetime->sadb_lifetime_exttype); 
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++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[ADDRTOA_BUF];
++      
++      DEBUGGING(
++              "pfkey_address_parse:\n");
++      /* sanity checks... */
++      if(!pfkey_address) {
++              DEBUGGING(
++                      "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) {
++              DEBUGGING(
++                      "pfkey_address_parse: size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
++                      pfkey_address->sadb_address_len,
++                      sizeof(struct sadb_address),
++                      sizeof(struct sockaddr));
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_address->sadb_address_reserved) {
++              DEBUGGING(
++                      "pfkey_address_parse: res=%d, must be zero.\n",
++                      pfkey_address->sadb_address_reserved);
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_address->sadb_address_exttype) {   
++      case SADB_EXT_ADDRESS_SRC:
++      case SADB_EXT_ADDRESS_DST:
++      case SADB_EXT_ADDRESS_PROXY:
++      case SADB_X_EXT_ADDRESS_DST2:
++      case SADB_X_EXT_ADDRESS_SRC_FLOW:
++      case SADB_X_EXT_ADDRESS_DST_FLOW:
++      case SADB_X_EXT_ADDRESS_SRC_MASK:
++      case SADB_X_EXT_ADDRESS_DST_MASK:
++              break;
++      default:
++              DEBUGGING( 
++                      "pfkey_address_parse: unexpected ext_type=%d.\n", 
++                      pfkey_address->sadb_address_exttype); 
++              SENDERR(EINVAL); 
++      }
++      
++      switch(s->sa_family) {
++      case AF_INET:
++              DEBUGGING(
++                      "pfkey_address_parse: found address family=%d, AF_INET.\n",
++                      s->sa_family);
++              saddr_len = sizeof(struct sockaddr_in);
++              addrtoa(((struct sockaddr_in*)s)->sin_addr, 0, ipaddr_txt, sizeof(ipaddr_txt));
++              DEBUGGING(
++                      "pfkey_address_parse: found address=%s.\n",
++                      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:
++              DEBUGGING(
++                      "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)) {
++              DEBUGGING(
++                      "pfkey_address_parse: size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
++                      pfkey_address->sadb_address_len,
++                      sizeof(struct sadb_address),
++                      saddr_len);
++              SENDERR(EINVAL);
++      }
++      
++      if(pfkey_address->sadb_address_prefixlen != 0) {
++              DEBUGGING(
++                      "pfkey_address_parse: address prefixes not supported yet.\n");
++              SENDERR(EAFNOSUPPORT); /* not supported yet */
++      }
++      
++      /* XXX check if port!=0 */
++      
++      DEBUGGING(
++              "pfkey_address_parse: successful.\n");
++ errlab:
++      return error;
++}
++
++static int
++pfkey_key_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
++
++      DEBUGGING(
++              "pfkey_key_parse:\n");
++      /* sanity checks... */
++
++      if(!pfkey_key) {
++              DEBUGGING(
++                      "pfkey_key_parse: NULL pointer passed in.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_key_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_key->sadb_key_len,
++                      sizeof(struct sadb_key));
++              SENDERR(EINVAL);
++      }
++
++      if(!pfkey_key->sadb_key_bits) {
++              DEBUGGING(
++                      "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) * 8 + pfkey_key->sadb_key_bits,
++               64)) {
++              DEBUGGING(
++                      "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) {
++              DEBUGGING(
++                      "pfkey_key_parse: res=%d, must be zero.\n",
++                      pfkey_key->sadb_key_reserved);
++              SENDERR(EINVAL);
++      }
++
++      if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ||
++             (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) {
++              DEBUGGING(
++                      "pfkey_key_parse: expecting extension type AUTH or ENCRYPT, got %d.\n",
++                      pfkey_key->sadb_key_exttype);
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "pfkey_key_parse: success, found len=%d exttype=%d bits=%d reserved=%d.\n",
++              pfkey_key->sadb_key_len,
++              pfkey_key->sadb_key_exttype,
++              pfkey_key->sadb_key_bits,
++              pfkey_key->sadb_key_reserved);
++
++errlab:
++      return error;
++}
++
++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) {
++              DEBUGGING(
++                      "pfkey_ident_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_ident->sadb_ident_len,
++                      sizeof(struct sadb_ident));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
++              DEBUGGING(
++                      "pfkey_ident_parse: ident_type=%d out of range, must be less than %d.\n",
++                      pfkey_ident->sadb_ident_reserved,
++                      SADB_IDENTTYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_ident->sadb_ident_reserved) {
++              DEBUGGING(
++                      "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)) {
++                      DEBUGGING(
++                              "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 == SADB_EXT_IDENTITY_SRC) ||
++             (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) {
++              DEBUGGING(
++                      "pfkey_key_parse: expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
++                      pfkey_ident->sadb_ident_exttype);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++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(
++                      "pfkey_sens_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_sens->sadb_sens_len,
++                      sizeof(struct sadb_sens));
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "pfkey_sens_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;
++}
++
++static int
++pfkey_prop_parse(struct sadb_ext *pfkey_ext)
++{
++      int error = 0;
++      int i;
++      struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
++
++      /* sanity checks... */
++      if(pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_prop_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_prop->sadb_prop_len,
++                      sizeof(struct sadb_prop));
++              SENDERR(EINVAL);
++      }
++
++      for(i=0; i<3; i++) {
++              if(pfkey_prop->sadb_prop_reserved[i]) {
++                      DEBUGGING(
++                              "pfkey_prop_parse: res[%d]=%d, must be zero.\n",
++                              i, pfkey_prop->sadb_prop_reserved[i]);
++                      SENDERR(EINVAL);
++              }
++      }
++
++      DEBUGGING(
++              "pfkey_prop_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;
++}
++
++static int
++pfkey_supported_parse(struct sadb_ext *pfkey_ext)
++{
++      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->sadb_supported_len <
++         sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_supported_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_supported->sadb_supported_len,
++                      sizeof(struct sadb_supported));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_supported->sadb_supported_reserved) {
++              DEBUGGING(
++                      "pfkey_supported_parse: res=%d, must be zero.\n",
++                      pfkey_supported->sadb_supported_reserved);
++              SENDERR(EINVAL);
++      }
++
++      pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
++      for(i = 0;
++          i < pfkey_supported->sadb_supported_len -
++                  (sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN);
++          i++) {
++              /* process algo description */
++              if(!pfkey_alg->sadb_alg_reserved) {
++                      DEBUGGING(
++                              "pfkey_supported_parse: alg#%d, alg_id=%d, res=%d, must be zero.\n",
++                              i,
++                              pfkey_alg->sadb_alg_id,
++                              pfkey_alg->sadb_alg_reserved);
++                      SENDERR(EINVAL);
++              }
++              pfkey_alg += sizeof(struct sadb_alg);
++      }
++      
++      DEBUGGING(
++              "pfkey_supported_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;
++}
++
++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(
++                      "pfkey_spirange_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_spirange->sadb_spirange_len,
++                      sizeof(struct sadb_spirange));
++                SENDERR(EINVAL);
++        }
++      
++        if(pfkey_spirange->sadb_spirange_reserved) {
++              DEBUGGING(
++                      " pfkey_spirange_parse: reserved=%d must be set to zero.\n",
++                      pfkey_spirange->sadb_spirange_reserved);
++                SENDERR(EINVAL);
++        }
++      
++        if(pfkey_spirange->sadb_spirange_max < pfkey_spirange->sadb_spirange_min) {
++              DEBUGGING(
++                      " pfkey_spirange_parse: minspi=%d must be < maxspi=%d.\n",
++                      pfkey_spirange->sadb_spirange_min,
++                      pfkey_spirange->sadb_spirange_max);
++                SENDERR(EINVAL);
++        }
++      
++      if(pfkey_spirange->sadb_spirange_min <= 255) {
++              DEBUGGING(
++                      " pfkey_spirange_parse: minspi=%d must be > 255.\n",
++                      pfkey_spirange->sadb_spirange_min);
++              SENDERR(EEXIST);
++      }
++      
++ errlab:
++      return error;
++}
++
++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(
++                      "pfkey_x_kmprivate_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_x_kmprivate->sadb_x_kmprivate_len,
++                      sizeof(struct sadb_x_kmprivate));
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
++              DEBUGGING(
++                      " pfkey_x_kmprivate_parse: reserved=%d must be set to zero.\n",
++                      pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
++              SENDERR(EINVAL);
++      }
++
++      DEBUGGING(
++              "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;
++}
++
++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(
++              "pfkey_x_satype_parse:\n");
++      /* sanity checks... */
++      if(pfkey_x_satype->sadb_x_satype_len !=
++         sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_x_satype_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_x_satype->sadb_x_satype_len,
++                      sizeof(struct sadb_x_satype));
++              SENDERR(EINVAL);
++      }
++      
++      if(!pfkey_x_satype->sadb_x_satype_satype) {
++              DEBUGGING(
++                      "pfkey_x_satype_parse: satype is zero, must be non-zero.\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) {
++              DEBUGGING(
++                      "pfkey_x_satype_parse: satype %d > max %d\n", 
++                      pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++
++      if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
++              DEBUGGING(
++                      "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(
++                              " pfkey_x_satype_parse: reserved[%d]=%d must be set to zero.\n",
++                              i, pfkey_x_satype->sadb_x_satype_reserved[i]);
++                      SENDERR(EINVAL);
++              }
++      }
++      
++errlab:
++      return error;
++}
++
++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(
++              "pfkey_x_debug_parse:\n");
++      /* sanity checks... */
++      if(pfkey_x_debug->sadb_x_debug_len !=
++         sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
++              DEBUGGING(
++                      "pfkey_x_debug_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
++                      pfkey_x_debug->sadb_x_debug_len,
++                      sizeof(struct sadb_x_debug));
++              SENDERR(EINVAL);
++      }
++      
++      for(i = 0; i < 4; i++) {
++              if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
++                      DEBUGGING(
++                              " 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;
++}
++
++int (*ext_default_parsers[SADB_EXT_MAX +1])(struct sadb_ext*) =
++{
++      NULL, /* pfkey_msg_parse, */
++      pfkey_sa_parse,
++      pfkey_lifetime_parse,
++      pfkey_lifetime_parse,
++      pfkey_lifetime_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_key_parse,
++      pfkey_key_parse,
++      pfkey_ident_parse,
++      pfkey_ident_parse,
++      pfkey_sens_parse,
++      pfkey_prop_parse,
++      pfkey_supported_parse,
++      pfkey_supported_parse,
++      pfkey_spirange_parse,
++      pfkey_x_kmprivate_parse,
++      pfkey_x_satype_parse,
++      pfkey_sa_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_address_parse,
++      pfkey_x_ext_debug_parse
++};
++
++int
++pfkey_msg_parse(struct sadb_msg *pfkey_msg,
++              int (*ext_parsers[])(struct sadb_ext*),
++              struct sadb_ext *extensions[],
++              int dir)
++{
++      int error = 0;
++      int remain;
++      struct sadb_ext *pfkey_ext;
++      int extensions_seen = 0;
++      
++      DEBUGGING(
++              "pfkey_msg_parse: parsing message "
++              "ver=%d, type=%d, errno=%d, satype=%d, 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,
++              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 -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
++      
++      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) {
++              DEBUGGING(
++                      "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) {
++              DEBUGGING(
++                      "pfkey_msg_parse: msg type not set, must be non-zero..\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_msg->sadb_msg_type > SADB_MAX) {
++              DEBUGGING(
++                      "pfkey_msg_parse: msg type=%d > max=%d.\n",
++                      pfkey_msg->sadb_msg_type,
++                      SADB_MAX);
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_msg->sadb_msg_type) {
++      case SADB_GETSPI:
++      case SADB_UPDATE:
++      case SADB_ADD:
++      case SADB_DELETE:
++      case SADB_GET:
++      case SADB_ACQUIRE:
++      case SADB_REGISTER:
++      case SADB_EXPIRE:
++#if 0
++      case SADB_X_PROMISC:
++      case SADB_X_PCHANGE:
++#endif
++      case SADB_X_GRPSA:
++              if(!pfkey_msg->sadb_msg_satype) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: satype is zero, must be non-zero for msg_type %d.\n", pfkey_msg->sadb_msg_type);
++                      SENDERR(EINVAL);
++              }
++              switch(pfkey_msg->sadb_msg_satype) {
++              case SADB_SATYPE_ESP:
++              case SADB_SATYPE_AH:
++              case SADB_X_SATYPE_IPIP:
++                      break;
++              default:
++                      DEBUGGING(
++                              "pfkey_msg_parse: satype=%d is not supported yet.\n", pfkey_msg->sadb_msg_satype);
++                      SENDERR(EINVAL);
++              }
++              break;
++      default:
++      }
++      
++      DEBUGGING(
++              "pfkey_msg_parse: remain=%d, ext_type=%d, ext_len=%d.\n", 
++              remain, pfkey_ext->sadb_ext_type, pfkey_ext->sadb_ext_len);
++      
++      DEBUGGING(
++              "pfkey_msg_parse: extensions "
++              "permitted=%08x, required=%08x.\n",
++              extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
++              extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
++      
++      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) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: remain %d less than ext len %d.\n", 
++                              remain, pfkey_ext->sadb_ext_len);
++                      SENDERR(EINVAL);
++              }
++              
++              DEBUGGING(
++                      "pfkey_msg_parse: parsing ext type=%d remain=%d.\n",
++                      pfkey_ext->sadb_ext_type,
++                      remain);
++              
++              /* Is the extension header type valid? */
++              if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: ext type %d invalid, SADB_EXT_MAX=%d.\n", 
++                              pfkey_ext->sadb_ext_type, SADB_EXT_MAX);
++                      SENDERR(EINVAL);
++              }
++              
++              /* Have we already seen this type of extension? */
++              if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0)
++              {
++                      DEBUGGING(
++                              "pfkey_msg_parse: ext type %d already seen.\n", 
++                              pfkey_ext->sadb_ext_type);
++                      SENDERR(EINVAL);
++              }
++              
++              /* Is this type of extension permitted for this type of message? */
++              if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] &
++                   1<<pfkey_ext->sadb_ext_type)) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: ext type %d not permitted, exts_perm_in=%08x, 1<<type=%08x\n", 
++                              pfkey_ext->sadb_ext_type, 
++                              extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
++                              1<<pfkey_ext->sadb_ext_type);
++                      SENDERR(EINVAL);
++              }
++
++              DEBUGGING(
++                      "pfkey_msg_parse: About to parse extension %d %p with parser %p.\n",
++                      pfkey_ext->sadb_ext_type,
++                      pfkey_ext,
++                      ext_parsers[pfkey_ext->sadb_ext_type]);
++              /* Parse the extension */
++              if((error = ext_parsers[pfkey_ext->sadb_ext_type](pfkey_ext))) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: extension parsing for type %d failed with error %d.\n",
++                              pfkey_ext->sadb_ext_type, error); 
++                      SENDERR(-error);
++              }
++              DEBUGGING(
++                      "pfkey_msg_parse: Extension %d parsed.\n",
++                      pfkey_ext->sadb_ext_type);
++              
++              /* Mark that we have seen this extension and remember the header location */
++              extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type );
++              extensions[pfkey_ext->sadb_ext_type] = pfkey_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(
++                      "pfkey_msg_parse: unexpected remainder of %d.\n", 
++                      remain);
++              /* why is there still something remaining? */
++              SENDERR(EINVAL);
++      }
++
++      /* check required extensions */
++      DEBUGGING(
++              "pfkey_msg_parse: extensions "
++              "permitted=%08x, seen=%08x, required=%08x.\n",
++              extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
++              extensions_seen,
++              extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
++      
++      if((extensions_seen &
++          extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) !=
++         extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) {
++              DEBUGGING(
++                      "pfkey_msg_parse: required extensions missing:%08x.\n",
++                      extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] -
++                      (extensions_seen &
++                       extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]));
++              SENDERR(EINVAL);
++      }
++      
++      if((((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_type == SADB_ADD) ||
++         (((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_type == SADB_UPDATE)) {
++
++              /* check maturity */
++              if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
++                 SADB_SASTATE_MATURE) {
++                      DEBUGGING(
++                              "pfkey_msg_parse: "
++                              "state=%d for add or update should be MATURE=%d.\n",
++                              ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
++                              SADB_SASTATE_MATURE);
++                      SENDERR(EINVAL);
++              }
++              
++              /* check AH and ESP */
++              if(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype ==
++                 SADB_SATYPE_AH) {
++                      if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
++                           ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
++                           SADB_AALG_NONE)) {
++                              DEBUGGING(
++                                      "pfkey_msg_parse: "
++                                      "auth alg is zero, must be non-zero for AH SAs.\n");
++                              SENDERR(EINVAL);
++                      }
++                      if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
++                         SADB_EALG_NONE) {
++                              DEBUGGING(
++                                      "pfkey_msg_parse: "
++                                      "AH handed encalg=%d, must be zero.\n",
++                                      ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
++                              SENDERR(EINVAL);
++                      }
++              }
++              
++              if(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype ==
++                 SADB_SATYPE_ESP) {
++                      if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
++                           ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
++                           SADB_EALG_NONE)) {
++                              DEBUGGING(
++                                      "pfkey_msg_parse: "
++                                      "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
++                                      ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
++                                      ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
++                              SENDERR(EINVAL);
++                      }
++                      if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
++                          SADB_EALG_NULL) &&
++                         (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
++                          SADB_AALG_NONE) ) {
++                              DEBUGGING(
++                                      "pfkey_msg_parse: "
++                                      "ESP handed encNULL+authNONE, illegal combination.\n");
++                              SENDERR(EINVAL);
++                      }
++              }
++      }
++              
++errlab:
++
++      return error;
++}
++
++/*
++ * $Log$
++ * Revision 1.15  2000/01/24 21:15:31  rgb
++ * Added disabled pluto pfkey lib debug flag.
++ * Added algo debugging reporting.
++ *
++ * Revision 1.14  2000/01/22 23:24:29  rgb
++ * Added new functions proto2satype() and satype2proto() and lookup
++ * table satype_tbl.  Also added proto2name() since it was easy.
++ *
++ * Revision 1.13  2000/01/21 09:43:59  rgb
++ * Cast ntohl(spi) as (unsigned long int) to shut up compiler.
++ *
++ * Revision 1.12  2000/01/21 06:28:19  rgb
++ * Added address cases for eroute flows.
++ * Indented compiler directives for readability.
++ * Added klipsdebug switching capability.
++ *
++ * Revision 1.11  1999/12/29 21:14:59  rgb
++ * Fixed debug text cut and paste typo.
++ *
++ * Revision 1.10  1999/12/10 17:45:24  rgb
++ * Added address debugging.
++ *
++ * Revision 1.9  1999/12/09 23:11:42  rgb
++ * Ditched <string.h> include since we no longer use memset().
++ * Use new pfkey_extensions_init() instead of memset().
++ * Added check for SATYPE in pfkey_msg_build().
++ * Tidy up comments and debugging comments.
++ *
++ * Revision 1.8  1999/12/07 19:55:26  rgb
++ * Removed unused first argument from extension parsers.
++ * Removed static pluto debug flag.
++ * Moved message type and state checking to pfkey_msg_parse().
++ * Changed print[fk] type from lx to x to quiet compiler.
++ * Removed redundant remain check.
++ * Changed __u* types to uint* to avoid use of asm/types.h and
++ * sys/types.h in userspace code.
++ *
++ * Revision 1.7  1999/12/01 22:20:51  rgb
++ * Moved pfkey_lib_debug variable into the library.
++ * Added pfkey version check into header parsing.
++ * Added check for SATYPE only for those extensions that require a
++ * non-zero value.
++ *
++ * Revision 1.6  1999/11/27 11:58:05  rgb
++ * Added ipv6 headers.
++ * Moved sadb_satype2proto protocol lookup table from
++ * klips/net/ipsec/pfkey_v2_parser.c.
++ * Enable lifetime_current checking.
++ * Debugging error messages added.
++ * Add argument to pfkey_msg_parse() for direction.
++ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
++ * Add CVS log entry to bottom of file.
++ * Moved auth and enc alg check to pfkey_msg_parse().
++ * Enable accidentally disabled spirange parsing.
++ * Moved protocol/algorithm checks from klips/net/ipsec/pfkey_v2_parser.c
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/pfkeyv2.h linux-2.2.14/net/ipsec/libfreeswan/pfkeyv2.h
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/pfkeyv2.h  Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/pfkeyv2.h       Tue Feb  8 22:22:11 2000
+@@ -0,0 +1,275 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++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
++
++#define PF_KEY_V2 2
++#define PFKEYV2_REVISION        199806L
++
++#define SADB_RESERVED    0
++#define SADB_GETSPI      1
++#define SADB_UPDATE      2
++#define SADB_ADD         3
++#define SADB_DELETE      4
++#define SADB_GET         5
++#define SADB_ACQUIRE     6
++#define SADB_REGISTER    7
++#define SADB_EXPIRE      8
++#define SADB_FLUSH       9
++#define SADB_DUMP       10
++#define SADB_X_PROMISC  11
++#define SADB_X_PCHANGE  12
++#define SADB_X_GRPSA    13
++#define SADB_X_ADDFLOW        14
++#define SADB_X_DELFLOW        15
++#define SADB_X_DEBUG  16
++#define SADB_MAX        16
++
++struct sadb_msg {
++  uint8_t sadb_msg_version;
++  uint8_t sadb_msg_type;
++  uint8_t sadb_msg_errno;
++  uint8_t sadb_msg_satype;
++  uint16_t sadb_msg_len;
++  uint16_t sadb_msg_reserved;
++  uint32_t sadb_msg_seq;
++  uint32_t sadb_msg_pid;
++};
++
++struct sadb_ext {
++  uint16_t sadb_ext_len;
++  uint16_t sadb_ext_type;
++};
++
++struct 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;
++};
++
++struct sadb_lifetime {
++  uint16_t sadb_lifetime_len;
++  uint16_t sadb_lifetime_exttype;
++  uint32_t sadb_lifetime_allocations;
++  uint64_t sadb_lifetime_bytes;
++  uint64_t sadb_lifetime_addtime;
++  uint64_t sadb_lifetime_usetime;
++};
++
++struct sadb_address {
++  uint16_t sadb_address_len;
++  uint16_t sadb_address_exttype;
++  uint8_t sadb_address_proto;
++  uint8_t sadb_address_prefixlen;
++  uint16_t sadb_address_reserved;
++};
++
++struct sadb_key {
++  uint16_t sadb_key_len;
++  uint16_t sadb_key_exttype;
++  uint16_t sadb_key_bits;
++  uint16_t sadb_key_reserved;
++};
++
++struct sadb_ident {
++  uint16_t sadb_ident_len;
++  uint16_t sadb_ident_exttype;
++  uint16_t sadb_ident_type;
++  uint16_t sadb_ident_reserved;
++  uint64_t sadb_ident_id;
++};
++
++struct sadb_sens {
++  uint16_t sadb_sens_len;
++  uint16_t sadb_sens_exttype;
++  uint32_t sadb_sens_dpd;
++  uint8_t sadb_sens_sens_level;
++  uint8_t sadb_sens_sens_len;
++  uint8_t sadb_sens_integ_level;
++  uint8_t sadb_sens_integ_len;
++  uint32_t sadb_sens_reserved;
++};
++
++struct sadb_prop {
++  uint16_t sadb_prop_len;
++  uint16_t sadb_prop_exttype;
++  uint8_t sadb_prop_replay;
++  uint8_t sadb_prop_reserved[3];
++};
++
++struct sadb_comb {
++  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;
++};
++
++struct sadb_supported {
++  uint16_t sadb_supported_len;
++  uint16_t sadb_supported_exttype;
++  uint32_t sadb_supported_reserved;
++};
++
++struct sadb_alg {
++  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;
++};
++
++struct sadb_spirange {
++  uint16_t sadb_spirange_len;
++  uint16_t sadb_spirange_exttype;
++  uint32_t sadb_spirange_min;
++  uint32_t sadb_spirange_max;
++  uint32_t sadb_spirange_reserved;
++};
++
++struct sadb_x_kmprivate {
++  uint16_t sadb_x_kmprivate_len;
++  uint16_t sadb_x_kmprivate_exttype;
++  uint32_t sadb_x_kmprivate_reserved;
++};
++
++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];
++};
++  
++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;
++  uint8_t sadb_x_debug_reserved[4];
++};
++  
++#define SADB_EXT_RESERVED             0
++#define SADB_EXT_SA                   1
++#define SADB_EXT_LIFETIME_CURRENT     2
++#define SADB_EXT_LIFETIME_HARD        3
++#define SADB_EXT_LIFETIME_SOFT        4
++#define SADB_EXT_ADDRESS_SRC          5
++#define SADB_EXT_ADDRESS_DST          6
++#define SADB_EXT_ADDRESS_PROXY        7
++#define SADB_EXT_KEY_AUTH             8
++#define SADB_EXT_KEY_ENCRYPT          9
++#define SADB_EXT_IDENTITY_SRC         10
++#define SADB_EXT_IDENTITY_DST         11
++#define SADB_EXT_SENSITIVITY          12
++#define SADB_EXT_PROPOSAL             13
++#define SADB_EXT_SUPPORTED_AUTH       14
++#define SADB_EXT_SUPPORTED_ENCRYPT    15
++#define SADB_EXT_SPIRANGE             16
++#define SADB_X_EXT_KMPRIVATE          17
++#define SADB_X_EXT_SATYPE2            18
++#define SADB_X_EXT_SA2                19
++#define SADB_X_EXT_ADDRESS_DST2       20
++#define SADB_X_EXT_ADDRESS_SRC_FLOW   21
++#define SADB_X_EXT_ADDRESS_DST_FLOW   22
++#define SADB_X_EXT_ADDRESS_SRC_MASK   23
++#define SADB_X_EXT_ADDRESS_DST_MASK   24
++#define SADB_X_EXT_DEBUG              25
++#define SADB_EXT_MAX                  25
++
++#define SADB_SATYPE_UNSPEC    0
++#define SADB_SATYPE_AH        2
++#define SADB_SATYPE_ESP       3
++#define SADB_SATYPE_RSVP      5
++#define SADB_SATYPE_OSPFV2    6
++#define SADB_SATYPE_RIPV2     7
++#define SADB_SATYPE_MIP       8
++#define SADB_X_SATYPE_IPIP    9
++#define SADB_X_SATYPE_COMP    10
++#define SADB_SATYPE_MAX       10
++
++#define SADB_SASTATE_LARVAL   0
++#define SADB_SASTATE_MATURE   1
++#define SADB_SASTATE_DYING    2
++#define SADB_SASTATE_DEAD     3
++#define SADB_SASTATE_MAX      3
++
++#define SADB_SAFLAGS_PFS              1
++#define SADB_X_SAFLAGS_REPLACEFLOW    2
++#define SADB_X_SAFLAGS_CLEARFLOW      3
++
++#define SADB_AALG_NONE        0
++#define SADB_AALG_MD5HMAC     2
++#define SADB_AALG_SHA1HMAC    3
++#define SADB_AALG_MAX         3
++
++#define SADB_EALG_NONE        0
++#define SADB_EALG_DESCBC      2
++#define SADB_EALG_3DESCBC     3
++#define SADB_EALG_NULL        11
++#define SADB_EALG_MAX         11
++
++#define SADB_IDENTTYPE_RESERVED   0
++#define SADB_IDENTTYPE_PREFIX     1
++#define SADB_IDENTTYPE_FQDN       2
++#define SADB_IDENTTYPE_USERFQDN   3
++#define SADB_IDENTTYPE_MAX        3
++
++#define SADB_KEY_FLAGS_MAX     0
++#endif /* __PFKEY_V2_H */
++
++/*
++ * $Log$
++ * Revision 1.7  2000/01/21 06:28:37  rgb
++ * Added flow add/delete message type macros.
++ * Added flow address extension type macros.
++ * Tidied up spacing.
++ * Added klipsdebug switching capability.
++ *
++ * Revision 1.6  1999/11/27 11:56:08  rgb
++ * Add SADB_X_SATYPE_COMP for compression, eventually.
++ *
++ * Revision 1.5  1999/11/23 22:23:16  rgb
++ * This file has been moved in the distribution from klips/net/ipsec to
++ * lib.
++ *
++ * Revision 1.4  1999/04/29 15:23:29  rgb
++ * Add GRPSA support.
++ * Add support for a second SATYPE, SA and DST_ADDRESS.
++ * Add IPPROTO_IPIP support.
++ *
++ * Revision 1.3  1999/04/15 17:58:08  rgb
++ * Add RCSID labels.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/rangetoa.c linux-2.2.14/net/ipsec/libfreeswan/rangetoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/rangetoa.c Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/rangetoa.c      Sun Apr 11 01:24:21 1999
+@@ -0,0 +1,61 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/satoa.c linux-2.2.14/net/ipsec/libfreeswan/satoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/satoa.c    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/satoa.c Fri Nov 19 02:13:22 1999
+@@ -0,0 +1,82 @@
++/*
++ * convert from binary form of SA ID 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$
++ */
++#include "internal.h"
++#include "freeswan.h"
++
++static struct typename {
++      char type;
++      char *name;
++} typenames[] = {
++      { SA_AH,        "ah" },
++      { SA_ESP,       "esp" },
++      { SA_IPIP,      "tun" },
++      { 0,            NULL }
++};
++
++/*
++ - satoa - convert SA to ASCII "ah507@1.2.3.4"
++ */
++size_t                                /* space needed for full conversion */
++satoa(sa, format, dst, dstlen)
++struct sa_id sa;
++int format;                   /* character */
++char *dst;                    /* need not be valid if dstlen is 0 */
++size_t dstlen;
++{
++      size_t len;
++      int base;
++      struct typename *tn;
++      char buf[30+ADDRTOA_BUF];
++
++      switch (format) {
++      case 0:
++              base = 16;      /* temporarily at least */
++              break;
++      case 'd':
++              base = 10;
++              break;
++      default:
++              return 0;
++              break;
++      }
++
++      for (tn = typenames; tn->name != NULL; tn++)
++              if (sa.proto == tn->type)
++                      break;
++      if (tn->name == NULL)
++              return 0;
++
++      if (strcmp(tn->name, PASSTHROUGHTYPE) == 0 &&
++                                      sa.spi == PASSTHROUGHSPI &&
++                                      sa.dst.s_addr == PASSTHROUGHDST) {
++              strcpy(buf, PASSTHROUGHNAME);
++              len = strlen(buf);
++      } else {
++              strcpy(buf, tn->name);
++              len = strlen(buf);
++              len += ultoa(ntohl(sa.spi), base, buf+len, sizeof(buf)-len);
++              *(buf+len-1) = '@';
++              len += addrtoa(sa.dst, 0, buf+len, sizeof(buf)-len);
++      }
++
++      if (dst != NULL) {
++              if (len > dstlen)
++                      *(buf+dstlen-1) = '\0';
++              strcpy(dst, buf);
++      }
++      return len;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/subnetof.c linux-2.2.14/net/ipsec/libfreeswan/subnetof.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/subnetof.c Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/subnetof.c      Sun Apr 11 01:24:22 1999
+@@ -0,0 +1,60 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/subnettoa.c linux-2.2.14/net/ipsec/libfreeswan/subnettoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/subnettoa.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/subnettoa.c     Sun Apr 11 01:24:22 1999
+@@ -0,0 +1,62 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/libfreeswan/ultoa.c linux-2.2.14/net/ipsec/libfreeswan/ultoa.c
+--- linux-2.2.14.orig/net/ipsec/libfreeswan/ultoa.c    Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/libfreeswan/ultoa.c Wed Oct 13 20:09:06 1999
+@@ -0,0 +1,67 @@
++/*
++ * 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$
++ */
++#include "internal.h"
++#include "freeswan.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;
++}
+diff -durN linux-2.2.14.orig/net/ipsec/pfkey_v2.c linux-2.2.14/net/ipsec/pfkey_v2.c
+--- linux-2.2.14.orig/net/ipsec/pfkey_v2.c     Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/pfkey_v2.c  Tue Feb  8 22:21:55 2000
+@@ -0,0 +1,1543 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API domain socket I/F
++ * Copyright (C) 1999  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$
++ */
++
++/*
++ *            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>
++
++#include <linux/config.h>
++#include <linux/kernel.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>
++#include <linux/in.h>
++#include <linux/fs.h>
++#include <linux/malloc.h>
++#include <asm/segment.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/sock.h>
++/* #include <net/tcp.h> */
++#include <net/af_unix.h>
++#ifdef CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif /* CONFIG_PROC_FS */
++
++#include <linux/types.h>
++ 
++#include <freeswan.h>
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#endif /* NET_21 */
++#include <pfkeyv2.h>
++#include <pfkey.h>
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_netlink.h"
++
++#ifdef DEBUG_IPSEC
++int debug_pfkey = 0;
++#endif
++
++#define min(a,b)      (((a)<(b))?(a):(b))
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++#ifdef NET_21_
++static atomic_t pfkey_nr_socks = ATOMIC_INI(0);
++#endif /* NET_21 */
++
++struct proto_ops pfkey_ops;
++struct sock *pfkey_sock_list = NULL;
++
++struct socket_list *pfkey_open_sockets = NULL;
++struct socket_list *pfkey_registered_sockets = NULL;
++
++int pfkey_msg_interp(struct sock *, struct sadb_msg *);
++
++void
++pfkey_list_remove_socket(struct socket *socketp, struct socket_list* sockets)
++{
++      struct socket_list *socket_listp,*prev;
++      socket_listp = sockets;
++      prev = NULL;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_remove_socket: 0x%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_s((void*)socket_listp, sizeof(struct socket_list));
++                      
++                      break;
++              }
++              prev = socket_listp;
++              socket_listp = socket_listp->next;
++      }
++}
++
++
++void
++pfkey_list_insert_socket(struct socket *socketp, struct socket_list* sockets)
++{
++      struct socket_list *socket_listp;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_list_insert_socket: sock=%p\n",socketp);
++      
++      socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL);
++      if(socket_listp == NULL)        {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_list_insert_socket: memory allocation error.\n");
++              return;
++      }
++      
++      socket_listp->socketp = socketp;
++      socket_listp->next = sockets;
++      sockets = socket_listp;
++}
++  
++#ifdef NET_21_
++static void pfkey_destruct(struct sock *sk)
++{
++      return;
++}
++#endif /* NET_21 */
++
++#ifndef NET_21
++static void
++pfkey_state_change(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_state_change: .\n");
++      if(!sk->dead) {
++              wake_up_interruptible(sk->sleep);
++      }
++}
++#endif /* !NET_21 */
++
++#ifndef NET_21
++static void
++pfkey_data_ready(struct sock *sk, int len)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_data_ready: .sk=%p len=%d\n", sk, len);
++      if(!sk->dead) {
++              wake_up_interruptible(sk->sleep);
++              sock_wake_async(sk->socket, 1);
++      }
++}
++
++static void
++pfkey_write_space(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_write_space: .\n");
++      if(!sk->dead) {
++              wake_up_interruptible(sk->sleep);
++              sock_wake_async(sk->socket, 2);
++      }
++}
++
++static void
++pfkey_insert_socket(struct sock *sk)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_insert_socket: sk=%p\n", sk);
++      cli();
++      sk->next=pfkey_sock_list;
++      pfkey_sock_list=sk;
++      sti();
++}
++
++static void
++pfkey_remove_socket(struct sock *sk)
++{
++      struct sock **s;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_remove_socket: .\n");
++      cli();
++      s=&pfkey_sock_list;
++
++      while(*s!=NULL) {
++              if(*s==sk) {
++                      *s=sk->next;
++                      /* XXX rgb */ 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 /* !NET_21 */
++
++/* static */ void
++pfkey_destroy_socket(struct sock *sk)
++{
++      struct sk_buff *skb;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: .\n");
++#ifdef NET_21
++      /* sklist_destroy_socket(&pfkey_sock_list, sk); */
++      sklist_remove_socket(&pfkey_sock_list, sk);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: sklist_remove_socket called.\n");
++#else /* NET_21 */
++      pfkey_remove_socket(sk);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: pfkey_remove_socket called.\n");
++#endif /* NET_21 */
++      
++#ifdef NET_21_
++#if 0
++      skb_queue_purge(&sk->receive_queue);
++      skb_queue_purge(&sk->write_queue);
++#endif
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: "
++                  "sk(%p)->receive_queue(%p) not dequeued, not freeing, "
++                  "allowing memory to leak.\n", sk, sk->receive_queue.next);
++#else /* NET_21 */
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: "
++                  "sk(%p)->(&%p)receive_queue.{next=%p,prev=%p}.\n",
++                  sk,
++                  &(sk->receive_queue),
++                  sk->receive_queue.next,
++                  sk->receive_queue.prev);
++      while(sk && ((skb=skb_dequeue(&(sk->receive_queue)))!=NULL)) {
++#ifdef NET_21
++if(0 && debug_pfkey) {                KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_destroy_socket: skb=%p dequeued.\n", skb);
++              printk(KERN_INFO "klips_debug: pfkey_skb contents:");
++              printk(" next:%p", skb->next);
++              printk(" prev:%p", skb->prev);
++              printk(" list:%p", skb->list);
++              printk(" sk:%p", skb->sk);
++              printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec);
++              printk(" dev:%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(" dev->name:%s", skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL"); */
++              printk(" h:%p", skb->h.raw);
++              printk(" nh:%p", skb->nh.raw);
++              printk(" mac:%p", skb->mac.raw);
++              printk(" dst:%p", skb->dst);
++#if 0
++              { int i;
++              printk(" cb");
++              for(i=0; i<48; i++) {
++                      printk(":%2x", skb->cb[i]);
++              }
++              }
++#endif
++              printk(" len:%d", skb->len);
++              printk(" csum:%d", skb->csum);
++              printk(" used:%d", skb->used);
++              printk(" is_clone:%d", skb->is_clone);
++              printk(" cloned:%d", skb->cloned);
++              printk(" pkt_type:%d", skb->pkt_type);
++              printk(" pkt_bridged:%d", skb->pkt_bridged);
++              printk(" ip_summed:%d", skb->ip_summed);
++              printk(" priority:%d", skb->priority);
++              printk(" protocol:%d", skb->protocol);
++              printk(" security:%d", skb->security);
++              printk(" truesize:%d", skb->truesize);
++              printk(" head:%p", skb->head);
++              printk(" data:%p", skb->data);
++              printk(" tail:%p", skb->tail);
++              printk(" end:%p", skb->end);
++#if 0
++              { unsigned int i;
++              printk(" data");
++              for(i=(unsigned int)(skb->head); i<(unsigned int)(skb->end); i++) {
++                      printk(":%2x", (unsigned char)(*(char*)(i)));
++              }
++              }
++#endif
++              printk(" destructor:%p", skb->destructor);
++              printk("\n");
++}
++#if 1
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_destroy_socket: skb=%p freed.\n", skb);
++              kfree_skb(skb);
++#else
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_destroy_socket: skb=%p leaking.\n", skb);
++#endif
++
++#ifdef THIS_IS_A_QUICKREF_OF_THE_STRUCT_SK_BUFF
++      struct sk_buff  * next;                 /* Next buffer in list                          */
++      struct sk_buff  * prev;                 /* Previous buffer in list                      */
++      struct sk_buff_head * list;             /* List we are on                               */
++      struct sock     *sk;                    /* Socket we are owned by                       */
++      struct timeval  stamp;                  /* Time we arrived                              */
++      struct device   *dev;                   /* Device we arrived on/are leaving by          */
++
++      /* Transport layer header */
++      union
++      {
++              struct tcphdr   *th;
++              struct udphdr   *uh;
++              struct icmphdr  *icmph;
++              struct igmphdr  *igmph;
++              struct iphdr    *ipiph;
++              struct spxhdr   *spxh;
++              unsigned char   *raw;
++      } h;
++
++      /* Network layer header */
++      union
++      {
++              struct iphdr    *iph;
++              struct ipv6hdr  *ipv6h;
++              struct arphdr   *arph;
++              struct ipxhdr   *ipxh;
++              unsigned char   *raw;
++      } nh;
++  
++      /* Link layer header */
++      union 
++      {       
++              struct ethhdr   *ethernet;
++              unsigned char   *raw;
++      } mac;
++
++      struct  dst_entry *dst;
++
++      char            cb[48];  
++
++      unsigned int    len;                    /* Length of actual data                        */
++      unsigned int    csum;                   /* Checksum                                     */
++      volatile char   used;                   /* Data moved to user and not MSG_PEEK          */
++      unsigned char   is_clone,               /* We are a clone                               */
++                      cloned,                 /* head may be cloned (check refcnt to be sure). */
++                      pkt_type,               /* Packet class                                 */
++                      pkt_bridged,            /* Tracker for bridging                         */
++                      ip_summed;              /* Driver fed us an IP checksum                 */
++      __u32           priority;               /* Packet queueing priority                     */
++      atomic_t        users;                  /* User count - see datagram.c,tcp.c            */
++      unsigned short  protocol;               /* Packet protocol from driver.                 */
++      unsigned short  security;               /* Security level of packet                     */
++      unsigned int    truesize;               /* Buffer size                                  */
++
++      unsigned char   *head;                  /* Head of buffer                               */
++      unsigned char   *data;                  /* Data head pointer                            */
++      unsigned char   *tail;                  /* Tail pointer                                 */
++      unsigned char   *end;                   /* End pointer                                  */
++      void            (*destructor)(struct sk_buff *);        /* Destruct function            */
++#endif
++
++#else /* NET_21 */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_destroy_socket: skb=%p dequeued and freed.\n", skb);
++              kfree_skb(skb, FREE_WRITE);
++
++#endif /* NET_21 */
++      }
++#endif /* NET_21 */
++
++      sk->dead = 1;
++      sk_free(sk);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_destroy_socket: destroyed.\n");
++}
++
++/* static */ int
++pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
++{
++      int error;
++      struct sk_buff * skb = NULL;
++      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;
++      }
++
++#ifdef NET_21
++      sk = sock->sk;
++#else /* NET_21 */
++      sk = sock->data;
++#endif /* NET_21 */
++
++      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",
++                  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 %p.\n", skb);
++      
++#if 0
++      memset(skb, 0, sizeof(*skb));  /* this is a bad idea because it resets the data pointers */
++#else
++      skb->dev = NULL;
++#endif
++      
++      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));
++#ifdef NET_21
++              kfree_skb(skb);
++#else /* NET_21 */
++              kfree_skb(skb, FREE_WRITE);
++#endif /* NET_21 */
++              return -ENOBUFS;
++      }
++      skb->h.raw = skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
++      memcpy(skb->h.raw, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
++
++#ifndef NET_21
++      skb->free = 1;
++#endif /* !NET_21 */
++
++      if((error = sock_queue_rcv_skb(sk, skb)) < 0) {
++              skb->sk=NULL;
++#ifdef NET_21
++              kfree_skb(skb);
++#else /* NET_21 */
++              kfree_skb(skb, FREE_WRITE);
++#endif /* NET_21 */
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_upmsg: "
++                          "error=%d calling sock_queue_rcv_skb with skb=%p.\n",
++                          error, skb);
++              return error;
++      }
++      return 0;
++}
++
++/* static */ int
++pfkey_create(struct socket *sock, int protocol)
++{
++      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=%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;
++      }
++
++#ifdef NET_21
++      sock->state = SS_UNCONNECTED;
++#endif /* NET_21 */
++      MOD_INC_USE_COUNT;
++#ifdef NET_21
++      if((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1)) == NULL)
++#else /* NET_21 */
++      if((sk=(struct sock *)sk_alloc(GFP_KERNEL)) == NULL)
++#endif /* NET_21 */
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_create: Out of memory trying to allocate.\n");
++              MOD_DEC_USE_COUNT;
++              return -ENOMEM;
++      }
++
++#ifndef NET_21
++      memset(sk, 0, sizeof(*sk));
++#endif /* !NET_21 */
++
++#ifdef NET_21
++      sock_init_data(sock, sk);
++
++      sk->destruct = NULL; /* pfkey_destruct; */
++      sk->reuse = 1;
++      sock->ops = &pfkey_ops;
++
++      sk->zapped=0;
++      sk->family = PF_KEY;
++/*    sk->num = protocol; */
++      sk->protocol = protocol;
++      key_pid(sk) = current->pid;
++      sklist_insert_socket(&pfkey_sock_list, sk);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_create: sock->fasync_list=%p sk->sleep=%p.\n",
++                  sock->fasync_list,
++                  sk->sleep);
++#else /* NET_21 */
++      sk->type=sock->type;
++      init_timer(&sk->timer);
++      skb_queue_head_init(&sk->write_queue);
++      skb_queue_head_init(&sk->receive_queue);
++      skb_queue_head_init(&sk->back_log);
++      sk->rcvbuf=SK_RMEM_MAX;
++      sk->sndbuf=SK_WMEM_MAX;
++      sk->allocation=GFP_KERNEL;
++      sk->state=TCP_CLOSE;
++      sk->priority=SOPRI_NORMAL;
++      sk->state_change=pfkey_state_change;
++      sk->data_ready=pfkey_data_ready;
++      sk->write_space=pfkey_write_space;
++      sk->error_report=pfkey_state_change;
++      sk->mtu=4096;
++      sk->socket=sock;
++      sock->data=(void *)sk;
++      sk->sleep=sock->wait;
++      pfkey_insert_socket(sk);
++#endif /* NET_21 */
++
++      pfkey_list_insert_socket(sock, pfkey_open_sockets);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_create: Socket sock=%p sk=%p initialised.\n", sock, sk);
++      return 0;
++}
++
++#ifndef NET_21
++static int
++pfkey_dup(struct socket *newsock, struct socket *oldsock)
++{
++      struct sock *sk;
++
++      if(newsock==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_dup: No new socket attached.\n");
++              return -EINVAL;
++      }
++              
++      if(oldsock==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_dup: No old socket attached.\n");
++              return -EINVAL;
++      }
++              
++#ifdef NET_21
++      sk=oldsock->sk;
++#else /* NET_21 */
++      sk=oldsock->data;
++#endif /* NET_21 */
++      
++      /* May not have data attached */
++      if(sk==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_dup: No sock attached to old socket.\n");
++              return -EINVAL;
++      }
++              
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_dup: .\n");
++
++      return pfkey_create(newsock, sk->protocol);
++}
++#endif /* !NET_21 */
++
++/* static */ int
++#ifdef NETDEV_23
++pfkey_release(struct socket *sock)
++#else
++pfkey_release(struct socket *sock, struct socket *peersock)
++#endif
++{
++      struct sock *sk;
++
++      if(sock==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_release: No socket attached.\n");
++              return 0; /* -EINVAL; */
++      }
++              
++#ifdef NET_21
++      sk=sock->sk;
++#else /* NET_21 */
++      sk=sock->data;
++#endif /* NET_21 */
++      
++      /* May not have data attached */
++      if(sk==NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_release: No sk attached to sock=%p.\n", sock);
++              return 0; /* -EINVAL; */
++      }
++              
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_release: .sock=%p sk=%p\n", sock, sk);
++
++      /* sklist_remove_socket(&pfkey_sock_list, sk); */
++
++#ifdef NET_21
++      if(!sk->dead)
++#endif /* NET_21 */
++              if(sk->state_change) {
++                      sk->state_change(sk);
++              }
++
++#ifdef NET_21
++      sock->sk = NULL;
++#endif /* NET_21 */
++
++      /* Try to flush out this socket. Throw out buffers at least */
++#ifdef NET_21_
++      sklist_destroy_socket(&pfkey_sock_list, sk);
++#else /* NET_21 */
++      pfkey_destroy_socket(sk);
++#endif /* NET_21 */
++
++      pfkey_list_remove_socket(sock, pfkey_open_sockets);
++      pfkey_list_remove_socket(sock, pfkey_registered_sockets);
++
++      MOD_DEC_USE_COUNT;
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_release: succeeded.\n");
++
++      return 0;
++}
++
++#ifndef NET_21
++static int
++pfkey_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_bind: operation not supported.\n");
++      return -EINVAL;
++}
++
++static int
++pfkey_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_connect: operation not supported.\n");
++      return -EINVAL;
++}
++
++static int
++pfkey_socketpair(struct socket *a, struct socket *b)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_socketpair: operation not supported.\n");
++      return -EINVAL;
++}
++
++static int
++pfkey_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_aaccept: operation not supported.\n");
++      return -EINVAL;
++}
++
++static int
++pfkey_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
++              int peer)
++{
++      struct sockaddr *ska = (struct sockaddr*)uaddr;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getname: .\n");
++      ska->sa_family = PF_KEY;
++      *uaddr_len = sizeof(*ska);
++      return 0;
++}
++
++static int
++pfkey_select(struct socket *sock, int sel_type, select_table *wait)
++{
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_select: .sock=%p sk=%p sel_type=%d\n",
++                  sock,
++                  sock->data,
++                  sel_type);
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_select: Null socket passed in.\n");
++              return -EINVAL;
++      }
++      return datagram_select(sock->data, sel_type, wait);
++}
++
++static int
++pfkey_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_ioctl: not supported.\n");
++      return -EINVAL;
++}
++
++static int
++pfkey_listen(struct socket *sock, int backlog)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_listen: not supported.\n");
++      return -EINVAL;
++}
++#endif /* !NET_21 */
++
++/* 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;
++      }
++
++#ifdef NET_21
++      sk=sock->sk;
++#else /* NET_21 */
++      sk=sock->data;
++#endif /* NET_21 */
++      
++      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->shutdown|=SEND_SHUTDOWN;
++              sk->state_change(sk);
++      }
++
++      if(mode&RCV_SHUTDOWN) {
++              sk->shutdown|=RCV_SHUTDOWN;
++              sk->state_change(sk);
++      }
++      return 0;
++}
++
++#ifndef NET_21
++static int
++pfkey_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++#ifndef NET_21
++      struct sock *sk;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_setsockopt: Null socket passed in.\n");
++              return -EINVAL;
++      }
++      
++      sk=sock->data;
++      
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_setsockopt: Null sock passed in.\n");
++              return -EINVAL;
++      }
++#endif /* !NET_21 */
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_setsockopt: .\n");
++      if(level!=SOL_SOCKET) {
++              return -EOPNOTSUPP;
++      }
++#ifdef NET_21
++      return sock_setsockopt(sock, level, optname, optval, optlen);
++#else /* NET_21 */
++      return sock_setsockopt(sk, level, optname, optval, optlen);
++#endif /* NET_21 */
++}
++
++static int
++pfkey_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++#ifndef NET_21
++      struct sock *sk;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_setsockopt: Null socket passed in.\n");
++              return -EINVAL;
++      }
++      
++      sk=sock->data;
++      
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_setsockopt: Null sock passed in.\n");
++              return -EINVAL;
++      }
++#endif /* !NET_21 */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getsockopt: .\n");
++      if(level!=SOL_SOCKET) {
++              return -EOPNOTSUPP;
++      }
++#ifdef NET_21
++      return sock_getsockopt(sock, level, optname, optval, optlen);
++#else /* NET_21 */
++      return sock_getsockopt(sk, level, optname, optval, optlen);
++#endif /* NET_21 */
++}
++
++static int
++pfkey_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_fcntl: not supported.\n");
++      return -EINVAL;
++}
++#endif /* !NET_21 */
++
++/*
++ *    Send PF_KEY data down.
++ */
++              
++/* static */ int
++#ifdef NET_21
++pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++#else /* NET_21 */
++pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
++#endif /* NET_21 */
++{
++      struct sock *sk;
++      int error = 0;
++#ifdef NET_21
++#if 0
++      struct sockaddr*ska;
++#endif
++#endif /* NET_21 */
++#if 0
++      struct sk_buff *skb;
++#endif /* 0 */
++      struct sadb_msg * pfkey_msg = NULL;
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: Null socket passed in.\n");
++              SENDERR(EINVAL);
++      }
++      
++#ifdef NET_21
++      sk = sock->sk;
++#else /* NET_21 */
++      sk = sock->data;
++#endif /* NET_21 */
++
++      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);
++      }
++
++#if 0
++#ifdef NET_21
++      ska = (struct sockaddr*)msg->msg_name;
++#endif /* NET_21 */
++#endif
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sendmsg: .\n");
++      if(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);
++      }
++
++#ifdef NET_21
++      if(msg->msg_control)
++#else /* NET_21 */
++      if(flags || msg->msg_control)
++#endif /* NET_21 */
++      {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: can't set flags or set msg_control.\n");
++              SENDERR(EINVAL);
++      }
++              
++      if(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", len);
++              SENDERR(EINVAL);
++      }
++
++      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",
++                          len, IPSEC_PFKEYv2_ALIGN);
++              SENDERR(EMSGSIZE);
++      }
++
++      /* XXX when this becomes a lib, keying daemons must be able to receive errors */
++      if(pfkey_msg->sadb_msg_errno) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: errno set to %d.\n",
++                          pfkey_msg->sadb_msg_errno);
++              SENDERR(EINVAL);
++      }
++
++      /* check PID */
++      if(pfkey_msg->sadb_msg_pid != current->pid) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: pid (%d) does not equal sending process pid (%d).\n",
++                          pfkey_msg->sadb_msg_pid, current->pid);
++              SENDERR(EINVAL);
++      }
++
++      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 > 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))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: pfkey_msg_parse returns %d.\n",
++                          error);
++              SENDERR(-error);
++      }
++ errlab:
++      if(pfkey_msg) {
++              struct sock *sockp = pfkey_sock_list;
++
++              pfkey_msg->sadb_msg_errno = error;
++              while(sockp != NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_sendmsg: "
++                                  "send up pfkey_msg=%p to socket=%p.\n",
++                                  pfkey_msg, sockp->socket);
++                      pfkey_upmsg(sockp->socket, pfkey_msg);
++                      sockp = sockp->next;
++              }
++              kfree_s((void*)pfkey_msg, len);
++      }
++
++      if(error) {
++              return error;
++      } else {
++              return len;
++      }
++}
++
++/*
++ *    Receive PF_KEY data up.
++ */
++              
++/* static */ int
++#ifdef NET_21
++pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
++#else /* NET_21 */
++pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
++#endif /* NET_21 */
++{
++      struct sock *sk;
++#ifdef NET_21
++      int noblock = flags & MSG_DONTWAIT;
++#endif /* NET_21 */
++#if 0
++      struct sockaddr *ska;
++#endif
++      struct sk_buff *skb;
++      int error;
++#if 0
++      unsigned char *sp;
++      int len;
++      int num;
++#endif /* 0 */
++
++      if(sock == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: Null socket passed in.\n");
++              return -EINVAL;
++      }
++
++#ifdef NET_21
++      sk = sock->sk;
++#else /* NET_21 */
++      sk = sock->data;
++#endif /* NET_21 */
++
++      if(sk == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: Null sock passed in for sock=%p.\n", sock);
++              return -EINVAL;
++      }
++
++      if(msg == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_recvmsg: Null msghdr passed in for sock=%p, sk=%p.\n",
++                          sock, sk);
++              return -EINVAL;
++      }
++
++#if 0
++#ifdef NET_21
++      ska = (struct sockaddr*)msg->msg_name;
++#endif /* NET_21 */
++#endif
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_recvmsg: sock=%p sk=%p msg=%p size=%d.\n",
++                  sock, sk, msg, size);
++      if(flags) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: flags (%d) not supported.\n",
++                          flags);
++              return -EOPNOTSUPP;
++      }
++              
++#ifdef NET_21
++      msg->msg_namelen = 0; /* sizeof(*ska); */
++#else /* NET_21 */
++      if(addr_len) {
++              *addr_len = 0; /* sizeof(*ska); */
++      }
++#endif /* NET_21 */
++              
++      if(sk->err) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sendmsg: sk->err=%d.\n", 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;
++      }
++#ifdef NET_21
++      else if(size <skb->len) {
++              msg->msg_flags |= MSG_TRUNC;
++      }
++#endif /* NET_21 */
++
++      skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
++        sk->stamp=skb->stamp;
++
++#if 0
++      if(ska) {
++              memset(ska, 0, sizeof(* ska));
++              ska->sa_family = PF_KEY;
++      }
++#endif
++
++      skb_free_datagram(sk, skb);
++      return size;
++}
++
++#ifdef NET_21
++struct net_proto_family pfkey_family_ops = {
++      PF_KEY,
++      pfkey_create
++};
++
++#ifndef SOCKOPS_WRAPPED
++#define SOCKOPS_WRAPPED(name) name
++#endif
++
++struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
++      PF_KEY,
++#ifndef NETDEV_23
++      sock_no_dup,
++#endif
++      pfkey_release,
++      sock_no_bind,
++      sock_no_connect,
++      sock_no_socketpair,
++      sock_no_accept,
++      sock_no_getname,
++      datagram_poll,
++      sock_no_ioctl,
++      sock_no_listen,
++      pfkey_shutdown,
++      sock_no_setsockopt,
++      sock_no_getsockopt,
++      sock_no_fcntl,
++      pfkey_sendmsg,
++      pfkey_recvmsg
++#ifdef NETDEV_23
++      , sock_no_mmap
++#endif
++};
++
++#ifdef NETDEV_23
++#include <linux/smp_lock.h>
++SOCKOPS_WRAP(pfkey, PF_KEY);
++#endif
++
++#else /* NET_21 */
++struct proto_ops pfkey_proto_ops = {
++      PF_KEY,
++      pfkey_create,
++      pfkey_dup,
++      pfkey_release,
++      pfkey_bind,
++      pfkey_connect,
++      pfkey_socketpair,
++      pfkey_accept,
++      pfkey_getname,
++      pfkey_select,
++      pfkey_ioctl,
++      pfkey_listen,
++      pfkey_shutdown,
++      pfkey_setsockopt,
++      pfkey_getsockopt,
++      pfkey_fcntl,
++      pfkey_sendmsg,
++      pfkey_recvmsg
++};
++#endif /* NET_21 */
++   
++#ifdef CONFIG_PROC_FS
++#ifndef PROC_FS_2325
++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 */
++)
++{
++      off_t pos=0;
++      off_t begin=0;
++      int len=0;
++      struct sock *sk=pfkey_sock_list;
++      
++      len+= sprintf(buffer,"sock     pid  d sleep    socket   next     prev     e destruct r z fa n p r  w o sndbf stamp    Flags    Type     St\n");
++      
++      while(sk!=NULL) {
++#ifdef NET_21
++              len+=sprintf(buffer+len,"%8p %4d %d %8p %8p %8p %8p %d %8p %d %d %2d %d %d %d %d %d %2d %d.%06d %08lX %08X %02X\n",
++                           sk,
++                           
++                           key_pid(sk),
++                           sk->dead,
++                           sk->sleep,
++                           sk->socket,
++                           sk->next,
++                           sk->prev,
++                           sk->err,
++                           sk->destruct,
++                           sk->reuse,
++                           sk->zapped,
++                           sk->family,
++                           sk->num,
++                           sk->protocol,
++                           atomic_read(&sk->rmem_alloc),
++                           atomic_read(&sk->wmem_alloc),
++                           atomic_read(&sk->omem_alloc),
++                           sk->sndbuf,
++                           (unsigned int)sk->stamp.tv_sec,
++                           (unsigned int)sk->stamp.tv_usec,
++
++                           sk->socket->flags,
++                           sk->socket->type,
++                           sk->socket->state);
++#else /* NET_21 */
++              len+=sprintf(buffer+len,"%8p %4d %d %8p %8p %8p %8p %d %d %d %d %d %2d %d.%06d %08lX %08X %02X\n",
++                           sk,
++                           
++                           key_pid(sk),
++                           sk->dead,
++                           sk->sleep,
++                           sk->socket,
++                           sk->next,
++                           sk->prev,
++                           sk->err,
++                           sk->reuse,
++                           sk->zapped,
++                           sk->num,
++                           sk->protocol,
++                           sk->sndbuf,
++                           (unsigned int)sk->stamp.tv_sec,
++                           (unsigned int)sk->stamp.tv_usec,
++
++                           sk->socket->flags,
++                           sk->socket->type,
++                           sk->socket->state);
++#endif /* NET_21 */
++              
++              pos=begin+len;
++              if(pos<offset)
++              {
++                      len=0;
++                      begin=pos;
++              }
++              if(pos>offset+length)
++                      break;
++              sk=sk->next;
++      }
++      *start=buffer+(offset-begin);
++      len-=(offset-begin);
++      if(len>length)
++              len=length;
++      return len;
++}
++
++#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
++};
++#endif /* !PROC_FS_2325 */
++#endif /* CONFIG_PROC_FS */
++
++/* void */
++int
++pfkey_init(void)
++{
++      int error = 0;
++      
++        printk(KERN_INFO "FreeS/WAN: initialising PF_KEY domain sockets.\n");
++
++#ifdef NET_21
++        sock_register(&pfkey_family_ops);
++#else /* NET_21 */
++        sock_register(pfkey_proto_ops.family, &pfkey_proto_ops);
++#endif /* NET_21 */
++
++#ifdef CONFIG_PROC_FS
++#  ifndef PROC_FS_2325
++#    ifdef PROC_FS_21
++      proc_register(proc_net, &proc_net_pfkey);
++#    else /* PROC_FS_21 */
++      proc_register_dynamic(&proc_net, &proc_net_pfkey);
++#    endif /* PROC_FS_21 */
++#  else /* !PROC_FS_2325 */
++      proc_net_create ("pf_key", 0, pfkey_get_info);
++#  endif /* !PROC_FS_2325 */
++#endif          /* CONFIG_PROC_FS */
++
++      return error;
++}
++
++/* void */
++int
++pfkey_cleanup(void)
++{
++      int error = 0;
++      
++        printk(KERN_INFO "FreeS/WAN: shutting down PF_KEY domain sockets.\n");
++#ifdef NET_21
++        sock_unregister(PF_KEY);
++#else /* NET_21 */
++        sock_unregister(pfkey_proto_ops.family);
++#endif /* NET_21 */
++#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");
++#  else /* !PROC_FS_2325 */
++      proc_net_remove ("pf_key");
++#  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 */
++void
++pfkey_proto_init(struct net_proto *pro)
++{
++      pfkey_init();
++}
++#endif /* MODULE */
++
++/*
++ * $Log$
++ * Revision 1.26  2000/01/22 03:46:59  rgb
++ * Fixed pfkey error return mechanism so that we are able to free the
++ * local copy of the pfkey_msg, plugging a memory leak and silencing
++ * the bad object free complaints.
++ *
++ * Revision 1.25  2000/01/21 06:19:44  rgb
++ * Moved pfkey_list_remove_socket() calls to before MOD_USE_DEC_COUNT.
++ * Added debugging to pfkey_upmsg.
++ *
++ * Revision 1.24  2000/01/10 16:38:23  rgb
++ * MB fixups for 2.3.x.
++ *
++ * Revision 1.23  1999/12/09 23:22:16  rgb
++ * Added more instrumentation for debugging 2.0 socket
++ * selection/reading.
++ * Removed erroneous 2.0 wait==NULL check bug in select.
++ *
++ * Revision 1.22  1999/12/08 20:32:16  rgb
++ * Tidied up 2.0.xx support, after major pfkey work, eliminating
++ * msg->msg_name twiddling in the process, since it is not defined
++ * for PF_KEYv2.
++ *
++ * Revision 1.21  1999/12/01 22:17:19  rgb
++ * Set skb->dev to zero on new skb in case it is a reused skb.
++ * Added check for skb_put overflow and freeing to avoid upmsg on error.
++ * Added check for wrong pfkey version and freeing to avoid upmsg on
++ * error.
++ * Shut off content dumping in pfkey_destroy.
++ * Added debugging message for size of buffer allocated for upmsg.
++ *
++ * Revision 1.20  1999/11/27 12:11:00  rgb
++ * Minor clean-up, enabling quiet operation of pfkey if desired.
++ *
++ * Revision 1.19  1999/11/25 19:04:21  rgb
++ * Update proc_fs code for pfkey to use dynamic registration.
++ *
++ * Revision 1.18  1999/11/25 09:07:17  rgb
++ * Implemented SENDERR macro for propagating error codes.
++ * Fixed error return code bug.
++ *
++ * Revision 1.17  1999/11/23 23:07:20  rgb
++ * Change name of pfkey_msg_parser to pfkey_msg_interp since it no longer
++ * parses. (PJO)
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ *
++ * Revision 1.16  1999/11/20 22:00:22  rgb
++ * Moved socketlist type declarations and prototypes for shared use.
++ * Renamed reformatted and generically extended for use by other socket
++ * lists pfkey_{del,add}_open_socket to pfkey_list_{remove,insert}_socket.
++ *
++ * Revision 1.15  1999/11/18 04:15:09  rgb
++ * Make pfkey_data_ready temporarily available for 2.2.x testing.
++ * Clean up pfkey_destroy_socket() debugging statements.
++ * Add Peter Onion's code to send messages up to all listening sockets.
++ * Changed all occurrences of #include "../../../lib/freeswan.h"
++ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
++ * klips/net/ipsec/Makefile.
++ * Replaced all kernel version macros to shorter, readable form.
++ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
++ *
++ * Revision 1.14  1999/11/17 16:01:00  rgb
++ * Make pfkey_data_ready temporarily available for 2.2.x testing.
++ * Clean up pfkey_destroy_socket() debugging statements.
++ * Add Peter Onion's code to send messages up to all listening sockets.
++ * Changed #include "../../../lib/freeswan.h" to #include <freeswan.h>
++ * which works due to -Ilibfreeswan in the klips/net/ipsec/Makefile.
++ *
++ * Revision 1.13  1999/10/27 19:59:51  rgb
++ * Removed af_unix comments that are no longer relevant.
++ * Added debug prink statements.
++ * Added to the /proc output in pfkey_get_info.
++ * Made most functions non-static to enable oops tracing.
++ * Re-enable skb dequeueing and freeing.
++ * Fix skb_alloc() and skb_put() size bug in pfkey_upmsg().
++ *
++ * Revision 1.12  1999/10/26 17:05:42  rgb
++ * Complete re-ordering based on proto_ops structure order.
++ * Separated out proto_ops structures for 2.0.x and 2.2.x for clarity.
++ * Simplification to use built-in socket ops where possible for 2.2.x.
++ * Add shorter macros for compiler directives to visually clean-up.
++ * Add lots of sk skb dequeueing debugging statements.
++ * Added to the /proc output in pfkey_get_info.
++ *
++ * Revision 1.11  1999/09/30 02:55:10  rgb
++ * Bogus skb detection.
++ * Fix incorrect /proc/net/ipsec-eroute printk message.
++ *
++ * Revision 1.10  1999/09/21 15:22:13  rgb
++ * Temporary fix while I figure out the right way to destroy sockets.
++ *
++ * Revision 1.9  1999/07/08 19:19:44  rgb
++ * Fix pointer format warning.
++ * Fix missing member error under 2.0.xx kernels.
++ *
++ * Revision 1.8  1999/06/13 07:24:04  rgb
++ * Add more debugging.
++ *
++ * Revision 1.7  1999/06/10 05:24:17  rgb
++ * Clarified compiler directives.
++ * Renamed variables to reduce confusion.
++ * Used sklist_*_socket() kernel functions to simplify 2.2.x socket support.
++ * Added lots of sanity checking.
++ *
++ * Revision 1.6  1999/06/03 18:59:50  rgb
++ * More updates to 2.2.x socket support.  Almost works, oops at end of call.
++ *
++ * Revision 1.5  1999/05/25 22:44:05  rgb
++ * Start fixing 2.2 sockets.
++ *
++ * Revision 1.4  1999/04/29 15:21:34  rgb
++ * Move log to the end of the file.
++ * Eliminate min/max redefinition in #include <net/tcp.h>.
++ * Correct path for pfkey #includes
++ * Standardise an error return method.
++ * Add debugging instrumentation.
++ * Move message type checking to pfkey_msg_parse().
++ * Add check for errno incorrectly set.
++ * Add check for valid PID.
++ * Add check for reserved illegally set.
++ * Add check for message out of bounds.
++ *
++ * Revision 1.3  1999/04/15 17:58:07  rgb
++ * Add RCSID labels.
++ *
++ * Revision 1.2  1999/04/15 15:37:26  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.1.2.2  1999/04/13 20:37:12  rgb
++ * Header Title correction.
++ *
++ * Revision 1.1.2.1  1999/03/26 20:58:55  rgb
++ * Add pfkeyv2 support to KLIPS.
++ *
++ *
++ * RFC 2367
++ * PF_KEY_v2 Key Management API
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/pfkey_v2_parser.c linux-2.2.14/net/ipsec/pfkey_v2_parser.c
+--- linux-2.2.14.orig/net/ipsec/pfkey_v2_parser.c      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/pfkey_v2_parser.c   Tue Feb  8 22:21:56 2000
+@@ -0,0 +1,2234 @@
++/*
++ * RFC2367 PF_KEYv2 Key management API message parser
++ * Copyright (C) 1999  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$
++ */
++
++/*
++ *            Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
++ */
++
++char pfkey_v2_parser_c_version[] = "$Id$";
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <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 */
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#define ip_chk_addr inet_addr_type
++#define IS_MYADDR RTN_LOCAL
++#endif
++#include <asm/checksum.h>
++#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 "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.h"
++#include "ipsec_xform.h"
++#include "ipsec_ah.h"
++#include "ipsec_esp.h"
++#include "ipsec_tunnel.h"
++#include "ipsec_rcv.h"
++
++#include <pfkeyv2.h>
++#include <pfkey.h>
++
++
++#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
++
++#ifndef min
++#define min(a,b)      (((a)<(b))?(a):(b))
++#endif
++
++extern int des_set_key(caddr_t, caddr_t);
++
++struct sklist_t {
++      struct socket *sk;
++      struct sklist_t* next;
++} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev;
++
++__u32 pfkey_msg_seq = 0;
++
++int
++pfkey_alloc_tdb(struct tdb** tdb)
++{
++      int error = 0;
++      if(*tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_alloc_tdb: tdb already allocated\n");
++              SENDERR(EEXIST);
++      }
++
++      if((*tdb = kmalloc(sizeof(**tdb), GFP_ATOMIC) ) == NULL) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_alloc_tdb: memory allocation error\n");
++              SENDERR(ENOMEM);
++      }
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_alloc_tdb: "
++                  "allocated tdb=%p.\n", tdb);
++
++      memset((caddr_t)*tdb, 0, sizeof(**tdb));
++ errlab:
++      return(error);
++}
++
++int
++pfkey_alloc_eroute(struct eroute** eroute)
++{
++      int error = 0;
++      if(*eroute) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_alloc_eroute: eroute 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: "
++                  "allocated eroute=%p.\n", 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;
++
++ errlab:
++      return(error);
++}
++
++static int pfkey_sa_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
++{
++      struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
++      int error = 0;
++      struct tdb* tdbp;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_sa_process: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_sa_process: "
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_ext->sadb_ext_type) {
++      case SADB_EXT_SA:
++              tdbp = extr->tdb;
++              break;
++      case SADB_X_EXT_SA2:
++              if(pfkey_alloc_tdb(&(extr->tdb2)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              tdbp = extr->tdb2;
++              break;
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_sa_process: invalid exttype=%d.\n",
++                          pfkey_ext->sadb_ext_type);
++              SENDERR(EINVAL);
++      }
++
++      tdbp->tdb_said.spi = pfkey_sa->sadb_sa_spi;
++      tdbp->tdb_replaywin = pfkey_sa->sadb_sa_replay;
++      tdbp->tdb_state = pfkey_sa->sadb_sa_state;
++      tdbp->tdb_flags = pfkey_sa->sadb_sa_flags;
++      tdbp->tdb_replaywin_lastseq = tdbp->tdb_replaywin_bitmap = 0;
++
++      switch(tdbp->tdb_said.proto) {
++              case IPPROTO_AH:
++                      tdbp->tdb_authalg = pfkey_sa->sadb_sa_auth;
++                      tdbp->tdb_encalg = SADB_EALG_NONE;
++
++                      break;
++              case IPPROTO_ESP:
++                      tdbp->tdb_authalg = pfkey_sa->sadb_sa_auth;
++                      tdbp->tdb_encalg = pfkey_sa->sadb_sa_encrypt;
++
++                      break;
++              case IPPROTO_IPIP:
++                      tdbp->tdb_authalg = AH_NONE;
++                      tdbp->tdb_encalg = ESP_NONE;
++                      break;
++#ifdef CONFIG_IPSEC_COMP
++              case IPPROTO_COMP:
++                      break;
++#endif /* CONFIG_IPSEC_COMP */
++              default:
++#if 0
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_sa_process: proto=0.\n");
++                      SENDERR(EINVAL);
++#endif
++      }
++
++errlab:
++      return error;
++}
++
++static 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->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_lifetime_process: "
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_lifetime->sadb_lifetime_exttype) {
++      case SADB_EXT_LIFETIME_CURRENT:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_lifetime_process: "
++                          "lifetime_current not supported yet.\n");
++              SENDERR(EINVAL);
++              break;
++      case SADB_EXT_LIFETIME_HARD:
++              if(pfkey_lifetime->sadb_lifetime_allocations &&
++                 (!extr->tdb->tdb_lifetime_allocations_h ||
++                  (pfkey_lifetime->sadb_lifetime_allocations < extr->tdb->tdb_lifetime_allocations_h))) {
++                      extr->tdb->tdb_lifetime_allocations_h =
++                              pfkey_lifetime->sadb_lifetime_allocations;
++                      if(!extr->tdb->tdb_lifetime_allocations_s &&
++                         (extr->tdb->tdb_lifetime_allocations_h < extr->tdb->tdb_lifetime_allocations_s)) {
++                              extr->tdb->tdb_lifetime_allocations_s = extr->tdb->tdb_lifetime_allocations_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_bytes &&
++                 (!extr->tdb->tdb_lifetime_bytes_h ||
++                  (pfkey_lifetime->sadb_lifetime_bytes < extr->tdb->tdb_lifetime_bytes_h))) {
++                      extr->tdb->tdb_lifetime_bytes_h =
++                              pfkey_lifetime->sadb_lifetime_bytes;
++                      if(!extr->tdb->tdb_lifetime_bytes_s &&
++                         (extr->tdb->tdb_lifetime_bytes_h < extr->tdb->tdb_lifetime_bytes_s)) {
++                              extr->tdb->tdb_lifetime_bytes_s = extr->tdb->tdb_lifetime_bytes_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_addtime &&
++                 (!extr->tdb->tdb_lifetime_addtime_h ||
++                  (pfkey_lifetime->sadb_lifetime_addtime < extr->tdb->tdb_lifetime_addtime_h))) {
++                      extr->tdb->tdb_lifetime_addtime_h =
++                              pfkey_lifetime->sadb_lifetime_addtime;
++                      if(extr->tdb->tdb_lifetime_addtime_s &&
++                         (extr->tdb->tdb_lifetime_addtime_h < extr->tdb->tdb_lifetime_addtime_s)) {
++                              extr->tdb->tdb_lifetime_addtime_s = extr->tdb->tdb_lifetime_addtime_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_usetime &&
++                 (!extr->tdb->tdb_lifetime_usetime_h ||
++                  (pfkey_lifetime->sadb_lifetime_usetime < extr->tdb->tdb_lifetime_usetime_h))) {
++                      extr->tdb->tdb_lifetime_usetime_h =
++                              pfkey_lifetime->sadb_lifetime_usetime;
++                      if(extr->tdb->tdb_lifetime_usetime_s &&
++                         (extr->tdb->tdb_lifetime_usetime_h < extr->tdb->tdb_lifetime_usetime_s)) {
++                              extr->tdb->tdb_lifetime_usetime_s = extr->tdb->tdb_lifetime_usetime_h;
++                      }
++              }
++              break;
++      case SADB_EXT_LIFETIME_SOFT:
++              if(pfkey_lifetime->sadb_lifetime_allocations &&
++                 (!extr->tdb->tdb_lifetime_allocations_s ||
++                  (pfkey_lifetime->sadb_lifetime_allocations < extr->tdb->tdb_lifetime_allocations_s))) {
++                      extr->tdb->tdb_lifetime_allocations_s =
++                              pfkey_lifetime->sadb_lifetime_allocations;
++                      if(extr->tdb->tdb_lifetime_allocations_h &&
++                         (extr->tdb->tdb_lifetime_allocations_h < extr->tdb->tdb_lifetime_allocations_s)) {
++                              extr->tdb->tdb_lifetime_allocations_s = extr->tdb->tdb_lifetime_allocations_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_bytes &&
++                 (!extr->tdb->tdb_lifetime_bytes_s ||
++                  (pfkey_lifetime->sadb_lifetime_bytes < extr->tdb->tdb_lifetime_bytes_s))) {
++                      extr->tdb->tdb_lifetime_bytes_s =
++                              pfkey_lifetime->sadb_lifetime_bytes;
++                      if(extr->tdb->tdb_lifetime_bytes_h &&
++                         (extr->tdb->tdb_lifetime_bytes_h < extr->tdb->tdb_lifetime_bytes_s)) {
++                              extr->tdb->tdb_lifetime_bytes_s = extr->tdb->tdb_lifetime_bytes_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_addtime &&
++                 (!extr->tdb->tdb_lifetime_addtime_s ||
++                  (pfkey_lifetime->sadb_lifetime_addtime < extr->tdb->tdb_lifetime_addtime_s))) {
++                      extr->tdb->tdb_lifetime_addtime_s =
++                              pfkey_lifetime->sadb_lifetime_addtime;
++                      if(extr->tdb->tdb_lifetime_addtime_h &&
++                         (extr->tdb->tdb_lifetime_addtime_h < extr->tdb->tdb_lifetime_addtime_s)) {
++                              extr->tdb->tdb_lifetime_addtime_s = extr->tdb->tdb_lifetime_addtime_h;
++                      }
++              }
++              if(pfkey_lifetime->sadb_lifetime_usetime &&
++                 (!extr->tdb->tdb_lifetime_usetime_s ||
++                  (pfkey_lifetime->sadb_lifetime_usetime < extr->tdb->tdb_lifetime_usetime_s))) {
++                      extr->tdb->tdb_lifetime_usetime_s =
++                              pfkey_lifetime->sadb_lifetime_usetime;
++                      if(extr->tdb->tdb_lifetime_usetime_h &&
++                         (extr->tdb->tdb_lifetime_usetime_h < extr->tdb->tdb_lifetime_usetime_s)) {
++                              extr->tdb->tdb_lifetime_usetime_s = extr->tdb->tdb_lifetime_usetime_h;
++                      }
++              }
++              break;
++      default:
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: pfkey_lifetime_build: invalid exttype=%d.\n",
++                      pfkey_ext->sadb_ext_type);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++static 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;
++      struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
++      struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
++      struct tdb* tdbp;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_address_process:\n");
++      
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process:\n"
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(s->sa_family) {
++      case AF_INET:
++              saddr_len = sizeof(struct sockaddr_in);
++              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 SADB_EXT_ADDRESS_SRC:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: found src address.\n");
++              sap = (unsigned char **)&(extr->tdb->tdb_addr_s);
++              extr->tdb->tdb_addr_s_size = saddr_len;
++              break;
++      case SADB_EXT_ADDRESS_DST:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: found dst address.\n");
++              sap = (unsigned char **)&(extr->tdb->tdb_addr_d);
++              extr->tdb->tdb_addr_d_size = saddr_len;
++              break;
++      case SADB_EXT_ADDRESS_PROXY:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: found proxy address.\n");
++              sap = (unsigned char **)&(extr->tdb->tdb_addr_p);
++              extr->tdb->tdb_addr_p_size = saddr_len;
++              break;
++      case SADB_X_EXT_ADDRESS_DST2:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_address_process: found 2nd dst address.\n");
++              if(pfkey_alloc_tdb(&(extr->tdb2)) == ENOMEM) {
++                      SENDERR(ENOMEM);
++              }
++              sap = (unsigned char **)&(extr->tdb2->tdb_addr_d);
++              extr->tdb2->tdb_addr_d_size = saddr_len;
++              break;
++      case 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);
++              break;
++      case 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);
++              break;
++      case 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);
++              break;
++      case 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);
++              break;
++      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 SADB_EXT_ADDRESS_SRC:
++      case SADB_EXT_ADDRESS_DST:
++      case SADB_EXT_ADDRESS_PROXY:
++      case SADB_X_EXT_ADDRESS_DST2:
++              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);
++              }
++              (unsigned int)(*sap) = ((struct sockaddr_in*)s)->sin_addr.s_addr;
++#ifdef DEBUG_IPSEC
++              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->%s\n",
++                                          buf1, buf2);
++                      }
++#endif
++              }
++      }
++
++      tdbp = extr->tdb;
++      switch(pfkey_address->sadb_address_exttype) {
++      case SADB_X_EXT_ADDRESS_DST2:
++              tdbp = extr->tdb2;
++      case SADB_EXT_ADDRESS_DST:
++              if(s->sa_family == AF_INET) {
++                      tdbp->tdb_said.dst.s_addr = ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr.s_addr;
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: tdbp->tdb_said.dst.s_addr=%08x,\n"
++                                  "klips_debug:                     ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr.s_addr=%08x,\n",
++                                  tdbp->tdb_said.dst.s_addr,
++                                  ((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr.s_addr
++                              );
++                      addrtoa(((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr,
++                              0,
++                              ipaddr_txt,
++                              sizeof(ipaddr_txt));
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: tdb_said.dst set to %s.\n",
++                                  ipaddr_txt);
++              } else {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_address_process: "
++                                  "uh, tdb_said.dst doesn't do address family=%d yet, "
++                                  "said will be invalid.\n",
++                                  s->sa_family);
++              }
++      default:
++      }
++      
++      /* XXX check if port!=0 */
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_address_process: successful.\n");
++ errlab:
++      return error;
++}
++
++static 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->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_key_process: "
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++        switch(pfkey_key->sadb_key_exttype) {
++        case SADB_EXT_KEY_AUTH:
++                extr->tdb->tdb_key_bits_a = pfkey_key->sadb_key_bits;
++              if(!(extr->tdb->tdb_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);
++              }
++              memcpy(extr->tdb->tdb_key_a,
++                     (char*)pfkey_key + sizeof(struct sadb_key),
++                     DIVUP(pfkey_key->sadb_key_bits, 8));
++              break;
++      case SADB_EXT_KEY_ENCRYPT: /* Key(s) */
++              extr->tdb->tdb_key_bits_e = pfkey_key->sadb_key_bits;
++              if(!(extr->tdb->tdb_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);
++              }
++              memcpy(extr->tdb->tdb_key_e,
++                     (char*)pfkey_key + sizeof(struct sadb_key),
++                     DIVUP(pfkey_key->sadb_key_bits, 8));
++              break;
++      default:
++              SENDERR(EINVAL);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_key_process: success.\n");
++errlab:
++      return error;
++}
++
++static 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;
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_ident_process: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_ident_process: "
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      switch(pfkey_ident->sadb_ident_exttype) {
++      case SADB_EXT_IDENTITY_SRC:
++              extr->tdb->tdb_ident_type_s = pfkey_ident->sadb_ident_type;
++              extr->tdb->tdb_ident_id_s = pfkey_ident->sadb_ident_id;
++              extr->tdb->tdb_ident_len_s = pfkey_ident->sadb_ident_len -
++                      sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN;
++              if(!(extr->tdb->tdb_ident_data_s = kmalloc(pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN, GFP_KERNEL))) {
++                      SENDERR(ENOMEM);
++              }
++              memcpy(extr->tdb->tdb_ident_data_s,
++                     (char*)pfkey_ident + sizeof(struct sadb_ident),
++                     pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN);
++              break;
++      case SADB_EXT_IDENTITY_DST: /* Identity(ies) */
++              extr->tdb->tdb_ident_type_d = pfkey_ident->sadb_ident_type;
++              extr->tdb->tdb_ident_id_d = pfkey_ident->sadb_ident_id;
++              extr->tdb->tdb_ident_len_d = pfkey_ident->sadb_ident_len -
++                      sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN;
++              if(!(extr->tdb->tdb_ident_data_d = kmalloc(pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN, GFP_KERNEL))) {
++                      SENDERR(ENOMEM);
++              }
++              memcpy(extr->tdb->tdb_ident_data_d,
++                     (char*)pfkey_ident + sizeof(struct sadb_ident),
++                     pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN);
++              break;
++      default:
++              SENDERR(EINVAL);
++      }
++errlab:
++      return error;
++}
++
++static 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;
++}
++
++static 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;
++}
++
++static 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;
++}
++
++static 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;
++}
++
++static 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;
++}
++
++static 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,
++                  "klips_debug: pfkey_x_satype_process: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_x_satype_process: "
++                          "extr or extr->tdb is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      if(pfkey_alloc_tdb(&(extr->tdb2)) == ENOMEM) {
++              SENDERR(ENOMEM);
++      }
++      if(!(extr->tdb2->tdb_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_x_satype_process: proto lookup from satype=%d failed.\n",
++                          pfkey_x_satype->sadb_x_satype_satype);
++              SENDERR(EINVAL);
++      }
++
++errlab:
++      return error;
++}
++
++static 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;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_debug_process: .\n");
++
++#ifdef DEBUG_IPSEC
++              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;
++                      if(debug_netlink)
++                              printk("klips_debug:pfkey_x_debug_process: set\n");
++              } else {
++                      if(debug_netlink)
++                              printk("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;
++              }
++#else
++              printk("klips_debug:pfkey_x_debug_process: debugging not enabled\n");
++              SENDERR(EINVAL);
++#endif        
++      
++/*errlab:*/
++      return error;
++}
++
++
++int
++pfkey_tdb_init(struct tdb *tdbp, struct sadb_ext **extensions)
++{
++        int i;
++        int error = 0;
++        char sa[SATOA_BUF];
++      char ipaddr_txt[ADDRTOA_BUF];
++      char ipaddr2_txt[ADDRTOA_BUF];
++      unsigned char kb[AHMD596_BLKLEN];
++
++      if(!tdbp) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_tdb_init: "
++                          "tdbp is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(tdbp->tdb_said, 0, sa, SATOA_BUF);
++
++        KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_tdb_init: (pfkey defined) called for SA:%s\n", sa);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_tdb_init: calling init routine of %s%s%s\n",
++                  TDB_XFORM_NAME(tdbp));
++      
++      switch(tdbp->tdb_said.proto) {
++              
++#ifdef CONFIG_IPSEC_IPIP
++      case IPPROTO_IPIP: {
++              addrtoa(((struct sockaddr_in*)(tdbp->tdb_addr_s))->sin_addr,
++                      0,
++                      ipaddr_txt, sizeof(ipaddr_txt));
++              addrtoa(((struct sockaddr_in*)(tdbp->tdb_addr_d))->sin_addr,
++                      0,
++                      ipaddr2_txt, sizeof(ipaddr_txt));
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_tdb_init: "
++                          "(pfkey defined) IPIP tdb set for %s->%s.\n",
++                          ipaddr_txt,
++                          ipaddr2_txt);
++      }
++      break;
++#endif /* !CONFIG_IPSEC_IPIP */
++#ifdef CONFIG_IPSEC_AH
++      case IPPROTO_AH:
++              switch(tdbp->tdb_authalg) {
++# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++              case AH_MD5: {
++                      unsigned char *akp;
++                      MD5_CTX *ictx;
++                      MD5_CTX *octx;
++                      
++                      if(tdbp->tdb_key_bits_a != (AHMD596_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect key size: %d bits"
++                                          "-- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_a, AHMD596_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: hmac md5-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                  ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+3)));
++#  endif
++                      
++                      tdbp->tdb_auth_bits = AHMD596_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = tdbp->tdb_key_a;
++                      
++                      if((tdbp->tdb_key_a = (caddr_t)
++                          kmalloc((tdbp->tdb_key_a_size = sizeof(struct md5_ctx)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++
++                      for (i = 0; i < DIVUP(tdbp->tdb_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->ictx);
++                      MD5Init(ictx);
++                      MD5Update(ictx, kb, AHMD596_BLKLEN);
++
++                      for (i = 0; i < AHMD596_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->octx);
++                      MD5Init(octx);
++                      MD5Update(octx, kb, AHMD596_BLKLEN);
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_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
++                      
++                              /* zero key buffer -- paranoid */
++                      memset(akp, 0, DIVUP(tdbp->tdb_key_bits_a, BITS_PER_OCTET));
++              }
++              break;
++# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++              case AH_SHA: {
++                      
++                      unsigned char *akp;
++                      SHA1_CTX *ictx;
++                      SHA1_CTX *octx;
++                      
++                      if(tdbp->tdb_key_bits_a != (AHSHA196_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect key size: %d bits"
++                                          "-- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_a, AHSHA196_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: hmac sha1-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                  ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+3)));
++#  endif
++                      
++                      tdbp->tdb_auth_bits = AHSHA196_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = tdbp->tdb_key_a;
++                      
++                      if((tdbp->tdb_key_a = (caddr_t)
++                          kmalloc((tdbp->tdb_key_a_size = sizeof(struct sha1_ctx)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      
++                      for (i = 0; i < DIVUP(tdbp->tdb_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct sha1_ctx*)(tdbp->tdb_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*)(tdbp->tdb_key_a))->octx);
++                      SHA1Init(octx);
++                      SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                      
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_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] );
++                      
++                              /* zero key buffer -- paranoid */
++                      memset(akp, 0, DIVUP(tdbp->tdb_key_bits_a, BITS_PER_OCTET));
++              }
++              break;
++# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: "
++                                  "authalg=%d support not available in the kernel",
++                                  tdbp->tdb_authalg);
++                      SENDERR(EINVAL);
++              }
++#endif /* CONFIG_IPSEC_AH */
++#ifdef CONFIG_IPSEC_ESP
++      case IPPROTO_ESP: {
++              unsigned char *akp, *ekp;
++              
++              switch(tdbp->tdb_encalg) {
++# ifdef CONFIG_IPSEC_ENC_DES
++              case ESP_DES:
++# endif /* CONFIG_IPSEC_ENC_DES */
++# ifdef CONFIG_IPSEC_ENC_3DES
++              case ESP_3DES:
++# endif /* CONFIG_IPSEC_ENC_3DES */
++# if defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES)
++                      if((tdbp->tdb_iv = (caddr_t)
++                          kmalloc((tdbp->tdb_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      get_random_bytes((void *)tdbp->tdb_iv, EMT_ESPDES_IV_SZ);
++                      break;
++# endif /* defined(CONFIG_IPSEC_ENC_DES) || defined(CONFIG_IPSEC_ENC_3DES) */
++              case ESP_NONE:
++# ifdef CONFIG_IPSEC_ENC_NULL
++              case ESP_NULL:
++# endif /* CONFIG_IPSEC_ENC_NULL */
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: "
++                                  "encalg=%d support not available in the kernel",
++                                  tdbp->tdb_encalg);
++                      SENDERR(EINVAL);
++              }
++              
++              switch(tdbp->tdb_encalg) {
++# ifdef CONFIG_IPSEC_ENC_DES
++              case ESP_DES:
++                      if(tdbp->tdb_key_bits_e != (EMT_ESPDES_KEY_SZ * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect encryption"
++                                          "key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_e, EMT_ESPDES_KEY_SZ * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++                      /* save encryption key pointer */
++                      ekp = tdbp->tdb_key_e;
++                      
++                      if((tdbp->tdb_key_e = (caddr_t)
++                          kmalloc((tdbp->tdb_key_e_size = sizeof(struct des_eks)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: des key 1 is 0x%08lx%08lx\n",
++                                  ntohl(*((__u32 *)ed->eme_key)),
++                                  ntohl(*((__u32 *)ed->eme_key + 1)));
++#  endif
++                      error = des_set_key((caddr_t)ekp, (caddr_t)(tdbp->tdb_key_e));
++                      if (error == -1)
++                              printk("klips_debug:pfkey_tdb_init: parity error in des key\n");
++                      else if (error == -2)
++                              printk("klips_debug:pfkey_tdb_init: illegal weak des key\n");
++                      if (error) {
++                              memset(tdbp->tdb_key_e, 0, sizeof(struct des_eks));
++                              kfree_s(tdbp->tdb_key_e, sizeof(struct des_eks));
++                              memset(ekp, 0, DIVUP(tdbp->tdb_key_bits_e, BITS_PER_OCTET));
++                              SENDERR(EINVAL);
++                      }
++                      memset(ekp, 0, DIVUP(tdbp->tdb_key_bits_e, BITS_PER_OCTET));
++                      break;
++# endif /* CONFIG_IPSEC_ENC_DES */
++# ifdef CONFIG_IPSEC_ENC_3DES
++              case ESP_3DES:
++                      if(tdbp->tdb_key_bits_e != (EMT_ESP3DES_KEY_SZ * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect encryption"
++                                          "key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_e, EMT_ESP3DES_KEY_SZ * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++                      /* save encryption key pointer */
++                      ekp = tdbp->tdb_key_e;
++                      
++                      if((tdbp->tdb_key_e = (caddr_t)
++                          kmalloc((tdbp->tdb_key_e_size = 3 * sizeof(struct des_eks)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      
++                      for(i = 0; i < 3; i++) {
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: 3des key %d/3 is 0x%08lx%08lx\n",
++                                          i + 1,
++                                          ntohl(*((__u32 *)ed->eme_key + i * 2)),
++                                          ntohl(*((__u32 *)ed->eme_key + i * 2 + 1)));
++#  endif
++                              error = des_set_key((caddr_t)ekp + EMT_ESPDES_KEY_SZ * i,
++                                                  (caddr_t)&((struct des_eks*)(tdbp->tdb_key_e))[i]);
++                              if (error == -1)
++                                      printk("klips_debug:pfkey_tdb_init: parity error in des key %d/3\n", i + 1);
++                              else if (error == -2)
++                                      printk("klips_debug:pfkey_tdb_init: illegal weak des key %d/3\n", i + 1);
++                              if (error) {
++                                      memset(tdbp->tdb_key_e, 0, 3 * sizeof(struct des_eks));
++                                      kfree_s(tdbp->tdb_key_e, 3 * sizeof(struct des_eks));
++                                      memset(ekp, 0, DIVUP(tdbp->tdb_key_bits_e, BITS_PER_OCTET));
++                                      SENDERR(EINVAL);
++                              }
++                      }
++
++                      /* paranoid */
++                      memset(ekp, 0, DIVUP(tdbp->tdb_key_bits_e, BITS_PER_OCTET));
++                      
++                      break;
++# endif /* CONFIG_IPSEC_ENC_3DES */
++# ifdef CONFIG_IPSEC_ENC_NULL
++              case ESP_NULL:
++# endif /* CONFIG_IPSEC_ENC_NULL */
++              case ESP_NONE:
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: "
++                                  "encalg=%d support not available in the kernel",
++                                  tdbp->tdb_encalg);
++                      SENDERR(EINVAL);
++              }
++              
++              switch(tdbp->tdb_authalg) {
++# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
++              case AH_MD5: {
++                      MD5_CTX *ictx;
++                      MD5_CTX *octx;
++
++                      if(tdbp->tdb_key_bits_a != (AHMD596_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect authorisation"
++                                          " key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_a, AHMD596_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: hmac md5-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                  ntohl(*(((__u32 *)(tdbp->tdb_key_a))+0)),
++                                  ntohl(*(((__u32 *)(tdbp->tdb_key_a))+1)),
++                                  ntohl(*(((__u32 *)(tdbp->tdb_key_a))+2)),
++                                  ntohl(*(((__u32 *)(tdbp->tdb_key_a))+3)));
++#  endif
++                      tdbp->tdb_auth_bits = AHMD596_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = tdbp->tdb_key_a;
++                      
++                      if((tdbp->tdb_key_a = (caddr_t)
++                          kmalloc((tdbp->tdb_key_a_size = sizeof(struct md5_ctx)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      
++                      for (i = 0; i < DIVUP(tdbp->tdb_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->ictx);
++                      MD5Init(ictx);
++                      MD5Update(ictx, kb, AHMD596_BLKLEN);
++
++                      for (i = 0; i < AHMD596_BLKLEN; i++) {
++                              kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
++                      }
++
++                      octx = &(((struct md5_ctx*)(tdbp->tdb_key_a))->octx);
++                      MD5Init(octx);
++                      MD5Update(octx, kb, AHMD596_BLKLEN);
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_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
++                      /* paranoid */
++                      memset(akp, 0, DIVUP(tdbp->tdb_key_bits_a, BITS_PER_OCTET));
++                      break;
++              }
++# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
++# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
++              case AH_SHA: {
++                      SHA1_CTX *ictx;
++                      SHA1_CTX *octx;
++
++                      if(tdbp->tdb_key_bits_a != (AHSHA196_KLEN * 8)) {
++                              KLIPS_PRINT(debug_pfkey,
++                                          "klips_debug:pfkey_tdb_init: incorrect authorisation"
++                                          " key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
++                                          tdbp->tdb_key_bits_a, AHSHA196_KLEN * 8);
++                              SENDERR(EINVAL);
++                      }
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: hmac sha1-96 key is 0x%08lx %08lx %08lx %08lx\n",
++                                  ntohl(*(((__u32 *)ed->ame_key)+0)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+1)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+2)),
++                                  ntohl(*(((__u32 *)ed->ame_key)+3)));
++#  endif
++                      tdbp->tdb_auth_bits = AHSHA196_ALEN * 8;
++                      
++                      /* save the pointer to the key material */
++                      akp = tdbp->tdb_key_a;
++
++                      if((tdbp->tdb_key_a = (caddr_t)
++                          kmalloc((tdbp->tdb_key_a_size = sizeof(struct sha1_ctx)),
++                                  GFP_ATOMIC)) == NULL) {
++                              SENDERR(ENOMEM);
++                      }
++                      
++                      for (i = 0; i < DIVUP(tdbp->tdb_key_bits_a, 8); i++) {
++                              kb[i] = akp[i] ^ HMAC_IPAD;
++                      }
++                      for (; i < AHMD596_BLKLEN; i++) {
++                              kb[i] = HMAC_IPAD;
++                      }
++
++                      ictx = &(((struct sha1_ctx*)(tdbp->tdb_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*)(tdbp->tdb_key_a))->octx;
++                      SHA1Init(octx);
++                      SHA1Update(octx, kb, AHSHA196_BLKLEN);
++                      
++#  if 0 /* we don't really want to print these unless there are really big problems */
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_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
++                      memset(akp, 0, DIVUP(tdbp->tdb_key_bits_a, BITS_PER_OCTET));
++                      break;
++              }
++# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
++              case AH_NONE:
++                      break;
++              default:
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_tdb_init: "
++                                  "authalg=%d support not available in the kernel",
++                                  tdbp->tdb_authalg);
++                      SENDERR(EINVAL);
++              }
++      }
++                      break;
++#endif /* !CONFIG_IPSEC_ESP */
++#ifdef CONFIG_IPSEC_COMP
++      case IPPROTO_COMP:
++#endif /* CONFIG_IPSEC_COMP */
++      default:
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_tdb_init: "
++                          "proto=%d unknown",
++                          tdbp->tdb_said.proto);
++              SENDERR(EINVAL);
++      }
++      
++ errlab:
++      return(error);
++}
++
++int
++pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      ipsec_spi_t minspi = 256, maxspi = -1L;
++      int found_avail = 0;
++      struct tdb *tdbq;
++      char sa[SATOA_BUF];
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getspi_parse: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_getspi_parse: error, extr or extr->tdb pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      if(extensions[SADB_EXT_SPIRANGE]) {
++              minspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_min;
++              maxspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_max;
++      }
++
++      if(maxspi == minspi) {
++              extr->tdb->tdb_spi = maxspi;
++              if((tdbq = gettdb(&(extr->tdb->tdb_said)))) {
++                      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug: pfkey_getspi_parse: EMT_GETSPI found an old Tunnel Descriptor Block\n"
++                                  "klips_debug:                for SA: %s, delete it first.\n", sa);
++                      SENDERR(EEXIST);
++              } else {
++                      found_avail = 1;
++              }
++      } else {
++              int i = 0;
++              while( ( i < (maxspi - minspi)) && !found_avail ) {
++                      get_random_bytes((void*) &(extr->tdb->tdb_spi),
++                                       /* sizeof(extr->tdb->tdb_spi) */
++                                       ( maxspi - minspi + 256 ) / 256 );
++                      extr->tdb->tdb_spi = htonl(minspi +
++                                            (extr->tdb->tdb_spi %
++                                            (maxspi - minspi + 1)));
++                      i++;
++                      tdbq = gettdb(&(extr->tdb->tdb_said));
++                      if(!tdbq) {
++                              found_avail = 1;
++                      }
++              }
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++
++      if (!found_avail) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_getspi_parse: found an old Tunnel Descriptor Block\n"
++                          "klips_debug:                for SA: %s, delete it first.\n", sa);
++              SENDERR(EEXIST);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->tdb->tdb_dst.s_addr) == IS_MYADDR) {
++              extr->tdb->tdb_flags |= EMT_INBOUND;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: pfkey_getspi_parse: existing Tunnel Descriptor Block not found (this\n"
++                  "klips_debug:                is good) for SA: %s, %s-bound, allocating.\n",
++                  sa, extr->tdb->tdb_flags & EMT_INBOUND ? "in" : "out");
++      
++      /* XXX extr->tdb->tdb_rcvif = &(enc_softc[em->em_if].enc_if);*/
++      extr->tdb->tdb_rcvif = NULL;
++      extr->tdb->tdb_lifetime_addtime_c = jiffies/HZ;
++
++      extr->tdb->tdb_state = SADB_SASTATE_LARVAL;
++
++      if(!extr->tdb->tdb_lifetime_allocations_c) {
++              extr->tdb->tdb_lifetime_allocations_c += 1;
++      }
++
++      puttdb(extr->tdb);
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_getspi_parse: successful for SA: %s\n", sa);
++      
++ errlab:
++      extr->tdb->tdb_state = SADB_SASTATE_DEAD;
++      return error;
++}
++
++int
++pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct tdb* tdbq;
++      char sa[SATOA_BUF];
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse: .\n");
++
++      if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != 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[SADB_EXT_SA])->sadb_sa_state,
++                          SADB_SASTATE_MATURE);
++              SENDERR(EINVAL);
++      }
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: error, extr or extr->tdb pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++
++      tdbq = gettdb(&(extr->tdb->tdb_said));
++      if (!tdbq) {
++              spin_unlock_irqrestore(&tdb_lock, flags);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_update_parse: reserved Tunnel Descriptor Block\n"
++                          "klips_debug:            for SA: %s not found.  Call SADB_GETSPI first or call SADB_ADD instead.\n", sa);
++              SENDERR(EEXIST);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->tdb->tdb_dst.s_addr) == IS_MYADDR) {
++              extr->tdb->tdb_flags |= EMT_INBOUND;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: pfkey_update_parse: existing Tunnel Descriptor Block found (this\n"
++                  "klips_debug:                is good) for SA: %s, %s-bound, updating.\n",
++                  sa, extr->tdb->tdb_flags & EMT_INBOUND ? "in" : "out");
++      
++      /* XXX extr->tdb->tdb_rcvif = &(enc_softc[em->em_if].enc_if);*/
++      extr->tdb->tdb_rcvif = NULL;
++      if ((error = pfkey_tdb_init(extr->tdb, extensions))) {
++              spin_unlock_irqrestore(&tdb_lock, flags);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: "
++                          "not successful for SA: %s, deleting.\n", sa);
++              ipsec_tdbwipe(extr->tdb);
++              SENDERR(-error);
++      }
++
++      if((error = deltdbchain(tdbq))) {
++              spin_unlock_irqrestore(&tdb_lock, flags);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_update_parse: "
++                          "error, trouble deleting intermediate tdb for SA=%s.\n", sa);
++              SENDERR(-error);
++      }
++
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      puttdb(extr->tdb);
++      ipsec_tdbwipe(tdbq);
++      
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_update_parse: successful for SA: %s\n", sa);
++      
++ errlab:
++      return error;
++}
++
++int
++pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct tdb* tdbq;
++      char sa[SATOA_BUF];
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: parsing add message\n");
++
++      if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != 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[SADB_EXT_SA])->sadb_sa_state,
++                          SADB_SASTATE_MATURE);
++              SENDERR(EINVAL);
++      }
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: extr or extr->tdb pointer NULL\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++
++      tdbq = gettdb(&(extr->tdb->tdb_said));
++      if (tdbq) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: found an old Tunnel Descriptor Block\n"
++                          "klips_debug:                for SA: %s, delete it first.\n", sa);
++              SENDERR(EEXIST);
++      }
++
++      if(ip_chk_addr((unsigned long)extr->tdb->tdb_dst.s_addr) == IS_MYADDR) {
++              extr->tdb->tdb_flags |= EMT_INBOUND;
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: existing Tunnel Descriptor Block not found (this\n"
++                  "klips_debug:                is good) for SA: %s, %s-bound, allocating.\n",
++                  sa, extr->tdb->tdb_flags & EMT_INBOUND ? "in" : "out");
++      
++      /* XXX extr->tdb->tdb_rcvif = &(enc_softc[em->em_if].enc_if);*/
++      extr->tdb->tdb_rcvif = NULL;
++      
++      if ((error = pfkey_tdb_init(extr->tdb, extensions))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_add_parse: not successful for SA: %s, deleting.\n", sa);
++              ipsec_tdbwipe(extr->tdb);
++              SENDERR(-error);
++      }
++
++      extr->tdb->tdb_lifetime_addtime_c = jiffies / HZ;
++      if(!extr->tdb->tdb_lifetime_allocations_c) {
++              extr->tdb->tdb_lifetime_allocations_c += 1;
++      }
++
++      puttdb(extr->tdb);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_add_parse: successful for SA: %s\n", sa);
++      
++ errlab:
++      /* XXX send a message up about success/failure */
++      return error;
++}
++
++int
++pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      struct tdb *tdbp;
++      char sa[SATOA_BUF];
++      int error = 0;
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_delete_parse: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_delete_parse: "
++                          "extr or extr->tdb pointer NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++
++      tdbp = gettdb(&(extr->tdb->tdb_said));
++      if (tdbp == NULL) {
++              spin_unlock_irqrestore(&tdb_lock, flags);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_delete_parse: Tunnel Descriptor Block not found for SA:\n"
++                          "klips_debug:                %s, could not delete.\n", sa);
++              SENDERR(ENXIO);  /* XXX -- wrong error message... */
++      } else {
++              if((error = deltdbchain(tdbp))) {
++                      spin_unlock_irqrestore(&tdb_lock, flags);
++                      SENDERR(-error);
++              }
++              spin_unlock_irqrestore(&tdb_lock, flags);
++      }
++ errlab:
++      ipsec_tdbwipe(extr->tdb);
++      return error;
++}
++
++int
++pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++      struct tdb *tdbp;
++      char sa[SATOA_BUF];
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_get_parse: .\n");
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_get_parse: "
++                          "extr or extr->tdb pointer NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa, SATOA_BUF);
++
++      spin_lock_irqsave(&tdb_lock, flags);
++
++      tdbp = gettdb(&(extr->tdb->tdb_said));
++      if (tdbp == NULL) {
++              spin_unlock_irqrestore(&tdb_lock, flags);
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_get_parse: Tunnel Descriptor Block not found for SA:\n"
++                          "klips_debug:                %s, could not get.\n", sa);
++              SENDERR(ENXIO);  /* XXX -- wrong error message... */
++      } else {
++              /* build message to send up */
++#if 0
++              pfkey_upmsg(sk->sock /* sockp->socket */, new_pfkey_msg); */
++#endif
++              spin_unlock_irqrestore(&tdb_lock, flags);
++      }
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++int
++pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_acquire_parse: .\n");
++
++      /* ++pfkey_msg_seq */
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++int
++pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_register_parse: .\n");
++
++      pfkey_list_insert_socket(sk->socket, pfkey_open_sockets);
++
++      switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
++      case SADB_SATYPE_AH:
++              /* send up register msg with supported AH algos */
++              break;
++      case SADB_SATYPE_ESP:
++              /* send up register msg with supported ESP algos */
++              break;
++      default:
++              /* send up register msg with *all* supported algos */
++      }
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++int
++pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_expire_parse: .\n");
++
++      SENDERR(ENOSYS);
++ errlab:
++      return error;
++}
++
++int
++pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug: pfkey_flush_parse: flushing type %d SAs\n",
++                  ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
++
++      if ((error = ipsec_tdbcleanup(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype)))
++              SENDERR(-error);
++ errlab:
++      return error;
++}
++
++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;
++}
++
++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;
++}
++
++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;
++}
++
++int
++pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      struct tdb *tdb1p, *tdb2p, *tdbp;
++      char sa1[SATOA_BUF], sa2[SATOA_BUF];
++      int error = 0;
++      unsigned long flags; /* save irq state for spinlock */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_grpsa_parse: .\n");
++
++      spin_lock_irqsave(&tdb_lock, flags);
++
++      if(!extr || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_grpsa_parse: "
++                          "extr or extr->tdb is NULL, fatal.\n");
++              SENDERR(EINVAL);
++      }
++
++      satoa(extr->tdb->tdb_said, 0, sa1, SATOA_BUF);
++      if(extr->tdb2) {
++              satoa(extr->tdb2->tdb_said, 0, sa2, SATOA_BUF);
++      }
++
++      if(!(tdb1p = gettdb(&(extr->tdb->tdb_said)))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug: pfkey_x_grpsa_parse: reserved Tunnel Descriptor Block\n"
++                          "klips_debug:            for SA: %s not found.  Call SADB_ADD/UPDATE first.\n", sa1);
++              SENDERR(EEXIST);
++      }
++      if(extr->tdb2) { /* GRPSA */
++              if(!(tdb2p = gettdb(&(extr->tdb2->tdb_said)))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug: pfkey_x_grpsa_parse: reserved Tunnel Descriptor Block\n"
++                                  "klips_debug:            for SA: %s not found.  Call SADB_ADD/UPDATE first.\n", sa2);
++                      SENDERR(EEXIST);
++              }
++
++              /* Is either one already linked? */
++              if(tdb1p->tdb_onext) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug: pfkey_x_grpsa_parse: Tunnel Descriptor Block\n"
++                                  "klips_debug:                for SA: %s is already linked.\n", sa1);
++                      SENDERR(EEXIST);
++              }
++              if(tdb2p->tdb_inext) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug: pfkey_x_grpsa_parse: Tunnel Descriptor Block\n"
++                                  "klips_debug:                for SA: %s is already linked.\n", sa2);
++                      SENDERR(EEXIST);
++              }
++              
++              /* Is extr->tdb already linked to extr->tdb2? */
++              tdbp = tdb2p;
++              while(tdbp) {
++                      if(tdbp == tdb1p) {
++                              SENDERR(EEXIST);
++                      }
++                      tdbp = tdb2p->tdb_onext;
++              }
++              
++              /* link 'em */
++              tdb1p->tdb_onext = tdb2p;
++              tdb2p->tdb_inext = tdb1p;
++      } else { /* UNGRPSA */
++              while(tdb1p->tdb_onext) {
++                      tdb1p = tdb1p->tdb_onext;
++              }
++              while(tdb1p->tdb_inext) {
++                      tdbp = tdb1p;
++                      tdb1p = tdb1p->tdb_inext;
++                      tdbp->tdb_inext = NULL;
++                      tdb1p->tdb_onext = NULL;
++              }
++      }
++
++ errlab:
++      spin_unlock_irqrestore(&tdb_lock, flags);
++
++      ipsec_tdbwipe(extr->tdb);
++      if(extr->tdb2) {
++              ipsec_tdbwipe(extr->tdb2);
++      }
++
++      return error;
++}
++
++int
++pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++#ifdef DEBUG_IPSEC
++      char buf1[64], buf2[64];
++#endif /* DEBUG_IPSEC */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: .\n");
++
++      if(!extr || !extr->tdb || !extr->eroute) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "missing extr, tdb or eroute data.\n");
++              SENDERR(EINVAL);
++      }
++
++#ifdef DEBUG_IPSEC
++      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
++      if(extr->tdb->tdb_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))) == EINVAL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_addflow_parse: "
++                                  "breakeroute returned %d.\n", error);
++                      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->tdb->tdb_said))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_addflow_parse: "
++                          "makeroute returned %d.\n", error);
++              SENDERR(-error);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: "
++                  "makeroute call successful.\n");
++
++      ipsec_tdbwipe(extr->tdb);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_addflow_parse: "
++                  "extr->tdb cleaned up and freed.\n");
++
++ errlab:
++      return error;
++}
++
++int
++pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
++{
++      int error = 0;
++#ifdef DEBUG_IPSEC
++      char buf1[64], buf2[64];
++#endif /* DEBUG_IPSEC */
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_delflow_parse: .\n");
++
++      if(!extr || !extr->eroute || !extr->tdb) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_x_delflow_parse: "
++                          "extr, extr->tdb or extr->eroute is NULL, fatal\n");
++              SENDERR(EINVAL);
++      }
++
++      if(extr->tdb->tdb_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 {
++#ifdef DEBUG_IPSEC
++              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
++              if((error = ipsec_breakroute(&(extr->eroute->er_eaddr),
++                                           &(extr->eroute->er_emask)))) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_x_delflow_parse: "
++                                  "breakeroute returned %d.\n", error);
++                      SENDERR(-error);
++              }
++      }
++      
++      ipsec_tdbwipe(extr->tdb);
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_x_delflow_parse: "
++                  "extr->tdb cleaned up and freed.\n");
++
++ errlab:
++      return error;
++}
++
++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;
++}
++
++
++int (*ext_processors[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
++};
++
++
++int (*msg_parsers[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
++};
++
++int
++pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg)
++{
++      int error = 0;
++      int i;
++      struct sadb_ext *extensions[SADB_EXT_MAX+1];
++      struct pfkey_extracted_data extr = {NULL, NULL, NULL};
++      
++      pfkey_extensions_init(extensions);
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_msg_interp: parsing message "
++                  "ver=%d, type=%d, errno=%d, satype=%d, 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,
++                  pfkey_msg->sadb_msg_len,
++                  pfkey_msg->sadb_msg_reserved,
++                  pfkey_msg->sadb_msg_seq,
++                  pfkey_msg->sadb_msg_pid);
++      
++      if((error = pfkey_alloc_tdb(&(extr.tdb)))) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: "
++                          "something's really wrong, extr.tdb=%p should be NULL.\n", extr.tdb);
++              SENDERR(-error);
++      }
++
++      KLIPS_PRINT(debug_pfkey,
++                  "klips_debug:pfkey_msg_interp: "
++                  "allocated extr->tdb=%p.\n", extr.tdb);
++
++      if(pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
++              KLIPS_PRINT(debug_pfkey,
++                          "klips_debug:pfkey_msg_interp: satype %d > max %d\n", 
++                          pfkey_msg->sadb_msg_satype, SADB_SATYPE_MAX);
++              SENDERR(EINVAL);
++      }
++      
++      switch(pfkey_msg->sadb_msg_type) {
++      case SADB_GETSPI:
++      case SADB_UPDATE:
++      case SADB_ADD:
++      case SADB_DELETE:
++      case SADB_X_GRPSA:
++              if(!(extr.tdb->tdb_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);
++              }
++              break;
++      case SADB_X_ADDFLOW:
++              extr.tdb->tdb_said.proto = satype2proto(pfkey_msg->sadb_msg_satype);
++              break;
++      default:
++      }
++      
++      /* 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 <= SADB_EXT_MAX;i++) {
++              if(extensions[i] != NULL) {
++                      KLIPS_PRINT(debug_pfkey,
++                                  "klips_debug:pfkey_msg_interp: "
++                                  "processing ext %d %p with processor %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 with msg_parser %p.\n",
++                  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:
++      return(error);
++}
++
++/*
++ * $Log$
++ * Revision 1.30  2000/01/22 23:21:13  rgb
++ * Use new function satype2proto().
++ *
++ * Revision 1.29  2000/01/22 08:40:21  rgb
++ * Invert condition to known value to avoid AF_INET6 in 2.0.36.
++ *
++ * Revision 1.28  2000/01/22 07:58:57  rgb
++ * Fixed REPLACEFLOW bug, missing braces around KLIPS_PRINT *and* SENDERR.
++ *
++ * Revision 1.27  2000/01/22 03:48:01  rgb
++ * Added extr pointer component debugging.
++ *
++ * Revision 1.26  2000/01/21 09:41:25  rgb
++ * Changed a (void*) to (char*) cast to do proper pointer math.
++ * Don't call tdbwipe if tdb2 is NULL.
++ *
++ * Revision 1.25  2000/01/21 06:21:01  rgb
++ * Added address cases for eroute flows.
++ * Tidied up compiler directive indentation for readability.
++ * Added ictx,octx vars for simplification.
++ * Added macros for HMAC padding magic numbers.
++ * Converted from double tdb arguments to one structure (extr)
++ * containing pointers to all temporary information structures
++ * and checking for valid arguments to all ext processors and
++ * msg type parsers.
++ * Added spiungrp'ing.
++ * Added klipsdebug switching capability.
++ * Removed sa_process() check for zero protocol.
++ * Added address case for DST2 for grouping.
++ * Added/changed minor debugging instrumentation.
++ * Fixed spigrp for single said, ungrouping case.
++ * Added code to parse addflow and delflow messages.
++ * Removed redundant statements duplicating tdbwipe() functionality
++ * and causing double kfrees.
++ * Permit addflow to have a protocol of 0.
++ *
++ * Revision 1.24  1999/12/09 23:23:00  rgb
++ * Added check to pfkey_sa_process() to do eroutes.
++ * Converted to DIVUP() macro.
++ * Converted if() to switch() in pfkey_register_parse().
++ * Use new pfkey_extensions_init() instead of memset().
++ *
++ * Revision 1.23  1999/12/01 22:18:13  rgb
++ * Preset minspi and maxspi values in case and spirange extension is not
++ * included and check for the presence of an spirange extension before
++ * using it.  Initialise tdb_sastate to LARVAL.
++ * Fixed debugging output typo.
++ * Fixed authentication context initialisation bugs (4 places).
++ *
++ * Revision 1.22  1999/11/27 11:53:08  rgb
++ * Moved pfkey_msg_parse prototype to pfkey.h
++ * Moved exts_permitted/required prototype to pfkey.h.
++ * Moved sadb_satype2proto protocol lookup table to lib/pfkey_v2_parse.c.
++ * Deleted SADB_X_EXT_SA2 code from pfkey_sa_process() since it will never
++ * be called.
++ * Moved protocol/algorithm checks to lib/pfkey_v2_parse.c
++ * Debugging error messages added.
++ * Enable lifetime_current checking.
++ * Remove illegal requirement for SA extension to be present in an
++ * originating GETSPI call.
++ * Re-instate requirement for UPDATE or ADD message to be MATURE.
++ * Add argument to pfkey_msg_parse() for direction.
++ * Fixed IPIP dst address bug and purged redundant, leaky code.
++ *
++ * Revision 1.21  1999/11/24 05:24:20  rgb
++ * hanged 'void*extensions' to 'struct sadb_ext*extensions'.
++ * Fixed indention.
++ * Ditched redundant replay check.
++ * Fixed debug message text from 'parse' to 'process'.
++ * Added more debug output.
++ * Forgot to zero extensions array causing bug, fixed.
++ *
++ * Revision 1.20  1999/11/23 23:08:13  rgb
++ * Move all common parsing code to lib/pfkey_v2_parse.c and rename
++ * remaining bits to *_process. (PJO)
++ * Add macros for dealing with alignment and rounding up more opaquely.
++ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
++ * Sort out pfkey and freeswan headers, putting them in a library path.
++ * Corrected a couple of bugs in as-yet-inactive code.
++ *
++ * Revision 1.19  1999/11/20 22:01:10  rgb
++ * Add more descriptive error messages for non-zero reserved fields.
++ * Add more descriptive error message for spirange parsing.
++ * Start on supported extension parsing.
++ * Start on register and get message parsing.
++ *
++ * Revision 1.18  1999/11/18 04:09:20  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.17  1999/11/17 15:53:41  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.16  1999/10/26 16:57:43  rgb
++ * Add shorter macros for compiler directives to visually clean-up.
++ * Give ipv6 code meaningful compiler directive.
++ * Add comments to other #if 0 debug code.
++ * Remove unused *_bh_atomic() calls.
++ * Fix mis-placed spinlock.
++ *
++ * Revision 1.15  1999/10/16 18:27:10  rgb
++ * Clean-up unused cruft.
++ * Fix-up lifetime_allocations_c and lifetime_addtime_c initialisations.
++ *
++ * Revision 1.14  1999/10/08 18:37:34  rgb
++ * Fix end-of-line spacing to sate whining PHMs.
++ *
++ * Revision 1.13  1999/10/03 18:49:12  rgb
++ * Spinlock fixes for 2.0.xx and 2.3.xx.
++ *
++ * Revision 1.12  1999/10/01 15:44:54  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.11  1999/10/01 00:05:45  rgb
++ * Added tdb structure locking.
++ * Use 'jiffies' instead of do_get_timeofday().
++ * Fix lifetime assignments.
++ *
++ * Revision 1.10  1999/09/21 15:24:45  rgb
++ * Rework spirange code to save entropy and prevent endless loops.
++ *
++ * Revision 1.9  1999/09/16 12:10:21  rgb
++ * Minor fixes to random spi selection for correctness and entropy conservation.
++ *
++ * Revision 1.8  1999/05/25 22:54:46  rgb
++ * Fix comparison that should be an assignment in an if.
++ *
++ * Revision 1.7  1999/05/09 03:25:37  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.6  1999/05/08 21:32:30  rgb
++ * Fix error return reporting.
++ *
++ * Revision 1.5  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.4  1999/04/29 15:22:40  rgb
++ * Standardise an error return method.
++ * Add debugging instrumentation.
++ * Add check for existence of macros min/max.
++ * Add extensions permitted/required in/out filters.
++ * Add satype-to-protocol table.
++ * Add a second tdb pointer to each parser to accomodate GRPSA.
++ * Move AH & no_algo_set to GETSPI, UPDATE and ADD.
++ * Add OOO window check.
++ * Add support for IPPROTO_IPIP and hooks for IPPROTO_COMP.
++ * Add timestamp to lifetime parse.
++ * Fix address structure length checking bug.
++ * Fix address structure allocation bug (forgot to kmalloc!).
++ * Add checks for extension lengths.
++ * Add checks for extension reserved illegal values.
++ * Add check for spirange legal values.
++ * Add an extension type for parsing a second satype, SA and
++ * DST_ADDRESS.
++ * Make changes to tdb_init() template to get pfkey_tdb_init(),
++ * eliminating any mention of xformsw.
++ * Implement getspi, update and grpsa (not tested).
++ * Add stubs for as yet unimplemented message types.
++ * Add table of message parsers to substitute for msg_parse switch.
++ *
++ * Revision 1.3  1999/04/15 17:58:07  rgb
++ * Add RCSID labels.
++ *
++ * Revision 1.2  1999/04/15 15:37:26  rgb
++ * Forward check changes from POST1_00 branch.
++ *
++ * Revision 1.1.2.1  1999/03/26 20:58:56  rgb
++ * Add pfkeyv2 support to KLIPS.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/radij.c linux-2.2.14/net/ipsec/radij.c
+--- linux-2.2.14.orig/net/ipsec/radij.c        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/radij.c     Tue Feb  8 22:21:57 2000
+@@ -0,0 +1,1092 @@
++char radij_c_version[] = "RCSID $Id$";
++
++/*
++ * 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.
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h> /* printk() */
++#include <linux/malloc.h> /* kmalloc() */
++#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 <freeswan.h>
++#ifdef NET_21
++#include <asm/uaccess.h>
++#include <linux/in6.h>
++#endif /* NET_21 */
++#include <asm/checksum.h>
++#include <net/ip.h>
++
++#include "radij.h"
++#include "ipsec_encap.h"
++#include "ipsec_radij.h"
++#include "ipsec_netlink.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=0x%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=0x%p\n", t);
++      do {
++              register struct radij_mask *m;
++              
++              t = t->rj_p;
++              KLIPS_PRINT(debug_radij,
++                          "klips_debug:rj_match: **** t=0x%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);
++                      mstart = maskedKey + off;
++                      do {
++                              cp2 = mstart;
++                              cp3 = m->rm_mask + off;
++                              KLIPS_PRINT(debug_radij,
++                                          "klips_debug:rj_match: ***** cp2=0x%p cp3=0x%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;
++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: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: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 /* (0) rgb */ ENOMEM;
++              }
++              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);
++      if (keyduplicated) {
++              do {
++                      if (tt->rj_mask == netmask)
++                              return /* (0) rgb */ ENXIO;
++                      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 ))
++              return /* tt rgb */ 0; /* 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;
++                      return /* tt rgb */ 0;
++              }
++              if (rj_refines(netmask, m->rm_mask))
++                      break;
++      }
++      MKGet(m);
++      if (m == 0) {
++              printk("klips_debug:Mask for route not entered\n");
++              return /* (tt) rgb */ 0;
++      }
++      Bzero(m, sizeof *m);
++      m->rm_b = b_leaf;
++      m->rm_mask = netmask;
++      m->rm_mklist = *mp;
++      *mp = m;
++      tt->rj_mklist = m;
++      return /* tt rgb */ 0;
++}
++
++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 /* (0) rgb */ -EFAULT;
++      /*
++       * 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 /* (0) rgb */ -ENXIO;
++      }
++      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 /* (0) rgb */ -EFAULT;
++#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 us\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:%s %p at %p\n",
++                                          "rj_delete: Orphaned Mask", 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 /* (tt) rgb */ 0;
++}
++
++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 -1;
++      }
++
++      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 DEBUG_IPSEC
++              if(debug_radij) {
++                      printk("klips_debug:RN_WALKTREE: for: rn=%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 /* DEBUG_IPSEC */
++              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 DEBUG_IPSEC
++              if(debug_radij) {
++                      printk("klips_debug:RN_WALKTREE: processing leaves, rn=%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 /* DEBUG_IPSEC */
++              /* Process leaves */
++              while ((rn = base)) {
++                      base = rn->rj_dupedkey;
++#ifdef DEBUG_IPSEC
++                      if(debug_radij) {
++                              printk("klips_debug:RN_WALKTREE: while: base=%p rn=%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 /* DEBUG_IPSEC */
++                      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 == 0)
++              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;
++
++      KLIPS_PRINT(1, "klips_debug: rj_init: version: %s\n", radij_c_version);
++      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 = %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 = %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 = %08x", (u_int)rn->rj_dupedkey);
++              }
++              printk("\n");
++      }
++}
++
++#ifdef RJ_DEBUG
++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_s(mknp2, sizeof(struct radij_mask));
++      }
++}
++
++int
++radijcleartree(void)
++{
++      return rj_walktree(rnh, ipsec_rj_walker_delete, NULL);
++}
++
++int
++radijcleanup(void)
++{
++      int error = 0;
++
++      rj_free_mkfreelist();
++
++/*    rj_walktree(mask_rjhead, ipsec_rj_walker_delete, NULL); */
++      if(mask_rjhead) {
++              kfree_s(mask_rjhead, sizeof(* mask_rjhead));
++      }
++
++      if(rj_zeroes) {
++              kfree_s(rj_zeroes, 3 * sizeof(struct sockaddr_encap));
++      }
++
++      error = radijcleartree();
++      kfree_s(rnh, sizeof(* rnh));
++
++      return error;
++}
++
++/*
++ * $Log$
++ * Revision 1.25  2000/01/21 06:21:47  rgb
++ * Change return codes to negative on error.
++ *
++ * Revision 1.24  1999/11/18 04:09:20  rgb
++ * Replaced all kernel version macros to shorter, readable form.
++ *
++ * Revision 1.23  1999/11/17 15:53:41  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.22  1999/10/15 22:17:28  rgb
++ * Modify radijcleanup() to call radijcleartree().
++ *
++ * Revision 1.21  1999/10/08 18:37:34  rgb
++ * Fix end-of-line spacing to sate whining PHMs.
++ *
++ * Revision 1.20  1999/10/01 15:44:54  rgb
++ * Move spinlock header include to 2.1> scope.
++ *
++ * Revision 1.19  1999/10/01 08:35:52  rgb
++ * Add spinlock include to shut up compiler for 2.0.38.
++ *
++ * Revision 1.18  1999/09/23 18:02:52  rgb
++ * De-alarm the search failure message so it doesn't sound so grave.
++ *
++ * Revision 1.17  1999/05/25 21:26:01  rgb
++ * Fix rj_walktree() sanity checking bug.
++ *
++ * Revision 1.16  1999/05/09 03:25:38  rgb
++ * Fix bug introduced by 2.2 quick-and-dirty patch.
++ *
++ * Revision 1.15  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.14  1999/04/29 15:24:15  rgb
++ * Add sanity checking for null pointer arguments.
++ * Standardise an error return method.
++ *
++ * Revision 1.13  1999/04/11 00:29:02  henry
++ * GPL boilerplate
++ *
++ * Revision 1.12  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.11  1999/02/17 16:52:53  rgb
++ * Convert DEBUG_IPSEC to KLIPS_PRINT
++ * Clean out unused cruft.
++ *
++ * Revision 1.10  1999/01/22 06:30:05  rgb
++ * Cruft clean-out.
++ * 64-bit clean-up.
++ *
++ * Revision 1.9  1998/12/01 13:22:04  rgb
++ * Added support for debug printing of version info.
++ *
++ * Revision 1.8  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.7  1998/10/25 02:43:26  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.6  1998/10/19 14:30:06  rgb
++ * Added inclusion of freeswan.h.
++ *
++ * Revision 1.5  1998/10/09 04:33:27  rgb
++ * Added 'klips_debug' prefix to all klips printk debug statements.
++ * Fixed output formatting slightly.
++ *
++ * Revision 1.4  1998/07/28 00:06:59  rgb
++ * Add debug detail to tree traversing.
++ *
++ * Revision 1.3  1998/07/14 18:07:58  rgb
++ * Add a routine to clear the eroute tree.
++ *
++ * Revision 1.2  1998/06/25 20:03:22  rgb
++ * Cleanup #endif comments.  Debug output for rj_init.
++ *
++ * 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.8  1998/05/25 20:34:15  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.7  1998/05/21 12:58:58  rgb
++ * Moved 'extern' definitions to ipsec_radij.h to support /proc 3k limit fix.
++ *
++ * Revision 1.6  1998/04/23 20:57:29  rgb
++ * Cleaned up compiler warnings for unused debugging functions.
++ *
++ * Revision 1.5  1998/04/22 16:51:38  rgb
++ * Tidy up radij debug code from recent rash of modifications to debug code.
++ *
++ * Revision 1.4  1998/04/21 21:28:56  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.3  1998/04/14 17:30:37  rgb
++ * Fix up compiling errors for radij tree memory reclamation.
++ *
++ * Revision 1.2  1998/04/12 22:03:25  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:06:15  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:39:04  ji
++ * Minor cleanups.
++ * Rationalized debugging code.
++ *
++ * Revision 0.2  1996/11/02 00:18:33  ji
++ * First limited release.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/radij.h linux-2.2.14/net/ipsec/radij.h
+--- linux-2.2.14.orig/net/ipsec/radij.h        Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/radij.h     Thu Nov 18 05:09:20 1999
+@@ -0,0 +1,291 @@
++/*
++ * RCSID $Id$
++ */
++
++/*
++ * 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
++
++#ifndef NET_21
++#ifndef min
++static __inline__ int min(unsigned int a, unsigned int b)
++{
++        if (a > b)
++                a = b;
++        return a;
++}
++#endif /* !min */
++
++#ifndef max
++static __inline__ int max(unsigned int a, unsigned int b)
++{
++        if (a < b)
++                a = b;
++        return a;
++}
++#endif /* !max */
++#endif /* NET_21 */
++
++/*
++ * 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$
++ * 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.
++ *
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/sysctl_net_ipsec.c linux-2.2.14/net/ipsec/sysctl_net_ipsec.c
+--- linux-2.2.14.orig/net/ipsec/sysctl_net_ipsec.c     Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/sysctl_net_ipsec.c  Sun Apr 11 02:29:03 1999
+@@ -0,0 +1,52 @@
++/*
++ * sysctl interface to net IPSEC subsystem.
++ * Copyright (C) 1996  Mike Shaver.
++ * Copyright (C) 1998, 1999  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$
++ */
++
++/* -*- linux-c -*-
++ *
++ * Adapted April 3, 1998, Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
++ * from sysctl_net_ipv4.c, Begun April 1, 1996, Mike Shaver.
++ */
++
++#include <linux/mm.h>
++#include <linux/sysctl.h>
++
++#if 0
++extern int       debug_ah;
++extern int       debug_esp;
++extern int       debug_tunnel;
++extern int       debug_eroute;
++extern int       debug_spi;
++extern int       debug_radij;
++extern int       debug_netlink;
++extern int       debug_xform;
++#endif
++
++ctl_table ipsec_table[] = {
++      {0}
++};
++
++/*
++ * $Log$
++ * Revision 1.4  1999/04/11 00:29:03  henry
++ * GPL boilerplate
++ *
++ * Revision 1.3  1999/04/06 04:54:29  rgb
++ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy.  This includes
++ * patch shell fixes.
++ *
++ */
+diff -durN linux-2.2.14.orig/net/ipsec/version.c linux-2.2.14/net/ipsec/version.c
+--- linux-2.2.14.orig/net/ipsec/version.c      Thu Jan  1 01:00:00 1970
++++ linux-2.2.14/net/ipsec/version.c   Tue Feb  8 22:22:28 2000
+@@ -0,0 +1,2 @@
++/* silly pointless RCSID $Id$ */
++static const char freeswan_version[] = "1.3";
+diff -durN linux-2.2.14.orig/net/ipv4/af_inet.c linux-2.2.14/net/ipv4/af_inet.c
+--- linux-2.2.14.orig/net/ipv4/af_inet.c       Mon Aug  9 21:05:13 1999
++++ linux-2.2.14/net/ipv4/af_inet.c    Mon Apr 24 13:11:00 2000
+@@ -1140,6 +1140,17 @@
+       ip_mr_init();
+ #endif
++#if defined(CONFIG_IPSEC)
++      {
++               extern /* void */ int ipsec_init(void);
++              /*
++               *  Initialise AF_INET ESP and AH protocol support including 
++               *  e-routing and SA tables
++               */
++              ipsec_init();
++      }
++#endif /* CONFIG_IPSEC */
++
+ #ifdef CONFIG_INET_RARP
+       rarp_ioctl_hook = rarp_ioctl;
+ #endif
+diff -durN linux-2.2.14.orig/net/netlink/af_netlink.c linux-2.2.14/net/netlink/af_netlink.c
+--- linux-2.2.14.orig/net/netlink/af_netlink.c Wed Jun  2 20:29:28 1999
++++ linux-2.2.14/net/netlink/af_netlink.c      Mon Apr 24 13:11:00 2000
+@@ -49,6 +49,7 @@
+ #ifdef NL_EMULATE_DEV
+ static struct socket *netlink_kernel[MAX_LINKS];
++unsigned netlink_open_map = 0;
+ #endif
+ static int netlink_dump(struct sock *sk);
+@@ -737,6 +738,7 @@
+       struct sock *sk = netlink_kernel_create(unit, NULL);
+       if (sk == NULL)
+               return -ENOBUFS;
++      netlink_open_map&=~(1<<unit);
+       sk->protinfo.af_netlink.handler = function;
+       netlink_kernel[unit] = sk->socket;
+       return 0;
+@@ -750,6 +752,7 @@
+       synchronize_bh();
+       sock_release(sock);
++      netlink_open_map&=~(1<<unit);
+ }
+ int netlink_post(int unit, struct sk_buff *skb)
+diff -durN linux-2.2.14.orig/net/netlink/netlink_dev.c linux-2.2.14/net/netlink/netlink_dev.c
+--- linux-2.2.14.orig/net/netlink/netlink_dev.c        Wed Jun  2 20:29:28 1999
++++ linux-2.2.14/net/netlink/netlink_dev.c     Mon Apr 24 13:11:00 2000
+@@ -29,7 +29,7 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+-static unsigned open_map = 0;
++extern unsigned netlink_open_map;
+ static struct socket *netlink_user[MAX_LINKS];
+ /*
+@@ -109,10 +109,10 @@
+       
+       if (minor>=MAX_LINKS)
+               return -ENODEV;
+-      if (open_map&(1<<minor))
++      if (netlink_open_map&(1<<minor))
+               return -EBUSY;
+-      open_map |= (1<<minor);
++      netlink_open_map |= (1<<minor);
+       MOD_INC_USE_COUNT;
+       
+       err = -EINVAL;
+@@ -143,7 +143,7 @@
+       return 0;
+ out:
+-      open_map &= ~(1<<minor);
++      netlink_open_map &= ~(1<<minor);
+       MOD_DEC_USE_COUNT;
+       return err;
+ }
+@@ -154,7 +154,7 @@
+       struct socket *sock = netlink_user[minor];
+       netlink_user[minor] = NULL;
+-      open_map &= ~(1<<minor);
++      netlink_open_map &= ~(1<<minor);
+       sock_release(sock);
+       MOD_DEC_USE_COUNT;
+       return 0;
This page took 1.375263 seconds and 4 git commands to generate.