Index: freeswan/klips/net/ipsec/.cvsignore
diff -u /dev/null freeswan/klips/net/ipsec/.cvsignore:1.1.2.2
--- /dev/null	Fri Jul 12 16:03:45 2002
+++ freeswan/klips/net/ipsec/.cvsignore	Wed May 15 16:53:01 2002
@@ -0,0 +1,3 @@
+GNUmakefile
+libdes
+libfreeswan
Index: freeswan/klips/net/ipsec/Config.in
diff -u freeswan/klips/net/ipsec/Config.in:1.1.1.1 freeswan/klips/net/ipsec/Config.in:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/Config.in:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/Config.in	Mon Apr 15 12:13:42 2002
@@ -29,6 +29,11 @@
   bool '      3DES encryption algorithm' CONFIG_IPSEC_ENC_3DES
 fi
 
+bool '   IPSEC Modular Extensions' CONFIG_IPSEC_ALG
+if [ "$CONFIG_IPSEC_ALG" != "n" ]; then
+	source net/ipsec/alg/Config.in
+fi
+
 bool '   IPSEC: IP Compression' CONFIG_IPSEC_IPCOMP
 
 bool '   IPSEC Debugging Option' CONFIG_IPSEC_DEBUG
Index: freeswan/klips/net/ipsec/GNUmakefile
diff -u /dev/null freeswan/klips/net/ipsec/GNUmakefile:1.1.2.8
--- /dev/null	Fri Jul 12 16:03:45 2002
+++ freeswan/klips/net/ipsec/GNUmakefile	Tue Jun  4 10:55:16 2002
@@ -0,0 +1,190 @@
+# vim:aw:ai
+#
+# null-patch, non-root GNUmakefile addon for freeswan modules compilation
+# 
+# It will not "affect" normal KLIPS  building because this GNUmakefile
+# it's not copied to /usr/src/linux
+#
+# Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+# $Id: GNUmakefile,v 1.1.2.8 2002/06/04 13:55:16 jjo Exp $
+#
+# 1) Copy me to klips/net/ipsec 
+# 2)  
+#     cd klibs/net/ipsec
+#     make prep TOPDIR=/path/to/usr/src/linux \
+#		[CONFIG=/path/to/.config | CONFIG=/dev/null]
+# 3)  
+#     make all TOPDIR=.... CONFIG=....
+#CONFIG_IPSEC_ENC_3DES=y
+#CONFIG_IPSEC_AUTH_HMAC_MD5=y
+#CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ALG_AES=m
+
+
+
+ifndef INIT_DONE
+INIT_DONE:=1
+LOCALKLIPS:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+IPSEC_ROOT:=$(LOCALKLIPS)/../../..
+export INIT_DONE LOCALKLIPS IPSEC_ROOT
+endif
+
+MODVERSIONS_H:=$(shell f=$(TOPDIR)/include/linux/modversions.h;test -f $$f && echo -n $$f || echo -n $(TOPDIR)/include/linux/modsetver.h)
+#MODVERSIONS_H:=$(LOCALKLIPS)/local_modversions.h
+
+ifdef UML
+	CFLAGS_KERNEL=-D__KERNEL__ -I/u2/src/v2.4/uml-linux/linux/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2  -fno-strict-aliasing -fno-common -g  -U__i386__ -Ui386 -DUM_FASTCALL -D__arch_um__ -DSUBARCH="i386" -DNESTING=0 -D_LARGEFILE64_SOURCE -I/u2/src/v2.4/uml-linux/linux/arch/um/include -Derrno=kernel_errno -DMODULE  
+	KINCLUDE=-I$(TOPDIR)/include -I/usr/src/v2.4/uml-linux/linux/arch/um/include
+	CONFIG_USERMODE=y
+	ARCH=um
+else
+	CFLAGS_KERNEL=-D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe 
+	KINCLUDE=-I$(TOPDIR)/include
+endif
+
+CONFIG=$(TOPDIR)/.config
+include $(CONFIG)
+CONFIG_IPSEC=m
+CONFIG_IPSEC_MODULE=y
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_IPCOMP=y
+
+CONFIG_M586 :=$(shell uname -m | sed -n "s/i586/y/p" )
+CONFIG_M686 :=$(shell uname -m | sed -n "s/i686/y/p" )
+export CONFIG_M586 CONFIG_M686
+cflags-arch-$(CONFIG_M586) 		+= -march=i586
+cflags-arch-$(CONFIG_M586_TSC)		+= -march=i586
+cflags-arch-$(CONFIG_M686)		+= -march=i686
+cflags-arch-$(CONFIG_MPENTIUMIII)	+= -march=i686
+cflags-arch-$(CONFIG_MK7)		+= -march=i686 -malign-functions=4
+CFLAGS_ARCH := $(cflags-arch-y)
+
+ifndef $(CONFIG_SHELL)
+CONFIG_SHELL=/bin/bash
+endif
+export CONFIG_SHELL TOPDIR
+
+ifdef CONFIG_SMP
+EXTRA_CFLAGS += -D__SMP__
+EXTRA_AFLAGS += -D__SMP__
+endif
+
+CFLAGS_IPSEC:=\
+	-DMODULE \
+	-DMODVERSIONS \
+	-include $(MODVERSIONS_H) \
+	-DCONFIG_IPSEC_MODULE=1\
+	-DCONFIG_IPSEC_IPIP=1\
+	-DCONFIG_IPSEC_AH=1\
+	-DCONFIG_IPSEC_ESP=1\
+	-DCONFIG_IPSEC_IPCOMP=1\
+	-DCONFIG_IPSEC_DEBUG=1 \
+	-DCONFIG_IPSEC_ALG=1 \
+
+cflags-ipsec-$(CONFIG_IPSEC_ENC_3DES)	+= -DCONFIG_IPSEC_ENC_3DES=1
+cflags-ipsec-$(CONFIG_IPSEC_ALG_AES)	+= -DCONFIG_IPSEC_ALG_AES=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_MD5)+= -DCONFIG_IPSEC_AUTH_HMAC_MD5=1
+cflags-ipsec-$(CONFIG_IPSEC_AUTH_HMAC_SHA1)+= -DCONFIG_IPSEC_AUTH_HMAC_SHA1=1
+CFLAGS_IPSEC+=$(cflags-ipsec-y)
+export CONFIG_IPSEC
+export CONFIG_IPSEC_MODULE
+
+
+CFLAGS:=$(KINCLUDE) $(CFLAGS_KERNEL) $(CFLAGS_IPSEC) $(CFLAGS_ARCH) 
+EXTRA_CFLAGS:=-I$(LOCALKLIPS) -I$(IPSEC_ROOT)/lib 
+# libdes options: OPTS1
+OPTS1:=$(CFLAGS) $(EXTRA_CFLAGS)
+export OPTS1 CFLAGS
+
+include Makefile
+
+all: modules alg_modules
+
+ifdef UML
+local_modversions_h:
+	> local_modversions.h
+else
+local_modversions_h:
+	(echo "#ifndef _LINUX_MODVERSIONS_H";\
+	  echo "#define _LINUX_MODVERSIONS_H"; \
+	  echo "#include <linux/modsetver.h>"; \
+	  cd $(TOPDIR)/include/linux/modules; \
+	  perl -ne 'print "#define __ver_$$1\t$$2$$3\n#define $$1\t_set_ver($$1)\n" if (/ (.*)_R(smp)?([a-z0-9]{8})\W/);' /proc/ksyms ;\
+	  echo "#endif"; \
+	) > local_modversions.h
+endif
+un_local_modversions_h:
+	@rm -f local_modversions.h
+
+DOTT3 :=../../..
+DOTT4 :=../../../..
+DOTT5 :=../../../../..
+DOTT6 :=../../../../../..
+DOTT7 :=../../../../../..
+klink: 
+	#rm -rf $(LOCALKLIPS)
+	@mkdir -p libdes/asm/perlasm
+	@mkdir -p libfreeswan
+	@mkdir -p zlib
+	@cd libfreeswan;ln -sf $(DOTT4)/lib/Makefile.kernel Makefile
+	@ln -sf $(DOTT3)/Makefile.inc .
+	@ln -sf $(DOTT3)/Makefile.ver .
+	
+	@cd libfreeswan;ln -sf $(DOTT4)/lib/*.[ch] .
+	@cd libdes;ln -sf $(DOTT4)/libdes/Makefile .
+	@cd libdes;ln -sf $(DOTT4)/libdes/*.[ch] .
+	@cd libdes/asm;ln -sf $(DOTT5)/libdes/asm/*.pl .
+	@cd libdes/asm/perlasm;ln -sf $(DOTT6)/libdes/asm/perlasm/[a-z]*.pl .
+	@cd zlib;ln -sf $(DOTT4)/zlib/Makefile .
+	@cd zlib;ln -sf $(DOTT4)/zlib/*.[chS] .
+	@ln -sf $(DOTT3)/pluto $(LOCALKLIPS)
+
+un_klink:
+	@rm -f $(LOCALKLIPS)/pluto
+	@rm -f zlib/*.[chS]
+	@rm -f zlib/Makefile
+	@rm -f zlib/*.[oa] zlib/.*.?.flags
+	@rm -f libdes/asm/perlasm/[a-z]*.pl
+	@rm -f libdes/asm/*.pl
+	@rm -f libdes/asm/*.[oS] libdes/asm/.*.?.flags
+	@rm -f libdes/*.[ch]
+	@rm -f libdes/*.[oa] libdes/.*.?.flags
+	@rm -f libdes/Makefile
+	@rm -f libfreeswan/*.[ch]
+	@rm -f libfreeswan/*.[oa] libfreeswan/.*.?.flags
+	@rm -f Makefile.inc
+	@rm -f Makefile.ver
+	@rm -f libfreeswan/Makefile
+	@rmdir zlib
+	@rmdir libfreeswan
+	@rmdir libdes/asm/perlasm libdes/asm libdes
+
+%/GNUmakefile: GNUmakefile
+	ln -sf ../GNUmakefile $(dir $@)
+
+put_Makefiles: libdes/GNUmakefile libfreeswan/GNUmakefile
+
+un_put_Makefiles:
+	@rm -f libdes/GNUmakefile libfreeswan/GNUmakefile
+
+alg_modules:
+	(cd alg && \
+	        $(MAKE) CC='$(CC)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' \
+		LIBCRYPTO=$(LOCALKLIPS)/../../../libcrypto \
+		alg_modules;)
+
+version_c:
+	$(MAKE) -C ../../../lib version.c
+
+un_version_c:
+	@rm -f ../../../lib/version.c
+
+prep: klink put_Makefiles local_modversions_h version_c
+un_prep: un_version_c un_local_modversions_h un_put_Makefiles un_klink 
+
+.PHONY: prep klink put_Makefiles local_modversions_h version_c
+
+
Index: freeswan/klips/net/ipsec/Makefile
diff -u freeswan/klips/net/ipsec/Makefile:1.1.1.1 freeswan/klips/net/ipsec/Makefile:1.1.1.1.2.2
--- freeswan/klips/net/ipsec/Makefile:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/Makefile	Fri Apr 19 13:51:53 2002
@@ -35,7 +35,10 @@
 obj-y +=  pfkey_v2.o pfkey_v2_parser.o 
 
 export-objs := radij.o
-obj-m += $(O_TARGET)
+
+obj-$(CONFIG_IPSEC_ALG) +=ipsec_alg.o alg/ipsec_alg_static.o
+export-objs += ipsec_alg.o
+subdir-m += alg
 
 # 'override CFLAGS' should really be 'EXTRA_CFLAGS'
 EXTRA_CFLAGS += -Ilibfreeswan -Ilibdes
@@ -73,6 +76,23 @@
 subdir-$(CONFIG_IPSEC) += libfreeswan
 obj-y += libfreeswan/libkernel.a
 
+###
+### Pre Rules.make
+###
+# undo O_TARGET, obj-y if no static
+ifneq ($(CONFIG_IPSEC),y)
+O_TARGET := 
+ipsec_obj-y := $(obj-y)
+obj-y :=
+subdir-y :=
+endif
+
+# Define obj-m if modular ipsec 
+ifeq ($(CONFIG_IPSEC),m)
+obj-m += ipsec.o
+endif
+
+
 # These rules translate from new to old makefile rules
 # Translate to Rules.make lists.
 multi-used      := $(filter $(list-multi), $(obj-y) $(obj-m))
@@ -81,14 +101,30 @@
 O_OBJS          := $(obj-y)
 M_OBJS          := $(obj-m)
 MIX_OBJS        := $(filter $(export-objs), $(active-objs))
-#OX_OBJS := $(export-objs)
+OX_OBJS := $(export-objs)
 SUB_DIRS := $(subdir-y)
 ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
 MOD_SUB_DIRS := $(subdir-m)
 
+#   dunno why, but some 2.2 setups may need explicit -DEXPORT_SYMTAB
+#   uncomment next line if ipsec_alg.c compilation fails with
+#   "parse error before `EXPORT_SYMTAB_not_defined'"  --Juanjo
+# CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
+#
+
 include $(TOPDIR)/Rules.make
 
-$(obj-y) $(obj-m):  $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
+###
+### Post Rules.make
+###
+# for modular ipsec, no O_TARGET defined => define ipsec.o creation rules
+ifeq ($(CONFIG_IPSEC),m)
+ipsec.o : $(ipsec_obj-y)
+	rm -f $@
+	$(LD) $(LD_EXTRAFLAGS) -r $(ipsec_obj-y) -o $@
+endif
+
+$(ipsec_obj-y) $(obj-y) $(obj-m):  $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
 
 libdes/libdes.a:
 	( cd libdes && \
@@ -102,6 +138,9 @@
 
 zlib/zlib.a:
 	$(MAKE) -C zlib
+
+alg/ipsec_alg_static.o: dummy
+	$(MAKE) -C alg CC='$(CC)' CFLAGS='$(CFLAGS)' ipsec_alg_static.o
 
 clean:
 	-rm -f *.o
Index: freeswan/klips/net/ipsec/defconfig
diff -u freeswan/klips/net/ipsec/defconfig:1.1.1.1 freeswan/klips/net/ipsec/defconfig:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/defconfig:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/defconfig	Mon Apr 15 12:13:42 2002
@@ -51,6 +51,12 @@
 # To enable userspace-switchable KLIPS debugging, say 'y'.
 CONFIG_IPSEC_DEBUG=y
 
+# modular algo extensions (and new ALGOs)
+CONFIG_IPSEC_ALG=y
+CONFIG_IPSEC_ALG_AES=m
+CONFIG_IPSEC_ALG_TWOFISH=m
+CONFIG_IPSEC_ALG_SERPENT=m
+
 #
 #
 # $Log: defconfig,v $
Index: freeswan/klips/net/ipsec/ipsec_ah.h
diff -u freeswan/klips/net/ipsec/ipsec_ah.h:1.1.1.1 freeswan/klips/net/ipsec/ipsec_ah.h:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_ah.h:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_ah.h	Mon Apr 15 12:13:42 2002
@@ -35,6 +35,11 @@
 
 #define AHMD596_BLKLEN  	64		/* MD5 block length */
 #define AHSHA196_BLKLEN 	64		/* SHA1 block length */
