--- /dev/null
+
+ 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;