+#define AHSHA2_256_BLKLEN 	64		/* SHA2-256 block length */
+#define AHSHA2_384_BLKLEN 	128 		/* SHA2-384 block length (?) */
+#define AHSHA2_512_BLKLEN 	128		/* SHA2-512 block length */
+
+#define AH_BLKLEN_MAX 		128		/* keep up to date! */
 
 #define AH_AMAX         	AHSHA196_ALEN   /* keep up to date! */
 #define AHHMAC_HASHLEN  	12              /* authenticator length of 96bits */
Index: freeswan/klips/net/ipsec/ipsec_alg.c
diff -u /dev/null freeswan/klips/net/ipsec/ipsec_alg.c:1.1.2.6
--- /dev/null	Fri Jul 12 16:03:45 2002
+++ freeswan/klips/net/ipsec/ipsec_alg.c	Wed May 15 09:16:38 2002
@@ -0,0 +1,814 @@
+/*
+ * Modular extensions service and registration functions
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * 
+ * Version: 0.7.3
+ *
+ * $Id: ipsec_alg.c,v 1.1.2.6 2002/05/15 12:16:38 jjo Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include <linux/netdevice.h>   /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h>          /* struct iphdr */
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/types.h>
+#include <linux/string.h>	/* memcmp() */
+#include <linux/random.h>	/* get_random_bytes() */
+#include <linux/errno.h>  /* error codes */
+#ifdef SPINLOCK
+# ifdef SPINLOCK_23
+#  include <linux/spinlock.h> /* *lock* */
+# else /* SPINLOCK_23 */
+#  include <asm/spinlock.h> /* *lock* */
+# endif /* SPINLOCK_23 */
+#endif /* SPINLOCK */
+#ifdef NET_21
+# include <asm/uaccess.h>
+# include <linux/in6.h>
+# define proto_priv cb
+#endif /* NET21 */
+#include "ipsec_param.h"
+#include <freeswan.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_IPCOMP
+# include "ipcomp.h"
+#endif /* CONFIG_IPSEC_COMP */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "ipsec_sa.h"
+#include "ipsec_alg.h"
+
+#if SADB_EALG_MAX < 255
+#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )
+#endif
+
+static rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;
+#define IPSEC_ALG_HASHSZ	16	/* must be power of 2, even 2^0=1 */
+static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];
+
+/*	Old gcc's will fail here 	*/
+#define barf_out(fmt, args...)  do { printk(KERN_ERR __FUNCTION__ ": (%s) " fmt, ixt->ixt_name , ## args)\
+	; goto out; } while(0)
+
+/* 
+ * 	Must be already protected by lock 
+ */
+static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {
+	if (ixt->ixt_module)
+		__MOD_INC_USE_COUNT(ixt->ixt_module);
+	atomic_inc(&ixt->ixt_refcnt);
+}
+static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
+	atomic_dec(&ixt->ixt_refcnt);
+	if (ixt->ixt_module)
+		__MOD_DEC_USE_COUNT(ixt->ixt_module);
+}
+/*
+ * 	simple hash function, optimized for 0-hash (1 list) special
+ * 	case
+ */
+#if IPSEC_ALG_HASHSZ > 1
+static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {
+	return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));
+}
+#else
+#define ipsec_alg_hashfn(x,y) (0)
+#endif
+
+/*****************************************************************
+ *
+ * 	INTERNAL table handling: insert, delete, find
+ *
+ *****************************************************************/
+
+/*	
+ *	hash table initialization, called from ipsec_alg_init()
+ */
+static void ipsec_alg_hash_init(void) {
+	struct list_head *head = ipsec_alg_hash_table;
+	int i = IPSEC_ALG_HASHSZ;
+	do {
+		INIT_LIST_HEAD(head);
+		head++;
+		i--;
+	} while (i);
+}
+/*
+ * 	hash list lookup by {alg_type, alg_id} and table head,
+ * 	must be already protected by lock
+ */
+static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {
+	struct list_head *p;
+	struct ipsec_alg *ixt=NULL;
+	for (p=head->next; p!=head; p=p->next) {
+		ixt = list_entry(p, struct ipsec_alg, ixt_list);
+		if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {
+			goto out;
+		}
+	}
+	ixt=NULL;
+out:
+	return ixt;
+}
+/*
+ * 	inserts (in front) a new entry in hash table, 
+ * 	called from ipsec_alg_register() when new algorithm is registered.
+ */
+static int ipsec_alg_insert(struct ipsec_alg *ixt) {
+	int ret=-EINVAL;
+	unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);
+	struct list_head *head= ipsec_alg_hash_table + hashval;
+	/* 	new element must be virgin ... */
+	if (ixt->ixt_list.next != &ixt->ixt_list || 
+		ixt->ixt_list.prev != &ixt->ixt_list) {
+		printk(KERN_ERR __FUNCTION__ ": ixt object \"%s\" "
+				"list head not initialized\n",
+				ixt->ixt_name);
+		return ret;
+	}
+	write_lock_bh(&ipsec_alg_lock);
+	if (__ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head))
+		barf_out(KERN_WARNING "ipsec_alg for alg_type=%d, alg_id=%d already exist."
+				"Not loaded (ret=%d).\n",
+				ixt->ixt_alg_type,
+				ixt->ixt_alg_id, ret=-EEXIST);
+	list_add(&ixt->ixt_list, head);
+	ret=0;
+out:
+	write_unlock_bh(&ipsec_alg_lock);
+	return ret;
+}
+/*
+ * 	deletes an existing entry in hash table, 
+ * 	called from ipsec_alg_unregister() when algorithm is unregistered.
+ */
+static int ipsec_alg_delete(struct ipsec_alg *ixt) {
+	write_lock_bh(&ipsec_alg_lock);
+	list_del(&ixt->ixt_list);
+	write_unlock_bh(&ipsec_alg_lock);
+	return 0;
+}
+/*
+ * 	here @user context (read-only when @kernel bh context) 
+ * 	-> no bh disabling
+ *
+ * 	called from ipsec_sa_init() -> ipsec_alg_sa_init()
+ */
+static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id) {
+	unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);
+	struct list_head *head= ipsec_alg_hash_table + hashval;
+	struct ipsec_alg *ixt;
+	read_lock(&ipsec_alg_lock);
+	ixt=__ipsec_alg_find(alg_type, alg_id, head);
+	if (ixt) __ipsec_alg_usage_inc(ixt);
+	read_unlock(&ipsec_alg_lock);
+	return ixt;
+}
+
+static void ipsec_alg_put(struct ipsec_alg *ixt) {
+	__ipsec_alg_usage_dec((struct ipsec_alg *)ixt);
+}
+
+/*****************************************************************
+ *
+ * 	INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+/*
+ * 	main encrypt service entry point
+ * 	called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and
+ * 	ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt) {
+	int ret;
+	struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+	KLIPS_PRINT(debug_rcv||debug_tunnel,
+		    "klips_debug:ipsec_alg_esp_encrypt: "
+		    "entering with encalg=%d, ixt_e=%p\n",
+		    sa_p->ips_encalg, ixt_e);
+	if (!ixt_e) {
+		KLIPS_PRINT(debug_rcv||debug_tunnel,
+			    "klips_debug:ipsec_alg_esp_encrypt: "
+			    "NULL ipsec_alg_enc object\n");
+		return -1;
+	}
+	KLIPS_PRINT(debug_rcv||debug_tunnel,
+		    "klips_debug:ipsec_alg_esp_encrypt: "
+		    "calling cbc_encrypt encalg=%d "
+		    "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",
+			sa_p->ips_encalg, 
+			sa_p->ips_key_e, idat, ilen, iv, encrypt);
+	ret=ixt_e->ixt_e_cbc_encrypt(sa_p->ips_key_e, idat, idat, ilen, iv, encrypt);
+	KLIPS_PRINT(debug_rcv||debug_tunnel,
+		    "klips_debug:ipsec_alg_esp_encrypt: "
+		    "returned ret=%d\n",
+		    ret);
+	return ret;
+}
+/*
+ * 	encryption key context creation function
+ * 	called from pfkey_v2_parser.c:pfkey_ips_init() 
+ */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {
+	int ret=-EINVAL;
+	int keyminbits, keymaxbits;
+	caddr_t ekp;
+	struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
+
+	KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:ipsec_alg_enc_key_create: "
+		    "entering with encalg=%d ixt_e=%p\n",
+		    sa_p->ips_encalg, ixt_e);
+	if (!ixt_e) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:ipsec_alg_enc_key_create: "
+			    "NULL ipsec_alg_enc object\n");
+		return -EPROTO;
+	}
+	if (ixt_e->ixt_e_validate_key) {
+		if ((ret=ixt_e->ixt_e_validate_key(sa_p)) < 0) {
+			KLIPS_PRINT(debug_pfkey,
+				"klips_debug:pfkey_ipsec_sa_init: "
+				"error calling validate_key() "
+				"key_bits_e=%d\n",
+				sa_p->ips_key_bits_e);
+			goto ixt_out;
+		}
+	} else {
+		keyminbits=ixt_e->ixt_keyminbits;
+		keymaxbits=ixt_e->ixt_keymaxbits;
+		if(sa_p->ips_key_bits_e<keyminbits || 
+				sa_p->ips_key_bits_e>keymaxbits) {
+			KLIPS_PRINT(debug_pfkey,
+				"klips_debug:ipsec_alg_enc_key_create: "
+				"incorrect encryption key size: %d bits -- "
+				"must be between %d,%d bits\n" /*octets (bytes)\n"*/,
+				sa_p->ips_key_bits_e, keyminbits, keymaxbits);
+			ret=-EINVAL;
+			goto ixt_out;
+		}
+	}
+	/* save encryption key pointer */
+	ekp = sa_p->ips_key_e;
+
+	if((sa_p->ips_key_e = (caddr_t)
+	    kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
+		    GFP_ATOMIC)) == NULL) {
+		ret=-ENOMEM;
+		goto ixt_out;
+	}
+	/* zero-out key_e */
+	memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);
+
+	/* I cast here to allow more decoupling in alg module */
+	KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:ipsec_alg_enc_key_create: about to call:"
+			    "set_key(key_e=%p, ekp=%p, key_size=%d)\n",
+			    (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+	ret = ixt_e->ixt_e_set_key((caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
+	/* paranoid */
+	memset(ekp, 0, sa_p->ips_key_bits_e/8);
+	kfree(ekp);
+ixt_out:
+	return ret;
+}
+
+/***************************************************************
+ *
+ * 	INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+
+/*
+ * 	auth key context creation function
+ * 	called from pfkey_v2_parser.c:pfkey_ips_init() 
+ */
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {
+	int ret=-EINVAL;
+	struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+	int keyminbits, keymaxbits;
+	unsigned char *akp;
+	unsigned int aks;
+	KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:ipsec_alg_auth_key_create: "
+		    "entering with authalg=%d ixt_a=%p\n",
+		    sa_p->ips_authalg, ixt_a);
+	if (!ixt_a) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:ipsec_alg_auth_key_create: "
+			    "NULL ipsec_alg_auth object\n");
+		return -EPROTO;
+	}
+	keyminbits=ixt_a->ixt_keyminbits;
+	keymaxbits=ixt_a->ixt_keymaxbits;
+	if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:ipsec_alg_auth_key_create: incorrect auth"
+			    "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,
+			    sa_p->ips_key_bits_a, keyminbits, keymaxbits);
+		ret=-EINVAL;
+		goto ixt_out;
+	}
+	/* save auth key pointer */
+	sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */
+	akp = sa_p->ips_key_a;
+	aks = sa_p->ips_key_a_size;
+
+	/* will hold: 2 ctx and a blocksize buffer: kb */
+	sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;
+	if((sa_p->ips_key_a = 
+		(caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {
+		ret=-ENOMEM;
+		goto ixt_out;
+	}
+	ixt_a->ixt_a_hmac_set_key(sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */
+	ret=0;
+	memset(akp, 0, aks);
+	kfree(akp);
+			
+ixt_out:
+	return ret;
+}
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) {
+	struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
+	if (!ixt_a) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:ipsec_sa_esp_hash: "
+			    "NULL ipsec_alg_auth object\n");
+		return -EPROTO;
+	}
+	KLIPS_PRINT(debug_tunnel|debug_rcv,
+			"klips_debug:ipsec_sa_esp_hash: "
+			"hashing %p (%d bytes) to %p (%d bytes)\n",
+			espp, len,
+			hash, hashlen);
+	ixt_a->ixt_a_hmac_hash(sa_p->ips_key_a, 
+			espp, len,
+			hash, hashlen);
+	return 0;
+}
+
+/***************************************************************
+ *
+ * 	INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+
+/* validation for registering (enc) module */
+static int check_enc(struct ipsec_alg_enc *ixt) {
+	int ret=-EINVAL;
+	if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_EALG_MAX)
+		barf_out("invalid alg_id=%d >= %d\n", ixt->ixt_alg_id, SADB_EALG_MAX);
+	if (ixt->ixt_blocksize==0) /*  || ixt->ixt_blocksize%2) need for ESP_NULL */
+		barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+	if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0)
+		goto zero_key_ok;
+	if (ixt->ixt_keyminbits==0)
+		barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+	if (ixt->ixt_keymaxbits==0)
+		barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+	if (ixt->ixt_e_keylen==0)
+		barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);
+zero_key_ok:
+	if (ixt->ixt_e_ctx_size==0)
+		barf_out(KERN_ERR "invalid key_e_size=%d\n", ixt->ixt_e_ctx_size);
+	if (ixt->ixt_e_cbc_encrypt==NULL)
+		barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");
+	ret=0;
+out:
+	return ret;
+}
+
+/* validation for registering (auth) module */
+static int check_auth(struct ipsec_alg_auth *ixt) {
+	int ret=-EINVAL;
+	if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX)
+		barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX);
+	if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2)
+		barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
+	if (ixt->ixt_blocksize>AH_BLKLEN_MAX)
+		barf_out(KERN_ERR "sorry blocksize=%d > %d. "
+			"Please increase AH_BLKLEN_MAX and recompile\n", 
+			ixt->ixt_blocksize,
+			AH_BLKLEN_MAX);
+	if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0)
+		goto zero_key_ok;
+	if (ixt->ixt_keyminbits==0)
+		barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
+	if (ixt->ixt_keymaxbits==0)
+		barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
+	if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits)
+		barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");
+	if (ixt->ixt_a_keylen==0)
+		barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);
+zero_key_ok:
+	if (ixt->ixt_a_ctx_size==0)
+		barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);
+	if (ixt->ixt_a_hmac_set_key==NULL)
+		barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");
+	if (ixt->ixt_a_hmac_hash==NULL)
+		barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");
+	ret=0;
+out:
+	return ret;
+}
+
+/* 
+ * Generic (enc, auth) registration entry point 
+ */
+int register_ipsec_alg(struct ipsec_alg *ixt) {
+	int ret=-EINVAL;
+	/*	Validation 	*/
+	if (ixt==NULL)
+		barf_out("NULL ipsec_alg object passed\n");
+	if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00))
+		barf_out("incorrect version: %d.%d.%d-%d, "
+			"must be %d.%d.%d[-%d]\n",
+				IPSEC_ALG_VERSION_QUAD(ixt->ixt_version), 
+				IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION));
+	switch(ixt->ixt_alg_type) {
+		case IPSEC_ALG_TYPE_AUTH:
+			if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0))
+				goto out;
+			break;
+		case IPSEC_ALG_TYPE_ENCRYPT: 
+			if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0))
+				goto out;
+			if (ixt->ixt_ivlen == 0)
+				ixt->ixt_ivlen = ixt->ixt_blocksize*8;
+			break;
+		default:
+			barf_out("alg_type=%d not supported", ixt->ixt_alg_type);
+	}
+	INIT_LIST_HEAD(&ixt->ixt_list);
+	ret = ipsec_alg_insert(ixt);
+	if (ret<0) 
+		barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed."
+				"Not loaded (ret=%d).\n",
+				ixt->ixt_alg_id, ret);
+
+	ret = pfkey_list_insert_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+	if (ret==0) {
+		ixt->ixt_state |= IPSEC_ALG_ST_SUPP;
+		/*	send register event to userspace	*/
+		pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+	} else
+		printk(KERN_ERR "pfkey_list_insert_supported returned %d. "
+				"Loading anyway.\n", ret);
+	ret=0;
+out:
+	return ret;
+}
+
+/* 
+ * 	unregister ipsec_alg object from own tables, if 
+ * 	success => calls pfkey_list_remove_supported()
+ */
+int unregister_ipsec_alg(struct ipsec_alg *ixt) {
+	int ret= -EINVAL;
+	switch(ixt->ixt_alg_type) {
+		case IPSEC_ALG_TYPE_AUTH:
+		case IPSEC_ALG_TYPE_ENCRYPT: 
+			break;
+		default:
+			/*	this is not a typo :) */
+			barf_out("frog found in list (\"%s\"): ixt_p=NULL\n", 
+				ixt->ixt_name);
+	}
+
+	ret=ipsec_alg_delete(ixt);
+	if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) {
+		ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP;
+		pfkey_list_remove_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
+		/*	send register event to userspace	*/
+		pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+	}
+
+out:
+	return ret;
+}
+/*
+ * 	Must be called from user context
+ * 	used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_encrypt(int enc_alg, int test) {
+	int ret;
+	caddr_t buf;
+	int iv_size, keysize, key_e_size;
+	struct ipsec_alg_enc *ixt_e;
+	#define BUFSZ	1024
+	#define MARGIN	0
+	#define test_enc   (buf+MARGIN)
+	#define test_dec   (test_enc+BUFSZ+MARGIN)
+	#define test_tmp   (test_dec+BUFSZ+MARGIN)
+	#define test_key_e (test_tmp+BUFSZ+MARGIN)
+	#define test_iv    (test_key_e+key_e_size+MARGIN)
+	#define test_key   (test_iv+iv_size+MARGIN)
+	#define test_size  (BUFSZ*3+key_e_size+iv_size+keysize+MARGIN*7)
+	ixt_e=(struct ipsec_alg_enc *)ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, enc_alg);
+	if (ixt_e==NULL) {
+		KLIPS_PRINT(1, 
+			    "klips_debug:" __FUNCTION__ ": "
+			    "encalg=%d object not found\n",
+			    enc_alg);
+		ret=-EINVAL;
+		goto out;
+	}
+	iv_size=ixt_e->ixt_blocksize;
+	key_e_size=ixt_e->ixt_e_ctx_size;
+	keysize=ixt_e->ixt_e_keylen;
+	KLIPS_PRINT(1, 
+		    "klips_debug:" __FUNCTION__ ": "
+		    "enc_alg=%d blocksize=%d key_e_size=%d keysize=%d\n",
+		    enc_alg, iv_size, key_e_size, keysize);
+	if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+		ret= -ENOMEM;
+		goto out;
+	}
+	get_random_bytes(test_key, keysize);
+	get_random_bytes(test_iv, iv_size);
+	ixt_e->ixt_e_set_key(test_key_e, test_key, keysize);
+	get_random_bytes(test_enc, BUFSZ);
+	memcpy(test_tmp, test_enc, BUFSZ);
+	ret=ixt_e->ixt_e_cbc_encrypt(test_key_e, test_enc, test_enc, BUFSZ, test_iv, 1);
+	printk(KERN_INFO
+		    "klips_info:" __FUNCTION__ ": "
+		    "cbc_encrypt=1 ret=%d\n", 
+		    	ret);
+	ret=memcmp(test_enc, test_tmp, BUFSZ);
+	printk(KERN_INFO
+		    "klips_info:" __FUNCTION__ ": "
+		    "memcmp(enc, tmp) ret=%d: %s\n", ret,
+			ret!=0? "OK. (encr->DIFFers)" : "FAIL! (encr->SAME)" );
+	memcpy(test_dec, test_enc, BUFSZ);
+	ret=ixt_e->ixt_e_cbc_encrypt(test_key_e, test_dec, test_dec, BUFSZ, test_iv, 0);
+	printk(KERN_INFO
+		    "klips_info:" __FUNCTION__ ": "
+		    "cbc_encrypt=0 ret=%d\n", ret);
+	ret=memcmp(test_dec, test_tmp, BUFSZ);
+	printk(KERN_INFO
+		    "klips_info:" __FUNCTION__ ": "
+		    "memcmp(dec,tmp) ret=%d: %s\n", ret,
+			ret==0? "OK. (encr->decr->SAME)" : "FAIL! (encr->decr->DIFFers)" );
+	{
+		/*	Shamelessly taken from drivers/md sources  O:)  */
+		unsigned long now;
+		int i, count, max=0;
+		int encrypt, speed;
+		for (encrypt=0; encrypt <2;encrypt ++) {
+			for (i = 0; i < 5; i++) {
+				now = jiffies;
+				count = 0;
+				while (jiffies == now) {
+					mb();
+					ixt_e->ixt_e_cbc_encrypt(test_key_e, test_tmp, test_tmp, BUFSZ, test_iv, encrypt);
+					mb();
+					count++;
+					mb();
+				}
+				if (count > max)
+					max = count;
+			}
+			speed = max * (HZ * BUFSZ / 1024);
+			printk(KERN_INFO
+				    "klips_info:" __FUNCTION__ ": "
+				    "%s %s speed=%d KB/s\n", 
+				    ixt_e->ixt_name,
+				    encrypt? "encrypt": "decrypt", speed);
+		}
+	}
+	kfree(buf);
+	ipsec_alg_put((struct ipsec_alg *)ixt_e);
+out:
+	return ret;
+	#undef test_enc  
+	#undef test_dec  
+	#undef test_tmp  
+	#undef test_key_e
+	#undef test_iv   
+	#undef test_key  
+	#undef test_size 
+}
+/*
+ * 	Must be called from user context
+ * 	used at module load type for testing algo implementation
+ */
+static int ipsec_alg_test_auth(int auth_alg, int test) {
+	int ret;
+	caddr_t buf;
+	int blocksize, keysize, key_a_size;
+	struct ipsec_alg_auth *ixt_a;
+	#define BUFSZ	1024
+	#define MARGIN	0
+	#define test_auth  (buf+MARGIN)
+	#define test_key_a (test_auth+BUFSZ+MARGIN)
+	#define test_key   (test_key_a+key_a_size+MARGIN)
+	#define test_hash  (test_key+keysize+MARGIN)
+	#define test_size  (BUFSZ+key_a_size+keysize+AHHMAC_HASHLEN+MARGIN*4)
+	ixt_a=(struct ipsec_alg_auth *)ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, auth_alg);
+	if (ixt_a==NULL) {
+		KLIPS_PRINT(1, 
+			    "klips_debug:" __FUNCTION__ ": "
+			    "encalg=%d object not found\n",
+			    auth_alg);
+		ret=-EINVAL;
+		goto out;
+	}
+	blocksize=ixt_a->ixt_blocksize;
+	key_a_size=ixt_a->ixt_a_ctx_size;
+	keysize=ixt_a->ixt_a_keylen;
+	KLIPS_PRINT(1, 
+		    "klips_debug:" __FUNCTION__ ": "
+		    "auth_alg=%d blocksize=%d key_a_size=%d keysize=%d\n",
+		    auth_alg, blocksize, key_a_size, keysize);
+	if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
+		ret= -ENOMEM;
+		goto out;
+	}
+	get_random_bytes(test_key, keysize);
+	ixt_a->ixt_a_hmac_set_key(test_key_a, test_key, keysize);
+	get_random_bytes(test_auth, BUFSZ);
+	ret=ixt_a->ixt_a_hmac_hash(test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+	printk(KERN_INFO
+		    "klips_info:" __FUNCTION__ ": "
+		    "ret=%d\n", ret);
+	{
+		/*	Shamelessly taken from drivers/md sources  O:)  */
+		unsigned long now;
+		int i, count, max=0;
+		int speed;
+		for (i = 0; i < 5; i++) {
+			now = jiffies;
+			count = 0;
+			while (jiffies == now) {
+				mb();
+				ixt_a->ixt_a_hmac_hash(test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
+				mb();
+				count++;
+				mb();
+			}
+			if (count > max)
+				max = count;
+		}
+		speed = max * (HZ * BUFSZ / 1024);
+		printk(KERN_INFO
+				"klips_info:" __FUNCTION__ ": "
+				"%s hash speed=%d KB/s\n", 
+				ixt_a->ixt_name,
+				speed);
+	}
+	kfree(buf);
+	ipsec_alg_put((struct ipsec_alg *)ixt_a);
+out:
+	return ret;
+	#undef test_auth 
+	#undef test_key_a
+	#undef test_key  
+	#undef test_hash 
+	#undef test_size 
+}
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int test) {
+	switch(alg_type) {
+		case IPSEC_ALG_TYPE_ENCRYPT:
+			return ipsec_alg_test_encrypt(alg_id, test);
+			break;
+		case IPSEC_ALG_TYPE_AUTH:
+			return ipsec_alg_test_auth(alg_id, test);
+			break;
+	}
+	printk(KERN_ERR "klips_info: ipsec_alg_test() called incorrectly: "
+			"alg_type=%d alg_id=%d\n",
+			alg_type, alg_id);
+	return -EINVAL;
+}
+int ipsec_alg_init(void) {
+	KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+			"KLIPS alg v=%d.%d.%d-%d (EALG_MAX=%d, AALG_MAX=%d)\n",
+			IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION),
+			SADB_EALG_MAX, SADB_AALG_MAX);
+	/*	Initialize tables */
+	write_lock_bh(&ipsec_alg_lock);
+	ipsec_alg_hash_init();
+	write_unlock_bh(&ipsec_alg_lock);
+	/*	Initialize static algos 	*/
+	KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
+		"calling ipsec_alg_static_init()\n");
+	ipsec_alg_static_init();
+	return 0;
+}
+
+/**********************************************
+ *
+ * 	INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/*	
+ *	Called from pluto -> pfkey_v2_parser.c:pfkey_ipsec_sa_init()	
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p) {
+	struct ipsec_alg_enc *ixt_e;
+	struct ipsec_alg_auth *ixt_a;
+
+	/*	Only ESP for now ... */
+	if (sa_p->ips_said.proto != IPPROTO_ESP)
+		return -EPROTONOSUPPORT;
+	KLIPS_PRINT(debug_pfkey, "klips_debug: " __FUNCTION__ "() :"
+			"entering for encalg=%d, authalg=%d\n",
+			    sa_p->ips_encalg, sa_p->ips_authalg);
+	if ((ixt_e=(struct ipsec_alg_enc *)
+		ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, sa_p->ips_encalg))) {
+		KLIPS_PRINT(debug_pfkey,
+		    "klips_debug: " __FUNCTION__ "() :"
+		    "found ipsec_alg (ixt_e=%p) for encalg=%d\n",
+		    ixt_e, sa_p->ips_encalg);
+		sa_p->ips_alg_enc=ixt_e;
+	}
+	if ((ixt_a=(struct ipsec_alg_auth *)
+		ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, sa_p->ips_authalg))) {
+		KLIPS_PRINT(debug_pfkey,
+		    "klips_debug: " __FUNCTION__ "() :"
+		    "found ipsec_alg (ixt_a=%p) for auth=%d\n",
+		    ixt_a, sa_p->ips_authalg);
+		sa_p->ips_alg_auth=ixt_a;
+	}
+	return 0;
+}
+
+/*	
+ *	Called from pluto -> ipsec_sa.c:ipsec_sa_delchain()
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p) {
+	struct ipsec_alg *ixt;
+	if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_enc)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug: " __FUNCTION__ "() :"
+				"unlinking for encalg=%d\n",
+				ixt->ixt_alg_id);
+		ipsec_alg_put(ixt);
+	}
+	if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_auth)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug: " __FUNCTION__ "() :"
+				"unlinking for authalg=%d\n",
+				ixt->ixt_alg_id);
+		ipsec_alg_put(ixt);
+	}
+	return 0;
+}
+/*
+ * 	As the author of this module, I ONLY ALLOW using it from
+ * 	GPL (or same LICENSE TERMS as kernel source) modules.
+ *
+ * 	In respect to hardware crypto engines this means:
+ * 	* Closed-source device drivers ARE NOT ALLOWED to use 
+ * 	  this interface.
+ * 	* Closed-source VHDL/Verilog firmware running on 
+ * 	  the crypto hardware device IS ALLOWED to use this interface
+ * 	  via a GPL (or same LICENSE TERMS as kernel source) device driver.
+ * 	--Juan Jose Ciarlante 20/03/2002 (thanks RGB for the correct wording)
+ */
+
+/*	
+ *	These symbols can only be used from GPL modules	
+ *	for now, I'm disabling this because it creates false
+ *	symbol problems for old modutils.
+ */
+
+/* #ifndef EXPORT_SYMBOL_GPL */
+#undef EXPORT_SYMBOL_GPL
+#define EXPORT_SYMBOL_GPL EXPORT_SYMBOL
+/* #endif */
+EXPORT_SYMBOL_GPL(register_ipsec_alg);
+EXPORT_SYMBOL_GPL(unregister_ipsec_alg);
+EXPORT_SYMBOL_GPL(ipsec_alg_test);
Index: freeswan/klips/net/ipsec/ipsec_alg.h
diff -u /dev/null freeswan/klips/net/ipsec/ipsec_alg.h:1.1.2.4
--- /dev/null	Fri Jul 12 16:03:45 2002
+++ freeswan/klips/net/ipsec/ipsec_alg.h	Mon Apr 29 19:11:30 2002
@@ -0,0 +1,242 @@
+/*
+ * Modular extensions service and registration functions interface
+ *
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: ipsec_alg.h,v 1.1.2.4 2002/04/29 22:11:30 jjo Exp $
+ *
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+#ifndef IPSEC_ALG_H
+#define IPSEC_ALG_H
+
+#define IPSEC_ALG_VERSION	0x00070301
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+/*	
+ *	The following structs are used via pointers in ipsec_alg object to
+ *	avoid ipsec_alg.h coupling with freeswan headers, thus simplifying
+ *	module development
+ */
+struct ipsec_sa;
+struct esp;
+
+/**************************************
+ *
+ *	Main registration object 
+ *
+ *************************************/
+#define IPSEC_ALG_VERSION_QUAD(v)	\
+	(v>>24),((v>>16)&0xff),((v>>8)&0xff),(v&0xff)
+/*	
+ *	Main ipsec_alg objects: "OOPrograming wannabe"
+ *	Hierachy (carefully handled with _minimal_ cast'ing):
+ *
+ *      ipsec_alg+
+ *		 +->ipsec_alg_enc  (ixt_alg_type=SADB_EXT_SUPPORTED_ENCRYPT)
+ *		 +->ipsec_alg_auth (ixt_alg_type=SADB_EXT_SUPPORTED_AUTH)
+ */
+
+/***************************************************************
+ *
+ * 	INTERFACE object: struct ipsec_alg
+ *
+ ***************************************************************/
+
+/* 
+ * 	common part for every struct ipsec_alg_*	
+ * 	(sortof poor's man OOP)
+ */
+#define IPSEC_ALG_STRUCT_COMMON \
+	unsigned ixt_version;	/* only allow this version (or 'near')*/ \
+	struct list_head ixt_list;	/* dlinked list */ \
+	struct module *ixt_module;	/* THIS_MODULE */ \
+	unsigned ixt_state;		/* state flags */ \
+	atomic_t ixt_refcnt; 	/* ref. count when pointed from ipsec_sa */ \
+	char ixt_name[16];	/* descriptive short name, eg. "3des" */ \
+	uint8_t  ixt_blocksize;	/* blocksize in bytes */ \
+	\
+	/* THIS IS A COPY of struct supported (lib/pfkey.h)        \
+	 * please keep in sync until we migrate 'supported' stuff  \
+	 * to ipsec_alg \
+	 */ \
+	uint16_t ixt_alg_type;	/* correspond to IPSEC_ALG_{ENCRYPT,AUTH} */ \
+	uint8_t  ixt_alg_id;	/* enc. alg. number, eg. ESP_3DES */ \
+	uint8_t  ixt_ivlen;	/* ivlen in bits */ \
+	uint16_t ixt_keyminbits;/* min. keybits (of entropy) */ \
+	uint16_t ixt_keymaxbits;/* max. keybits (of entropy) */
+
+#define ixt_support ixt_alg_type
+	
+#define IPSEC_ALG_ST_SUPP 0x01
+#define IPSEC_ALG_ST_REGISTERED 0x02
+struct ipsec_alg {
+	IPSEC_ALG_STRUCT_COMMON
+};
+/* 
+ * 	Note the const in cbc_encrypt IV arg:
+ * 	some ciphers like to toast passed IV (eg. 3DES): make a local IV copy
+ */
+struct ipsec_alg_enc {
+	IPSEC_ALG_STRUCT_COMMON
+	unsigned ixt_e_keylen;		/* raw key length in bytes          */
+	unsigned ixt_e_ctx_size;	/* sa_p->key_e_size */
+	int (*ixt_e_set_key)(__u8 *key_e, const __u8 *key, int keysize);
+	int (*ixt_e_cbc_encrypt)(__u8 *key_e, __u8 *in, __u8 *out, int ilen, const __u8 *iv, int encrypt);
+	int (*ixt_e_validate_key)(struct ipsec_sa *sa_p);	/* optional */
+};
+struct ipsec_alg_auth {
+	IPSEC_ALG_STRUCT_COMMON
+	unsigned ixt_a_keylen;		/* raw key length in bytes          */
+	unsigned ixt_a_ctx_size;	/* sa_p->key_a_size */
+	unsigned ixt_a_authlen;		/* 'natural' auth. hash len (bytes) */
+	int (*ixt_a_hmac_set_key)(__u8 *key_a, const __u8 *key, int keylen);
+	int (*ixt_a_hmac_hash)(__u8 *key_a, const __u8 *dat, int len, __u8 *hash, int hashlen);
+};
+/*	
+ *	These are _copies_ of SADB_EXT_SUPPORTED_{AUTH,ENCRYPT}, 
+ *	to avoid header coupling for true constants
+ *	about headers ... "cp is your friend" --Linus
+ */
+#define IPSEC_ALG_TYPE_AUTH	14
+#define IPSEC_ALG_TYPE_ENCRYPT	15
+
+/***************************************************************
+ *
+ * 	INTERFACE for module loading,testing, and unloading
+ *
+ ***************************************************************/
+/*	-  registration calls 	*/
+int register_ipsec_alg(struct ipsec_alg *);
+int unregister_ipsec_alg(struct ipsec_alg *);
+/*	-  optional (simple test) for algos 	*/
+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int testparm);
+/*	inline wrappers (usefull for type validation */
+static inline int register_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+	return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
+	return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int register_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+	return register_ipsec_alg((struct ipsec_alg*)ixt);
+}
+static inline int unregister_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
+	return unregister_ipsec_alg((struct ipsec_alg*)ixt);
+}
+
+/*****************************************************************
+ *
+ * 	INTERFACE for ENC services: key creation, encrypt function
+ *
+ *****************************************************************/
+
+#define IPSEC_ALG_ENCRYPT 1
+#define IPSEC_ALG_DECRYPT 0
+
+/* 	encryption key context creation function */
+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p);
+/* 
+ * 	ipsec_alg_esp_encrypt(): encrypt ilen bytes in idat returns
+ * 	0 or ERR<0
+ */
+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 *idat, int ilen, const __u8 *iv, int action);
+
+/***************************************************************
+ *
+ * 	INTERFACE for AUTH services: key creation, hash functions
+ *
+ ***************************************************************/
+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p);
+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) ;
+#define ipsec_alg_sa_esp_update(c,k,l) ipsec_alg_sa_esp_hash(c,k,l,NULL,0)
+
+/* only called from ipsec_init.c */
+int ipsec_alg_init(void);
+
+/* algo module glue for static algos */
+void ipsec_alg_static_init(void);
+typedef int (*ipsec_alg_init_func_t) (void);
+
+/**********************************************
+ *
+ * 	INTERFACE for ipsec_sa init and wipe
+ *
+ **********************************************/
+
+/* returns true if ipsec_sa has ipsec_alg obj attached */
+#define IPSEC_ALG_SA_ESP_ENC(sa_p) ((sa_p)->ips_alg_enc)
+#define IPSEC_ALG_SA_ESP_AUTH(sa_p) ((sa_p)->ips_alg_auth)
+/* 
+ * Initializes ipsec_sa's ipsec_alg object, using already loaded
+ * proto, authalg, encalg.; links ipsec_alg objects (enc, auth)
+ */
+int ipsec_alg_sa_init(struct ipsec_sa *sa_p);
+/* 
+ * Destroys ipsec_sa's ipsec_alg object
+ * unlinking ipsec_alg objects
+ */
+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p);
+
+/**********************************************
+ *
+ * 	2.2 backport for some 2.4 useful module stuff
+ *
+ **********************************************/
+#ifdef MODULE
+#ifndef THIS_MODULE
+#define THIS_MODULE          (&__this_module)
+#endif
+#ifndef module_init
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+
+#define module_init(x) \
+        int init_module(void) __attribute__((alias(#x))); \
+        static inline __init_module_func_t __init_module_inline(void) \
+        { return x; }
+#define module_exit(x) \
+        void cleanup_module(void) __attribute__((alias(#x))); \
+        static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+        { return x; }
+#endif
+
+#define IPSEC_ALG_MODULE_INIT( func_name )	\
+	static int func_name(void);		\
+	module_init(func_name);			\
+	static int __init func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name )	\
+	static void func_name(void);		\
+	module_exit(func_name);			\
+	static void __exit func_name(void)
+#else	/* not MODULE */
+#ifndef THIS_MODULE
+#define THIS_MODULE          NULL
+#endif
+/*	
+ *	I only want module_init() magic 
+ *	when algo.c file *is THE MODULE*, in all other
+ *	cases, initialization is called explicitely from ipsec_alg_init()
+ */
+#define IPSEC_ALG_MODULE_INIT( func_name )	\
+	extern int func_name(void);		\
+	int func_name(void)
+#define IPSEC_ALG_MODULE_EXIT( func_name )	\
+	extern void func_name(void);		\
+	void func_name(void)
+#endif
+
+#endif /* IPSEC_ALG_H */
Index: freeswan/klips/net/ipsec/ipsec_esp.h
diff -u freeswan/klips/net/ipsec/ipsec_esp.h:1.1.1.1 freeswan/klips/net/ipsec/ipsec_esp.h:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_esp.h:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_esp.h	Mon Apr 15 12:13:42 2002
@@ -24,6 +24,8 @@
 #define IPPROTO_ESP 50
 #endif /* IPPROTO_ESP */
 
+#define ESP_HEADER_LEN		8	/* 64 bits header (spi+rpl)*/
+
 #define EMT_ESPDESCBC_ULEN	20	/* coming from user mode */
 #define EMT_ESPDES_KMAX		64	/* 512 bit secret key enough? */
 #define EMT_ESPDES_KEY_SZ	8	/* 56 bit secret key with parity = 64 bits */
@@ -31,6 +33,9 @@
 #define EMT_ESPDES_IV_SZ	8	/* IV size */
 #define ESP_DESCBC_BLKLEN       8       /* DES-CBC block size */
 
+#define ESP_IV_MAXSZ		16	/* This is _critical_ */
+#define ESP_IV_MAXSZ_INT	(ESP_IV_MAXSZ/sizeof(int))
+
 #define DB_ES_PKTRX	0x0001
 #define DB_ES_PKTRX2	0x0002
 #define DB_ES_TDB	0x0010
@@ -61,6 +66,7 @@
 	int redo,
 	struct inet_protocol *protocol);
 
+/* XXX: only for 64 bits IVs, eg. ESP_3DES */
 struct esp
 {
 	__u32	esp_spi;		/* Security Parameters Index */
Index: freeswan/klips/net/ipsec/ipsec_init.c
diff -u freeswan/klips/net/ipsec/ipsec_init.c:1.1.1.1 freeswan/klips/net/ipsec/ipsec_init.c:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_init.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_init.c	Mon Apr 15 12:13:42 2002
@@ -82,6 +82,7 @@
 #endif /* CONFIG_IPSEC_IPCOMP */
 
 #include "ipsec_proto.h"
+#include "ipsec_alg.h"
 
 #include <pfkeyv2.h>
 #include <pfkey.h>
@@ -126,10 +127,12 @@
 ipsec_init(void)
 {
 	int error = 0;
+#ifdef CONFIG_IPSEC_ENC_3DES
 	extern int des_check_key;
 
 	/* turn off checking of keys */
 	des_check_key=0;
+#endif /* CONFIG_IPSEC_ENC_3DES */
 
 	KLIPS_PRINT(1, "klips_info:ipsec_init: "
 		    "KLIPS startup, FreeS/WAN IPSec version: %s\n",
@@ -168,6 +171,9 @@
 #ifdef CONFIG_SYSCTL
         error |= ipsec_sysctl_register();
 #endif                                                                          
+#ifdef CONFIG_IPSEC_ALG
+	ipsec_alg_init();
+#endif
 	return error;
 }	
 
Index: freeswan/klips/net/ipsec/ipsec_rcv.c
diff -u freeswan/klips/net/ipsec/ipsec_rcv.c:1.1.1.1 freeswan/klips/net/ipsec/ipsec_rcv.c:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_rcv.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_rcv.c	Mon Apr 15 12:13:42 2002
@@ -79,6 +79,8 @@
 
 #include "ipsec_proto.h"
 
+#include "ipsec_alg.h"
+
 #ifdef CONFIG_IPSEC_DEBUG
 int debug_ah = 0;
 int debug_esp = 0;
@@ -195,7 +197,7 @@
 #ifdef CONFIG_IPSEC_ESP
 	struct esp *espp = NULL;
 	int esphlen = 0;
-	__u32 iv[2];
+	__u32 iv[ESP_IV_MAXSZ_INT];
 #endif /* !CONFIG_IPSEC_ESP */
 #ifdef CONFIG_IPSEC_AH
 	struct ah *ahp = NULL;
@@ -248,6 +250,10 @@
 	struct sockaddr_encap policy_eaddr;
 	struct sockaddr_encap policy_emask;
 #endif /* INBOUND_POLICY_CHECK_eroute */
+#ifdef CONFIG_IPSEC_ALG
+	struct ipsec_alg_enc *ixt_e=NULL;
+	struct ipsec_alg_auth *ixt_a=NULL;
+#endif /* CONFIG_IPSEC_ALG */
 
 	/* Don't unlink in the middle of a turnaround */
 	MOD_INC_USE_COUNT;
@@ -760,6 +766,15 @@
 
 		/* authenticate, if required */
 		idat = dat + iphlen;
+#ifdef CONFIG_IPSEC_ALG
+		if ((ixt_a=IPSEC_ALG_SA_ESP_AUTH(tdbp))) {
+			authlen = AHHMAC_HASHLEN;
+			KLIPS_PRINT(debug_rcv,
+					"klips_debug:ipsec_rcv: "
+					"authalg=%d authlen=%d\n",
+					tdbp->tdb_authalg, authlen);
+		} else
+#endif /* CONFIG_IPSEC_ALG */
 		switch(tdbp->tdb_authalg) {
 #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
 		case AH_MD5:
@@ -835,6 +850,42 @@
 			    tdbp->tdb_encalg,
 			    tdbp->tdb_authalg);
 		
+#ifdef CONFIG_IPSEC_ALG
+		if (ixt_a) {
+			KLIPS_PRINT(debug_rcv,
+					"klips_debug:ipsec_rcv: "
+					"ipsec_alg hashing ... ");
+			if(proto == IPPROTO_ESP) {
+				ipsec_alg_sa_esp_hash(tdbp,
+						(caddr_t)espp, ilen,
+						hash, AHHMAC_HASHLEN);
+#ifdef CONFIG_IPSEC_AH
+#ifdef IPSEC_ALG_WHEN_AH_IS_READY
+			} else {
+				ipo = *ipp;
+				ipo.tos = 0;
+				ipo.frag_off = 0;
+				ipo.ttl = 0;
+				ipo.check = 0;
+
+				ipsec_alg_hmac_update(tdbp->tdb_key_a,
+						(caddr_t)&ipo, 
+						sizeof(struct iphdr));
+				ipsec_alg_hmac_update(tdbp->tdb_key_a,
+						(caddr_t)ahp,
+						ahhlen - AHHMAC_HASHLEN);
+				ipsec_alg_hmac_update(tdbp->tdb_key_a,
+						(caddr_t)zeroes,
+						AHHMAC_HASHLEN);
+				ipsec_alg_hmac_hash(tdbp->tdb_key_a,
+						(caddr_t)dat + iphlen + ahhlen,
+						len - iphlen - ahhlen,
+						hash, AHHMAC_HASHLEN);
+#endif
+#endif /* CONFIG_IPSEC_AH */
+			}
+		} else
+#endif /* CONFIG_IPSEC_ALG */
 		if(tdbp->tdb_authalg) {
 			switch(tdbp->tdb_authalg) {
 #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
@@ -966,12 +1017,23 @@
 		switch(proto) {
 #ifdef CONFIG_IPSEC_ESP
 		case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+			if ((ixt_e=IPSEC_ALG_SA_ESP_ENC(tdbp))) {
+				esphlen = ESP_HEADER_LEN + ixt_e->ixt_blocksize;
+				KLIPS_PRINT(debug_rcv,
+						"klips_debug:ipsec_rcv: "
+						"encalg=%d esphlen=%d\n",
+						tdbp->tdb_encalg, esphlen);
+			} else
+#endif /* CONFIG_IPSEC_ALG */
 			switch(tdbp->tdb_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
 			case ESP_3DES:
 				iv[0] = *((__u32 *)(espp->esp_iv)    );
 				iv[1] = *((__u32 *)(espp->esp_iv) + 1);
 				esphlen = sizeof(struct esp);
 				break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
 			default:
 				tdbp->tdb_alg_errs += 1;
 				spin_unlock(&tdb_lock);
@@ -983,7 +1045,29 @@
 			idat += esphlen;
 			ilen -= esphlen;
 			
+#ifdef CONFIG_IPSEC_ALG
+			if (ixt_e)
+			{
+				if (ipsec_alg_esp_encrypt(tdbp, 
+					idat, ilen, espp->esp_iv, 
+					IPSEC_ALG_DECRYPT) <= 0)
+				{
+					spin_unlock(&tdb_lock);
+					printk("klips_error:ipsec_rcv: "
+						"got packet with esplen = %d "
+						"from %s -- should be on "
+						"ENC(%d) octet boundary, "
+						"packet dropped\n",
+							ilen,
+							ipaddr_txt,
+							tdbp->tdb_encalg);
+					stats->rx_errors++;
+					goto rcvleave;
+				}
+			} else
+#endif /* CONFIG_IPSEC_ALG */
 			switch(tdbp->tdb_encalg) {
+#ifdef CONFIG_IPSEC_ENC_3DES
 			case ESP_3DES:
 				if ((ilen) % 8) {
 					tdbp->tdb_encsize_errs += 1;
@@ -1005,6 +1089,8 @@
 						     ((struct des_eks *)(tdbp->tdb_key_e))[2].ks,
 						     (des_cblock *)iv, 0);
 				break;
+#endif /* CONFIG_IPSEC_ENC_3DES */
+			default:
 			}
 			next_header = idat[ilen - 1];
 			padlen = idat[ilen - 2];
Index: freeswan/klips/net/ipsec/ipsec_sa.c
diff -u freeswan/klips/net/ipsec/ipsec_sa.c:1.1.1.1 freeswan/klips/net/ipsec/ipsec_sa.c:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_sa.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_sa.c	Mon Apr 15 12:13:42 2002
@@ -74,6 +74,7 @@
 #include <pfkey.h>
 
 #include "ipsec_proto.h"
+#include "ipsec_alg.h"
 
 
 #ifdef CONFIG_IPSEC_DEBUG
@@ -467,6 +468,10 @@
 		kfree(ips->ips_ident_d.data);
         }
 	ips->ips_ident_d.data = NULL;
+
+	if (IPSEC_ALG_SA_ESP_ENC(ips)||IPSEC_ALG_SA_ESP_AUTH(ips)) {
+		ipsec_alg_sa_wipe(ips);
+	}
 	
 	memset((caddr_t)ips, 0, sizeof(*ips));
 	kfree(ips);
Index: freeswan/klips/net/ipsec/ipsec_sa.h
diff -u freeswan/klips/net/ipsec/ipsec_sa.h:1.1.1.1 freeswan/klips/net/ipsec/ipsec_sa.h:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_sa.h:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_sa.h	Mon Apr 15 12:13:42 2002
@@ -112,6 +112,8 @@
 	__u8		ips_sens_integ_len;
 	__u64*		ips_sens_integ_bitmap;
 #endif
+	struct ipsec_alg_enc *ips_alg_enc;
+	struct ipsec_alg_auth *ips_alg_auth;
 };
 
 enum ipsec_direction {
Index: freeswan/klips/net/ipsec/ipsec_tunnel.c
diff -u freeswan/klips/net/ipsec/ipsec_tunnel.c:1.1.1.1 freeswan/klips/net/ipsec/ipsec_tunnel.c:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_tunnel.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_tunnel.c	Mon Apr 15 12:13:42 2002
@@ -61,6 +61,8 @@
 # include <linux/netfilter_ipv4.h>
 #endif /* NETDEV_23 */
 
+#include "ipsec_alg.h"
+
 #include <linux/if_arp.h>
 #ifdef MSS_HACK
 # include <net/tcp.h>		/* TCP options */
@@ -478,6 +480,7 @@
 /*	struct device *virtdev; */
 	short physmtu;
 	short mtudiff;
+	int blocksize = 8;
 #ifdef NET_21
 	struct rtable *rt = NULL;
 #endif /* NET_21 */
@@ -488,6 +491,10 @@
 	int error = 0;
 	uint32_t eroute_pid = 0;
 	struct ipsec_sa tdb;
+#ifdef CONFIG_IPSEC_ALG
+	struct ipsec_alg_enc *ixt_e = NULL;
+	struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
 
 	dport=sport=0;
 
@@ -1120,6 +1127,12 @@
 #endif /* CONFIG_IPSEC_AH */
 #ifdef CONFIG_IPSEC_ESP
 			case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+				if ((ixt_e=IPSEC_ALG_SA_ESP_ENC(tdbp))) {
+					blocksize = ixt_e->ixt_blocksize;
+					headroom += ESP_HEADER_LEN+blocksize;
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_encalg) {
 #ifdef CONFIG_IPSEC_ENC_3DES
 				case ESP_3DES:
@@ -1131,6 +1144,11 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}
+#ifdef CONFIG_IPSEC_ALG
+				if ((ixt_a=IPSEC_ALG_SA_ESP_AUTH(tdbp))) {
+					tailroom += AHHMAC_HASHLEN;
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_authalg) {
 #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
 				case AH_MD5:
@@ -1149,7 +1167,7 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}			
-				tailroom += ((8 - ((pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+				tailroom += ((blocksize - ((pyldsz + 2 * sizeof(unsigned char)) % blocksize)) % blocksize) + 2;
 				break;
 #endif /* !CONFIG_IPSEC_ESP */
 #ifdef CONFIG_IPSEC_IPIP
@@ -1180,6 +1198,10 @@
 				goto cleanup;
 			}
 			tdbp = tdbp->tdb_onext;
+#ifdef CONFIG_IPSEC_ALG
+			ixt_e = NULL;	/* invalidate ipsec_alg */
+			ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
 			KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
 				    "klips_debug:ipsec_tunnel_start_xmit: "
 				    "Required head,tailroom: %d,%d\n", 
@@ -1381,7 +1403,7 @@
 		while (tdbp) {
 #ifdef CONFIG_IPSEC_ESP
 			struct esp *espp;
-			__u32 iv[2];
+			__u32 iv[ESP_IV_MAXSZ_INT];
 			unsigned char *idat, *pad;
 			int authlen = 0, padlen = 0, i;
 #endif /* !CONFIG_IPSEC_ESP */
@@ -1420,6 +1442,12 @@
 #endif /* CONFIG_IPSEC_AH */
 #ifdef CONFIG_IPSEC_ESP
 			case IPPROTO_ESP:
+#ifdef CONFIG_IPSEC_ALG
+				if ((ixt_e=IPSEC_ALG_SA_ESP_ENC(tdbp))) {
+					blocksize = ixt_e->ixt_blocksize;
+					headroom += ESP_HEADER_LEN+blocksize;
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_encalg) {
 #ifdef CONFIG_IPSEC_ENC_3DES
 				case ESP_3DES:
@@ -1431,6 +1459,11 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}
+#ifdef CONFIG_IPSEC_ALG
+				if ((ixt_a=IPSEC_ALG_SA_ESP_AUTH(tdbp))) {
+					authlen = AHHMAC_HASHLEN;
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_authalg) {
 #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
 				case AH_MD5:
@@ -1449,7 +1482,7 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}		
-				tailroom += ((8 - ((pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+				tailroom += ((blocksize - ((pyldsz + 2 * sizeof(unsigned char)) % blocksize)) % blocksize) + 2;
 				tailroom += authlen;
 				break;
 #endif /* !CONFIG_IPSEC_ESP */
@@ -1517,6 +1550,9 @@
 				espp->esp_spi = tdbp->tdb_said.spi;
 				espp->esp_rpl = htonl(++(tdbp->tdb_replaywin_lastseq));
 				
+#ifdef CONFIG_IPSEC_ALG
+				if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_encalg) {
 #if defined(CONFIG_IPSEC_ENC_3DES)
 #ifdef CONFIG_IPSEC_ENC_3DES
@@ -1548,6 +1584,23 @@
 				dat[len - authlen - 1] = iph->protocol;
 				iph->protocol = IPPROTO_ESP;
 				
+#ifdef CONFIG_IPSEC_ALG
+				/* Do all operations here:
+				 * copy IV->ESP, encrypt, update ips IV
+				 */
+				if (ixt_e) {
+					int ret;
+					memcpy(espp->esp_iv, 
+						tdbp->ips_iv, 
+						ixt_e->ixt_blocksize);
+					ret=ipsec_alg_esp_encrypt(tdbp, 
+						idat, ilen, espp->esp_iv,
+						IPSEC_ALG_ENCRYPT);
+					memcpy(tdbp->ips_iv,
+						idat + ilen - ixt_e->ixt_blocksize,
+						ixt_e->ixt_blocksize);
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				switch(tdbp->tdb_encalg) {
 #ifdef CONFIG_IPSEC_ENC_3DES
 				case ESP_3DES:
@@ -1565,6 +1618,9 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}
+#ifdef CONFIG_IPSEC_ALG
+				if (!ixt_e)
+#endif /* CONFIG_IPSEC_ALG */
 				
 				switch(tdbp->tdb_encalg) {
 #if defined(CONFIG_IPSEC_ENC_3DES)
@@ -1583,6 +1639,14 @@
 					stats->tx_errors++;
 					goto cleanup;
 				}
+#ifdef CONFIG_IPSEC_ALG
+				if (ixt_a) {
+					ipsec_alg_sa_esp_hash(tdbp,
+					(caddr_t)espp, len - iphlen - authlen,
+					&(dat[len - authlen]), authlen);
+
+				} else
+#endif /* CONFIG_IPSEC_ALG */
 				
 				switch(tdbp->tdb_authalg) {
 #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
@@ -1833,6 +1897,10 @@
 
 			tdbprev = tdbp;
 			tdbp = tdbp->ips_onext;
+#ifdef CONFIG_IPSEC_ALG
+			ixt_e = NULL;	/* invalidate ipsec_alg */
+			ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
 			
 		}
 		/* end encapsulation loop here XXX */
Index: freeswan/klips/net/ipsec/ipsec_xform.h
diff -u freeswan/klips/net/ipsec/ipsec_xform.h:1.1.1.1 freeswan/klips/net/ipsec/ipsec_xform.h:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/ipsec_xform.h:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/ipsec_xform.h	Mon Apr 15 12:13:42 2002
@@ -46,6 +46,12 @@
 #define AH_NONE			0
 #define AH_MD5			2
 #define AH_SHA			3
+/* draft-ietf-ipsec-ciph-aes-cbc-03.txt */
+#define AH_SHA2_256		5
+#define AH_SHA2_384		6
+#define AH_SHA2_512		7
+#define AH_RIPEMD		8
+#define AH_MAX			15
 
 /* IPsec ESP transform values */
 
@@ -58,7 +64,14 @@
 #define ESP_3IDEA		8
 #define ESP_RC4			10
 #define ESP_NULL		11
+#define ESP_AES			12
 
+/* as draft-ietf-ipsec-ciph-aes-cbc-02.txt */
+#define ESP_MARS		249
+#define	ESP_RC6			250
+#define ESP_SERPENT		252
+#define ESP_TWOFISH		253
+			 
 /* IPCOMP transform values */
 
 #define IPCOMP_NONE		0
@@ -79,7 +92,16 @@
 	(x) == IPPROTO_IPIP ? "IPIP" : \
 	(x) == IPPROTO_COMP ? "COMP" : \
 	"UNKNOWN_proto"
-
+static inline const char *enc_name_id (unsigned id) {
+	static char buf[16];
+	snprintf(buf, sizeof(buf), "_ID%d", id);
+	return buf;
+}
+static inline const char *auth_name_id (unsigned id) {
+	static char buf[16];
+	snprintf(buf, sizeof(buf), "_ID%d", id);
+	return buf;
+}
 #define IPS_XFORM_NAME(x) \
 	PROTO2TXT((x)->ips_said.proto), \
 	(x)->ips_said.proto == IPPROTO_COMP ? \
@@ -87,11 +109,28 @@
 		 "_DEFLATE" : "_UNKNOWN_comp") : \
 	(x)->ips_encalg == ESP_NONE ? "" : \
 	(x)->ips_encalg == ESP_3DES ? "_3DES" : \
-	"_UNKNOWN_encr", \
+ 	(x)->ips_encalg == ESP_RC5 ? "_RC5" : \
+ 	(x)->ips_encalg == ESP_IDEA ? "_IDEA" : \
+ 	(x)->ips_encalg == ESP_CAST ? "_CAST" : \
+ 	(x)->ips_encalg == ESP_BLOWFISH ? "_BLOWFISH" : \
+ 	(x)->ips_encalg == ESP_3IDEA ? "_3IDEA" : \
+ 	(x)->ips_encalg == ESP_RC4 ? "_RC4" : \
+ 	(x)->ips_encalg == ESP_NULL ? "_NULL" : \
+ 	(x)->ips_encalg == ESP_AES ? "_AES" : \
+ 	(x)->ips_encalg == ESP_MARS ? "_MARS" : \
+ 	(x)->ips_encalg == ESP_RC6 ? "_RC6" : \
+ 	(x)->ips_encalg == ESP_TWOFISH ? "_TWOFISH" : \
+ 	(x)->ips_encalg == ESP_SERPENT ? "_SERPENT" : \
+	enc_name_id(x->ips_encalg)/* "_UNKNOWN_encr" */, \
 	(x)->ips_authalg == AH_NONE ? "" : \
 	(x)->ips_authalg == AH_MD5 ? "_HMAC_MD5" : \
 	(x)->ips_authalg == AH_SHA ? "_HMAC_SHA1" : \
-	"_UNKNOWN_auth" \
+	(x)->ips_authalg == AH_SHA2_256 ? "_HMAC_SHA2_256" : \
+	(x)->ips_authalg == AH_SHA2_384 ? "_HMAC_SHA2_384" : \
+	(x)->ips_authalg == AH_SHA2_512 ? "_HMAC_SHA2_512" : \
+	(x)->ips_authalg == AH_RIPEMD ? "_HMAC_RIPEMD" : \
+	auth_name_id(x->ips_authalg) /* "_UNKNOWN_auth" */ \
+
 
 #define _IPSEC_XFORM_H_
 #endif /* _IPSEC_XFORM_H_ */
Index: freeswan/klips/net/ipsec/pfkey_v2.c
diff -u freeswan/klips/net/ipsec/pfkey_v2.c:1.1.1.1 freeswan/klips/net/ipsec/pfkey_v2.c:1.1.1.1.2.1
--- freeswan/klips/net/ipsec/pfkey_v2.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/pfkey_v2.c	Mon Apr 15 12:13:42 2002
@@ -1619,13 +1619,23 @@
 	int i;
 	
 	static struct supported supported_init_ah[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
 		{SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
 		{SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1HMAC, 0, 160, 160}
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
 	};
 	static struct supported supported_init_esp[] = {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
 		{SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5HMAC, 0, 128, 128},
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
 		{SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1HMAC, 0, 160, 160},
-		{SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DESCBC, 128, 168, 168}
+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
+#ifdef CONFIG_IPSEC_ENC_3DES
+		{SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DESCBC, 64, 168, 168},
+#endif /* CONFIG_IPSEC_ENC_3DES */
 	};
 	static struct supported supported_init_ipip[] = {
 		{SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32}
Index: freeswan/klips/net/ipsec/pfkey_v2_parser.c
diff -u freeswan/klips/net/ipsec/pfkey_v2_parser.c:1.1.1.1 freeswan/klips/net/ipsec/pfkey_v2_parser.c:1.1.1.1.2.2
--- freeswan/klips/net/ipsec/pfkey_v2_parser.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/net/ipsec/pfkey_v2_parser.c	Tue Apr 16 11:46:43 2002
@@ -84,6 +84,7 @@
 
 #include "ipsec_proto.h"
 
+#include "ipsec_alg.h"
 
 #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
 
@@ -204,6 +205,9 @@
 	case IPPROTO_ESP:
 		tdbp->tdb_authalg = pfkey_sa->sadb_sa_auth;
 		tdbp->tdb_encalg = pfkey_sa->sadb_sa_encrypt;
+#ifdef CONFIG_IPSEC_ALG
+		ipsec_alg_sa_init(tdbp);
+#endif /* CONFIG_IPSEC_ALG */
 		break;
 	case IPPROTO_IPIP:
 		tdbp->tdb_authalg = AH_NONE;
@@ -784,6 +788,10 @@
 	char ipaddr_txt[ADDRTOA_BUF];
 	char ipaddr2_txt[ADDRTOA_BUF];
 	unsigned char kb[AHMD596_BLKLEN];
+#ifdef CONFIG_IPSEC_ALG
+	struct ipsec_alg_enc *ixt_e = NULL;
+	struct ipsec_alg_auth *ixt_a = NULL;
+#endif /* CONFIG_IPSEC_ALG */
 
 	if(!tdbp) {
 		KLIPS_PRINT(debug_pfkey,
@@ -992,20 +1000,20 @@
 		unsigned char *akp, *ekp;
 		unsigned int aks, eks;
 		
+		tdbp->tdb_iv_size = 0;
+#ifdef CONFIG_IPSEC_ALG
+		if ((ixt_e=IPSEC_ALG_SA_ESP_ENC(tdbp))) {
+			tdbp->tdb_iv_size = ixt_e->ixt_blocksize;
+		} else	
+#endif /* CONFIG_IPSEC_ALG */
 		switch(tdbp->tdb_encalg) {
 # ifdef CONFIG_IPSEC_ENC_3DES
 		case ESP_3DES:
 # endif /* CONFIG_IPSEC_ENC_3DES */
 # if 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);
-			tdbp->tdb_iv_bits = tdbp->tdb_iv_size * 8;
-			break;
+			tdbp->tdb_iv_size = EMT_ESPDES_IV_SZ;
 # endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-		case ESP_NONE:
+                case ESP_NONE:
 			break;
 		default:
 			KLIPS_PRINT(debug_pfkey,
@@ -1014,7 +1022,23 @@
 				    tdbp->tdb_encalg);
 			SENDERR(EINVAL);
 		}
+
+		/* Create IV */
+		if (tdbp->tdb_iv_size) {
+			if((tdbp->tdb_iv = (caddr_t)
+			    kmalloc(tdbp->tdb_iv_size, GFP_ATOMIC)) == NULL) {
+				SENDERR(ENOMEM);
+			}
+			get_random_bytes((void *)tdbp->tdb_iv, tdbp->tdb_iv_size);
+			tdbp->tdb_iv_bits = tdbp->tdb_iv_size * 8;
+		}
 		
+#ifdef CONFIG_IPSEC_ALG
+		if (ixt_e) {
+			if ((error=ipsec_alg_enc_key_create(tdbp)) < 0)
+				SENDERR(-error);
+		} else
+#endif /* CONFIG_IPSEC_ALG */
 		switch(tdbp->tdb_encalg) {
 # ifdef CONFIG_IPSEC_ENC_3DES
 		case ESP_3DES:
@@ -1071,7 +1095,7 @@
 			kfree(ekp);
 			break;
 # endif /* CONFIG_IPSEC_ENC_3DES */
-		case ESP_NONE:
+                case ESP_NONE:
 			break;
 		default:
 			KLIPS_PRINT(debug_pfkey,
@@ -1080,6 +1104,13 @@
 				    tdbp->tdb_encalg);
 			SENDERR(EINVAL);
 		}
+
+#ifdef CONFIG_IPSEC_ALG
+		if ((ixt_a=IPSEC_ALG_SA_ESP_AUTH(tdbp))) {
+			if ((error=ipsec_alg_auth_key_create(tdbp)) < 0)
+				SENDERR(-error);
+		} else	
+#endif /* CONFIG_IPSEC_ALG */
 		
 		switch(tdbp->tdb_authalg) {
 # ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
@@ -2241,20 +2272,12 @@
 DEBUG_NO_STATIC int
 pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
 {
-	unsigned int alg_num_a = 0, alg_num_e = 0;
-	struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
-	struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-	struct sadb_msg *pfkey_reply = NULL;
-	struct supported_list *pfkey_supported_listp;
-	struct socket_list *pfkey_socketsp;
 	int error = 0;
 	uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
 
 	KLIPS_PRINT(debug_pfkey,
 		    "klips_debug:pfkey_register_parse: .\n");
 
-	pfkey_extensions_init(extensions_reply);
-
 	/* XXX I don't know if we want an upper bound, since userspace may
 	   want to register itself for an satype > SADB_SATYPE_MAX. */
 	if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
@@ -2276,36 +2299,68 @@
 	};
 	
 	/* send up register msg with supported SATYPE algos */
+
+	error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[SADB_EXT_RESERVED]);
+ errlab:
+	return error;
+}
+DEBUG_NO_STATIC int
+pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
+{
+	struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
+	struct sadb_msg *pfkey_reply = NULL;
+	struct socket_list *pfkey_socketsp;
+	struct supported_list *pfkey_supported_listp;
+	unsigned int alg_num_a = 0, alg_num_e = 0;
+	struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
+	int error = 0;
+
+	pfkey_extensions_init(extensions_reply);
+
+	if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+			    "SAtype=%d unspecified or unknown.\n",
+			    satype);
+		SENDERR(EINVAL);
+	}
+	if(!(pfkey_registered_sockets[satype])) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+			    "no sockets registered for SAtype=%d(%s).\n",
+			    satype,
+			    satype2name(satype));
+		SENDERR(EPROTONOSUPPORT);
+	}
+	/* send up register msg with supported SATYPE algos */
 	pfkey_supported_listp = pfkey_supported_list[satype];
 	KLIPS_PRINT(debug_pfkey,
-		    "klips_debug:pfkey_register_parse: "
+		    "klips_debug:pfkey_register_reply: "
 		    "pfkey_supported_list[%d]=%p\n",
 		    satype,
 		    pfkey_supported_list[satype]);
 	while(pfkey_supported_listp) {
 		KLIPS_PRINT(debug_pfkey,
-			    "klips_debug:pfkey_register_parse: "
+			    "klips_debug:pfkey_register_reply: "
 			    "checking supported=%p\n",
 			    pfkey_supported_listp);
 		if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
 			KLIPS_PRINT(debug_pfkey,
-				    "klips_debug:pfkey_register_parse: "
+				    "klips_debug:pfkey_register_reply: "
 				    "adding auth alg.\n");
 			alg_num_a++;
 		}
 		if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
 			KLIPS_PRINT(debug_pfkey,
-				    "klips_debug:pfkey_register_parse: "
+				    "klips_debug:pfkey_register_reply: "
 				    "adding encrypt alg.\n");
 			alg_num_e++;
 		}
 		pfkey_supported_listp = pfkey_supported_listp->next;
 	}
-	
+
 	if(alg_num_a) {
 		if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
 			KLIPS_PRINT(debug_pfkey,
-				    "klips_debug:pfkey_register_parse: "
+				    "klips_debug:pfkey_register_reply: "
 				    "auth alg memory allocation error\n");
 			SENDERR(ENOMEM);
 		}
@@ -2315,7 +2370,7 @@
 	if(alg_num_e) {
 		if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
 			KLIPS_PRINT(debug_pfkey,
-				    "klips_debug:pfkey_register_parse: "
+				    "klips_debug:pfkey_register_reply: "
 				    "enc alg memory allocation error\n");
 			SENDERR(ENOMEM);
 		}
@@ -2332,7 +2387,7 @@
 				alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
 				alg_ap->sadb_alg_reserved = 0;
 				KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-					    "klips_debug:pfkey_register_parse: "
+					    "klips_debug:pfkey_register_reply: "
 					    "adding auth=%p\n",
 					    alg_ap);
 				alg_ap++;
@@ -2346,14 +2401,14 @@
 				alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
 				alg_ep->sadb_alg_reserved = 0;
 				KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-					    "klips_debug:pfkey_register_parse: "
+					    "klips_debug:pfkey_register_reply: "
 					    "adding encrypt=%p\n",
 					    alg_ep);
 				alg_ep++;
 			}
 		}
 		KLIPS_PRINT(debug_pfkey,
-			    "klips_debug:pfkey_register_parse: "
+			    "klips_debug:pfkey_register_reply: "
 			    "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
 			    satype,
 			    satype2name(satype),
@@ -2364,13 +2419,12 @@
 			    pfkey_supported_listp->supportedp->supported_alg_maxbits);
 		pfkey_supported_listp = pfkey_supported_listp->next;
 	}
-	
 	if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
 							  SADB_REGISTER,
 							  satype,
 							  0,
-							  ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-							  ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
+							  sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq,
+							  sadb_msg? sadb_msg->sadb_msg_pid: current->pid),
 			      extensions_reply) &&
 	     (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_AUTH],
 									SADB_EXT_SUPPORTED_AUTH,
@@ -2382,30 +2436,31 @@
 									alg_num_e,
 									alg_e),
 					  extensions_reply) : 1))) {
-		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_parse: "
-			    "failed to build the register message extensions\n");
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+			    "failed to build the register message extensions_reply\n");
 		SENDERR(-error);
 	}
 	
 	if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_parse: "
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
 			    "failed to build the register message\n");
 		SENDERR(-error);
 	}
+	/* this should go to all registered sockets for that satype only */
 	for(pfkey_socketsp = pfkey_registered_sockets[satype];
 	    pfkey_socketsp;
 	    pfkey_socketsp = pfkey_socketsp->next) {
 		if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-			KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_parse: "
-				    "sending up register reply message for satype=%d(%s) to socket=%p failed with error=%d.\n",
+			KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+				    "sending up acquire message for satype=%d(%s) to socket=%p failed with error=%d.\n",
 				    satype,
 				    satype2name(satype),
 				    pfkey_socketsp->socketp,
 				    error);
 			SENDERR(-error);
 		}
-		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_parse: "
-			    "sending up register reply message for satype=%d(%s) to socket=%p succeeded.\n",
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
+			    "sending up register message for satype=%d(%s) to socket=%p succeeded.\n",
 			    satype,
 			    satype2name(satype),
 			    pfkey_socketsp->socketp);
@@ -2418,7 +2473,6 @@
 	if(alg_e) {
 		kfree(alg_e);
 	}
-
 	if (pfkey_reply) {
 		pfkey_msg_free(&pfkey_reply);
 	}
Index: freeswan/klips/net/ipsec/alg/Makefile
diff -u /dev/null freeswan/klips/net/ipsec/alg/Makefile:1.1.2.9
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/klips/net/ipsec/alg/Makefile	Tue Jun  4 10:15:47 2002
@@ -0,0 +1,100 @@
+# $Id: Makefile,v 1.1.2.9 2002/06/04 13:15:47 jjo Exp $
+KLIPSDIR:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)/..
+
+#LIBCRYPTO:=$(KLIPSDIR)/../../../libcrypto
+LIBCRYPTO:=$(KLIPSDIR)/libcrypto
+EXTRA_CFLAGS:=-I$(KLIPSDIR) -I$(KLIPSDIR)/libfreeswan -I$(LIBCRYPTO)/include -I$(LIBCRYPTO)
+ifeq ($(CONFIG_IPSEC_DEBUG),y)
+EXTRA_CFLAGS += -g
+endif
+EXTRA_CFLAGS += -Wall -Wpointer-arith -Wstrict-prototypes
+
+MOD_LIST_NAME := NET_MISC_MODULES
+
+#O_TARGET := ipsec_alg_static.o
+
+subdir-  := 
+subdir-n := 
+subdir-y :=
+subdir-m :=
+
+obj-y := ipsec_alg_static_init.o
+
+ARCH_ASM-y :=
+ARCH_ASM-$(CONFIG_M586)		:= i586
+ARCH_ASM-$(CONFIG_M586TSC)	:= i586
+ARCH_ASM-$(CONFIG_M586MMX)	:= i586
+ARCH_ASM-$(CONFIG_MK6)		:= i586
+ARCH_ASM-$(CONFIG_M686)		:= i686
+ARCH_ASM-$(CONFIG_MPENTIUMIII)	:= i686
+ARCH_ASM-$(CONFIG_MPENTIUM4)	:= i686
+ARCH_ASM-$(CONFIG_MK7)		:= i686
+ARCH_ASM-$(CONFIG_MCRUSOE)	:= i586
+ARCH_ASM-$(CONFIG_MWINCHIPC6)	:= i586
+ARCH_ASM-$(CONFIG_MWINCHIP2)	:= i586
+ARCH_ASM-$(CONFIG_MWINCHIP3D)	:= i586
+ARCH_ASM-$(CONFIG_USERMODE)	:= i586
+
+ARCH_ASM :=$(ARCH_ASM-y)
+ifdef NO_ASM
+ARCH_ASM :=
+endif
+
+# The algorithm makefiles may put dependences, short-circuit them
+null:
+
+makefiles=$(wildcard Makefile.alg_*)
+ifneq ($(makefiles), "")
+#include Makefile.alg_aes
+#include Makefile.alg_aes-opt
+include $(makefiles)
+endif
+
+# These rules translate from new to old makefile rules
+# Translate to Rules.make lists.
+multi-used      := $(filter $(list-multi), $(obj-y) $(obj-m))
+multi-objs      := $(foreach m, $(multi-used), $($(basename $(m))-objs))
+active-objs     := $(sort $(multi-objs) $(obj-y) $(obj-m))
+O_OBJS          := $(obj-y)
+M_OBJS          := $(obj-m)
+MIX_OBJS        := $(filter $(export-objs), $(active-objs))
+#OX_OBJS := $(export-objs)
+SUB_DIRS := $(subdir-y)
+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
+MOD_SUB_DIRS := $(subdir-m)
+
+
+ifdef TOPDIR
+include $(TOPDIR)/Rules.make
+endif
+
+ipsec_alg_static.o: $(obj-y) 
+	rm -f $@
+	$(LD) $(LD_EXTRAFLAGS) $(obj-y) -r -o $@
+
+perlasm: $(LIBCRYPTO)/perlasm
+	ln -sf $? $@
+
+$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h ../ipsec_alg.h
+$(alg_obj-y) $(alg_obj-m): perlasm $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h ../ipsec_alg.h
+
+
+alg_modules: perlasm $(ALG_MODULES)
+	@echo "ALG_MODULES=$(ALG_MODULES)"
+
+
+#
+# Construct alg. init. function: call ipsec_ALGO_init() for every static algo
+# Needed when there are static algos (with static or modular ipsec.o)
+#
+ipsec_alg_static_init.c: $(TOPDIR)/include/linux/autoconf.h Makefile $(makefiles) scripts/mk-static_init.c.sh
+	@echo "Re-creating $@"
+	$(SHELL) scripts/mk-static_init.c.sh $(static_init-func-y) > $@
+
+clean:
+	@for i in $(ALG_SUBDIRS);do test -d $$i && make -C $$i clean;done;exit 0
+	@find . -type l  -exec rm -f {} \;
+	-rm -f perlasm
+	-rm -rf $(ALG_SUBDIRS)
+	-rm -f *.o ipsec_alg_static_init.c
+
Index: freeswan/klips/net/ipsec/alg/scripts/mk-static_init.c.sh
diff -u /dev/null freeswan/klips/net/ipsec/alg/scripts/mk-static_init.c.sh:1.1.2.1
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/klips/net/ipsec/alg/scripts/mk-static_init.c.sh	Tue Apr 23 15:20:48 2002
@@ -0,0 +1,17 @@
+#!/bin/sh
+cat << EOF
+#include <linux/kernel.h>
+#include "../ipsec_alg.h"
+$(for i in $*; do
+	test -z "$i" && continue
+	echo "extern int $i(void);"
+done)
+void ipsec_alg_static_init(void){ 
+	int __attribute__ ((unused)) err=0;
+$(for i in $*; do
+	test -z "$i" && continue
+	echo "	if ((err=$i()) < 0)"
+	echo "		printk(KERN_WARNING \"$i() returned %d\", err);"
+done)
+}
+EOF
--- freeswan/klips/net/ipsec/alg/Config.in	Sun Dec 16 10:24:55 2001
+++ freeswan/klips/net/ipsec/alg/Config.in	Sun Dec 16 10:24:52 2001
@@ -0,0 +1 @@
+#Placeholder
Index: freeswan/klips/utils/Makefile
diff -u freeswan/klips/utils/Makefile:1.1.1.1 freeswan/klips/utils/Makefile:1.1.1.1.2.1
--- freeswan/klips/utils/Makefile:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/utils/Makefile	Mon Apr 15 12:13:43 2002
@@ -54,8 +54,17 @@
 	for f in $(addsuffix .5, $(ALL) version pf_key) ; do \
 		$(INSTALL) $$f $(MANDIR5)/ipsec_$$f || exit 1 ; done
 
-spi: spi.o
-	$(CC) $(DFLAGS) -o $@ $? $(FREESWANLIB)
+constants.o : ../../pluto/constants.c ../../pluto/constants.h
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+alg_info.o : ../../pluto/alg_info.c ../../pluto/alg_info.h
+	$(CC) $(CFLAGS) -DNO_PLUTO -c -o $@ $<
+
+kernel_alg.o : ../../pluto/kernel_alg.c ../../pluto/kernel_alg.h
+	$(CC) $(CFLAGS) -DNO_PLUTO -c -o $@ $<
+
+spi: spi.o constants.o alg_info.o kernel_alg.o
+	$(CC) $(DFLAGS) -o $@ $^ $(FREESWANLIB)
 
 eroute: eroute.o
 	$(CC) $(DFLAGS) -o $@ $? $(FREESWANLIB)
Index: freeswan/klips/utils/spi.c
diff -u freeswan/klips/utils/spi.c:1.1.1.1 freeswan/klips/utils/spi.c:1.1.1.1.2.3
--- freeswan/klips/utils/spi.c:1.1.1.1	Mon Apr 15 12:08:57 2002
+++ freeswan/klips/utils/spi.c	Wed May 29 23:12:47 2002
@@ -46,6 +46,18 @@
 #include <pfkey.h>
 #include "ipsec_xform.h"
 
+/* 	
+ * 	Manual conn support for ipsec_alg (modular algos).
+ * 	Rather ugly to include from pluto dir but avoids
+ * 	code duplication.
+ */
+#ifndef NO_KERNEL_ALG
+#include "../../pluto/alg_info.h"
+#include "../../pluto/constants.h"
+struct connection;
+#include "../../pluto/kernel_alg.h"
+#endif /* NO_KERNEL_ALG */
+
 char *program_name;
 char me[] = "ipsec spi";
 int debug = 0;
@@ -59,6 +71,20 @@
 int address_family = 0;
 unsigned char proto = 0;
 int alg = 0;
+
+#ifndef NO_KERNEL_ALG
+/* 
+ * 	Manual connection support for modular algos (ipsec_alg) --Juanjo.
+ */
+#define XF_OTHER_ALG (XF_CLR-1)	/* define magic XF_ symbol for alg_info's */
+#include <assert.h>
+const char *alg_string = NULL;	/* algorithm string */
+struct alg_info_esp *alg_info = NULL;	/* algorithm info got from string */
+struct esp_info *esp_info = NULL;	/* esp info from 1st (only) element */
+const char *alg_err;		/* auxiliar for parsing errors */
+int proc_read_ok = 0;		/* /proc/net/pf_key_support read ok */
+#endif /* NO_KERNEL_ALG */
+
 int replay_window = 0;
 char sa[SATOT_BUF];
 
@@ -539,6 +565,50 @@
 				alg = XF_ESP3DESSHA196;
 			} else if(!strcmp(optarg, "3des")) {
 				alg = XF_ESP3DES;
+#ifndef NO_KERNEL_ALG
+			} else if((alg_info=alg_info_esp_create_from_str(optarg, &alg_err))) {
+				int esp_ealg_id, esp_aalg_id;
+				alg = XF_OTHER_ALG;
+				if (alg_info->alg_info_cnt>1) {
+					fprintf(stderr, "%s: Invalid encryption algorithm '%s' "
+						"follows '--esp' option: lead too many(%d) "
+						"transforms\n",
+						program_name, optarg, alg_info->alg_info_cnt);
+					exit(1);
+				}
+				alg_string=optarg;
+				esp_info=&alg_info->esp[0];
+				if (debug) {
+					fprintf(stdout, "%s: alg_info: cnt=%d ealg[0]=%d aalg[0]=%d\n",
+						program_name, 
+						alg_info->alg_info_cnt,
+						esp_info->encryptalg,
+						esp_info->authalg);
+				}
+				esp_ealg_id=esp_info->esp_ealg_id;
+				esp_aalg_id=esp_info->esp_aalg_id;
+				if (kernel_alg_proc_read()==0) {
+					proc_read_ok++;
+					if (!kernel_alg_esp_enc_ok(esp_ealg_id, 0, 0))
+					{
+						fprintf(stderr, "%s: ESP encryptalg=%d (\"%s\") "
+								"not present\n",
+							program_name,
+							esp_ealg_id,
+							enum_name(&esp_transformid_names, esp_ealg_id));
+						exit(1);
+					}
+					if (!kernel_alg_esp_auth_ok(esp_aalg_id, 0))
+					{
+						fprintf(stderr, "%s: ESP authalg=%d (\"%s\")"
+								"not present\n",
+							program_name,
+							esp_aalg_id,
+							enum_name(&auth_alg_names, esp_aalg_id));
+						exit(1);
+					}
+				}
+#endif /* NO_KERNEL_ALG */
 			} else {
 				fprintf(stderr, "%s: Invalid encryption algorithm '%s' follows '--esp' option.\n",
 					program_name, optarg);
@@ -939,6 +1009,63 @@
 	}
 
 	switch(alg) {
+#ifndef NO_KERNEL_ALG
+	case XF_OTHER_ALG: 
+		/* validate keysizes */
+		if (proc_read_ok) {
+		       const struct sadb_alg *alg_p;
+		       int keylen, minbits, maxbits;
+		       alg_p=kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,SADB_EXT_SUPPORTED_ENCRYPT, 
+				       esp_info->encryptalg);
+		       assert(alg_p);
+		       keylen=enckeylen * 8;
+
+		       if (alg_p->sadb_alg_id==ESP_3DES) {
+			       maxbits=minbits=alg_p->sadb_alg_minbits * 8 /7;
+		       } else {
+			       minbits=alg_p->sadb_alg_minbits;
+			       maxbits=alg_p->sadb_alg_maxbits;
+		       }
+		       /* 
+			* if explicit keylen told in encrypt algo, eg "aes128"
+			* check actual keylen "equality"
+			*/
+		       if (esp_info->esp_ealg_keylen &&
+			       esp_info->esp_ealg_keylen!=keylen) {
+			       fprintf(stderr, "%s: invalid encryption keylen=%d, "
+					       "required %d by encrypt algo string=\"%s\"\n",
+				       program_name, 
+				       keylen,
+				       esp_info->esp_ealg_keylen,
+				       alg_string);
+			       exit(1);
+
+		       }
+		       /* thanks DES for this sh*t */
+
+		       if (minbits > keylen || maxbits < keylen) {
+			       fprintf(stderr, "%s: invalid encryption keylen=%d, "
+					       "must be between %d and %d bits\n",
+					       program_name, 
+					       keylen, minbits, maxbits);
+			       exit(1);
+		       }
+		       alg_p=kernel_alg_sadb_alg_get(SADB_SATYPE_ESP,SADB_EXT_SUPPORTED_AUTH, 
+				       esp_info->authalg);
+		       assert(alg_p);
+		       keylen=authkeylen * 8;
+		       minbits=alg_p->sadb_alg_minbits;
+		       maxbits=alg_p->sadb_alg_maxbits;
+		       if (minbits > keylen || maxbits < keylen) {
+			       fprintf(stderr, "%s: invalid auth keylen=%d, "
+					       "must be between %d and %d bits\n",
+					       program_name, 
+					       keylen, minbits, maxbits);
+			       exit(1);
+		       }
+
+		}
+#endif /* NO_KERNEL_ALG */
 	case XF_IP4:
 	case XF_IP6:
 	case XF_DEL:
@@ -1000,6 +1127,9 @@
 	case XF_ESP3DESSHA196:
 	case XF_ESP3DES:
 	case XF_COMPDEFLATE:
+#ifndef NO_KERNEL_ALG
+	case XF_OTHER_ALG:
+#endif /* NO_KERNEL_ALG */
 		break;
 	default:
 		fprintf(stderr, "%s: No action chosen.  See '%s --help' for usage.\n",
@@ -1136,6 +1266,15 @@
 	case XF_ESP3DESSHA196:
 		authalg = SADB_AALG_SHA1HMAC;
 		break;
+#ifndef NO_KERNEL_ALG
+	case XF_OTHER_ALG:
+		authalg= esp_info->authalg;
+		if(debug) {
+			fprintf(stdout, "%s: debug: authalg=%d\n",
+				program_name, authalg);
+		}
+		break;
+#endif /* NO_KERNEL_ALG */
 	case XF_ESP3DESMD5:
 	default:
 		authalg = SADB_AALG_NONE;
@@ -1149,6 +1288,15 @@
 	case XF_COMPDEFLATE:
 		encryptalg = SADB_X_CALG_DEFLATE;
 		break;
+#ifndef NO_KERNEL_ALG
+	case XF_OTHER_ALG:
+		encryptalg= esp_info->encryptalg;
+		if(debug) {
+			fprintf(stdout, "%s: debug: encryptalg=%d\n",
+				program_name, encryptalg);
+		}
+		break;
+#endif /* NO_KERNEL_ALG */
 	default:
 		encryptalg = SADB_EALG_NONE;
 	}
@@ -1334,6 +1482,9 @@
 		case XF_ESP3DESMD596:
 		case XF_AHHMACSHA1:
 		case XF_ESP3DESSHA196:
+#ifndef NO_KERNEL_ALG
+		case XF_OTHER_ALG:
+#endif /* NO_KERNEL_ALG */
 			if((error = pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH],
 						    SADB_EXT_KEY_AUTH,
 						    authkeylen * 8,
@@ -1355,6 +1506,9 @@
 		case XF_ESP3DES:
 		case XF_ESP3DESMD596:
 		case XF_ESP3DESSHA196:
+#ifndef NO_KERNEL_ALG
+		case XF_OTHER_ALG:
+#endif /* NO_KERNEL_ALG */
 			if((error = pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT],
 						    SADB_EXT_KEY_ENCRYPT,
 						    enckeylen * 8,

