--- openswan-2.4.13.org/Makefile.inc	2008-06-26 23:03:04.000000000 +0200
+++ openswan-2.4.13/Makefile.inc	2008-06-27 13:38:04.000000000 +0200
@@ -15,6 +15,25 @@
 # RCSID $Id: Makefile.inc,v 1.116.2.16 2007-11-02 03:07:27 paul Exp $
 
 
+#
+#include $(KERNELSRC)/.config
+#ifneq ($(CONFIG_OCF_CRYPTODEV),)
+HAVE_OCF := true
+#endif
+ifneq ($(CONFIG_LIB_LIBSSL),)
+HAVE_OPENSSL := true
+endif
+ifneq ($(CONFIG_USER_FLATFSD_FLATFSD),)
+USE_SINGLE_CONF_DIR := true
+endif
+ifneq ($(CONFIG_LIB_LIBPAM_FORCE)$(CONFIG_LIB_LIBPAM),)
+USE_XAUTHPAM := true
+HAVE_THREADS := true # the comments below about XAUTH say we need threads
+endif
+ifdef CONFIG_PROP_STATSD_STATSD
+EXTRA_DEFINES += -DEXTERNAL_STATE_LOGGING=1
+endif
+
 
 # Variables in this file with names starting with INC_ are not for use
 # by Makefiles which include it; they are subject to change without warning.
@@ -338,6 +357,11 @@
 # device. Normal use does not need any of this.
 USE_WEAKSTUFF?=false
 
+# Do we want all the configuration files like ipsec.conf and ipsec.secrets
+# and any certificates to be in a single directory defined by 
+# FINALCONFDDIR?
+USE_SINGLE_CONF_DIR?=false
+
 # should we include additional algorithms? It adds lots of
 # code space increases risk of bad crypto code, but offers possibilities 
 # of switching away from AES/3DES quickly. 
@@ -348,6 +372,12 @@
 # 
 HAVE_THREADS?=false
 
+# Do we have OCF available?
+HAVE_OCF?=false
+
+# Do we have Openssl libraries available for BIGNUM support?
+HAVE_OPENSSL?=false
+
 # Do we assume that the /bin/sh is BASH?
 # if so, then internationalization code is retained in the shell scripts
 USE_BASH?=true
--- openswan-2.4.13.org/include/pluto_constants.h	2005-11-16 23:41:30.000000000 +0100
+++ openswan-2.4.13/include/pluto_constants.h	2008-06-27 13:38:04.000000000 +0200
@@ -41,7 +41,8 @@
 enum dpd_action {
   DPD_ACTION_CLEAR = 0,
   DPD_ACTION_HOLD  = 1,
-  DPD_ACTION_RESTART =2
+  DPD_ACTION_RESTART = 2,
+  DPD_ACTION_RESTART_BY_PEER = 3
 };
 
 
--- openswan-2.4.13.org/lib/libcrypto/libaes/Makefile	2007-10-22 16:29:29.000000000 +0200
+++ openswan-2.4.13/lib/libcrypto/libaes/Makefile	2008-06-27 13:38:04.000000000 +0200
@@ -56,6 +56,11 @@
 #CFLAGS+= -Wwrite-strings
 CFLAGS+= -Wbad-function-cast 
 
+ifeq ($(HAVE_OCF),true)
+	CFLAGS += -DOCF_ASSIST=1
+	AES_CORE_OBJ += ocf_aes_assist.o
+endif
+
 .PHONY:	all install clean check depend checkprograms
 
 all:	$(LIB) 
--- openswan-2.4.13.org/lib/libcrypto/libaes/ocf_aes_assist.c	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/lib/libcrypto/libaes/ocf_aes_assist.c	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,224 @@
+/****************************************************************************/
+/*
+ * Use OCF/cryptodev interface for AES processing
+ * written by Toby Smith <toby@snapgear.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <fcntl.h>
+#include <linux/types.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include "crypto/aes.h"
+#include "crypto/aes_cbc.h"
+#include "crypto/ocf_assist.h"
+
+/****************************************************************************/
+
+#include <crypto/cryptodev.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static int crypto_fd = -1;
+static int crypto_tested = 0;
+
+/* have we found a functional ocf_assist method */
+static int have_assist = 0;
+
+/****************************************************************************/
+/*
+ *	return true if HW aes is present
+ *  The return value can also be used to determine which ocf_assist engine
+ *  has been detected. See the values in ocf_assist.h
+ */
+
+int
+ocf_aes_assist(void)
+{
+    if (!crypto_tested && !have_assist) {
+        crypto_fd = open("/dev/crypto", O_RDWR);
+
+        /* set the close-on-exec flag */
+        if ((crypto_fd < 0) || (fcntl(crypto_fd, F_SETFD, 1) < 0)) {
+            close(crypto_fd);
+            crypto_fd = -1;
+        }
+
+		if (crypto_fd != -1) {
+			struct session_op ses;
+			/* we have opened /dev/crypto */
+
+			/* test we can do aes */
+			memset(&ses, 0, sizeof(ses));
+			ses.key = (caddr_t)"12345678901234567890123456789012";
+			ses.cipher = CRYPTO_AES_CBC;
+			ses.keylen = 16;
+			if (ioctl(crypto_fd, CIOCGSESSION, &ses) != -1 &&
+				ioctl(crypto_fd, CIOCFSESSION, &ses.ses) != -1) {
+				/* fprintf(stderr, "AES_CBC capable\n"); */
+				have_assist |= OCF_PROVIDES_AES;
+			} else {
+				/* fprintf(stderr, "NOT AES_CBC capable\n"); */
+				close(crypto_fd);
+				crypto_fd = -1;
+			}
+
+			crypto_tested = 1;
+		}
+    }
+    return(have_assist);
+}
+
+/****************************************************************************/
+
+void
+ocf_aes_set_key(
+	aes_context (*cx),
+	const unsigned char in_key[],
+	int length,
+	const int f)
+{  
+#if defined(AES_BLOCK_SIZE)
+#define nc   (AES_BLOCK_SIZE / 4)
+#else
+#define nc   (cx->aes_Ncol)
+#endif
+
+    switch(length) {
+    case 32:			/* bytes */
+    case 256:			/* bits */
+		cx->aes_Nkey = 8;
+		break;
+    case 24:			/* bytes */
+    case 192:			/* bits */
+		cx->aes_Nkey = 6;
+		break;
+    case 16:			/* bytes */
+    case 128:			/* bits */
+    default:
+		cx->aes_Nkey = 4;
+		break;
+    }
+    cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6;
+    memcpy (cx->aes_e_key, in_key, cx->aes_Nkey*4);
+}
+
+/****************************************************************************/
+
+static void
+ocf_aes_cryptodev_internal(
+    u_int32_t cipher,
+    char (*key),
+    u_int32_t keylen,
+    u_int32_t operation,
+    __u8 (*src),
+    __u8 (*dst),
+    long len,
+    __u8 (*iv),
+    u_int32_t iv_len)
+{
+    struct session_op sop;
+    struct crypt_op cop;
+    u_int32_t fixed_len = len;
+    __u8 *fixed_src = NULL;
+
+    /* always make fixed_len a multiple of 16 - otherwise the CIOCCRYPT fails */
+    fixed_len = (len + 15) & ~15;
+
+    /*
+	 * if the input stream's length is not a multiple of 16, copy and zero pad
+	 */ 
+	if ((len & 15) && operation == COP_ENCRYPT) {
+        /* slow but safe */
+        fixed_src = (__u8 *)malloc(fixed_len);
+        if (!fixed_src) return;
+        memset(fixed_src + fixed_len - 15, 0, 15);
+        memcpy(fixed_src, src, len);
+    } else {
+        fixed_src = (__u8 *) src;
+    }
+
+    /*
+     * XXX
+     * cryptodev enforces the concept of a crypto session
+     * in which you perform operations. This ocf_assist stuff doesn't currently
+     * support that. So for now I'm creating sessions for each operation. 
+     */
+
+    /* create a session */
+    bzero(&sop, sizeof(sop));
+    sop.cipher = cipher;
+	sop.keylen = keylen;
+    sop.key = key;
+
+    if (ioctl(crypto_fd, CIOCGSESSION, &sop) < 0) {
+        /* fatal error condition - bail out */
+		goto failed;
+    }
+
+
+    /* perform the operation */
+    bzero(&cop, sizeof(cop));
+    cop.ses = sop.ses;
+    cop.op = operation;
+    cop.src = (char *)fixed_src;
+    cop.dst = (char *)dst;
+    cop.len = fixed_len;
+    cop.iv = iv;
+    if (ioctl(crypto_fd, CIOCCRYPT, &cop) < 0) {
+        /* fprintf(stderr, "%s CIOCCRYPT failed\n", __FUNCTION__);  */
+		goto failed;
+    }
+
+    if (ioctl(crypto_fd, CIOCFSESSION, &sop.ses) == -1)
+		goto failed;
+
+    if (fixed_src != src) free(fixed_src);
+	return;
+
+failed:
+	memset(dst, 0, len);
+    if (fixed_src != src) free(fixed_src);
+    return;
+}
+
+/****************************************************************************/
+
+int
+ocf_aes_cbc_encrypt(
+	aes_context *ctx,
+	__u8 (*input),
+	__u8 (*output),
+	long length,
+	__u8 (*ivec),
+	int enc)
+{
+	if (crypto_fd != -1) {
+		ocf_aes_cryptodev_internal(	
+			CRYPTO_AES_CBC,
+			/* ctx->aes_d_key isn't used here, just aes_e_key ??? */
+			/* enc ? ctx->aes_e_key : ctx->aes_d_key, */
+			(char *) ctx->aes_e_key,
+			ctx->aes_Nkey*4,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			input,
+			output,
+			length,
+			ivec,
+			16);
+		return length;
+	}
+	return length;
+}
+
+/****************************************************************************/
--- openswan-2.4.13.org/lib/libcrypto/libdes/Makefile	2007-10-22 16:31:29.000000000 +0200
+++ openswan-2.4.13/lib/libcrypto/libdes/Makefile	2008-06-27 13:38:04.000000000 +0200
@@ -64,12 +64,22 @@
 CPP=$(CC) -E
 
 # Assember version of des_encrypt*().
-DES_ENC=des_enc.o fcrypt_b.o		# normal C version
+DES_ENC=des_enc.o 
+#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 
 
+ifeq ($(HAVE_OCF),true)
+	EXTRA_CFLAGS += -DOCF_ASSIST=1
+	CPPFLAGS     += -DNO_FCRYPT=1
+	DES_ENC      += ocf_des_assist.o
+else
+	DES_ENC += fcrypt_b.o
+	FCRYPT = fcrypt.o
+endif
+
 LIBDIR=$(DESTDIR)$(INC_USRLOCAL)/lib
 INCDIR=$(DESTDIR)$(INC_USRLOCAL)/include
 MANDIR=$(MANTREE)
@@ -79,7 +89,7 @@
 MAN1=1
 MAN3=3
 SHELL=/bin/sh
-OBJ_LIT=cbc_enc.o ecb_enc.o $(DES_ENC) fcrypt.o set_key.o
+OBJ_LIT=cbc_enc.o ecb_enc.o $(DES_ENC) $(FCRYPT) 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 \
@@ -183,6 +193,9 @@
 asm/yx86unix.S:
 	(cd asm; perl crypt586.pl cpp >yx86unix.S)
 
+.c.o:
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
 test:	all
 	./destest
 
--- openswan-2.4.13.org/lib/libcrypto/libdes/destest.c	2004-07-10 10:07:08.000000000 +0200
+++ openswan-2.4.13/lib/libcrypto/libdes/destest.c	2008-06-27 13:38:04.000000000 +0200
@@ -472,7 +472,21 @@
 	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");
+		printf("des_ede3_cbc_encrypt chained encrypt error\n");
+		err=1;
+		}
+
+	memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+	memcpy(cbc_out,cbc_data,40);
+	des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_out,
+		16L,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
+	des_ede3_cbc_encrypt((C_Block *)&(cbc_out[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 inplace and chained encrypt error\n");
 		err=1;
 		}
 
@@ -485,6 +499,41 @@
 		err=1;
 		}
 
+	memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+	memcpy(cbc_in,cbc_out,40);
+	des_ede3_cbc_encrypt((C_Block *)cbc_in,(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 inplace decrypt error\n");
+		err=1;
+		}
+
+	memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+	des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
+		16L,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+	des_ede3_cbc_encrypt((C_Block *)&(cbc_out[16]),
+		(C_Block *)&(cbc_in[16]),
+		(long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+	if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+		{
+		printf("des_ede3_cbc_encrypt chained decrypt error\n");
+		err=1;
+		}
+
+	memcpy(iv3,cbc_iv,sizeof(cbc_iv));
+	memcpy(cbc_in,cbc_out,40);
+	des_ede3_cbc_encrypt((C_Block *)cbc_in,(C_Block *)cbc_in,
+		16L,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+	des_ede3_cbc_encrypt((C_Block *)&(cbc_in[16]),
+		(C_Block *)&(cbc_in[16]),
+		(long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
+	if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
+		{
+		printf("des_ede3_cbc_encrypt inplace and chained decrypt error\n");
+		err=1;
+		}
+
 #ifndef LIBDES_LIT
 	printf("Doing pcbc\n");
 	if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
--- openswan-2.4.13.org/lib/libcrypto/libdes/ocf_des_assist.c	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/lib/libcrypto/libdes/ocf_des_assist.c	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,357 @@
+/****************************************************************************/
+/*
+ * Use OCF/cryptodev interface for DES processing
+ * written by Toby Smith <toby@snapgear.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "crypto/des.h"
+#include "des/des_locl.h"
+#include "crypto/ocf_assist.h"
+
+/****************************************************************************/
+
+#include <crypto/cryptodev.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static int crypto_fd = -1;
+static int crypto_tested = 0;
+
+/* have we found a functional ocf_assist method */
+static int have_assist = 0;
+
+/****************************************************************************/
+/*
+ *	return provides flags if both DES and 3DES are present.
+ *	We need both as set_key cannot determine what we will call.
+ */
+
+int
+ocf_des_assist(void)
+{
+	if (!crypto_tested && !have_assist) {
+		struct session_op ses;
+		crypto_fd = open("/dev/crypto", O_RDWR);
+
+		/* set the close-on-exec flag */
+		if ((crypto_fd < 0) || (fcntl(crypto_fd, F_SETFD, 1) < 0)) {
+			close(crypto_fd);
+			crypto_fd = -1;
+		}
+
+		memset(&ses, 0, sizeof(ses));
+		ses.key = (caddr_t)"123456789012345678901234";
+
+		/* test we can do des ... */
+		if (crypto_fd != -1) {
+			crypto_tested = 1;
+			ses.cipher = CRYPTO_DES_CBC;
+			ses.keylen = 8;
+			if (ioctl(crypto_fd, CIOCGSESSION, &ses) != -1 &&
+					ioctl(crypto_fd, CIOCFSESSION, &ses.ses) != -1) {
+				/* ... and test we can do 3des */
+				ses.cipher = CRYPTO_3DES_CBC;
+				ses.keylen = 24;
+				if (ioctl(crypto_fd, CIOCGSESSION, &ses) != -1 &&
+						ioctl(crypto_fd, CIOCFSESSION, &ses.ses) != -1)
+					have_assist |= OCF_PROVIDES_DES_3DES;
+			}
+
+			if (!have_assist) {
+				close(crypto_fd);
+				crypto_fd = -1;
+			}
+		}
+	}
+	return(have_assist);
+}
+
+/****************************************************************************/
+
+int
+ocf_des_set_key(des_cblock (*key), des_key_schedule schedule)
+{
+	if (crypto_fd >= 0) {
+		memcpy(schedule, key, sizeof(*key));
+		return(0);
+	}
+	return(-1);
+}
+
+/****************************************************************************/
+
+static void
+ocf_des_cryptodev_internal(
+	u_int32_t cipher,
+	char (*key),
+	u_int32_t operation,
+	des_cblock (*src),
+	des_cblock (*dst),
+	u_int32_t len,
+	des_cblock (*iv),
+	u_int32_t iv_len)
+{
+	struct session_op sop;
+	struct crypt_op cop;
+	u_int32_t fixed_len = len;
+	des_cblock new_iv;
+	des_cblock *fixed_src = NULL;
+
+	/* always make fixed_len a multiple of 8 - otherwise the CIOCCRYPT fails */
+    fixed_len = (len + 7) & ~7;
+
+	/* if the input stream's length is not a multiple of 8, copy and zero pad */
+	if ((len & 7) && operation == COP_ENCRYPT) {
+		/* slow but safe */
+		fixed_src = (des_cblock *)malloc(fixed_len);
+		if (!fixed_src) return;
+		memset((char *)fixed_src + fixed_len - 8, 0, 8);
+		memcpy((char *)fixed_src, (char *)src, len);
+	} else {
+		fixed_src = src;
+	}
+
+	/* need to calculate the new iv before decrypting, as if we are decrypting
+	 * in place then the operation will destroy the last block of cipher text */
+	if (operation != COP_ENCRYPT) {
+		/* ciphertext will be in src */
+		memcpy((char *)new_iv, (char *)fixed_src + fixed_len - iv_len, iv_len);
+	}
+
+	/*
+	 * XXX
+	 * cryptodev enforces the concept of a crypto session
+	 * in which you perform operations. This ocf_assist stuff doesn't currently
+	 * support that. So for now I'm creating sessions for each operation. 
+	 */
+
+	/* create a session */
+	bzero(&sop, sizeof(sop));
+	sop.cipher = cipher;
+
+	if (cipher == CRYPTO_DES_CBC) {
+		sop.keylen = 8;
+	} else if (cipher == CRYPTO_3DES_CBC) {
+		sop.keylen = 24;
+	}
+	sop.key = key;
+
+	if (ioctl(crypto_fd, CIOCGSESSION, &sop) < 0) {
+		/* fatal error condition - bail out */
+		goto failed;
+	}
+
+	/* perform the operation */
+	bzero(&cop, sizeof(cop));
+	cop.ses = sop.ses;
+	cop.op = operation;
+	cop.src = (char *)fixed_src; 
+	cop.dst = (char *)dst;
+	cop.len = fixed_len;
+	cop.iv = (char *)iv;
+	if (ioctl(crypto_fd, CIOCCRYPT, &cop) < 0) {
+		/* fprintf(stderr, "%s CIOCCRYPT failed\n", __FUNCTION__); */
+		goto failed;
+	}
+
+	/* it doesn't look like cryptodev updates the iv in the cop
+	 * to allow manual chaining of several blocks, cbc style :( 
+	 * so we need to manually set this iv to the last block of ciphertext 
+	 */
+	if (operation == COP_ENCRYPT) {
+		/* ciphertext will be in dst */
+		memcpy((char *)iv, cop.dst + fixed_len - iv_len, iv_len); 
+	} else {
+		/* have to copy out the saved iv from new_iv */
+		memcpy((char *)iv, new_iv, iv_len);
+	}
+
+	if (ioctl(crypto_fd, CIOCFSESSION, &sop.ses) == -1)
+		goto failed;
+
+	if (fixed_src != src)
+		free(fixed_src);
+	return;
+
+failed:
+	if (fixed_src != src)
+		free(fixed_src);
+	memset(dst, 0, len);
+}
+
+/****************************************************************************/
+	
+void
+ocf_des_cbc_encrypt(
+	des_cblock (*input),
+	des_cblock (*output),
+	long length,
+	des_key_schedule schedule,
+	des_cblock (*ivec),
+	int enc)
+{
+	if (crypto_fd != -1) {
+		char key[8];
+		des_cblock iv;
+
+		memcpy(key, schedule, 8);
+		memcpy(&iv, ivec, sizeof(des_cblock));
+		ocf_des_cryptodev_internal(
+			CRYPTO_DES_CBC,
+			key,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			input,
+			output,
+			length,
+			&iv,
+			sizeof(des_cblock));
+		/* intentionally do NOT copy out the iv into ivec, this is the
+		 * ONLY difference between the cbc and ncbc versions 
+		 */
+	}
+}
+
+/****************************************************************************/
+
+void
+ocf_des_encrypt(
+	DES_LONG *data,
+	des_key_schedule ks,
+	int enc)
+{
+	if (crypto_fd != -1) {
+		char key[8];
+		des_cblock iv;
+		des_cblock datac;
+		register DES_LONG l;
+		unsigned char *p;
+
+		p=&datac[0];
+		l=data[0]; l2c(l,p);
+		l=data[1]; l2c(l,p);
+
+		memcpy(key, ks, 8);
+		memset(&iv, 0, sizeof(des_cblock));
+		/* single block ecb == single block cbc with iv=0 */
+		ocf_des_cryptodev_internal(
+			CRYPTO_DES_CBC,
+			key,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			&datac,
+			&datac,
+			sizeof(des_cblock),
+			&iv,
+			sizeof(des_cblock));
+
+		p=datac;
+		c2l(p,l); data[0]=l;
+		c2l(p,l); data[1]=l;
+	}
+}
+
+/****************************************************************************/
+
+void
+ocf_des_ede3_cbc_encrypt(
+	des_cblock (*input),
+	des_cblock (*output),
+	long length,
+	des_key_schedule ks1,
+	des_key_schedule ks2,
+	des_key_schedule ks3,
+	des_cblock (*ivec),
+	int enc)
+{
+	if (crypto_fd != -1) {
+		char key[8*3];
+		des_cblock iv;
+
+		memcpy(key, ks1, 8);
+		memcpy(key+8, ks2, 8);
+		memcpy(key+16, ks3, 8);
+		memcpy(&iv, ivec, sizeof(des_cblock));
+		ocf_des_cryptodev_internal(
+			CRYPTO_3DES_CBC,
+			key,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			input,
+			output,
+			length,
+			&iv,
+			sizeof(des_cblock));
+		memcpy(ivec, &iv, sizeof(des_cblock));
+	}
+}
+
+/****************************************************************************/
+
+void
+ocf_des_ncbc_encrypt(
+	des_cblock (*input),
+	des_cblock (*output),
+	long length,
+	des_key_schedule schedule,
+	des_cblock (*ivec),
+	int enc)
+{
+	if (crypto_fd != -1) {
+		char key[8];
+		des_cblock iv;
+
+		memcpy(key, schedule, 8);
+		memcpy(&iv, ivec, sizeof(des_cblock));
+		ocf_des_cryptodev_internal(
+			CRYPTO_DES_CBC,
+			key,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			input,
+			output,
+			length,
+			&iv,
+			sizeof(des_cblock));
+		memcpy(ivec, &iv, sizeof(des_cblock));
+	}
+}
+
+/****************************************************************************/
+
+void
+ocf_des_ecb_encrypt(
+	des_cblock (*input),
+	des_cblock (*output),
+	des_key_schedule ks,
+	int enc)
+{
+	if (crypto_fd != -1) {
+		char key[8];
+		des_cblock iv;
+
+		memcpy(key, ks, 8);
+		memset(&iv, 0, sizeof(des_cblock));
+		/* single block ecb == single block cbc with iv=0 */
+		ocf_des_cryptodev_internal(
+			CRYPTO_DES_CBC,
+			key,
+			enc ? COP_ENCRYPT : COP_DECRYPT,
+			input,
+			output,
+			sizeof(des_cblock),
+			&iv,
+			sizeof(des_cblock));
+	}
+}
+
+/****************************************************************************/
--- openswan-2.4.13.org/linux/include/crypto/ocf_assist.h	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/linux/include/crypto/ocf_assist.h	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,62 @@
+#ifndef _OCF_ASSIST_H
+#define _OCF_ASSIST_H 1
+/****************************************************************************/
+/* The various hw_assist functions return these bits */
+
+#define OCF_PROVIDES_AES		0x0001
+#define OCF_PROVIDES_DES_3DES	0x0002
+
+/****************************************************************************/
+#if !defined(OCF_ASSIST)
+/****************************************************************************/
+/*
+ *	stub it all out just in case
+ */
+
+#define ocf_aes_assist() (0)
+#define ocf_aes_set_key(a1,a2,a3,a4) 
+#define ocf_aes_cbc_encrypt(a1,a2,a3,a4,a5,a6)
+
+#define ocf_des_assist() (0)
+#define ocf_des_set_key(a, b)
+#define ocf_des_cbc_encrypt(a1,a2,a3,a4,a5,a6)
+#define ocf_des_encrypt(a1,a2,a3)
+#define ocf_des_ede3_cbc_encrypt(a1,a2,a3,a4,a5,a6,a7,a8)
+#define ocf_des_ncbc_encrypt(a1,a2,a3,a4,a5,a6)
+#define ocf_des_ecb_encrypt(a1,a2,a3,a4)
+
+/****************************************************************************/
+#else
+/****************************************************************************/
+
+#include <linux/types.h>
+#include "aes.h"
+#include "des.h"
+
+extern int	ocf_aes_assist(void);
+extern void	ocf_aes_set_key(aes_context *cx, const unsigned char in_key[],
+								int n_bytes, const int f);
+extern int	ocf_aes_cbc_encrypt(aes_context *ctx, __u8 *input,
+								__u8 *output, long length,
+								__u8 *ivec, int enc);
+
+extern int	ocf_des_assist(void);
+extern int	ocf_des_set_key(des_cblock *key, des_key_schedule schedule);
+extern void	ocf_des_cbc_encrypt(des_cblock *input, des_cblock *output,
+								long length, des_key_schedule schedule,
+								des_cblock *ivec, int enc);
+extern void	ocf_des_encrypt(DES_LONG *data, des_key_schedule ks, int enc);
+extern void	ocf_des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
+								long length, des_key_schedule ks1,
+								des_key_schedule ks2, des_key_schedule ks3,
+								des_cblock *ivec, int enc);
+extern void	ocf_des_ncbc_encrypt(des_cblock *input, des_cblock *output,
+								long length, des_key_schedule schedule,
+								des_cblock *ivec, int enc);
+extern void	ocf_des_ecb_encrypt(des_cblock *input, des_cblock *output,
+								des_key_schedule ks, int enc);
+
+/****************************************************************************/
+#endif /* !defined(OCF_ASSIST) */
+/****************************************************************************/
+#endif /* _OCF_ASSIST_H */
--- openswan-2.4.13.org/linux/include/des/des_locl.h	2004-08-04 02:33:56.000000000 +0200
+++ openswan-2.4.13/linux/include/des/des_locl.h	2008-06-27 13:38:04.000000000 +0200
@@ -74,6 +74,9 @@
 #endif
 
 #include "crypto/des.h"
+#ifdef OCF_ASSIST
+#include "crypto/ocf_assist.h"
+#endif
 
 #ifndef DES_DEFAULT_OPTIONS
 /* the following is tweaked from a config script, that is why it is a
@@ -505,11 +508,13 @@
 
 extern const DES_LONG des_SPtrans[8][64];
 
+#ifndef NO_FCRYPT
 #ifndef NOPROTO
 void fcrypt_body(DES_LONG *out,des_key_schedule ks,
 	DES_LONG Eswap0, DES_LONG Eswap1);
 #else
 void fcrypt_body();
 #endif
+#endif /* NO_FCRYPT */
 
 #endif
--- openswan-2.4.13.org/linux/include/openswan/ipsec_esp.h	2004-09-13 04:22:10.000000000 +0200
+++ openswan-2.4.13/linux/include/openswan/ipsec_esp.h	2008-06-27 13:38:04.000000000 +0200
@@ -65,6 +65,8 @@
 
 extern struct xform_functions esp_xform_funcs[];
 
+extern enum ipsec_rcv_value ipsec_rcv_esp_post_decrypt(struct ipsec_rcv_state *irs);
+
 #ifdef CONFIG_KLIPS_DEBUG
 extern int debug_esp;
 #endif /* CONFIG_KLIPS_DEBUG */
--- openswan-2.4.13.org/linux/include/openswan/ipsec_rcv.h	2006-10-06 23:39:26.000000000 +0200
+++ openswan-2.4.13/linux/include/openswan/ipsec_rcv.h	2008-06-27 13:38:04.000000000 +0200
@@ -46,6 +46,10 @@
 #include <linux/version.h>
 #include <openswan.h>
 
+#ifdef CONFIG_KLIPS_OCF
+#include <cryptodev.h>
+#endif
+
 #define IPSEC_BIRTH_TEMPLATE_MAXLEN 256
 
 struct ipsec_birth_reply {
@@ -57,6 +61,7 @@
 extern struct ipsec_birth_reply ipsec_ipv6_birth_packet;
 
 enum ipsec_rcv_value {
+	IPSEC_RCV_PENDING=2,
 	IPSEC_RCV_LASTPROTO=1,
 	IPSEC_RCV_OK=0,
 	IPSEC_RCV_BADPROTO=-1,
@@ -75,9 +80,27 @@
 	IPSEC_RCV_REPLAYFAILED=-15,
 	IPSEC_RCV_AUTHFAILED=-16,
 	IPSEC_RCV_REPLAYROLLED=-17,
-	IPSEC_RCV_BAD_DECRYPT=-18
+	IPSEC_RCV_BAD_DECRYPT=-18,
+	IPSEC_RCV_REALLYBAD=-19
 };
 
+/*
+ * state machine states
+ */
+
+#define IPSEC_RSM_INIT			0	/* make it easy, starting state is 0 */
+#define	IPSEC_RSM_DECAP_INIT	1
+#define	IPSEC_RSM_DECAP_CHK		2
+#define	IPSEC_RSM_AUTH_INIT		3
+#define	IPSEC_RSM_AUTH_CALC		4
+#define	IPSEC_RSM_AUTH_CHK		5
+#define	IPSEC_RSM_DECRYPT		6
+#define	IPSEC_RSM_DECAP_CONT	7	/* do we restart at IPSEC_RSM_DECAP_INIT */
+#define	IPSEC_RSM_CLEANUP		8
+#define	IPSEC_RSM_IPCOMP		9
+#define	IPSEC_RSM_COMPLETE		10
+#define IPSEC_RSM_DONE 			100
+
 struct ipsec_rcv_state {
 	struct sk_buff *skb;
 	struct net_device_stats *stats;
@@ -117,8 +140,41 @@
 	__u16		natt_dport;
 	int             natt_len; 
 #endif  
+
+	/*
+	 * rcv state machine use
+	 */
+	int		state;
+	int		next_state;
+	int		auth_checked;
+
+#ifdef CONFIG_KLIPS_OCF
+	struct work_struct	workq;
+#ifdef DECLARE_TASKLET
+	struct tasklet_struct	tasklet;
+#endif
+#endif
+#ifndef NET_21
+	struct net_device *devp;
+	struct inet_protocol *protop;
+#endif
+	struct xform_functions *proto_funcs;
+	__u8 proto;
+	int replay;
+	unsigned char *authenticator;
+	int esphlen;
+#ifdef CONFIG_KLIPS_ALG
+	struct ipsec_alg_auth *ixt_a;
+#endif
+	__u8 ttl, tos;
+	__u16 frag_off, check;
 };
 
+extern void ipsec_rsm(struct ipsec_rcv_state *irs);
+extern struct kmem_cache *ipsec_irs_cache;
+extern int ipsec_irs_max;
+extern atomic_t ipsec_irs_cnt;
+
 extern int
 #ifdef PROTO_HANDLER_SINGLE_PARM
 ipsec_rcv(struct sk_buff *skb);
--- openswan-2.4.13.org/linux/include/openswan/ipsec_sa.h	2007-09-05 04:31:15.000000000 +0200
+++ openswan-2.4.13/linux/include/openswan/ipsec_sa.h	2008-06-27 13:38:04.000000000 +0200
@@ -211,6 +211,9 @@
 	struct ipsec_alg_enc *ips_alg_enc;
 	struct ipsec_alg_auth *ips_alg_auth;
 	IPsecSAref_t	ips_ref_rel;
+
+	int			ocf_in_use;
+	int64_t		ocf_cryptoid;
 };
 
 struct IPsecSArefSubTable
--- openswan-2.4.13.org/linux/include/openswan/ipsec_xmit.h	2005-05-11 03:00:26.000000000 +0200
+++ openswan-2.4.13/linux/include/openswan/ipsec_xmit.h	2008-06-27 13:38:04.000000000 +0200
@@ -18,6 +18,10 @@
 
 #include "openswan/ipsec_sa.h"
 
+#ifdef CONFIG_KLIPS_OCF
+#include <cryptodev.h>
+#endif
+
 enum ipsec_xmit_value
 {
 	IPSEC_XMIT_STOLEN=2,
@@ -51,8 +55,26 @@
 	IPSEC_XMIT_IPSENDFAILURE=-26,
 	IPSEC_XMIT_ESPUDP=-27,
 	IPSEC_XMIT_ESPUDP_BADTYPE=-28,
+	IPSEC_XMIT_PENDING=-29,
 };
 
+
+/*
+ * state machine states
+ */
+
+#define IPSEC_XSM_INIT			0	/* make it easy, starting state is 0 */
+#define IPSEC_XSM_ENCAP_INIT	1
+#define IPSEC_XSM_ENCAP_SELECT	2
+#define IPSEC_XSM_ESP			3
+#define IPSEC_XSM_ESP_AH		4
+#define IPSEC_XSM_AH			5
+#define IPSEC_XSM_IPIP			6
+#define IPSEC_XSM_IPCOMP		7
+#define IPSEC_XSM_CONT			8
+#define IPSEC_XSM_DONE 			100
+
+
 struct ipsec_xmit_state
 {
 	struct sk_buff *skb;		/* working skb pointer */
@@ -108,6 +130,33 @@
 	uint16_t natt_sport;
 	uint16_t natt_dport;
 #endif
+
+	/*
+	 * xmit state machine use
+	 */
+	void (*xsm_complete)(struct ipsec_xmit_state *ixs,
+			enum ipsec_xmit_value stat);
+	int		state;
+	int		next_state;
+#ifdef CONFIG_KLIPS_OCF
+	struct work_struct	workq;
+#ifdef DECLARE_TASKLET
+	struct tasklet_struct	tasklet;
+#endif
+#endif
+#ifdef CONFIG_KLIPS_ALG
+	struct ipsec_alg_auth *ixt_a;
+	struct ipsec_alg_enc *ixt_e;
+#endif
+#ifdef CONFIG_KLIPS_ESP
+	struct esphdr *espp;
+	unsigned char *idat;
+#endif /* !CONFIG_KLIPS_ESP */
+	int blocksize;
+	int ilen, len;
+	unsigned char *dat;
+	__u8 frag_off, tos;
+	__u16 ttl, check;
 };
 
 enum ipsec_xmit_value
@@ -119,6 +168,11 @@
 enum ipsec_xmit_value
 ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs);
 
+extern void ipsec_xsm(struct ipsec_xmit_state *ixs);
+extern struct kmem_cache *ipsec_ixs_cache;
+extern int ipsec_ixs_max;
+extern atomic_t ipsec_ixs_cnt;
+
 extern void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er);
 
 
--- openswan-2.4.13.org/linux/net/ipsec/Config.in.os2_4	2006-10-11 20:14:33.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/Config.in.os2_4	2008-06-27 13:38:04.000000000 +0200
@@ -45,6 +45,8 @@
 
 bool '   IPsec Debugging Option' CONFIG_KLIPS_DEBUG
 
+bool '   IPsec: OCF HW Acceleration support' CONFIG_KLIPS_OCF
+
 #
 #
 # $Log: Config.in.os2_4,v $
--- openswan-2.4.13.org/linux/net/ipsec/Kconfig	2007-12-06 16:51:01.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/Kconfig	2008-06-27 13:38:04.000000000 +0200
@@ -67,9 +67,17 @@
 	   You should only disabled this if using the external OCF patch
 	   for hardware offload.
 
+config KLIPS_ALG
+	bool 'Enable algorithm plug-ins for encryption'
+	default y
+	help
+	   This option provides support for loading new algorithms into the 
+	   kernel for use to encrypt.
+
 config KLIPS_ENC_CRYPTOAPI
 	bool 'CryptoAPI algorithm interface'
 	default n
+	depends on KLIPS_ALG
 	help
 	   Enable the algorithm interface to make all CryptoAPI 1.0 algorithms
 	   available to KLIPS.
@@ -94,6 +102,7 @@
 config KLIPS_ENC_AES
 	bool 'AES encryption algorithm'
 	default y
+	depends on KLIPS_ALG
 	help
            The AES algorithm is used by ESP to provide for packet privacy.
 	   AES the NIST replacement for DES. AES is being widely analyzed,
@@ -114,6 +123,15 @@
 	   smaller. Once encrypted, compression will fail, so any link
 	   layer efforts (e.g. PPP) will not work. 
 
+config KLIPS_OCF
+	bool 'IPsec OCF Acceleration Support'
+	default n
+	help
+	   OCF provides Asynchronous crypto acceleration for kernel and
+	   user applications.   It supports various HW accelerators.
+	   If you have OCF support enabled and wish IPsec to utilise
+	   the hardware managed by OCF,  then enable this option.
+
 config KLIPS_DEBUG
 	bool 'IPsec debugging'
 	default y 
--- openswan-2.4.13.org/linux/net/ipsec/Makefile.fs2_4	2006-10-19 06:57:08.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/Makefile.fs2_4	2008-06-27 13:38:04.000000000 +0200
@@ -74,6 +74,7 @@
 obj-y += pfkey_v2.o pfkey_v2_parser.o pfkey_v2_ext_process.o 
 obj-y += version.o
 obj-$(CONFIG_KLIPS_ESP)     += ipsec_esp.o
+obj-$(CONFIG_KLIPS_OCF)     += ipsec_ocf.o
 obj-$(CONFIG_KLIPS_IPCOMP)  += ipsec_ipcomp.o
 
 # AH, if you really think you need it.
@@ -192,6 +193,9 @@
 #EXTRA_CFLAGS += -Wwrite-strings 
 #EXTRA_CFLAGS += -Wbad-function-cast 
 EXTRA_CFLAGS += -DIPCOMP_PREFIX
+ifneq ($(wildcard ${TOPDIR}/crypto/ocf),)
+EXTRA_CFLAGS += -I${TOPDIR}/crypto/ocf
+endif
 
 ifneq ($(strip $(KLIPSMODULE)),)
 # for when we aren't building in the kernel tree
--- openswan-2.4.13.org/linux/net/ipsec/Makefile.fs2_6	2006-10-11 20:14:33.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/Makefile.fs2_6	2008-06-27 13:38:04.000000000 +0200
@@ -61,6 +61,7 @@
 ipsec-objs += ${base-klips-objs}
 
 ipsec-$(CONFIG_KLIPS_ESP)     += ipsec_esp.o
+ipsec-$(CONFIG_KLIPS_OCF)     += ipsec_ocf.o
 ipsec-$(CONFIG_KLIPS_IPCOMP)  += ipsec_ipcomp.o
 ipsec-$(CONFIG_KLIPS_AUTH_HMAC_MD5)  += ipsec_md5c.o
 ipsec-$(CONFIG_KLIPS_AUTH_HMAC_SHA1) += ipsec_sha1.o
@@ -68,7 +69,7 @@
 # AH, if you really think you need it.
 ipsec-$(CONFIG_KLIPS_AH)   += ipsec_ah.o
 
-ipsec-y += ipsec_alg.o 
+ipsec-$(CONFIG_KLIPS_ALG) += ipsec_alg.o 
 
 # include code from DES subdir
 crypto-$(CONFIG_KLIPS_ENC_3DES) += des/ipsec_alg_3des.o
@@ -141,6 +142,7 @@
 ipsec-$(CONFIG_KLIPS_IPCOMP) += ${base-ipcomp-objs}
 
 EXTRA_CFLAGS += -DIPCOMP_PREFIX
+EXTRA_CFLAGS += -Icrypto/ocf -DCONFIG_KLIPS_OCF=1 
 
 #
 # $Log: Makefile.fs2_6,v $
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_ah.c	2007-09-05 04:56:09.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_ah.c	2008-06-27 13:38:04.000000000 +0200
@@ -64,6 +64,8 @@
 #include "openswan/ipsec_ah.h"
 #include "openswan/ipsec_proto.h"
 
+#include "ipsec_ocf.h"
+
 __u32 zeroes[AH_AMAX];
 
 enum ipsec_rcv_value
@@ -137,6 +139,11 @@
 	struct iphdr ipo;
 	int ahhlen;
 
+#ifdef CONFIG_KLIPS_OCF
+	if (irs->ipsp->ocf_in_use)
+		return(ipsec_ocf_rcv(irs));
+#endif
+
 	aa = irs->authfuncs;
 
 	/* copy the initialized keying material */
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_alg.c	2006-10-11 20:14:33.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_alg.c	2008-06-27 13:38:04.000000000 +0200
@@ -69,6 +69,9 @@
 #include "openswan/ipsec_alg.h"
 #include "openswan/ipsec_proto.h"
 
+#ifndef CONFIG_KLIPS_ALG
+#error This file _MUST_ be compiled with CONFIG_KLIPS_ALG enabled !
+#endif
 #if SADB_EALG_MAX < 255
 #warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )
 #endif
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_alg_cryptoapi.c	2008-06-26 22:57:46.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_alg_cryptoapi.c	2008-06-27 13:38:04.000000000 +0200
@@ -90,6 +90,10 @@
 #define CIPHERNAME_SERPENT	"serpent"
 #define CIPHERNAME_TWOFISH	"twofish"
 
+#ifndef CRYPTO_TFM_MODE_CBC
+#define	CRYPTO_TFM_MODE_CBC	0
+#endif
+
 #define ESP_SERPENT		252	/* from ipsec drafts */
 #define ESP_TWOFISH		253	/* from ipsec drafts */
 
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_esp.c	2007-09-05 04:56:09.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_esp.c	2008-06-27 13:38:04.000000000 +0200
@@ -68,6 +68,7 @@
 
 #include "openswan/ipsec_proto.h"
 #include "openswan/ipsec_alg.h"
+#include "ipsec_ocf.h"
 
 #ifdef CONFIG_KLIPS_DEBUG
 #define ESP_DMP(_x,_y,_z) if(debug_rcv && sysctl_ipsec_debug_verbose) ipsec_dmp_block(_x,_y,_z)
@@ -153,6 +154,11 @@
 		SHA1_CTX	sha1;
 	} tctx;
 
+#ifdef CONFIG_KLIPS_OCF
+	if (irs->ipsp->ocf_in_use)
+		return(ipsec_ocf_rcv(irs));
+#endif
+
 #ifdef CONFIG_KLIPS_ALG
 	if (irs->ipsp->ips_alg_auth) {
 		KLIPS_PRINT(debug_rcv,
@@ -204,15 +210,16 @@
 {
 	struct ipsec_sa *ipsp = irs->ipsp;
 	struct esphdr *espp = irs->protostuff.espstuff.espp;
-	int i;
-	int pad = 0, padlen;
-	int badpad = 0;
-	int esphlen = 0;
 	__u8 *idat;	/* pointer to content to be decrypted/authenticated */
 	int encaplen = 0;
 	struct sk_buff *skb;
 	struct ipsec_alg_enc *ixt_e=NULL;
 
+#ifdef CONFIG_KLIPS_OCF
+	if (ipsp->ocf_in_use)
+		return(ipsec_ocf_rcv(irs));
+#endif
+
 #ifdef CONFIG_KLIPS_ALG
 	skb=irs->skb;
 
@@ -229,14 +236,14 @@
 	encaplen = skb_transport_header(skb) - (skb_network_header(skb) + irs->iphlen);
 
 	ixt_e=ipsp->ips_alg_enc;
-	esphlen = ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;
+	irs->esphlen = ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;
 	KLIPS_PRINT(debug_rcv,
 		    "klips_debug:ipsec_rcv: "
 		    "encalg=%d esphlen=%d\n",
-		    ipsp->ips_encalg, esphlen);
+		    ipsp->ips_encalg, irs->esphlen);
 
-	idat += esphlen;
-	irs->ilen -= esphlen;
+	idat += irs->esphlen;
+	irs->ilen -= irs->esphlen;
 
 	if (ipsec_alg_esp_encrypt(ipsp, 
 				  idat, irs->ilen, espp->esp_iv, 
@@ -255,9 +262,29 @@
 			irs->stats->rx_errors++;
 		}
 		return IPSEC_RCV_BAD_DECRYPT;
-#endif /* CONFIG_KLIPS_ALG */
 	} 
 
+	return ipsec_rcv_esp_post_decrypt(irs);
+#else
+	return IPSEC_RCV_BAD_DECRYPT;
+#endif /* CONFIG_KLIPS_ALG */
+}
+
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_post_decrypt(struct ipsec_rcv_state *irs)
+{
+	struct sk_buff *skb;
+	__u8 *idat;	/* pointer to content to be decrypted/authenticated */
+	struct ipsec_sa *ipsp = irs->ipsp;
+	int pad = 0, padlen;
+	int badpad = 0;
+	int i;
+
+	skb = irs->skb;
+
+	idat = skb_transport_header(skb) + irs->esphlen;
+
 	ESP_DMP("postdecrypt", idat, irs->ilen);
 
 	irs->next_header = idat[irs->ilen - 1];
@@ -265,7 +292,7 @@
 	pad = padlen + 2 + irs->authlen;
 
 	KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-		    "klips_debug:ipsec_rcv: "
+		    "klips_debug:ipsec_rcv_esp_post_decrypt: "
 		    "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n",
 		    padlen);
 
@@ -292,23 +319,23 @@
 	}
 	if(badpad) {
 		KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-			    "klips_debug:ipsec_rcv: "
+			    "klips_debug:ipsec_rcv_esp_post_decrypt: "
 			    "warning, decrypted packet from %s has bad padding\n",
 			    irs->ipsaddr_txt);
 		KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-			    "klips_debug:ipsec_rcv: "
+			    "klips_debug:ipsec_rcv_esp_post_decrypt: "
 			    "...may be bad decryption -- not dropped\n");
 		ipsp->ips_errs.ips_encpad_errs += 1;
 	}
 
 	KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-		    "klips_debug:ipsec_rcv: "
+		    "klips_debug:ipsec_rcv_esp_post_decrypt: "
 		    "packet decrypted from %s: next_header = %d, padding = %d\n",
 		    irs->ipsaddr_txt,
 		    irs->next_header,
 		    pad - 2 - irs->authlen);
 
-	irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (esphlen + pad));
+	irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (irs->esphlen + pad));
 
 	/*
 	 * move the IP header forward by the size of the ESP header, which
@@ -327,14 +354,14 @@
 	/* skb_pull below, will move up by esphlen */
 
 	/* XXX not clear how this can happen, as the message indicates */
-	if(skb->len < esphlen) {
+	if(skb->len < irs->esphlen) {
 		printk(KERN_WARNING
-		       "klips_error:ipsec_rcv: "
+		       "klips_error:ipsec_rcv_esp_post_decrypt: "
 		       "tried to skb_pull esphlen=%d, %d available.  This should never happen, please report.\n",
-		       esphlen, (int)(skb->len));
+		       irs->esphlen, (int)(skb->len));
 		return IPSEC_RCV_ESP_DECAPFAIL;
 	}
-	skb_pull(skb, esphlen);
+	skb_pull(skb, irs->esphlen);
 	skb_set_network_header(skb, ipsec_skb_offset(skb, idat - irs->iphlen));
 	irs->ipp = ip_hdr(skb);
 
@@ -344,9 +371,9 @@
 	KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
 		    "klips_debug:ipsec_rcv: "
 		    "trimming to %d.\n",
-		    irs->len - esphlen - pad);
-	if(pad + esphlen <= irs->len) {
-		skb_trim(skb, irs->len - esphlen - pad);
+		    irs->len - irs->esphlen - pad);
+	if(pad + irs->esphlen <= irs->len) {
+		skb_trim(skb, irs->len - irs->esphlen - pad);
 	} else {
 		KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
 			    "klips_debug:ipsec_rcv: "
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_init.c	2007-11-16 04:31:52.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_init.c	2008-06-27 13:38:04.000000000 +0200
@@ -91,6 +91,10 @@
 #include "openswan/ipsec_proto.h"
 #include "openswan/ipsec_alg.h"
 
+#ifdef CONFIG_KLIPS_OCF
+#include "ipsec_ocf.h"
+#endif
+
 #include <pfkeyv2.h>
 #include <pfkey.h>
 
@@ -121,6 +125,32 @@
 int debug_netlink = 0;
 #endif /* CONFIG_KLIPS_DEBUG */
 
+/*
+ * We limit the number of outstanding RX/TX requests.
+ * Because we are now async,  we cannot just keep allocating
+ * these as fast as the come in,  crypto is usually much slower
+ * than your network interface
+ */
+struct kmem_cache *ipsec_irs_cache;
+struct kmem_cache *ipsec_ixs_cache;
+
+#if !defined(MODULE_PARM) && defined(module_param)
+/*
+ * As of 2.6.17 MODULE_PARM no longer exists, use module_param instead.
+ */
+#define	MODULE_PARM(a,b)	module_param(a,int,0)
+#endif
+
+atomic_t ipsec_irs_cnt;
+int ipsec_irs_max = 1000;
+MODULE_PARM(ipsec_irs_max,"i");
+MODULE_PARM_DESC(ipsec_irs_max, "Maximum outstanding receive packets");
+
+atomic_t ipsec_ixs_cnt;
+int ipsec_ixs_max = 1000;
+MODULE_PARM(ipsec_ixs_max,"i");
+MODULE_PARM_DESC(ipsec_ixs_max, "Maximum outstanding transmit packets");
+
 struct prng ipsec_prng;
 
 
@@ -254,9 +284,36 @@
 	ipsec_alg_init();
 #endif
 
+#ifdef CONFIG_KLIPS_OCF
+	ipsec_ocf_init();
+#endif
+
 	get_random_bytes((void *)seed, sizeof(seed));
 	prng_init(&ipsec_prng, seed, sizeof(seed));
 
+	atomic_set(&ipsec_irs_cnt, 0);
+	atomic_set(&ipsec_ixs_cnt, 0);
+
+	ipsec_irs_cache = kmem_cache_create("ipsec_irs",
+			sizeof(struct ipsec_rcv_state), 0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+			, NULL
+#endif
+			);
+	if (!ipsec_irs_cache) {
+		printk("Failed to get IRS cache\n");
+		error |= 1;
+	}
+	ipsec_ixs_cache = kmem_cache_create("ipsec_ixs",
+			sizeof(struct ipsec_xmit_state), 0, SLAB_HWCACHE_ALIGN, NULL
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+			, NULL
+#endif
+			);
+	if (!ipsec_ixs_cache) {
+		printk("Failed to get IXS cache\n");
+		error |= 1;
+	}
 	return error;
 }	
 
@@ -326,6 +383,13 @@
 
 	prng_final(&ipsec_prng);
 
+	if (ipsec_irs_cache)
+		kmem_cache_destroy(ipsec_irs_cache);
+	ipsec_irs_cache = NULL;
+	if (ipsec_ixs_cache)
+		kmem_cache_destroy(ipsec_ixs_cache);
+	ipsec_ixs_cache = NULL;
+
 	return error;
 }
 
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_ipcomp.c	2007-09-05 04:56:09.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_ipcomp.c	2008-06-27 13:38:04.000000000 +0200
@@ -142,7 +142,6 @@
 
 	skb = skb_decompress(skb, ipsp, &flags);
 	if (!skb || flags) {
-		spin_unlock(&tdb_lock);
 		KLIPS_PRINT(debug_rcv,
 			    "klips_debug:ipsec_rcv: "
 			    "skb_decompress() returned error flags=%x, dropped.\n",
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_ocf.c	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_ocf.c	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,728 @@
+/*
+ * IPSEC OCF support
+ *
+ * This code written by David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2005 Intel Corporation.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/version.h>
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h> /* printk() */
+
+#include <linux/errno.h>  /* error codes */
+#include <linux/types.h>  /* size_t */
+
+#include <linux/interrupt.h>
+
+#include <net/ip.h>
+
+#include <openswan.h>
+#include "openswan/ipsec_sa.h"
+#include "openswan/ipsec_rcv.h"
+#include "openswan/ipsec_xmit.h"
+#include "openswan/ipsec_tunnel.h"
+#include "openswan/ipsec_xform.h"
+#include "openswan/ipsec_auth.h"
+#include "openswan/ipsec_esp.h"
+#include "openswan/ipsec_ah.h"
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "ipsec_ocf.h"
+
+extern int debug_pfkey;
+extern int debug_rcv;
+
+/*
+ * Tuning parameters,  the settings below appear best for
+ * the IXP
+ */
+#define USE_BATCH 1	/* enable batch mode */
+#define USE_CBIMM 1	/* enable immediate callbacks */
+#define FORCE_QS  0	/* force use of queues for continuation of state machine */
+#ifdef DECLARE_TASKLET
+#define USE_TASKLET 1  /* use tasklet for continuation of state machine */
+#else
+#define USE_TASKLET 0  /* don't use tasklet for continuation of state machine */
+#endif
+/*
+ * Because some OCF operations are synchronous (ie., software encryption)
+ * we need to protect ourselves from distructive re-entry.  All we do
+ * is track where we are at and either callback  immediately or Q the
+ * callback to avoid conflicts.  This allows us to deal with the fact that
+ * OCF doesn't tell us if our crypto operations will be async or sync.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
+#define	_INIT_WORK(wq, fn, arg)	INIT_WORK(&(wq), (void (*)(struct work_struct *))(fn))
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+#define	_INIT_WORK(wq, fn, arg)	INIT_WORK(&(wq), (void (*)(struct work_queue *))(fn))
+#else
+#define	_INIT_WORK(wq, fn, arg)	INIT_WORK(&(wq), (void (*)(void *))(fn), (void *)(arg))
+#endif
+
+#define PROCESS_LATER(wq, sm, arg) \
+	({ \
+		_INIT_WORK(wq, sm, arg); \
+		schedule_work(&(wq)); \
+	})
+
+#define PROCESS_NOW(sm, arg) \
+	({ \
+		(*sm)(arg); \
+	})
+
+#if USE_TASKLET == 1
+	#define PROCESS_NEXT(this, wqsm, sm) ({ \
+		tasklet_init(&this->tasklet, \
+			(void (*)(unsigned long)) sm, (unsigned long)this); \
+		tasklet_schedule(&this->tasklet); \
+		})
+#elif FORCE_QS == 0
+	#define PROCESS_NEXT(this, wqsm, sm) \
+		if (in_interrupt()) { \
+			PROCESS_LATER(this->workq, wqsm, this); \
+		} else { \
+			PROCESS_NOW(sm, this); \
+		}
+#else
+	#define PROCESS_NEXT(this, wqsm, sm) PROCESS_LATER(this->workq, wqsm, this)
+#endif
+
+/*
+ * convert openswan values to OCF values
+ */
+
+static int
+ipsec_ocf_authalg(int authalg)
+{
+	switch (authalg) {
+	case AH_SHA:  return CRYPTO_SHA1_HMAC;
+	case AH_MD5:  return CRYPTO_MD5_HMAC;
+	}
+	return 0;
+}
+
+
+static int
+ipsec_ocf_encalg(int encalg)
+{
+	switch (encalg) {
+	case ESP_NULL:      return CRYPTO_NULL_CBC;
+	case ESP_DES:       return CRYPTO_DES_CBC;
+	case ESP_3DES:      return CRYPTO_3DES_CBC;
+	case ESP_AES:       return CRYPTO_AES_CBC;
+	case ESP_CAST:      return CRYPTO_CAST_CBC;
+	case ESP_BLOWFISH:  return CRYPTO_BLF_CBC;
+	}
+	return 0;
+}
+
+/*
+ * if we can do the request ops, setup the sessions and return true
+ * otherwise return false with ipsp unchanged
+ */
+
+int
+ipsec_ocf_sa_init(struct ipsec_sa *ipsp, int authalg, int encalg)
+{
+	struct cryptoini crie, cria;
+	int error;
+
+	KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x)\n",
+			authalg, encalg);
+
+	if (authalg && ipsp->ips_key_bits_a == 0) {
+		KLIPS_PRINT(debug_pfkey,
+				"klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x) a-key-bits=0\n",
+				authalg, encalg);
+		/* pretend we are happy with this */
+		return 1;
+	}
+
+	if (encalg && ipsp->ips_key_bits_e == 0) {
+		KLIPS_PRINT(debug_pfkey,
+				"klips_debug:ipsec_ocf_sa_init(a=0x%x,e=0x%x) e-key-bits=0\n",
+				authalg, encalg);
+		/* pretend we are happy with this */
+		return 1;
+	}
+
+	memset(&crie, 0, sizeof(crie));
+	memset(&cria, 0, sizeof(cria));
+
+	cria.cri_alg = ipsec_ocf_authalg(authalg);
+	cria.cri_klen = ipsp->ips_key_bits_a;
+	cria.cri_key  = ipsp->ips_key_a;
+	cria.cri_mlen = 12;
+
+	crie.cri_alg = ipsec_ocf_encalg(encalg);
+	crie.cri_klen = ipsp->ips_key_bits_e;
+	crie.cri_key  = ipsp->ips_key_e;
+	switch (crie.cri_alg) {
+	case CRYPTO_AES_CBC:
+		ipsp->ips_iv_size = 16;
+		break;
+	case CRYPTO_DES_CBC:
+	case CRYPTO_3DES_CBC:
+		ipsp->ips_iv_size = 8;
+		break;
+	default:
+		ipsp->ips_iv_size = 0;
+		break;
+	}
+	ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+	ipsp->ips_auth_bits = ipsp->ips_key_bits_a;
+
+	if (authalg && encalg) {
+		crie.cri_next = &cria;
+		error = crypto_newsession(&ipsp->ocf_cryptoid, &crie, 0);
+	} else if (encalg) {
+		error = crypto_newsession(&ipsp->ocf_cryptoid, &crie, 0);
+	} else if (authalg) {
+		error = crypto_newsession(&ipsp->ocf_cryptoid, &cria, 0);
+	} else {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init: "
+				"no authalg or encalg\n");
+		return 0;
+	}
+
+	if (error) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_init: "
+				"crypto_newsession failed 0x%x\n", error);
+		return 0;
+	}
+
+	/* make sure no ALG stuff bites us */
+	if (ipsp->ips_alg_enc)
+		printk("We received an ALG initted SA\n");
+	ipsp->ips_alg_enc = NULL;
+
+	ipsp->ocf_in_use = 1;
+	return 1;
+}
+
+
+int
+ipsec_ocf_sa_free(struct ipsec_sa *ipsp)
+{
+	KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf_sa_free()\n");
+	crypto_freesession(ipsp->ocf_cryptoid);
+	ipsp->ocf_cryptoid = -1;
+	ipsp->ocf_in_use = 0;
+	return 1;
+}
+
+#if USE_TASKLET == 0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void
+ipsec_rsm_wq(struct work_struct *work)
+{
+	struct ipsec_rcv_state *irs = container_of(work, struct ipsec_rcv_state, workq);
+	ipsec_rsm(irs);
+}
+#else
+#define	ipsec_rsm_wq	ipsec_rsm
+#endif
+#endif /* USE_TASKLET */
+
+static int
+ipsec_ocf_rcv_cb(struct cryptop *crp)
+{
+	struct ipsec_rcv_state *irs = (struct ipsec_rcv_state *)crp->crp_opaque;
+
+	KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb\n");
+	if (irs == NULL) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb: "
+				"NULL irs in callback\n");
+		return 0;
+	}
+
+	/*
+	 * we must update the state before returning to the state machine.
+	 * if we have an error,  terminate the processing by moving to the DONE
+	 * state
+	 */
+
+	irs->state = IPSEC_RSM_DONE; /* assume it went badly */
+	if (crp->crp_etype) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv_cb: "
+				"error in processing 0x%x\n", crp->crp_etype);
+	} else {
+		if (!irs->ipsp->ips_encalg) {
+			/* AH post processing, put back fields we had to zero */
+			irs->ipp->ttl      = irs->ttl;
+			irs->ipp->check    = irs->check;
+			irs->ipp->frag_off = irs->frag_off;
+			irs->ipp->tos      = irs->tos;
+			irs->state         = IPSEC_RSM_AUTH_CHK;
+			/* pull up the IP header again after processing */
+			skb_pull(irs->skb, ((unsigned char *)irs->protostuff.ahstuff.ahp) -
+								((unsigned char *)irs->ipp));
+		} else if (ipsec_rcv_esp_post_decrypt(irs) == IPSEC_RCV_OK) {
+			/* this one came up good, set next state */
+			irs->state         = IPSEC_RSM_DECAP_CONT;
+		}
+	}
+
+	crypto_freereq(crp);
+	crp = NULL;
+
+	/* setup the rest of the processing now */
+	PROCESS_NEXT(irs, ipsec_rsm_wq, ipsec_rsm);
+	return 0;
+}
+
+enum ipsec_rcv_value
+ipsec_ocf_rcv(struct ipsec_rcv_state *irs)
+{
+	struct cryptop *crp;
+	struct cryptodesc *crde, *crda = NULL;
+	struct ipsec_sa *ipsp;
+
+	KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv\n");
+
+	ipsp = irs->ipsp;
+	if (!ipsp) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
+				"no SA for rcv processing\n");
+		return IPSEC_RCV_SAIDNOTFOUND;
+	}
+
+	if (!irs->skb) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: no skb\n");
+		return IPSEC_RCV_SAIDNOTFOUND;
+	}
+
+	crp = crypto_getreq((ipsp->ips_authalg && ipsp->ips_encalg) ? 2 : 1);
+	if (!crp) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
+				"crypto_getreq returned NULL\n");
+		return IPSEC_RCV_REALLYBAD;
+	}
+
+	if (ipsp->ips_authalg) {
+		crda = crp->crp_desc;
+		crde = crda->crd_next;
+	} else {
+		crde = crp->crp_desc;
+		crda = crde->crd_next;
+	}
+
+	if (crda) {
+		/* Authentication descriptor */
+		crda->crd_alg = ipsec_ocf_authalg(ipsp->ips_authalg);
+		if (!crda->crd_alg) {
+			KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
+					"bad auth alg 0x%x\n", ipsp->ips_authalg);
+			crypto_freereq(crp);
+			return IPSEC_RCV_BADPROTO;
+		}
+
+		if (!crde) { /* assuming AH processing */
+			/* push the IP header so we can authenticate it */
+			skb_push(irs->skb, ((unsigned char *)irs->protostuff.ahstuff.ahp) -
+								((unsigned char *)irs->ipp));
+		}
+
+		crda->crd_key          = ipsp->ips_key_a;
+		crda->crd_klen         = ipsp->ips_key_bits_a;
+		crda->crd_inject       = irs->authenticator - irs->skb->data;
+		/* Copy the authenticator to check aganinst later */
+		memcpy(irs->hash, irs->authenticator, 12);
+
+		if (!crde) { /* assume AH processing */
+			/* AH processing, save fields we have to zero */
+			irs->ttl           = irs->ipp->ttl;
+			irs->check         = irs->ipp->check;
+			irs->frag_off      = irs->ipp->frag_off;
+			irs->tos           = irs->ipp->tos;
+			irs->ipp->ttl      = 0;
+			irs->ipp->check    = 0;
+			irs->ipp->frag_off = 0;
+			irs->ipp->tos      = 0;
+			crda->crd_len      = irs->skb->len;
+			crda->crd_skip     = ((unsigned char *)irs->ipp) - irs->skb->data;
+			memset(irs->authenticator, 0, 12);
+		} else {
+			crda->crd_len      = irs->ilen;
+			crda->crd_skip     =
+				((unsigned char *) irs->protostuff.espstuff.espp) -
+							irs->skb->data;
+			/*
+			 * It would be nice to clear the authenticator here
+			 * to be sure we do not see it again later when checking.
+			 * We cannot.  Some HW actually expects to check the in-data
+			 * hash and and flag an error if it is incorrect.
+			 *
+			 * What we do to allow this is to pass in the current in-data
+			 * value.  Your OCF driver must ensure that it fails a request
+			 * for hash+decrypt with an invalid hash value, or returns the
+			 * computed in-data hash as requested.
+			 *
+			 * If your driver does not check the in-data hash but just
+			 * computes it value,  you must ensure that it does not return
+			 * the original in-data hash by accident.  It must invalidate the
+			 * in-data hash itself to force an auth check error.
+			 *
+			 * All existing drivers that do not care about the current
+			 * in-data hash do this by clearing the in-data hash before
+			 * processing, either directly or via their implementation.
+			 */
+#if 0
+			memset(irs->authenticator, 0, 12);
+#endif
+		}
+	}
+
+	if (crde) {
+		crde->crd_alg = ipsec_ocf_encalg(ipsp->ips_encalg);
+		if (!crde->crd_alg) {
+			KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_ocf_rcv: "
+					"bad enc alg 0x%x\n", ipsp->ips_encalg);
+			crypto_freereq(crp);
+			return IPSEC_RCV_BADPROTO;
+		}
+
+		irs->esphlen     = ESP_HEADER_LEN + ipsp->ips_iv_size;
+		irs->ilen       -= irs->esphlen;
+		crde->crd_skip   = (skb_transport_header(irs->skb) - irs->skb->data) + irs->esphlen;
+		crde->crd_len    = irs->ilen;
+		crde->crd_inject = crde->crd_skip - ipsp->ips_iv_size;
+		crde->crd_klen   = ipsp->ips_key_bits_e;
+		crde->crd_key    = ipsp->ips_key_e;
+	}
+
+	crp->crp_ilen = irs->skb->len; /* Total input length */
+	crp->crp_flags =
+			CRYPTO_F_SKBUF |
+#if USE_CBIMM == 1
+			CRYPTO_F_CBIMM |
+#endif
+#if USE_BATCH == 1
+			CRYPTO_F_BATCH |
+#endif
+			0;
+	crp->crp_buf = (caddr_t) irs->skb;
+	crp->crp_callback = ipsec_ocf_rcv_cb;
+	crp->crp_sid = ipsp->ocf_cryptoid;
+	crp->crp_opaque = (caddr_t) irs;
+	if (crypto_dispatch(crp)){
+		crypto_freereq(crp);
+		return IPSEC_RCV_REALLYBAD;
+	}
+	return(IPSEC_RCV_PENDING);
+}
+
+#if USE_TASKLET == 0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void
+ipsec_xsm_wq(struct work_struct *work)
+{
+	struct ipsec_xmit_state *ixs = container_of(work, struct ipsec_xmit_state, workq);
+	ipsec_xsm(ixs);
+}
+#else
+#define	ipsec_xsm_wq	ipsec_xsm
+#endif
+#endif /* USE_TASKLET */
+
+static int
+ipsec_ocf_xmit_cb(struct cryptop *crp)
+{
+	struct ipsec_xmit_state *ixs = (struct ipsec_xmit_state *)crp->crp_opaque;
+
+	KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb\n");
+
+	if (ixs == NULL) {
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb: "
+				"NULL ixs in callback\n");
+		return 0;
+	}
+
+	/*
+	 * we must update the state before returning to the state machine.
+	 * if we have an error,  terminate the processing by moving to the DONE
+	 * state
+	 */
+
+	ixs->state = IPSEC_XSM_DONE; /* assume bad xmit */
+	if (crp->crp_etype) {
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit_cb: "
+				"error in processing 0x%x\n", crp->crp_etype);
+	} else {
+		if (!ixs->ipsp->ips_encalg) {
+			/* AH post processing, put back fields we had to zero */
+			ixs->iph->ttl      = ixs->ttl;
+			ixs->iph->check    = ixs->check;
+			ixs->iph->frag_off = ixs->frag_off;
+			ixs->iph->tos      = ixs->tos;
+		}
+		ixs->state = IPSEC_XSM_CONT; /* ESP was all good */
+	}
+
+	crypto_freereq(crp);
+	crp = NULL;
+
+	/* setup the rest of the processing now */
+	PROCESS_NEXT(ixs, ipsec_xsm_wq, ipsec_xsm);
+	return 0;
+}
+
+
+enum ipsec_xmit_value
+ipsec_ocf_xmit(struct ipsec_xmit_state *ixs)
+{
+	struct cryptop *crp;
+	struct cryptodesc *crde, *crda;
+	struct ipsec_sa *ipsp;
+
+	KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit\n");
+
+	ipsp = ixs->ipsp;
+	if (!ipsp) {
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
+				"no SA for rcv processing\n");
+		return IPSEC_XMIT_SAIDNOTFOUND;
+	}
+
+	if (!ixs->skb) {
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+				"klips_debug:ipsec_ocf_xmit: no skb\n");
+		return IPSEC_XMIT_SAIDNOTFOUND;
+	}
+
+	crp = crypto_getreq((ipsp->ips_authalg && ipsp->ips_encalg) ? 2 : 1);
+	if (!crp) {
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
+				"crypto_getreq returned NULL\n");
+		return IPSEC_XMIT_ERRMEMALLOC;
+	}
+
+	if (ipsp->ips_encalg) {
+		crde = crp->crp_desc;
+		crda = crde->crd_next;
+	} else {
+		crda = crp->crp_desc;
+		crde = crda->crd_next;
+	}
+
+	if (crda) {
+		/* Authentication descriptor */
+		crda->crd_alg = ipsec_ocf_authalg(ipsp->ips_authalg);
+		if (!crda->crd_alg) {
+			KLIPS_PRINT(debug_tunnel&DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
+					"bad auth alg 0x%x\n", ipsp->ips_authalg);
+			crypto_freereq(crp);
+			return IPSEC_RCV_BADPROTO;
+		}
+		if (!crde) { /* assume AH processing */
+			/* AH processing, save fields we have to zero */
+			crda->crd_skip     = ((unsigned char *) ixs->iph) - ixs->skb->data;
+			ixs->ttl           = ixs->iph->ttl;
+			ixs->check         = ixs->iph->check;
+			ixs->frag_off      = ixs->iph->frag_off;
+			ixs->tos           = ixs->iph->tos;
+			ixs->iph->ttl      = 0;
+			ixs->iph->check    = 0;
+			ixs->iph->frag_off = 0;
+			ixs->iph->tos      = 0;
+			crda->crd_inject   =
+				(((struct ahhdr *)(ixs->dat + ixs->iphlen))->ah_data) -
+					ixs->skb->data;
+			crda->crd_len      = ixs->len - ixs->authlen;
+			memset(ixs->skb->data + crda->crd_inject, 0, 12); // DM
+		} else {
+			crda->crd_skip     = ((unsigned char *) ixs->espp) - ixs->skb->data;
+			crda->crd_inject   = ixs->len - ixs->authlen;
+			crda->crd_len      = ixs->len - ixs->iphlen - ixs->authlen;
+		}
+		crda->crd_key    = ipsp->ips_key_a;
+		crda->crd_klen   = ipsp->ips_key_bits_a;
+	}
+
+	if (crde) {
+		/* Encryption descriptor */
+		crde->crd_alg = ipsec_ocf_encalg(ipsp->ips_encalg);
+		if (!crde->crd_alg) {
+			KLIPS_PRINT(debug_tunnel&DB_TN_XMIT, "klips_debug:ipsec_ocf_xmit: "
+					"bad enc alg 0x%x\n", ipsp->ips_encalg);
+			crypto_freereq(crp);
+			return IPSEC_RCV_BADPROTO;
+		}
+		crde->crd_flags  = CRD_F_ENCRYPT;
+		crde->crd_skip   = ixs->idat - ixs->dat;
+		crde->crd_len    = ixs->ilen;
+		crde->crd_inject = ((unsigned char *) ixs->espp->esp_iv) - ixs->dat;
+		crde->crd_klen   = ipsp->ips_key_bits_e;
+		crde->crd_key    = ipsp->ips_key_e;
+	}
+
+	crp->crp_ilen = ixs->skb->len; /* Total input length */
+	crp->crp_flags =
+			CRYPTO_F_SKBUF |
+#if USE_CBIMM == 1
+			CRYPTO_F_CBIMM |
+#endif
+#if USE_BATCH == 1
+			CRYPTO_F_BATCH |
+#endif
+			0;
+	crp->crp_buf = (caddr_t) ixs->skb;
+	crp->crp_callback = ipsec_ocf_xmit_cb;
+	crp->crp_sid = ipsp->ocf_cryptoid;
+	crp->crp_opaque = (caddr_t) ixs;
+	if (crypto_dispatch(crp)){
+		crypto_freereq(crp);
+		return IPSEC_XMIT_ERRMEMALLOC;
+	}
+	return(IPSEC_XMIT_PENDING);
+}
+
+
+
+
+#ifdef CONFIG_KLIPS_AH
+static struct ipsec_alg_supported ocf_ah_algs[] = {
+  {
+	  .ias_name       = "ocf-md5hmac",
+	  .ias_id         = AH_MD5,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 128,
+	  .ias_keymaxbits = 128,
+  },
+  {
+	  .ias_name       = "ocf-sha1hmac",
+	  .ias_id         = AH_SHA,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 160,
+	  .ias_keymaxbits = 160,
+  },
+  {
+	  .ias_name       = NULL,
+	  .ias_id         = 0,
+	  .ias_exttype    = 0,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 0,
+	  .ias_keymaxbits = 0,
+  }
+};
+#endif /* CONFIG_KLIPS_AH */
+
+static struct ipsec_alg_supported ocf_esp_algs[] = {
+  {
+	  .ias_name       = "ocf-md5hmac",
+	  .ias_id         = AH_MD5,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 128,
+	  .ias_keymaxbits = 128,
+  },
+  {
+	  .ias_name       = "ocf-sha1hmac",
+	  .ias_id         = AH_SHA,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_AUTH,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 160,
+	  .ias_keymaxbits = 160,
+  },
+  {
+	  .ias_name       = "ocf-aes",
+	  .ias_id         = ESP_AES,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
+	  .ias_ivlen      = 16,
+	  .ias_keyminbits = 128,
+	  .ias_keymaxbits = 256,
+  },
+  {
+	  .ias_name       = "ocf-3des",
+	  .ias_id         = ESP_3DES,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
+	  .ias_ivlen      = 8,
+	  .ias_keyminbits = 192,
+	  .ias_keymaxbits = 192,
+  },
+  {
+	  .ias_name       = "ocf-des",
+	  .ias_id         = ESP_DES,
+	  .ias_exttype    = SADB_EXT_SUPPORTED_ENCRYPT,
+	  .ias_ivlen      = 8,
+	  .ias_keyminbits = 64,
+	  .ias_keymaxbits = 64,
+  },
+  {
+	  .ias_name       = NULL,
+	  .ias_id         = 0,
+	  .ias_exttype    = 0,
+	  .ias_ivlen      = 0,
+	  .ias_keyminbits = 0,
+	  .ias_keymaxbits = 0,
+  }
+};
+
+static int
+ipsec_ocf_check_alg(struct ipsec_alg_supported *s)
+{
+	struct cryptoini cri;
+	int64_t cryptoid;
+
+	memset(&cri, 0, sizeof(cri));
+	if (s->ias_exttype == SADB_EXT_SUPPORTED_ENCRYPT)
+		cri.cri_alg  = ipsec_ocf_encalg(s->ias_id);
+	else
+		cri.cri_alg  = ipsec_ocf_authalg(s->ias_id);
+	cri.cri_klen     = s->ias_keyminbits;
+	cri.cri_key      = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+	if (crypto_newsession(&cryptoid, &cri, 0)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf:%s not supported\n",
+				s->ias_name);
+		return 0;
+	}
+	crypto_freesession(cryptoid);
+	KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_ocf:%s supported\n",
+			s->ias_name);
+	return 1;
+}
+
+void
+ipsec_ocf_init(void)
+{
+	struct ipsec_alg_supported *s;
+
+	for (s = ocf_esp_algs; s->ias_name; s++) {
+		if (ipsec_ocf_check_alg(s))
+			(void)pfkey_list_insert_supported(s,
+					&(pfkey_supported_list[SADB_SATYPE_ESP]));
+	}
+
+#ifdef CONFIG_KLIPS_AH
+	for (s = ocf_ah_algs; s->ias_name; s++) {
+		if (ipsec_ocf_check_alg(s))
+			(void)pfkey_list_insert_supported(s,
+					&(pfkey_supported_list[SADB_SATYPE_AH]));
+	}
+#endif
+
+	/* send register event to userspace	*/
+	pfkey_register_reply(SADB_SATYPE_ESP, NULL);
+	pfkey_register_reply(SADB_SATYPE_AH, NULL);
+}
+
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_ocf.h	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_ocf.h	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,41 @@
+#ifndef _IPSEC_OCF_H_
+#define _IPSEC_OCF_H_
+/****************************************************************************/
+/*
+ * IPSEC OCF support
+ *
+ * This code written by David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2005 Intel Corporation.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#include <linux/version.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_KLIPS_OCF
+
+#include <cryptodev.h>
+
+extern int  ipsec_ocf_sa_init(struct ipsec_sa *ipsp, int authalg, int encalg);
+extern int  ipsec_ocf_sa_free(struct ipsec_sa *ipsp);
+extern enum ipsec_rcv_value ipsec_ocf_rcv(struct ipsec_rcv_state *irs);
+extern enum ipsec_xmit_value ipsec_ocf_xmit(struct ipsec_xmit_state *ixs);
+extern void	ipsec_ocf_init(void);
+
+#endif
+
+/****************************************************************************/
+#endif /* _IPSEC_OCF_H_ */
+
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_proc.c	2008-03-08 18:09:53.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_proc.c	2008-06-27 13:38:04.000000000 +0200
@@ -228,6 +228,16 @@
 				len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x",
 					       sa_p->ips_iv_bits);
 
+#ifdef CONFIG_KLIPS_OCF
+				if (!sa_p->ips_iv) {
+					/* ocf doesn't set the IV, fake it for the UML tests */
+					len += ipsec_snprintf(buffer+len, length-len, "0cf0");
+					for (j = 0; j < (sa_p->ips_iv_bits / 8) - 2; j++) {
+						len += ipsec_snprintf(buffer+len, length-len, "%02x",
+								   (((__u32)sa_p) >> j) & 0xff);
+					}
+				} else
+#endif
 				for(j = 0; j < sa_p->ips_iv_bits / 8; j++) {
 					len += ipsec_snprintf(buffer+len, length-len, "%02x",
 						       (__u32)((__u8*)(sa_p->ips_iv))[j]);
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_rcv.c	2007-10-30 22:37:45.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_rcv.c	2008-06-27 13:38:04.000000000 +0200
@@ -4,6 +4,10 @@
  * Copyright (C) 1998-2003   Richard Guy Briggs.
  * Copyright (C) 2004        Michael Richardson <mcr@xelerance.com>
  *
+ * OCF/receive state machine written by
+ * David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -84,6 +88,10 @@
 #include "openswan/ipsec_alg.h"
 #include "openswan/ipsec_kern24.h"
 
+#ifdef CONFIG_KLIPS_OCF
+#include "ipsec_ocf.h"
+#endif
+
 #ifdef CONFIG_KLIPS_DEBUG
 int debug_rcv = 0;
 #endif /* CONFIG_KLIPS_DEBUG */
@@ -194,10 +202,229 @@
 };
 #endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
 
+#ifdef CONFIG_KLIPS_DEBUG
+DEBUG_NO_STATIC char *
+ipsec_rcv_err(int err)
+{
+	static char tmp[32];
+	switch ((int) err) {
+	case IPSEC_RCV_PENDING:			return("IPSEC_RCV_PENDING");
+	case IPSEC_RCV_LASTPROTO:		return("IPSEC_RCV_LASTPROTO");
+	case IPSEC_RCV_OK:				return("IPSEC_RCV_OK");
+	case IPSEC_RCV_BADPROTO:		return("IPSEC_RCV_BADPROTO");
+	case IPSEC_RCV_BADLEN:			return("IPSEC_RCV_BADLEN");
+	case IPSEC_RCV_ESP_BADALG:		return("IPSEC_RCV_ESP_BADALG");
+	case IPSEC_RCV_3DES_BADBLOCKING:return("IPSEC_RCV_3DES_BADBLOCKING");
+	case IPSEC_RCV_ESP_DECAPFAIL:	return("IPSEC_RCV_ESP_DECAPFAIL");
+	case IPSEC_RCV_DECAPFAIL:		return("IPSEC_RCV_DECAPFAIL");
+	case IPSEC_RCV_SAIDNOTFOUND:	return("IPSEC_RCV_SAIDNOTFOUND");
+	case IPSEC_RCV_IPCOMPALONE:		return("IPSEC_RCV_IPCOMPALONE");
+	case IPSEC_RCV_IPCOMPFAILED:	return("IPSEC_RCV_IPCOMPFAILED");
+	case IPSEC_RCV_SAIDNOTLIVE:		return("IPSEC_RCV_SAIDNOTLIVE");
+	case IPSEC_RCV_FAILEDINBOUND:	return("IPSEC_RCV_FAILEDINBOUND");
+	case IPSEC_RCV_LIFETIMEFAILED:	return("IPSEC_RCV_LIFETIMEFAILED");
+	case IPSEC_RCV_BADAUTH:			return("IPSEC_RCV_BADAUTH");
+	case IPSEC_RCV_REPLAYFAILED:	return("IPSEC_RCV_REPLAYFAILED");
+	case IPSEC_RCV_AUTHFAILED:		return("IPSEC_RCV_AUTHFAILED");
+	case IPSEC_RCV_REPLAYROLLED:	return("IPSEC_RCV_REPLAYROLLED");
+	case IPSEC_RCV_BAD_DECRYPT:		return("IPSEC_RCV_BAD_DECRYPT");
+	case IPSEC_RCV_REALLYBAD:		return("IPSEC_RCV_REALLYBAD");
+	}
+	snprintf(tmp, sizeof(tmp), "%d", err);
+	return tmp;
+}
+#endif
+
+/*
+ * here is a state machine to handle receiving ipsec packets.
+ * basically we keep getting re-entered until processing is
+ * complete.  For the simple case we step down the states and finish.
+ * each state is ideally some logical part of the process.  If a state
+ * can pend (ie., require async processing to complete),  then this
+ * should be the part of last action before it returns IPSEC_RCV_PENDING
+ *
+ * Any particular action may alter the next_state in irs to move us to
+ * a state other than the preferred "next_state",  but this is the
+ * exception and is highlighted when it is done.
+ *
+ * prototypes for state action
+ */
+
+static enum ipsec_rcv_value ipsec_rcv_init(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_decap_init(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_decap_chk(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_auth_init(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_auth_calc(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_auth_chk(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_decrypt(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_decap_cont(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_cleanup(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_ipcomp(struct ipsec_rcv_state *irs);
+static enum ipsec_rcv_value ipsec_rcv_complete(struct ipsec_rcv_state *irs);
+
+/*
+ * the state table and each action
+ */
+
+struct {
+	enum ipsec_rcv_value (*action)(struct ipsec_rcv_state *irs);
+	int next_state;
+} rcv_state_table[] = {
+	[IPSEC_RSM_INIT]       = {ipsec_rcv_init,       IPSEC_RSM_DECAP_INIT },
+	[IPSEC_RSM_DECAP_INIT] = {ipsec_rcv_decap_init, IPSEC_RSM_DECAP_CHK },
+	[IPSEC_RSM_DECAP_CHK]  = {ipsec_rcv_decap_chk,  IPSEC_RSM_AUTH_INIT },
+	[IPSEC_RSM_AUTH_INIT]  = {ipsec_rcv_auth_init,  IPSEC_RSM_AUTH_CALC },
+	[IPSEC_RSM_AUTH_CALC]  = {ipsec_rcv_auth_calc,  IPSEC_RSM_AUTH_CHK },
+	[IPSEC_RSM_AUTH_CHK]   = {ipsec_rcv_auth_chk,   IPSEC_RSM_DECRYPT },
+	[IPSEC_RSM_DECRYPT]    = {ipsec_rcv_decrypt,    IPSEC_RSM_DECAP_CONT },
+	[IPSEC_RSM_DECAP_CONT] = {ipsec_rcv_decap_cont, IPSEC_RSM_CLEANUP },
+	[IPSEC_RSM_CLEANUP]    = {ipsec_rcv_cleanup,    IPSEC_RSM_IPCOMP },
+	[IPSEC_RSM_IPCOMP]     = {ipsec_rcv_ipcomp,     IPSEC_RSM_COMPLETE },
+	[IPSEC_RSM_COMPLETE]   = {ipsec_rcv_complete,   IPSEC_RSM_DONE },
+
+	[IPSEC_RSM_DONE]       = {NULL,                 IPSEC_RSM_DONE},
+};
+
+
+
+struct sk_buff *ipsec_rcv_unclone(struct sk_buff *skb,
+				  struct ipsec_rcv_state *irs)
+{
+	/* if skb was cloned (most likely due to a packet sniffer such as
+	   tcpdump being momentarily attached to the interface), make
+	   a copy of our own to modify */
+	if(skb_cloned(skb)) {
+		/* include any mac header while copying.. */
+		if(skb_headroom(skb) < irs->hard_header_len) {
+			printk(KERN_WARNING "klips_error:ipsec_rcv: "
+			       "tried to skb_push hhlen=%d, %d available.  This should never happen, please report.\n",
+			       irs->hard_header_len,
+			       skb_headroom(skb));
+			goto rcvleave;
+		}
+		skb_push(skb, irs->hard_header_len);
+		if
+#ifdef SKB_COW_NEW
+		  (skb_cow(skb, skb_headroom(skb)) != 0)
+#else /* SKB_COW_NEW */
+		  ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
+#endif /* SKB_COW_NEW */
+		{
+			goto rcvleave;
+		}
+		if(skb->len < irs->hard_header_len) {
+			printk(KERN_WARNING "klips_error:ipsec_rcv: "
+			       "tried to skb_pull hhlen=%d, %d available.  This should never happen, please report.\n",
+			       irs->hard_header_len,
+			       skb->len);
+			goto rcvleave;
+		}
+		skb_pull(skb, irs->hard_header_len);
+	}
+	return skb;
+
+rcvleave:
+	ipsec_kfree_skb(skb);
+	return NULL;
+}
+
+
+
+
+#if !defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
+/*
+ * decapsulate a UDP encapsulated ESP packet
+ */
+struct sk_buff *ipsec_rcv_natt_decap(struct sk_buff *skb
+				     , struct ipsec_rcv_state *irs
+				     , int *udp_decap_ret_p)
+{
+	*udp_decap_ret_p = 0;
+	if (skb->sk && ip_hdr(skb) && ip_hdr(skb)->protocol==IPPROTO_UDP) {
+		/**
+		 * Packet comes from udp_queue_rcv_skb so it is already defrag,
+		 * checksum verified, ... (ie safe to use)
+		 *
+		 * If the packet is not for us, return -1 and udp_queue_rcv_skb
+		 * will continue to handle it (do not kfree skb !!).
+		 */
+
+#ifndef UDP_OPT_IN_SOCK
+		struct udp_opt {
+			__u32 esp_in_udp;
+		};
+		struct udp_opt *tp =  (struct udp_opt *)&(skb->sk->tp_pinfo.af_tcp);
+#else
+		struct udp_opt *tp =  &(skb->sk->tp_pinfo.af_udp);
+#endif
+
+		struct iphdr *ip = ip_hdr(skb);
+		struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
+		__u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
+		__u32 *udpdata32 = (__u32 *)udpdata;
+		
+		irs->natt_sport = ntohs(udp->source);
+		irs->natt_dport = ntohs(udp->dest);
+	  
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
+			    tp->esp_in_udp);
+		KLIPS_IP_PRINT(debug_rcv, ip);
+	  
+		if (udpdata < skb->tail) {
+			unsigned int len = skb->tail - udpdata;
+			if ((len==1) && (udpdata[0]==0xff)) {
+				KLIPS_PRINT(debug_rcv,
+					    "klips_debug:ipsec_rcv: "
+					    /* not IPv6 compliant message */
+					    "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
+				*udp_decap_ret_p = 0;
+				return NULL;
+			}
+			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
+				  (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
+				  (udpdata32[0]==0) && (udpdata32[1]==0) ) {
+				/* ESP Packet with Non-IKE header */
+				KLIPS_PRINT(debug_rcv, 
+					    "klips_debug:ipsec_rcv: "
+					    "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
+					    ntohl(udpdata32[2]));
+				irs->natt_type = ESPINUDP_WITH_NON_IKE;
+				irs->natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
+			}
+			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
+				  (len > sizeof(struct esphdr)) &&
+				  (udpdata32[0]!=0) ) {
+				/* ESP Packet without Non-ESP header */
+				irs->natt_type = ESPINUDP_WITH_NON_ESP;
+				irs->natt_len = sizeof(struct udphdr);
+				KLIPS_PRINT(debug_rcv, 
+					    "klips_debug:ipsec_rcv: "
+					    "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
+					    ntohl(udpdata32[0]));
+			}
+			else {
+				KLIPS_PRINT(debug_rcv,
+					    "klips_debug:ipsec_rcv: "
+					    "IKE packet - not handled here\n");
+				*udp_decap_ret_p = -1;
+				return NULL;
+			}
+		}
+		else {
+			return NULL;
+		}
+  	}
+	return skb;
+}
+#endif
+
 /*
- * decapsulate a single layer of the system
+ * get all the initial checking and setup done.  Not of this can be off
+ * loaded by any currently support hardware
  *
- * the following things should be setup to enter this function.
+ * the following things should be setup when we exit this function.
  *
  * irs->stats  == stats structure (or NULL)
  * irs->ipp    = IP header.
@@ -214,114 +441,394 @@
  * proto_funcs should be from ipsec_esp.c, ipsec_ah.c or ipsec_ipcomp.c.
  *
  */
-enum ipsec_rcv_value
-ipsec_rcv_decap_once(struct ipsec_rcv_state *irs
-		     , struct xform_functions *proto_funcs)
+
+static enum ipsec_rcv_value
+ipsec_rcv_init(struct ipsec_rcv_state *irs)
 {
-	int iphlen;
-	__u8 proto;
-	struct in_addr ipsaddr;
-	struct in_addr ipdaddr;
-	int replay = 0;	/* replay value in AH or ESP packet */
-	struct ipsec_sa* ipsnext = NULL;	/* next SA towards inside of packet */
-	struct ipsec_sa *newipsp;
+#ifdef CONFIG_KLIPS_DEBUG
+	struct net_device *dev;
+#endif /* CONFIG_KLIPS_DEBUG */
+	unsigned char protoc;
 	struct iphdr *ipp;
+	struct net_device_stats *stats = NULL;		/* This device's statistics */
+	struct net_device *ipsecdev = NULL, *prvdev;
+	struct ipsecpriv *prv;
+	char name[9];
+	int i;
 	struct sk_buff *skb;
-	struct ipsec_alg_auth *ixt_a=NULL;
-
-	skb = irs->skb;
-	irs->len = skb->len;
-	ipp = irs->ipp;
-	proto = ipp->protocol;
-	ipsaddr.s_addr = ipp->saddr;
-	addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
-	ipdaddr.s_addr = ipp->daddr;
-	addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
-
-	iphlen = ipp->ihl << 2;
-	irs->iphlen=iphlen;
-	ipp->check = 0;			/* we know the sum is good */
-	
-	KLIPS_PRINT(debug_rcv,
-		    "klips_debug:ipsec_rcv_decap_once: "
-		    "decap (%d) from %s -> %s\n",
-		    proto, irs->ipsaddr_txt, irs->ipdaddr_txt);
-
-	/*
-	 * 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.
-	 */
 
-	irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr;
-	irs->said.dst.u.v4.sin_family = AF_INET;
-
-	/* note: rcv_checks set up the said.spi value, if appropriate */
-	if(proto_funcs->rcv_checks) {
-		enum ipsec_rcv_value retval =
-		  (*proto_funcs->rcv_checks)(irs, skb);
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
-		if(retval < 0) {
-			return retval;
-		}
+	if (irs == NULL) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_init: NULL irs.");
+		return IPSEC_RCV_REALLYBAD;
 	}
 
-	irs->said.proto = proto;
-	irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));
-	if(irs->sa_len == 0) {
-		strcpy(irs->sa, "(error)");
+	skb = irs->skb;
+	if (!skb) {
+		KLIPS_PRINT(debug_rcv, "klips_debug:ipsec_rcv_init: NULL skb.");
+		return IPSEC_RCV_REALLYBAD;
 	}
+	dev = skb->dev;
 
-	newipsp = ipsec_sa_getbyid(&irs->said);
-	if (newipsp == NULL) {
+	if (skb->data == NULL) {
 		KLIPS_PRINT(debug_rcv,
 			    "klips_debug:ipsec_rcv: "
-			    "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
-			    irs->sa_len ? irs->sa : " (error)");
-		if(irs->stats) {
-			irs->stats->rx_dropped++;
-		}
-		return IPSEC_RCV_SAIDNOTFOUND;
+			    "NULL skb->data passed in, packet is bogus, dropping.\n");
+		return IPSEC_RCV_REALLYBAD;
 	}
 
-	/* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having
-	 * incremented the refcount, why in the world would we decrement it
-	 * here? */
-	/* ipsec_sa_put(irs->ipsp);*/ /* incomplete */
+	/* dev->hard_header_len is unreliable and should not be used */
+	/* klips26_rcv_encap will have already set hard_header_len for us */
+	if (irs->hard_header_len == 0) {
+		irs->hard_header_len = skb_mac_header(skb) ? (skb_network_header(skb) - skb_mac_header(skb)) : 0;
+		if((irs->hard_header_len < 0) || (irs->hard_header_len > skb_headroom(skb)))
+			irs->hard_header_len = 0;
+	}
 
-	/* If it is in larval state, drop the packet, we cannot process yet. */
-	if(newipsp->ips_state == SADB_SASTATE_LARVAL) {
-		KLIPS_PRINT(debug_rcv,
-			    "klips_debug:ipsec_rcv: "
-			    "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
-		if(irs->stats) {
-			irs->stats->rx_dropped++;
-		}
-		ipsec_sa_put(newipsp);
-		return IPSEC_RCV_SAIDNOTLIVE;
+	skb = ipsec_rcv_unclone(skb, irs);
+	if(skb == NULL) {
+		return IPSEC_RCV_REALLYBAD;
 	}
 
-	if(newipsp->ips_state == SADB_SASTATE_DEAD) {
-		KLIPS_PRINT(debug_rcv,
-			    "klips_debug:ipsec_rcv: "
-			    "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
-		if(irs->stats) {
-			irs->stats->rx_dropped++;
+#if IP_FRAGMENT_LINEARIZE
+	/* In Linux 2.4.4, we may have to reassemble fragments. They are
+	   not assembled automatically to save TCP from having to copy
+	   twice.
+	*/
+	if (skb_is_nonlinear(skb)) {
+#ifdef HAVE_NEW_SKB_LINEARIZE
+		if (skb_linearize_cow(skb) != 0)
+#else
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) 
+#endif
+		{
+			return IPSEC_RCV_REALLYBAD;
 		}
-		ipsec_sa_put(newipsp);
-		return IPSEC_RCV_SAIDNOTLIVE;
 	}
+#endif /* IP_FRAGMENT_LINEARIZE */
 
-	if(sysctl_ipsec_inbound_policy_check) {
-		if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
-			KLIPS_PRINT(debug_rcv,
-				    "klips_debug:ipsec_rcv: "
-				    "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
-				    irs->sa_len ? irs->sa : " (error)",
-				    irs->ipsaddr_txt);
-			if(irs->stats) {
-				irs->stats->rx_dropped++;
-			}
+	ipp = ip_hdr(skb);
+
+#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
+	if (irs->natt_len) {
+		/**
+		 * Now, we are sure packet is ESPinUDP, and we have a private
+		 * copy that has been linearized, remove natt_len bytes
+		 * from packet and modify protocol to ESP.
+		 */
+		if (((unsigned char *)skb->data > (unsigned char *)ip_hdr(skb))
+		    && ((unsigned char *)ip_hdr(skb) > (unsigned char *)skb->head))
+		{
+			unsigned int _len = (unsigned char *)skb->data -
+				(unsigned char *)ip_hdr(skb);
+			KLIPS_PRINT(debug_rcv,
+				"klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
+				_len);
+			skb_push(skb, _len);
+		}
+		KLIPS_PRINT(debug_rcv,
+		    "klips_debug:ipsec_rcv: "
+			"removing %d bytes from ESPinUDP packet\n", irs->natt_len);
+		ipp = (struct iphdr *)skb->data;
+		irs->iphlen = ipp->ihl << 2;
+		ipp->tot_len = htons(ntohs(ipp->tot_len) - irs->natt_len);
+		if (skb->len < irs->iphlen + irs->natt_len) {
+			printk(KERN_WARNING
+		       "klips_error:ipsec_rcv: "
+		       "ESPinUDP packet is too small (%d < %d+%d). "
+			   "This should never happen, please report.\n",
+		       (int)(skb->len), irs->iphlen, irs->natt_len);
+			return IPSEC_RCV_REALLYBAD;
+		}
+
+		/* advance payload pointer to point past the UDP header */
+		skb->h.raw = skb->h.raw + irs->natt_len;
+
+		/* modify protocol */
+		ipp->protocol = IPPROTO_ESP;
+
+		skb->sk = NULL;
+
+		KLIPS_IP_PRINT(debug_rcv, ip_hdr(skb));
+	}
+#endif
+
+	if (debug_rcv)
+	{
+	  	struct in_addr ipsaddr;
+		struct in_addr ipdaddr;
+
+		ipsaddr.s_addr = ipp->saddr;
+		addrtoa(ipsaddr, 0, irs->ipsaddr_txt
+			, sizeof(irs->ipsaddr_txt));
+		ipdaddr.s_addr = ipp->daddr;
+		addrtoa(ipdaddr, 0, irs->ipdaddr_txt
+			, sizeof(irs->ipdaddr_txt));
+	}
+
+	irs->iphlen = ipp->ihl << 2;
+
+	KLIPS_PRINT(debug_rcv,
+		    "klips_debug:ipsec_rcv: "
+		    "<<< Info -- ");
+	KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
+			skb->dev->name ? skb->dev->name : "NULL");
+	KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
+			dev->name ? dev->name : "NULL");
+	KLIPS_PRINTMORE(debug_rcv, "\n");
+
+	KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),
+		    "klips_debug:ipsec_rcv: "
+		    "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",
+		    skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",
+		    dev ? (dev->name ? dev->name : "NULL") : "NULL");
+
+	protoc = ipp->protocol;
+#ifndef NET_21
+	if((!protocol) || (protocol->protocol != protoc)) {
+		KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+			    "klips_debug:ipsec_rcv: "
+			    "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
+	}
+#endif /* !NET_21 */
+
+	if( (protoc != IPPROTO_AH) &&
+#ifdef CONFIG_KLIPS_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
+	    (protoc != IPPROTO_COMP) &&
+#endif /* CONFIG_KLIPS_IPCOMP */
+	    (protoc != IPPROTO_ESP) ) {
+		KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+			    "klips_debug:ipsec_rcv: Why the hell is someone "
+			    "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
+			    protoc);
+		return IPSEC_RCV_REALLYBAD;
+	}
+
+	if(skb->dev) {
+		for(i = 0; i < IPSEC_NUM_IF; i++) {
+			sprintf(name, IPSEC_DEV_FORMAT, i);
+			if(!strcmp(name, skb->dev->name)) {
+				prv = (struct ipsecpriv *)(skb->dev->priv);
+				if(prv) {
+					stats = (struct net_device_stats *) &(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 = __ipsec_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 net_device *)(prv->dev) : NULL;
+
+#if 0
+			KLIPS_PRINT(debug_rcv && prvdev,
+				    "klips_debug:ipsec_rcv: "
+				    "physical device for device %s is %s\n",
+				    name,
+				    prvdev->name);
+#endif
+			if(prvdev && skb->dev &&
+			   !strcmp(prvdev->name, skb->dev->name)) {
+				stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;
+				skb->dev = ipsecdev;
+				KLIPS_PRINT(debug_rcv && prvdev,
+					    "klips_debug:ipsec_rcv: "
+					    "assigning packet ownership to virtual device %s from physical device %s.\n",
+					    name, prvdev->name);
+				if(stats) {
+					stats->rx_packets++;
+				}
+				break;
+			}
+		}
+	} else {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "device supplied with skb is NULL\n");
+	}
+
+	if(stats == NULL) {
+		KLIPS_PRINT((debug_rcv),
+			    "klips_error:ipsec_rcv: "
+			    "packet received from physical I/F (%s) not connected to ipsec I/F.  Cannot record stats.  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");
+	}
+		
+	KLIPS_IP_PRINT(debug_rcv, ipp);
+
+	/* set up for decap */
+	irs->stats= stats;
+	irs->ipp  = ipp;
+	irs->ipsp = NULL;
+	irs->ilen = 0;
+	irs->authlen=0;
+	irs->authfuncs=NULL;
+	irs->skb = skb;
+	return IPSEC_RCV_OK;
+}
+
+
+static enum ipsec_rcv_value
+ipsec_rcv_decap_init(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
+
+	switch (irs->ipp->protocol) {
+	case IPPROTO_ESP:
+		irs->proto_funcs = esp_xform_funcs;
+		break;
+
+#ifdef CONFIG_KLIPS_AH
+	case IPPROTO_AH:
+		irs->proto_funcs = ah_xform_funcs;
+		break;
+#endif /* !CONFIG_KLIPS_AH */
+
+#ifdef CONFIG_KLIPS_IPCOMP
+	case IPPROTO_COMP:
+		irs->proto_funcs = ipcomp_xform_funcs;
+		break;
+#endif /* !CONFIG_KLIPS_IPCOMP */
+
+	default:
+		if (irs->stats) {
+			irs->stats->rx_errors++;
+		}
+		return IPSEC_RCV_BADPROTO;
+	}
+	return IPSEC_RCV_OK;
+}
+
+
+static enum ipsec_rcv_value
+ipsec_rcv_decap_chk(struct ipsec_rcv_state *irs)
+{
+	struct in_addr ipsaddr;
+	struct in_addr ipdaddr;
+	struct iphdr *ipp;
+	struct sk_buff *skb;
+
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
+
+	irs->replay = 0;
+#ifdef CONFIG_KLIPS_ALG
+	irs->ixt_a = NULL;
+#endif /* CONFIG_KLIPS_ALG */
+
+	skb = irs->skb;
+	irs->len = skb->len;
+	ipp = irs->ipp;
+	irs->proto = ipp->protocol;
+	if (debug_rcv) {
+	ipsaddr.s_addr = ipp->saddr;
+	addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
+	ipdaddr.s_addr = ipp->daddr;
+	addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+	}
+
+	irs->iphlen = ipp->ihl << 2;
+	ipp->check = 0;			/* we know the sum is good */
+	
+	KLIPS_PRINT(debug_rcv,
+		    "klips_debug:ipsec_rcv_decap_once: "
+		    "decap (%d) from %s -> %s\n",
+		    irs->proto, irs->ipsaddr_txt, irs->ipdaddr_txt);
+
+	/*
+	 * 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.
+	 */
+
+	irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr;
+	irs->said.dst.u.v4.sin_family = AF_INET;
+
+	/* note: rcv_checks set up the said.spi value, if appropriate */
+	if (irs->proto_funcs->rcv_checks)
+		return (*irs->proto_funcs->rcv_checks)(irs, irs->skb);
+
+	return IPSEC_RCV_OK;
+}
+
+
+static enum ipsec_rcv_value
+ipsec_rcv_auth_init(struct ipsec_rcv_state *irs)
+{
+	struct ipsec_sa *newipsp;
+
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
+
+	irs->said.proto = irs->proto;
+	if (debug_rcv) {
+	irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));
+	if(irs->sa_len == 0) {
+		strcpy(irs->sa, "(error)");
+	}
+	} else
+		irs->sa_len = 0;
+
+	newipsp = ipsec_sa_getbyid(&irs->said);
+	if (newipsp == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
+			    irs->sa_len ? irs->sa : " (error)");
+		if(irs->stats) {
+			irs->stats->rx_dropped++;
+		}
+		return IPSEC_RCV_SAIDNOTFOUND;
+	}
+
+	/* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having
+	 * incremented the refcount, why in the world would we decrement it
+	 * here? */
+	/* ipsec_sa_put(irs->ipsp);*/ /* incomplete */
+
+	/* If it is in larval state, drop the packet, we cannot process yet. */
+	if(newipsp->ips_state == SADB_SASTATE_LARVAL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
+		if(irs->stats) {
+			irs->stats->rx_dropped++;
+		}
+		ipsec_sa_put(newipsp);
+		return IPSEC_RCV_SAIDNOTLIVE;
+	}
+
+	if(newipsp->ips_state == SADB_SASTATE_DEAD) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
+		if(irs->stats) {
+			irs->stats->rx_dropped++;
+		}
+		ipsec_sa_put(newipsp);
+		return IPSEC_RCV_SAIDNOTLIVE;
+	}
+
+	if(sysctl_ipsec_inbound_policy_check) {
+		if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
+			KLIPS_PRINT(debug_rcv,
+				    "klips_debug:ipsec_rcv: "
+				    "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
+				    irs->sa_len ? irs->sa : " (error)",
+				    irs->ipsaddr_txt);
+			if(irs->stats) {
+				irs->stats->rx_dropped++;
+			}
 			ipsec_sa_put(newipsp);
 			return IPSEC_RCV_FAILEDINBOUND;
 		}
@@ -359,12 +866,8 @@
 				    irs->sa_len ? irs->sa : " (error)");
 		}
 
-
-
-
-
 #ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-		if (proto == IPPROTO_ESP) {
+		if (irs->proto == IPPROTO_ESP) {
 			KLIPS_PRINT(debug_rcv,
 				"klips_debug:ipsec_rcv: "
 				"natt_type=%u tdbp->ips_natt_type=%u : %s\n",
@@ -372,9 +875,9 @@
 				(irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
 			if (irs->natt_type != newipsp->ips_natt_type) {
 				KLIPS_PRINT(debug_rcv,
-					    "klips_debug:ipsec_rcv: "
-					    "SA:%s does not agree with expected NAT-T policy.\n",
-					    irs->sa_len ? irs->sa : " (error)");
+						"klips_debug:ipsec_rcv: "
+						"SA:%s does not agree with expected NAT-T policy.\n",
+						irs->sa_len ? irs->sa : " (error)");
 				if(irs->stats) {
 					irs->stats->rx_dropped++;
 				}
@@ -417,7 +920,7 @@
 		KLIPS_PRINT(debug_rcv,
 			    "klips_debug:ipsec_rcv_decap_once: "
 			    "decap (%d) failed lifetime check\n",
-			    proto);
+			    irs->proto);
 
 		return IPSEC_RCV_LIFETIMEFAILED;
 	}
@@ -483,7 +986,18 @@
 	irs->authfuncs=NULL;
 
 	/* authenticate, if required */
-	if ((ixt_a=irs->ipsp->ips_alg_auth)) {
+#ifdef CONFIG_KLIPS_OCF
+	if (irs->ipsp->ocf_in_use) {
+		irs->authlen = AHHMAC_HASHLEN;
+		irs->authfuncs = NULL;
+		irs->ictx = NULL;
+		irs->octx = NULL;
+		irs->ictx_len = 0;
+		irs->octx_len = 0;
+	} else
+#endif /* CONFIG_KLIPS_OCF */
+#ifdef CONFIG_KLIPS_ALG
+	if ((irs->ixt_a=irs->ipsp->ips_alg_auth)) {
 		irs->authlen = AHHMAC_HASHLEN;
 		irs->authfuncs = NULL;
 		irs->ictx = NULL;
@@ -496,6 +1010,7 @@
 				irs->ipsp->ips_authalg, 
 				irs->authlen);
 	} else
+#endif /* CONFIG_KLIPS_ALG */
 	switch(irs->ipsp->ips_authalg) {
 #ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
 	case AH_MD5:
@@ -539,27 +1054,44 @@
 	  KLIPS_PRINT(debug_rcv,
 		      "klips_debug:ipsec_rcv: "
 		      "runt %s packet with no data, dropping.\n",
-		      (proto == IPPROTO_ESP ? "esp" : "ah"));
+		      (irs->proto == IPPROTO_ESP ? "esp" : "ah"));
 	  if(irs->stats) {
 	    irs->stats->rx_dropped++;
 	  }
 	  return IPSEC_RCV_BADLEN;
 	}
 
-	if(irs->authfuncs || ixt_a) {
-		unsigned char *authenticator = NULL;
+	if(irs->authfuncs ||
+#ifdef CONFIG_KLIPS_OCF
+			irs->ipsp->ocf_in_use ||
+#endif
+#ifdef CONFIG_KLIPS_ALG
+			irs->ixt_a ||
+#endif
+			0) {
+	  if(irs->proto_funcs->rcv_setup_auth)
+	    return (*irs->proto_funcs->rcv_setup_auth)(irs, irs->skb,
+				&irs->replay, &irs->authenticator);
+	}
+	return IPSEC_RCV_OK;
+}
+
 
-		if(proto_funcs->rcv_setup_auth) {
-			enum ipsec_rcv_value retval
-			    = (*proto_funcs->rcv_setup_auth)(irs, skb,
-							 &replay,
-							 &authenticator);
-			if(retval < 0) {
-				return retval;
-			}
-		}
+static enum ipsec_rcv_value
+ipsec_rcv_auth_calc(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
-		if(!authenticator) {
+	if(irs->authfuncs ||
+#ifdef CONFIG_KLIPS_OCF
+			irs->ipsp->ocf_in_use ||
+#endif
+#ifdef CONFIG_KLIPS_ALG
+			irs->ixt_a ||
+#endif
+			0) {
+		if(!irs->authenticator) {
 			irs->ipsp->ips_errs.ips_auth_errs += 1;
 			if(irs->stats) {
 				irs->stats->rx_dropped++;
@@ -567,7 +1099,7 @@
 			return IPSEC_RCV_BADAUTH;
 		}
 
-		if(!ipsec_checkreplaywindow(irs->ipsp, replay)) {
+		if(!ipsec_checkreplaywindow(irs->ipsp, irs->replay)) {
 			irs->ipsp->ips_errs.ips_replaywin_errs += 1;
 			KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
 				    "klips_debug:ipsec_rcv: "
@@ -590,12 +1122,33 @@
 			    irs->ipsp->ips_authalg);
 
 		/* calculate authenticator */
-		if(proto_funcs->rcv_calc_auth == NULL) {
+		if(irs->proto_funcs->rcv_calc_auth == NULL) {
 			return IPSEC_RCV_BADAUTH;
 		}
-		(*proto_funcs->rcv_calc_auth)(irs, skb);
+		return (*irs->proto_funcs->rcv_calc_auth)(irs, irs->skb);
+	}
+	return IPSEC_RCV_OK;
+}
 
-		if (memcmp(irs->hash, authenticator, irs->authlen)) {
+static enum ipsec_rcv_value
+ipsec_rcv_auth_chk(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d) - %s\n", __FUNCTION__,
+			irs->state, irs->next_state,
+			irs->auth_checked ? "already checked" : "will check");
+
+	if (irs->auth_checked)
+		return IPSEC_RCV_OK;
+
+	if(irs->authfuncs ||
+#ifdef CONFIG_KLIPS_OCF
+			irs->ipsp->ocf_in_use ||
+#endif
+#ifdef CONFIG_KLIPS_ALG
+			irs->ixt_a ||
+#endif
+			0) {
+		if (memcmp(irs->hash, irs->authenticator, irs->authlen)) {
 			irs->ipsp->ips_errs.ips_auth_errs += 1;
 			KLIPS_PRINT(debug_rcv & DB_RX_INAU,
 				    "klips_debug:ipsec_rcv: "
@@ -604,9 +1157,9 @@
 				    ntohl(*(__u32*)&irs->hash[0]),
 				    ntohl(*(__u32*)&irs->hash[4]),
 				    ntohl(*(__u32*)&irs->hash[8]),
-				    ntohl(*(__u32*)authenticator),
-				    ntohl(*((__u32*)authenticator + 1)),
-				    ntohl(*((__u32*)authenticator + 2)));
+				    ntohl(*(__u32*)irs->authenticator),
+				    ntohl(*((__u32*)irs->authenticator + 1)),
+				    ntohl(*((__u32*)irs->authenticator + 2)));
 			if(irs->stats) {
 				irs->stats->rx_dropped++;
 			}
@@ -623,7 +1176,7 @@
 		memset(irs->hash, 0, irs->authlen);
 
 		/* If the sequence number == 0, expire SA, it had rolled */
-		if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) {
+		if(irs->ipsp->ips_replaywin && !irs->replay /* !irs->ipsp->ips_replaywin_lastseq */) {
 			ipsec_sa_delchain(irs->ipsp);
 			KLIPS_PRINT(debug_rcv,
 				    "klips_debug:ipsec_rcv: "
@@ -635,7 +1188,7 @@
 		}
 
 		/* now update the replay counter */
-		if (!ipsec_updatereplaywindow(irs->ipsp, replay)) {
+		if (!ipsec_updatereplaywindow(irs->ipsp, irs->replay)) {
 			irs->ipsp->ips_errs.ips_replaywin_errs += 1;
 			KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
 				    "klips_debug:ipsec_rcv: "
@@ -646,19 +1199,51 @@
 			}
 			return IPSEC_RCV_REPLAYROLLED;
 		}
+		irs->auth_checked = 1;
 	}
+	return IPSEC_RCV_OK;
+}
 
-	if(proto_funcs->rcv_decrypt) {
-		enum ipsec_rcv_value retval =
-		  (*proto_funcs->rcv_decrypt)(irs);
+static enum ipsec_rcv_value
+ipsec_rcv_decrypt(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
-		if(retval != IPSEC_RCV_OK) {
-			return retval;
-		}
+	if (irs->proto_funcs->rcv_decrypt) {
+		return (*irs->proto_funcs->rcv_decrypt)(irs);
 	}
+	return IPSEC_RCV_OK;
+}
+
+/*
+ * here we decide if there is more decapsulating required and
+ * change the next state appropriately
+ */
+static enum ipsec_rcv_value
+ipsec_rcv_decap_cont(struct ipsec_rcv_state *irs)
+{
+	struct sk_buff *skb;
+	struct iphdr *ipp;
+	struct in_addr ipsaddr;
+	struct in_addr ipdaddr;
+	struct ipsec_sa *ipsnext = NULL; /* next SA towards inside of packet */
+	enum ipsec_rcv_value rv;
+
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
 	/*
-	 *	Adjust pointers
+	 * if we haven't checked the auth values yet, do it now.
+	 * This is needed for the case where drivers do crypt+hash
+	 * in one operation.
+	 */
+	rv = ipsec_rcv_auth_chk(irs);
+	if (rv != IPSEC_RCV_OK)
+		return rv;
+
+	/*
+	 *	Adjust pointers after decrypt
 	 */
 	skb = irs->skb;
 	irs->len = skb->len;
@@ -669,10 +1254,12 @@
 	/* zero any options that there might be */
 	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
 
+	if (debug_rcv) {
 	ipsaddr.s_addr = ipp->saddr;
 	addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
 	ipdaddr.s_addr = ipp->daddr;
 	addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+	}
 
 	/*
 	 *	Discard the original ESP/AH header
@@ -747,111 +1334,50 @@
 	irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
 
 #ifdef CONFIG_NETFILTER
-	if(proto == IPPROTO_ESP || proto == IPPROTO_AH) {
+	if(irs->proto == IPPROTO_ESP || irs->proto == IPPROTO_AH) {
 		skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
 			| IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
 		KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
 			    "klips_debug:ipsec_rcv: "
 			    "%s SA sets skb->nfmark=0x%x.\n",
-			    proto == IPPROTO_ESP ? "ESP" : "AH",
+			    irs->proto == IPPROTO_ESP ? "ESP" : "AH",
 			    (unsigned)skb->nfmark);
 	}
 #endif /* CONFIG_NETFILTER */
 
+	/*
+	 * do we need to do more decapsulation
+	 */
+
+	if (irs->ipp->protocol == IPPROTO_ESP ||
+			irs->ipp->protocol == IPPROTO_AH ||
+#ifdef CONFIG_KLIPS_IPCOMP
+			irs->ipp->protocol == IPPROTO_COMP ||
+#endif /* CONFIG_KLIPS_IPCOMP */
+			0) {
+		irs->next_state = IPSEC_RSM_DECAP_INIT;
+	}
 	return IPSEC_RCV_OK;
 }
 
 
-/*
- * core decapsulation loop for all protocols.
- *
- * the following things should be setup to enter this function.
- *
- * irs->stats  == stats structure (or NULL)
- * irs->ipp    = IP header.
- * irs->ipsp   = NULL.
- * irs->ilen   = 0;
- * irs->authlen = 0;
- * irs->authfuncs = NULL;
- * irs->skb    = skb;
- * skb->nh.iph = ipp;
- * skb->h.raw  = start of payload
- *
- */
-int ipsec_rcv_decap(struct ipsec_rcv_state *irs)
+static enum ipsec_rcv_value
+ipsec_rcv_cleanup(struct ipsec_rcv_state *irs)
 {
-	struct ipsec_sa *ipsp = NULL;
-	struct ipsec_sa* ipsnext = NULL;
+	struct sk_buff *skb;
+	struct iphdr *ipp;
 	struct in_addr ipsaddr;
 	struct in_addr ipdaddr;
-	struct iphdr *ipp;
-	struct sk_buff *skb = NULL;
-
-	/* begin decapsulating loop here */
-
-	/*
-	  The spinlock is to prevent any other process from
-	  accessing or deleting the ipsec_sa hash table or any of the
-	  ipsec_sa s while we are using and updating them.
-
-	  This is not optimal, but was relatively straightforward
-	  at the time.  A better way to do it has been planned for
-	  more than a year, to lock the hash table and put reference
-	  counts on each ipsec_sa instead.  This is not likely to happen
-	  in KLIPS1 unless a volunteer contributes it, but will be
-	  designed into KLIPS2.
-	*/
-	spin_lock(&tdb_lock);
+	struct ipsec_sa *ipsnext = NULL; /* next SA towards inside of packet */
+	struct ipsec_sa *ipsp = NULL;
 
-	do {
-	        int decap_stat;
-		struct xform_functions *proto_funcs;
-
-		switch(irs->ipp->protocol) {
-		case IPPROTO_ESP:
-		  proto_funcs = esp_xform_funcs;
-		  break;
-		  
-#ifdef CONFIG_KLIPS_AH
-		case IPPROTO_AH:
-		  proto_funcs = ah_xform_funcs;
-		  break;
-#endif /* !CONFIG_KLIPS_AH */
-		  
-#ifdef CONFIG_KLIPS_IPCOMP
-		case IPPROTO_COMP:
-		  proto_funcs = ipcomp_xform_funcs;
-		  break;
-#endif /* !CONFIG_KLIPS_IPCOMP */
-		default:
-		  if(irs->stats) {
-		    irs->stats->rx_errors++;
-		  }
-		  decap_stat = IPSEC_RCV_BADPROTO;
-		  goto rcvleave;
-		}
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
-	        decap_stat = ipsec_rcv_decap_once(irs, proto_funcs);
-
-		if(decap_stat != IPSEC_RCV_OK) {
-			spin_unlock(&tdb_lock);
-			KLIPS_PRINT(debug_rcv,
-				    "klips_debug:ipsec_rcv: decap_once failed: %d\n",
-				    decap_stat);
-		
-			goto rcvleave;
-		}
-	/* end decapsulation loop here */
-	} while(   (irs->ipp->protocol == IPPROTO_ESP )
-		|| (irs->ipp->protocol == IPPROTO_AH  )
-#ifdef CONFIG_KLIPS_IPCOMP
-		|| (irs->ipp->protocol == IPPROTO_COMP)
-#endif /* CONFIG_KLIPS_IPCOMP */
-		);
 
 	/* set up for decap loop */
-	ipp  =irs->ipp;
-	ipsp =irs->ipsp;
+	ipp  = irs->ipp;
+	ipsp = irs->ipsp;
 	ipsnext = ipsp->ips_inext;
 	skb = irs->skb;
 
@@ -877,7 +1403,7 @@
 	    ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
 	  __u16 pkt_len = skb_tail_pointer(skb) - (unsigned char *)ipp;
 	  __u16 data_len = pkt_len - (ipp->ihl << 2);
-	  
+  	  
 	  switch (ipp->protocol) {
 	  case IPPROTO_TCP:
 	    if (data_len >= sizeof(struct tcphdr)) {
@@ -903,12 +1429,12 @@
 					       data_len, IPPROTO_TCP,
 					       csum_partial((unsigned char *)tcp, data_len, 0));
 	      }
-	    }
-	    else {
-	      KLIPS_PRINT(debug_rcv,
-			  "klips_debug:ipsec_rcv: "
+  	    }
+  	    else {
+  	      KLIPS_PRINT(debug_rcv,
+  			  "klips_debug:ipsec_rcv: "
 			  "NAT-T & TRANSPORT: can't fix TCP checksum\n");
-	    }
+  	    }
 	    break;
 	  case IPPROTO_UDP:
 	    if (data_len >= sizeof(struct udphdr)) {
@@ -945,22 +1471,22 @@
 			    "NAT-T & TRANSPORT: zero UDP checksum\n");
 		udp->check = 0;
 	      }
-	    }
-	    else {
-	      KLIPS_PRINT(debug_rcv,
-			  "klips_debug:ipsec_rcv: "
+  	    }
+  	    else {
+  	      KLIPS_PRINT(debug_rcv,
+  			  "klips_debug:ipsec_rcv: "
 			  "NAT-T & TRANSPORT: can't fix UDP checksum\n");
-	    }
+  	    }
 	    break;
 	  default:
 	    KLIPS_PRINT(debug_rcv,
 			"klips_debug:ipsec_rcv: "
 			"NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
 	    break;
-	  }
-	}
+  	  }
+  	}
 #endif
-
+  
 	/*
 	 * XXX this needs to be locked from when it was first looked
 	 * up in the decapsulation loop.  Perhaps it is better to put
@@ -971,7 +1497,6 @@
 		irs->sa_len = KLIPS_SATOT(debug_rcv, &irs->said, 0, irs->sa, sizeof(irs->sa));
 		if((ipp->protocol != IPPROTO_IPIP) && 
                    (ipp->protocol != IPPROTO_ATT_HEARTBEAT)) {  /* AT&T heartbeats to SIG/GIG */
-			spin_unlock(&tdb_lock);
 			KLIPS_PRINT(debug_rcv,
 				    "klips_debug:ipsec_rcv: "
 				    "SA:%s, Hey!  How did this get through?  Dropped.\n",
@@ -979,7 +1504,7 @@
 			if(irs->stats) {
 				irs->stats->rx_dropped++;
 			}
-			goto rcvleave;
+			return IPSEC_RCV_REALLYBAD;
 		}
 		if(sysctl_ipsec_inbound_policy_check) {
 			struct sockaddr_in *psin = (struct sockaddr_in*)(ipsp->ips_addr_s);
@@ -987,7 +1512,6 @@
 				char sa2[SATOT_BUF];
 				size_t sa_len2;
 				sa_len2 = KLIPS_SATOT(debug_rcv, &ipsnext->ips_said, 0, sa2, sizeof(sa2));
-				spin_unlock(&tdb_lock);
 				KLIPS_PRINT(debug_rcv,
 					    "klips_debug:ipsec_rcv: "
 					    "unexpected SA:%s after IPIP SA:%s\n",
@@ -996,10 +1520,9 @@
 				if(irs->stats) {
 					irs->stats->rx_dropped++;
 				}
-				goto rcvleave;
+				return IPSEC_RCV_FAILEDINBOUND;
 			}
 			if(ipp->saddr != psin->sin_addr.s_addr) {
-				spin_unlock(&tdb_lock);
 				KLIPS_PRINT(debug_rcv,
 					    "klips_debug:ipsec_rcv: "
 					    "SA:%s, src=%s(%08x) does not match expected 0x%08x.\n",
@@ -1009,7 +1532,7 @@
 				if(irs->stats) {
 					irs->stats->rx_dropped++;
 				}
-				goto rcvleave;
+				return IPSEC_RCV_FAILEDINBOUND;
 			}
 		}
 
@@ -1030,13 +1553,12 @@
 		ipsp->ips_life.ipl_packets.ipl_count += 1;
 
 		if(skb->len < irs->iphlen) {
-			spin_unlock(&tdb_lock);
 			printk(KERN_WARNING "klips_debug:ipsec_rcv: "
 			       "tried to skb_pull iphlen=%d, %d available.  This should never happen, please report.\n",
 			       irs->iphlen,
 			       (int)(skb->len));
 
-			goto rcvleave;
+			return IPSEC_RCV_REALLYBAD;
 		}
 
 		/*
@@ -1100,7 +1622,6 @@
 			subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
 				ipsp->ips_mask_d.u.v4.sin_addr,
 				0, dflow_txt, sizeof(dflow_txt));
-			spin_unlock(&tdb_lock);
 			KLIPS_PRINT(debug_rcv,
 				    "klips_debug:ipsec_rcv: "
 				    "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
@@ -1112,7 +1633,7 @@
 			if(irs->stats) {
 				irs->stats->rx_dropped++;
 			}
-			goto rcvleave;
+			return IPSEC_RCV_REALLYBAD;
 		}
 #ifdef CONFIG_NETFILTER
 		skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK))))
@@ -1124,8 +1645,6 @@
 #endif /* CONFIG_NETFILTER */
 	}
 
-	spin_unlock(&tdb_lock);
-
 	if(irs->stats) {
 		irs->stats->rx_bytes += skb->len;
 	}
@@ -1142,9 +1661,18 @@
 			skb_mac_header(skb), irs->hard_header_len);
 		skb_set_mac_header(skb, ipsec_skb_offset(skb, skb_network_header(skb) - irs->hard_header_len));
 	}
+	return IPSEC_RCV_OK;
+}
+
+
+static enum ipsec_rcv_value
+ipsec_rcv_ipcomp(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
 #ifdef CONFIG_KLIPS_IPCOMP
-	if(ipp->protocol == IPPROTO_COMP) {
+	if(irs->ipp->protocol == IPPROTO_COMP) {
 		unsigned int flags = 0;
 
 		if(sysctl_ipsec_inbound_policy_check) {
@@ -1154,14 +1682,14 @@
 			if (irs->stats) {
 				irs->stats->rx_errors++;
 			}
-			goto rcvleave;
+			return IPSEC_RCV_IPCOMPFAILED;
 		}
 		/*
 		  XXX need a ipsec_sa for updating ratio counters but it is not
 		  following policy anyways so it is not a priority
 		*/
-		skb = skb_decompress(skb, NULL, &flags);
-		if (!skb || flags) {
+		irs->skb = skb_decompress(irs->skb, NULL, &flags);
+		if (!irs->skb || flags) {
 			KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
 				"klips_debug:ipsec_rcv: "
 				"skb_decompress() returned error flags: %d, dropped.\n",
@@ -1169,10 +1697,19 @@
 			if (irs->stats) {
 				irs->stats->rx_errors++;
 			}
-			goto rcvleave;
+			return IPSEC_RCV_IPCOMPFAILED;
 		}
 	}
 #endif /* CONFIG_KLIPS_IPCOMP */
+	return IPSEC_RCV_OK;
+}
+
+
+static enum ipsec_rcv_value
+ipsec_rcv_complete(struct ipsec_rcv_state *irs)
+{
+	KLIPS_PRINT(debug_rcv, "klips_debug: %s(st=%d,nxt=%d)\n", __FUNCTION__,
+			irs->state, irs->next_state);
 
 	/*
 	 * make sure that data now starts at IP header, since we are going
@@ -1191,426 +1728,209 @@
 #endif
 
 #ifdef SKB_RESET_NFCT
-	nf_conntrack_put(skb->nfct);
-	skb->nfct = NULL;
+	nf_conntrack_put(irs->skb->nfct);
+	irs->skb->nfct = NULL;
 #if defined(CONFIG_NETFILTER_DEBUG) && defined(HAVE_SKB_NF_DEBUG)
-	skb->nf_debug = 0;
+	irs->skb->nf_debug = 0;
 #endif /* CONFIG_NETFILTER_DEBUG */
 #endif /* SKB_RESET_NFCT */
 	KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
 		    "klips_debug:ipsec_rcv: "
 		    "netif_rx() called.\n");
-	netif_rx(skb);
-	skb=NULL;
-
- rcvleave:
-	if(skb) {
-		ipsec_kfree_skb(skb);
-	}
-
-	/* KLIPS_DEC_USE; Artifact from refactor? bug # 454 */
-	return(0);
+	netif_rx(irs->skb);
+	irs->skb = NULL;
+	return IPSEC_RCV_OK;
 }
 
-struct sk_buff *ipsec_rcv_unclone(struct sk_buff *skb,
-				  struct ipsec_rcv_state *irs)
-{
-	/* if skb was cloned (most likely due to a packet sniffer such as
-	   tcpdump being momentarily attached to the interface), make
-	   a copy of our own to modify */
-	if(skb_cloned(skb)) {
-		/* include any mac header while copying.. */
-		if(skb_headroom(skb) < irs->hard_header_len) {
-			printk(KERN_WARNING "klips_error:ipsec_rcv: "
-			       "tried to skb_push hhlen=%d, %d available.  This should never happen, please report.\n",
-			       irs->hard_header_len,
-			       skb_headroom(skb));
-			goto rcvleave;
-		}
-		skb_push(skb, irs->hard_header_len);
-		if
-#ifdef SKB_COW_NEW
-		  (skb_cow(skb, skb_headroom(skb)) != 0)
-#else /* SKB_COW_NEW */
-		  ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
-#endif /* SKB_COW_NEW */
-		{
-			goto rcvleave;
-		}
-		if(skb->len < irs->hard_header_len) {
-			printk(KERN_WARNING "klips_error:ipsec_rcv: "
-			       "tried to skb_pull hhlen=%d, %d available.  This should never happen, please report.\n",
-			       irs->hard_header_len,
-			       skb->len);
-			goto rcvleave;
-		}
-		skb_pull(skb, irs->hard_header_len);
-	}
-	return skb;
-
-rcvleave:
-	ipsec_kfree_skb(skb);
-	return NULL;
-}
 
 
-#if !defined(NET_26) && defined(CONFIG_IPSEC_NAT_TRAVERSAL)
 /*
- * decapsulate a UDP encapsulated ESP packet
+ * ipsec_rsm is responsible for walking us through the state machine
+ * it is the only entry point into the receive processing and does
+ * appropriate checks and state changes for us.
  */
-struct sk_buff *ipsec_rcv_natt_decap(struct sk_buff *skb
-				     , struct ipsec_rcv_state *irs
-				     , int *udp_decap_ret_p)
-{
-	*udp_decap_ret_p = 0;
-	if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) {
-		/**
-		 * Packet comes from udp_queue_rcv_skb so it is already defrag,
-		 * checksum verified, ... (ie safe to use)
-		 *
-		 * If the packet is not for us, return -1 and udp_queue_rcv_skb
-		 * will continue to handle it (do not kfree skb !!).
-		 */
-
-#ifndef UDP_OPT_IN_SOCK
-		struct udp_opt {
-			__u32 esp_in_udp;
-		};
-		struct udp_opt *tp =  (struct udp_opt *)&(skb->sk->tp_pinfo.af_tcp);
-#else
-		struct udp_opt *tp =  &(skb->sk->tp_pinfo.af_udp);
-#endif
-
-		struct iphdr *ip = (struct iphdr *)skb->nh.iph;
-		struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
-		__u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
-		__u32 *udpdata32 = (__u32 *)udpdata;
-		
-		irs->natt_sport = ntohs(udp->source);
-		irs->natt_dport = ntohs(udp->dest);
-	  
-		KLIPS_PRINT(debug_rcv,
-			    "klips_debug:ipsec_rcv: "
-			    "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
-			    tp->esp_in_udp);
-		KLIPS_IP_PRINT(debug_rcv, ip);
-	  
-		if (udpdata < skb->tail) {
-			unsigned int len = skb->tail - udpdata;
-			if ((len==1) && (udpdata[0]==0xff)) {
-				KLIPS_PRINT(debug_rcv,
-					    "klips_debug:ipsec_rcv: "
-					    /* not IPv6 compliant message */
-					    "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
-				*udp_decap_ret_p = 0;
-				return NULL;
-			}
-			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
-				  (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
-				  (udpdata32[0]==0) && (udpdata32[1]==0) ) {
-				/* ESP Packet with Non-IKE header */
-				KLIPS_PRINT(debug_rcv, 
-					    "klips_debug:ipsec_rcv: "
-					    "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
-					    ntohl(udpdata32[2]));
-				irs->natt_type = ESPINUDP_WITH_NON_IKE;
-				irs->natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
-			}
-			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
-				  (len > sizeof(struct esphdr)) &&
-				  (udpdata32[0]!=0) ) {
-				/* ESP Packet without Non-ESP header */
-				irs->natt_type = ESPINUDP_WITH_NON_ESP;
-				irs->natt_len = sizeof(struct udphdr);
-				KLIPS_PRINT(debug_rcv, 
-					    "klips_debug:ipsec_rcv: "
-					    "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
-					    ntohl(udpdata32[0]));
-			}
-			else {
-				KLIPS_PRINT(debug_rcv,
-					    "klips_debug:ipsec_rcv: "
-					    "IKE packet - not handled here\n");
-				*udp_decap_ret_p = -1;
-				return NULL;
-			}
-		}
-		else {
-			return NULL;
-		}
-	}
-	return skb;
-}
-#endif
 
-
-int
-ipsec_rcv(struct sk_buff *skb
-#ifndef PROTO_HANDLER_SINGLE_PARM
-	  unsigned short xlen
-#endif /* PROTO_HANDLER_SINGLE_PARM */
-	  )
+void
+ipsec_rsm(struct ipsec_rcv_state *irs)
 {
-#ifdef CONFIG_KLIPS_DEBUG
-	struct net_device *dev = skb->dev;
-#endif /* CONFIG_KLIPS_DEBUG */
-	unsigned char protoc;
-	struct net_device_stats *stats = NULL;		/* This device's statistics */
-	struct net_device *ipsecdev = NULL, *prvdev;
-	struct ipsecpriv *prv;
-	struct ipsec_rcv_state nirs, *irs = &nirs;
-	struct iphdr *ipp;
-	char name[9];
-	int i;
-
-	/* Don't unlink in the middle of a turnaround */
-	KLIPS_INC_USE;
-
-	memset(&nirs, 0, sizeof(struct ipsec_rcv_state));
-
-	if (skb == NULL) {
+	if (irs == 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;
-	}
-
-#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
-	{
-		/* NET_26 NAT-T is handled by seperate function */
-		struct sk_buff *nskb;
-		int udp_decap_ret = 0;
-
-		nskb = ipsec_rcv_natt_decap(skb, irs, &udp_decap_ret);
-		if(nskb == NULL) {
-			/* return with non-zero, because UDP.c code
-			 * need to send it upstream.
-			 */
-			if(skb && udp_decap_ret == 0) {
-				ipsec_kfree_skb(skb);
-			}
-			KLIPS_DEC_USE;
-			return(udp_decap_ret);
-		}
-		skb = nskb;
-	}
-#endif /* NAT_T */
-
-	/* dev->hard_header_len is unreliable and should not be used */
-	/* klips26_rcv_encap will have already set hard_header_len for us?? */
-	if (irs->hard_header_len == 0) {
-		irs->hard_header_len = skb_mac_header(skb) ? (skb_network_header(skb) - skb_mac_header(skb)) : 0;
-		if((irs->hard_header_len < 0) || (irs->hard_header_len > skb_headroom(skb)))
-			irs->hard_header_len = 0;
-	}
-
-	skb = ipsec_rcv_unclone(skb, irs);
-	if(skb == NULL) {
-		goto rcvleave;
-	}
-
-#if IP_FRAGMENT_LINEARIZE
-	/* In Linux 2.4.4, we may have to reassemble fragments. They are
-	   not assembled automatically to save TCP from having to copy
-	   twice.
-	*/
-	if (skb_is_nonlinear(skb)) {
-#ifdef HAVE_NEW_SKB_LINEARIZE
-		if (skb_linearize_cow(skb) != 0)
-#else
-		if (skb_linearize(skb, GFP_ATOMIC) != 0) 
-#endif
-		{
-			goto rcvleave;
-		}
+			    "klips_debug:ipsec_rsm: "
+			    "irs == NULL.\n");
+		return;
 	}
-#endif /* IP_FRAGMENT_LINEARIZE */
 
-#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
-	if (irs->natt_len) {
-		/**
-		 * Now, we are sure packet is ESPinUDP, and we have a private
-		 * copy that has been linearized, remove natt_len bytes
-		 * from packet and modify protocol to ESP.
-		 */
-		if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph)
-		    && ((unsigned char *)skb->nh.iph > (unsigned char *)skb->head))
-		{
-			unsigned int _len = (unsigned char *)skb->data -
-				(unsigned char *)skb->nh.iph;
-			KLIPS_PRINT(debug_rcv,
-				"klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
-				_len);
-			skb_push(skb, _len);
-		}
-		KLIPS_PRINT(debug_rcv,
-		    "klips_debug:ipsec_rcv: "
-			"removing %d bytes from ESPinUDP packet\n", irs->natt_len);
-		ipp = skb->nh.iph;
-		irs->iphlen = ipp->ihl << 2;
-		ipp->tot_len = htons(ntohs(ipp->tot_len) - irs->natt_len);
-		if (skb->len < irs->iphlen + irs->natt_len) {
-			printk(KERN_WARNING
-		       "klips_error:ipsec_rcv: "
-		       "ESPinUDP packet is too small (%d < %d+%d). "
-			   "This should never happen, please report.\n",
-		       (int)(skb->len), irs->iphlen, irs->natt_len);
-			goto rcvleave;
-		}
-
-		/* advance payload pointer to point past the UDP header */
-		skb->h.raw = skb->h.raw + irs->natt_len;
+	/*
+	 * make sure nothing is removed from underneath us
+	 */
+	spin_lock_bh(&tdb_lock);
 
-		/* modify protocol */
-		ipp->protocol = IPPROTO_ESP;
+	/*
+	 * if we have a valid said,  then we must check it here to ensure it
+	 * hasn't gone away while we were waiting for a task to complete
+	 */
 
-		skb->sk = NULL;
+	if (irs->said.proto && ipsec_sa_getbyid(&irs->said) == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
+			    irs->sa_len ? irs->sa : " (error)");
+		if (irs->stats)
+			irs->stats->rx_dropped++;
 
-		KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);
+		/* drop through and cleanup */
+		irs->state = IPSEC_RSM_DONE;
 	}
-#endif
 
-	/* ipp = skb->nh.iph; */
-	ipp = ip_hdr(skb);
+	while (irs->state != IPSEC_RSM_DONE) {
+		int rc;
 
-	{
-	  	struct in_addr ipsaddr;
-		struct in_addr ipdaddr;
+		irs->next_state = rcv_state_table[irs->state].next_state;
 
-		ipsaddr.s_addr = ipp->saddr;
-		addrtoa(ipsaddr, 0, irs->ipsaddr_txt
-			, sizeof(irs->ipsaddr_txt));
-		ipdaddr.s_addr = ipp->daddr;
-		addrtoa(ipdaddr, 0, irs->ipdaddr_txt
-			, sizeof(irs->ipdaddr_txt));
+		rc = rcv_state_table[irs->state].action(irs);
+
+		if (rc == IPSEC_RCV_OK) {
+			/* some functions change the next state, see the state table */
+			irs->state = irs->next_state;
+		} else if (rc == IPSEC_RCV_PENDING) {
+			/*
+			 * things are on hold until we return here in the next/new state
+			 * we check our SA is valid when we return
+			 */
+			spin_unlock_bh(&tdb_lock);
+			return;
+		} else {
+			/* bad result, force state change to done */
+			KLIPS_PRINT(debug_rcv,
+					"klips_debug:ipsec_rsm: "
+					"processing completed due to %s.\n",
+					ipsec_rcv_err(rc));
+			irs->state = IPSEC_RSM_DONE;
+		}
 	}
 
-	irs->iphlen = ipp->ihl << 2;
+	/*
+	 * all done with anything needing locks
+	 */
+	spin_unlock_bh(&tdb_lock);
 
-	KLIPS_PRINT(debug_rcv,
-		    "klips_debug:ipsec_rcv: "
-		    "<<< Info -- ");
-	KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
-			skb->dev->name ? skb->dev->name : "NULL");
-	KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
-			dev->name ? dev->name : "NULL");
-	KLIPS_PRINTMORE(debug_rcv, "\n");
+	if (irs->skb) {
+		ipsec_kfree_skb(irs->skb);
+		irs->skb = NULL;
+	}
+	kmem_cache_free(ipsec_irs_cache, irs);
+	atomic_dec(&ipsec_irs_cnt);
 
-	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");
+	KLIPS_DEC_USE; /* once less packet using the driver */
+}
 
-	protoc = ipp->protocol;
-#ifndef NET_21
-	if((!protocol) || (protocol->protocol != protoc)) {
-		KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
+
+
+int
+ipsec_rcv(struct sk_buff *skb
+#ifndef PROTO_HANDLER_SINGLE_PARM
+	  unsigned short xlen
+#endif /* PROTO_HANDLER_SINGLE_PARM */
+	  )
+{
+	struct ipsec_rcv_state *irs = NULL;
+
+	/* Don't unlink in the middle of a turnaround */
+	KLIPS_INC_USE;
+
+	if (skb == NULL) {
+		KLIPS_PRINT(debug_rcv,
 			    "klips_debug:ipsec_rcv: "
-			    "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
+			    "NULL skb passed in.\n");
+		goto rcvleave;
 	}
-#endif /* !NET_21 */
 
-	if( (protoc != IPPROTO_AH) &&
-#ifdef CONFIG_KLIPS_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
-	    (protoc != IPPROTO_COMP) &&
-#endif /* CONFIG_KLIPS_IPCOMP */
-	    (protoc != IPPROTO_ESP) ) {
-		KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
-			    "klips_debug:ipsec_rcv: Why the hell is someone "
-			    "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
-			    protoc);
+	if (skb->data == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "NULL skb->data passed in, packet is bogus, dropping.\n");
 		goto rcvleave;
 	}
 
-	if(skb->dev) {
-		for(i = 0; i < IPSEC_NUM_IF; i++) {
-			sprintf(name, IPSEC_DEV_FORMAT, i);
-			if(!strcmp(name, skb->dev->name)) {
-				prv = (struct ipsecpriv *)(skb->dev->priv);
-				if(prv) {
-					stats = (struct net_device_stats *) &(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 = __ipsec_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 net_device *)(prv->dev) : NULL;
+	if (atomic_read(&ipsec_irs_cnt) >= ipsec_irs_max) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "exceeded outstanding RX packet cnt %d\n", ipsec_irs_max);
+		goto rcvleave;
+	}
 
-#if 0
-			KLIPS_PRINT(debug_rcv && prvdev,
-				    "klips_debug:ipsec_rcv: "
-				    "physical device for device %s is %s\n",
-				    name,
-				    prvdev->name);
-#endif
-			if(prvdev && skb->dev &&
-			   !strcmp(prvdev->name, skb->dev->name)) {
-				stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;
-				skb->dev = ipsecdev;
-				KLIPS_PRINT(debug_rcv && prvdev,
-					    "klips_debug:ipsec_rcv: "
-					    "assigning packet ownership to virtual device %s from physical device %s.\n",
-					    name, prvdev->name);
-				if(stats) {
-					stats->rx_packets++;
-				}
-				break;
-			}
-		}
-	} else {
+	irs = kmem_cache_alloc(ipsec_irs_cache, GFP_ATOMIC);
+	if (irs == NULL) {
 		KLIPS_PRINT(debug_rcv,
 			    "klips_debug:ipsec_rcv: "
-			    "device supplied with skb is NULL\n");
+			    "Cannot allocate ipsec_rcv_state.\n");
+		goto rcvleave;
 	}
+#if 0 /* optimised to only clear the essentials */
+	memset(irs, 0, sizeof(*irs));
+#else
+	irs->state = 0;
+	irs->next_state = 0;
+	irs->auth_checked = 0;
+	irs->stats = NULL;
+	irs->authenticator = NULL;
+	irs->said.proto = 0;
 
-	if(stats == NULL) {
-		KLIPS_PRINT((debug_rcv),
-			    "klips_error:ipsec_rcv: "
-			    "packet received from physical I/F (%s) not connected to ipsec I/F.  Cannot record stats.  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");
+	irs->hard_header_len = 0;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	irs->natt_type = 0;
+	irs->natt_len = 0;
+#endif
+#endif
+
+#if defined(CONFIG_IPSEC_NAT_TRAVERSAL) && !defined(NET_26)
+	{
+  		/* NET_26 NAT-T is handled by seperate function */
+  		struct sk_buff *nskb;
+		int udp_decap_ret = 0;
+  
+		nskb = ipsec_rcv_natt_decap(skb, irs, &udp_decap_ret);
+  		if(nskb == NULL) {
+			/* return with non-zero, because UDP.c code
+			 * need to send it upstream.
+			 */
+			if(skb && udp_decap_ret == 0) {
+				ipsec_kfree_skb(skb);
+			}
+			if (irs) {
+				kmem_cache_free(ipsec_irs_cache, irs);
+			}
+			KLIPS_DEC_USE;
+			return(udp_decap_ret);
+  		}
+  		skb = nskb;
 	}
-		
-	KLIPS_IP_PRINT(debug_rcv, ipp);
+#endif /* NAT_T */
 
-	/* set up for decap loop */
-	irs->stats= stats;
-	irs->ipp  = ipp;
-	irs->ipsp = NULL;
-	irs->ilen = 0;
-	irs->authlen=0;
-	irs->authfuncs=NULL;
 	irs->skb = skb;
 
-	ipsec_rcv_decap(irs);
-	KLIPS_DEC_USE;
+	/*
+	 * we hand off real early to the state machine because we just cannot
+	 * know how much processing it is off-loading
+	 */
+	atomic_inc(&ipsec_irs_cnt);
+	ipsec_rsm(irs);
+
 	return(0);
 
  rcvleave:
-	if(skb) {
+	if (irs) {
+		kmem_cache_free(ipsec_irs_cache, irs);
+	}
+	if (skb) {
 		ipsec_kfree_skb(skb);
 	}
+
 	KLIPS_DEC_USE;
 	return(0);
-
 }
 
+
 #ifdef NET_26
 /*
  * this entry point is not a protocol entry point, so the entry
@@ -1626,13 +1946,52 @@
  */
 int klips26_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 {
-	struct ipsec_rcv_state nirs, *irs = &nirs;
-	struct iphdr *ipp;
+	struct ipsec_rcv_state *irs = NULL;
 
 	/* Don't unlink in the middle of a turnaround */
 	KLIPS_INC_USE;
 
+	if (skb == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "NULL skb passed in.\n");
+		goto rcvleave;
+	}
+
+	if (skb->data == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "NULL skb->data passed in, packet is bogus, dropping.\n");
+		goto rcvleave;
+	}
+
+	if (atomic_read(&ipsec_irs_cnt) >= ipsec_irs_max) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "exceeded outstanding RX packet cnt %d\n", ipsec_irs_max);
+		goto rcvleave;
+	}
+
+	irs = kmem_cache_alloc(ipsec_irs_cache, GFP_ATOMIC);
+	if (irs == NULL) {
+		KLIPS_PRINT(debug_rcv,
+			    "klips_debug:ipsec_rcv: "
+			    "Cannot allocate ipsec_rcv_state.\n");
+		goto rcvleave;
+	}
+#if 0 /* optimised to only clear the essentials */
 	memset(irs, 0, sizeof(*irs));
+#else
+	irs->state = 0;
+	irs->next_state = 0;
+	irs->auth_checked = 0;
+	irs->stats = NULL;
+	irs->authenticator = NULL;
+	irs->said.proto = 0;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	irs->natt_len = 0;
+#endif
+#endif
 
 	/* XXX fudge it so that all nat-t stuff comes from ipsec0    */
 	/*     eventually, the SA itself will determine which device
@@ -1641,56 +2000,8 @@
 	{
 	  skb->dev = ipsec_get_device(0);
 	}
-
-	/* set up for decap loop */
 	irs->hard_header_len = skb->dev->hard_header_len;
 
-	skb = ipsec_rcv_unclone(skb, irs);
-
-#if IP_FRAGMENT_LINEARIZE
-	/* In Linux 2.4.4, we may have to reassemble fragments. They are
-	   not assembled automatically to save TCP from having to copy
-	   twice.
-	*/
-	if (skb_is_nonlinear(skb)) {
-#ifdef HAVE_NEW_SKB_LINEARIZE
-		if (skb_linearize_cow(skb) != 0) 
-#else
-		if (skb_linearize(skb, GFP_ATOMIC) != 0) 
-#endif
-		{
-			goto rcvleave;
-		}
-	}
-#endif /* IP_FRAGMENT_LINEARIZE */
-
-	/* ipp = skb->nh.iph; */
-	ipp =ip_hdr(skb);
-
-	{
-	  	struct in_addr ipsaddr;
-		struct in_addr ipdaddr;
-
-		ipsaddr.s_addr = ipp->saddr;
-		addrtoa(ipsaddr, 0, irs->ipsaddr_txt
-			, sizeof(irs->ipsaddr_txt));
-		ipdaddr.s_addr = ipp->daddr;
-		addrtoa(ipdaddr, 0, irs->ipdaddr_txt
-			, sizeof(irs->ipdaddr_txt));
-	}
-
-	irs->iphlen = ipp->ihl << 2;
-
-	KLIPS_IP_PRINT(debug_rcv, ipp);
-
-	irs->stats= NULL;
-	irs->ipp  = ipp;
-	irs->ipsp = NULL;
-	irs->ilen = 0;
-	irs->authlen=0;
-	irs->authfuncs=NULL;
-	irs->skb = skb;
-
 #ifdef CONFIG_IPSEC_NAT_TRAVERSAL
 	switch(encap_type) {
 	case UDP_ENCAP_ESPINUDP:
@@ -1706,20 +2017,27 @@
 	    printk(KERN_INFO "KLIPS received unknown UDP-ESP encap type %u\n",
 		   encap_type);
 	  }
-	  return -1;
+	  goto rcvleave;
 	}
-
 #endif
-	ipsec_rcv_decap(irs);
-	KLIPS_DEC_USE;
-	return 0;
+	irs->skb = skb;
 
-rcvleave:
-	if(skb) {
+	/*
+	 * we hand off real early to the state machine because we just cannot
+	 * know how much processing it is off-loading
+	 */
+	atomic_inc(&ipsec_irs_cnt);
+	ipsec_rsm(irs);
+
+	return(0);
+
+ rcvleave:
+	if (skb) {
 		ipsec_kfree_skb(skb);
 	}
+
 	KLIPS_DEC_USE;
-	return 0;
+	return(0);
 }
 #endif
 
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_sa.c	2007-09-05 04:56:10.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_sa.c	2008-06-27 13:38:04.000000000 +0200
@@ -73,6 +73,8 @@
 #include "openswan/ipsec_proto.h"
 #include "openswan/ipsec_alg.h"
 
+#include "ipsec_ocf.h"
+
 
 #ifdef CONFIG_KLIPS_DEBUG
 int debug_xform = 0;
@@ -1001,6 +1003,11 @@
 	}
 	ips->ips_iv = NULL;
 
+#ifdef CONFIG_KLIPS_OCF
+	if (ips->ocf_in_use)
+		ipsec_ocf_sa_free(ips);
+#endif
+
 	if(ips->ips_ident_s.data != NULL) {
 		memset((caddr_t)(ips->ips_ident_s.data),
                        0,
@@ -1088,6 +1095,12 @@
 
 #ifdef CONFIG_KLIPS_AH
 	case IPPROTO_AH:
+
+#ifdef CONFIG_KLIPS_OCF
+		if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, 0))
+		    break;
+#endif
+
 		switch(ipsp->ips_authalg) {
 # ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
 		case AH_MD5: {
@@ -1268,6 +1281,12 @@
 		unsigned int aks;
 #endif
 		ipsp->ips_iv_size = 0;
+
+#ifdef CONFIG_KLIPS_OCF
+		if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, ipsp->ips_encalg))
+		    break;
+#endif
+
 #ifdef CONFIG_KLIPS_ALG
 		ipsec_alg_sa_init(ipsp);
 		ixt_e=ipsp->ips_alg_enc;
@@ -1298,7 +1317,9 @@
 		
 		if ((error=ipsec_alg_enc_key_create(ipsp)) < 0)
 			SENDERR(-error);
+#endif /* CONFIG_KLIPS_ALG */
 
+#ifdef CONFIG_KLIPS_ALG
 		if ((ixt_a=ipsp->ips_alg_auth)) {
 			if ((error=ipsec_alg_auth_key_create(ipsp)) < 0)
 				SENDERR(-error);
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_tunnel.c	2007-09-18 20:26:18.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_tunnel.c	2008-06-27 13:38:04.000000000 +0200
@@ -3,6 +3,10 @@
  * Copyright (C) 1996, 1997  John Ioannidis.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Richard Guy Briggs.
  * 
+ * OCF/receive state machine written by
+ * David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -57,8 +61,17 @@
 # define PHYSDEV_TYPE
 #endif /* NET_21 */
 
+#ifndef NETDEV_TX_BUSY
+# ifdef NETDEV_XMIT_CN
+#  define NETDEV_TX_BUSY NETDEV_XMIT_CN
+# else
+#  define NETDEV_TX_BUSY 1
+# endif
+#endif
+
 #include <net/icmp.h>		/* icmp_send() */
 #include <net/ip.h>
+#include <net/arp.h>
 #ifdef NETDEV_23
 # include <linux/netfilter_ipv4.h>
 #endif /* NETDEV_23 */
@@ -207,7 +220,7 @@
 	 * The spinlock is to prevent any other process from accessing or deleting
 	 * the eroute while we are using and updating it.
 	 */
-	spin_lock(&eroute_lock);
+	spin_lock_bh(&eroute_lock);
 	
 	ixs->eroute = ipsec_findroute(&ixs->matcher);
 
@@ -420,7 +433,7 @@
 			ixs->eroute->er_last = ixs->skb;
 			ixs->skb = NULL;
 			ixs->stats->tx_dropped++;
-			spin_unlock(&eroute_lock);
+			spin_unlock_bh(&eroute_lock);
 			return IPSEC_XMIT_STOLEN;
 		}
 		ixs->outgoing_said = ixs->eroute->er_said;
@@ -447,7 +460,7 @@
 					       "Failed, tried to allocate %d bytes for source ident.\n", 
 					       len);
 					ixs->stats->tx_dropped++;
-					spin_unlock(&eroute_lock);
+					spin_unlock_bh(&eroute_lock);
 					return IPSEC_XMIT_ERRMEMALLOC;
 				}
 				memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len);
@@ -467,7 +480,7 @@
 					       "Failed, tried to allocate %d bytes for dest ident.\n", 
 					       len);
 					ixs->stats->tx_dropped++;
-					spin_unlock(&eroute_lock);
+					spin_unlock_bh(&eroute_lock);
 					return IPSEC_XMIT_ERRMEMALLOC;
 				}
 				memcpy(ixs->ips.ips_ident_d.data, ixs->eroute->er_ident_d.data, len);
@@ -475,7 +488,7 @@
 		}
 	}
 
-	spin_unlock(&eroute_lock);
+	spin_unlock_bh(&eroute_lock);
 	return IPSEC_XMIT_OK;
 }
 
@@ -584,7 +597,7 @@
 #else
 	/*skb_orphan(ixs->skb);*/
 	if((ixs->error = ip_route_output(&ixs->route,
-				    ixs->skb->nh.iph->daddr,
+				    ip_hdr(ixs->skb)->daddr,
 				    ixs->pass ? 0 : ip_hdr(ixs->skb)->saddr,
 				    RT_TOS(ip_hdr(ixs->skb)->tos),
                                     /* mcr->rgb: should this be 0 instead? */
@@ -695,8 +708,75 @@
 	if (ixs->ips.ips_ident_d.data) {
 		kfree(ixs->ips.ips_ident_d.data);
 	}
+	kmem_cache_free(ipsec_ixs_cache, ixs);
+	atomic_dec(&ipsec_ixs_cnt);
 }
 
+
+/*
+ * when encap processing is complete it call this for us to continue
+ */
+
+void
+ipsec_tunnel_xsm_complete(
+	struct ipsec_xmit_state *ixs,
+	enum ipsec_xmit_value stat)
+{
+	if(stat != IPSEC_XMIT_OK) {
+		if(stat == IPSEC_XMIT_PASS) {
+			goto bypass;
+		}
+		
+		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+				"klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
+				stat);
+		goto cleanup;
+	}
+
+	ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
+	ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
+	ixs->matcher.sen_proto = ixs->iph->protocol;
+	ipsec_extract_ports(ixs->iph, &ixs->matcher);
+
+	spin_lock_bh(&eroute_lock);
+	ixs->eroute = ipsec_findroute(&ixs->matcher);
+	if(ixs->eroute) {
+		ixs->outgoing_said = ixs->eroute->er_said;
+		ixs->eroute_pid = ixs->eroute->er_pid;
+		ixs->eroute->er_count++;
+		ixs->eroute->er_lasttime = jiffies/HZ;
+	}
+	spin_unlock_bh(&eroute_lock);
+
+	KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
+			/* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
+			(ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
+			ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
+			ixs->eroute,
+			"klips_debug:ipsec_tunnel_start_xmit: "
+			"We are recursing here.\n");
+
+	if (/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
+			(ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
+			ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
+			ixs->eroute) {
+		ipsec_xsm(ixs);
+		return;
+	}
+
+	stat = ipsec_tunnel_restore_hard_header(ixs);
+	if(stat != IPSEC_XMIT_OK) {
+		goto cleanup;
+	}
+
+bypass:
+	stat = ipsec_tunnel_send(ixs);
+
+cleanup:
+	ipsec_tunnel_cleanup(ixs);
+}
+
+
 /*
  *	This function assumes it is being called from dev_queue_xmit()
  *	and that skb is filled properly by that function.
@@ -704,20 +784,43 @@
 int
 ipsec_tunnel_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct ipsec_xmit_state ixs_mem;
-	struct ipsec_xmit_state *ixs = &ixs_mem;
+	struct ipsec_xmit_state *ixs = NULL;
 	enum ipsec_xmit_value stat;
 
+	if (atomic_read(&ipsec_ixs_cnt) >= ipsec_ixs_max)
+		return NETDEV_TX_BUSY;
+	ixs = kmem_cache_alloc(ipsec_ixs_cache, GFP_ATOMIC);
+	if (ixs == NULL)
+		return NETDEV_TX_BUSY;
+	atomic_inc(&ipsec_ixs_cnt);
+#if 0 /* optimised to only clear the required bits */
+	memset((caddr_t)ixs, 0, sizeof(*ixs));
+#else
+	ixs->pass = 0;
+	ixs->state = 0;
+	ixs->next_state = 0;
+	ixs->ipsp = NULL;
+	ixs->ipsq = NULL;
+	ixs->sa_len = 0;
+	ixs->stats = NULL;
+	ixs->ips.ips_ident_s.data = NULL;
+	ixs->ips.ips_ident_d.data = NULL;
+	ixs->outgoing_said.proto = 0;
 #ifdef CONFIG_IPSEC_NAT_TRAVERSAL
 	ixs->natt_type = 0, ixs->natt_head = 0;
 	ixs->natt_sport = 0, ixs->natt_dport = 0;
 #endif
+	ixs->tot_headroom = 0;
+	ixs->tot_tailroom = 0;
+	ixs->eroute = NULL;
+	ixs->hard_header_stripped = 0;
+	ixs->hard_header_len = 0;
+	ixs->cur_mtu = 0; /* FIXME: can we do something better ? */
 
-	memset((caddr_t)ixs, 0, sizeof(*ixs));
 	ixs->oskb = NULL;
 	ixs->saved_header = NULL;	/* saved copy of the hard header */
 	ixs->route = NULL;
-	memset((caddr_t)&(ixs->ips), 0, sizeof(ixs->ips));
+#endif /* memset */
 	ixs->dev = dev;
 	ixs->skb = skb;
 
@@ -745,55 +848,11 @@
 	}
 	
 	ixs->innersrc = ixs->iph->saddr;
-	/* start encapsulation loop here XXX */
-	do {
- 		stat = ipsec_xmit_encap_bundle(ixs);
-	 	if(stat != IPSEC_XMIT_OK) {
-			if(stat == IPSEC_XMIT_PASS) {
-				goto bypass;
-			}
-			
-			KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-				    "klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
-				    stat);
- 			goto cleanup;
-	 	}
-
-		ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
-		ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
-		ixs->matcher.sen_proto = ixs->iph->protocol;
-		ipsec_extract_ports(ixs->iph, &ixs->matcher);
-
-		spin_lock(&eroute_lock);
-		ixs->eroute = ipsec_findroute(&ixs->matcher);
-		if(ixs->eroute) {
-			ixs->outgoing_said = ixs->eroute->er_said;
-			ixs->eroute_pid = ixs->eroute->er_pid;
-			ixs->eroute->er_count++;
-			ixs->eroute->er_lasttime = jiffies/HZ;
-		}
-		spin_unlock(&eroute_lock);
-
-		KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
-			    /* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
-			    (ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
-			    ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
-			    ixs->eroute,
-			    "klips_debug:ipsec_tunnel_start_xmit: "
-			    "We are recursing here.\n");
 
-	} while(/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
-		(ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
-		ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
-		ixs->eroute);
-	
-	stat = ipsec_tunnel_restore_hard_header(ixs);
-	if(stat != IPSEC_XMIT_OK) {
-		goto cleanup;
-	}
+	ixs->xsm_complete = ipsec_tunnel_xsm_complete;
 
- bypass:
-	stat = ipsec_tunnel_send(ixs);
+	ipsec_xsm(ixs);
+	return 0;
 
  cleanup:
 	ipsec_tunnel_cleanup(ixs);
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_xform.c	2006-10-06 23:39:26.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/ipsec_xform.c	2008-06-27 13:38:04.000000000 +0200
@@ -64,12 +64,6 @@
 int debug_xform = 0;
 #endif /* CONFIG_KLIPS_DEBUG */
 
-#ifdef SPINLOCK
-spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
-#else /* SPINLOCK */
-spinlock_t tdb_lock;
-#endif /* SPINLOCK */
-
 /*
  * $Log: ipsec_xform.c,v $
  * Revision 1.65.2.1  2006-10-06 21:39:26  paul
--- openswan-2.4.13.org/linux/net/ipsec/ipsec_xmit.c	2007-10-30 22:38:56.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/ipsec_xmit.c	2008-06-27 13:38:04.000000000 +0200
@@ -4,6 +4,10 @@
  * Copyright (C) 1998-2003   Richard Guy Briggs.
  * Copyright (C) 2004-2005   Michael Richardson <mcr@xelerance.com>
  * 
+ * OCF/receive state machine written by
+ * David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -85,6 +89,7 @@
 
 #include "openswan/ipsec_proto.h"
 #include "openswan/ipsec_alg.h"
+#include "ipsec_ocf.h"
 
 
 /* 
@@ -373,6 +378,50 @@
 	return 1;
 }
 #endif	/* MSS_HACK */
+
+#ifdef CONFIG_KLIPS_DEBUG
+DEBUG_NO_STATIC char *
+ipsec_xmit_err(int err)
+{
+	static char tmp[32];
+	switch ((int) err) {
+	case IPSEC_XMIT_STOLEN:			return("IPSEC_XMIT_STOLEN");
+	case IPSEC_XMIT_PASS:			return("IPSEC_XMIT_PASS");
+	case IPSEC_XMIT_OK:				return("IPSEC_XMIT_OK");
+	case IPSEC_XMIT_ERRMEMALLOC:	return("IPSEC_XMIT_ERRMEMALLOC");
+	case IPSEC_XMIT_ESP_BADALG:		return("IPSEC_XMIT_ESP_BADALG");
+	case IPSEC_XMIT_BADPROTO:		return("IPSEC_XMIT_BADPROTO");
+	case IPSEC_XMIT_ESP_PUSHPULLERR:return("IPSEC_XMIT_ESP_PUSHPULLERR");
+	case IPSEC_XMIT_BADLEN:			return("IPSEC_XMIT_BADLEN");
+	case IPSEC_XMIT_AH_BADALG:		return("IPSEC_XMIT_AH_BADALG");
+	case IPSEC_XMIT_SAIDNOTFOUND:	return("IPSEC_XMIT_SAIDNOTFOUND");
+	case IPSEC_XMIT_SAIDNOTLIVE:	return("IPSEC_XMIT_SAIDNOTLIVE");
+	case IPSEC_XMIT_REPLAYROLLED:	return("IPSEC_XMIT_REPLAYROLLED");
+	case IPSEC_XMIT_LIFETIMEFAILED:	return("IPSEC_XMIT_LIFETIMEFAILED");
+	case IPSEC_XMIT_CANNOTFRAG:		return("IPSEC_XMIT_CANNOTFRAG");
+	case IPSEC_XMIT_MSSERR:			return("IPSEC_XMIT_MSSERR");
+	case IPSEC_XMIT_ERRSKBALLOC:	return("IPSEC_XMIT_ERRSKBALLOC");
+	case IPSEC_XMIT_ENCAPFAIL:		return("IPSEC_XMIT_ENCAPFAIL");
+	case IPSEC_XMIT_NODEV:			return("IPSEC_XMIT_NODEV");
+	case IPSEC_XMIT_NOPRIVDEV:		return("IPSEC_XMIT_NOPRIVDEV");
+	case IPSEC_XMIT_NOPHYSDEV:		return("IPSEC_XMIT_NOPHYSDEV");
+	case IPSEC_XMIT_NOSKB:			return("IPSEC_XMIT_NOSKB");
+	case IPSEC_XMIT_NOIPV6:			return("IPSEC_XMIT_NOIPV6");
+	case IPSEC_XMIT_NOIPOPTIONS:	return("IPSEC_XMIT_NOIPOPTIONS");
+	case IPSEC_XMIT_TTLEXPIRED:		return("IPSEC_XMIT_TTLEXPIRED");
+	case IPSEC_XMIT_BADHHLEN:		return("IPSEC_XMIT_BADHHLEN");
+	case IPSEC_XMIT_PUSHPULLERR:	return("IPSEC_XMIT_PUSHPULLERR");
+	case IPSEC_XMIT_ROUTEERR:		return("IPSEC_XMIT_ROUTEERR");
+	case IPSEC_XMIT_RECURSDETECT:	return("IPSEC_XMIT_RECURSDETECT");
+	case IPSEC_XMIT_IPSENDFAILURE:	return("IPSEC_XMIT_IPSENDFAILURE");
+	case IPSEC_XMIT_ESPUDP:			return("IPSEC_XMIT_ESPUDP");
+	case IPSEC_XMIT_ESPUDP_BADTYPE:	return("IPSEC_XMIT_ESPUDP_BADTYPE");
+	case IPSEC_XMIT_PENDING:		return("IPSEC_XMIT_PENDING");
+	}
+	snprintf(tmp, sizeof(tmp), "%d", err);
+	return tmp;
+}
+#endif
                                                         
 /*
  * Sanity checks
@@ -480,35 +529,20 @@
 	return IPSEC_XMIT_OK;
 }
 
+
 enum ipsec_xmit_value
-ipsec_xmit_encap_once(struct ipsec_xmit_state *ixs)
+ipsec_xmit_encap_init(struct ipsec_xmit_state *ixs)
 {
-#ifdef CONFIG_KLIPS_ESP
-	struct esphdr *espp;
-	unsigned char *idat, *pad;
-	int authlen = 0, padlen = 0, i;
-#endif /* !CONFIG_KLIPS_ESP */
-#ifdef CONFIG_KLIPS_AH
-	struct iphdr ipo;
-	struct ahhdr *ahp;
-#endif /* CONFIG_KLIPS_AH */
-#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
-	union {
-#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
-		MD5_CTX md5;
-#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
-#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
-		SHA1_CTX sha1;
-#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
-	} tctx;
-	__u8 hash[AH_AMAX];
-#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMACn_SHA1) */
-	int headroom = 0, tailroom = 0, ilen = 0, len = 0;
-	unsigned char *dat;
-	int blocksize = 8; /* XXX: should be inside ixs --jjo */
-	struct ipsec_alg_enc *ixt_e = NULL;
-	struct ipsec_alg_auth *ixt_a = NULL;
-	
+	ixs->blocksize = 8;
+	ixs->headroom = 0;
+	ixs->tailroom = 0;
+	ixs->authlen = 0;
+
+#ifdef CONFIG_KLIPS_ALG
+	ixs->ixt_e = NULL;
+	ixs->ixt_a = NULL;
+#endif /* CONFIG_KLIPS_ALG */
+
 	ixs->iphlen = ixs->iph->ihl << 2;
 	ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
 	ixs->sa_len = KLIPS_SATOT(debug_tunnel, &ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOT_BUF);
@@ -517,39 +551,74 @@
 		    "calling output for <%s%s%s>, SA:%s\n", 
 		    IPS_XFORM_NAME(ixs->ipsp),
 		    ixs->sa_len ? ixs->sa_txt : " (error)");
-	
 	switch(ixs->ipsp->ips_said.proto) {
 #ifdef CONFIG_KLIPS_AH
 	case IPPROTO_AH:
-		headroom += sizeof(struct ahhdr);
+		ixs->headroom += sizeof(struct ahhdr);
 		break;
 #endif /* CONFIG_KLIPS_AH */
-
 #ifdef CONFIG_KLIPS_ESP
 	case IPPROTO_ESP:
-		ixt_e=ixs->ipsp->ips_alg_enc;
-		if (ixt_e) {
-			blocksize = ixt_e->ixt_common.ixt_blocksize;
-			headroom += ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;
-		} else {
+#ifdef CONFIG_KLIPS_OCF
+		/*
+		 * this needs cleaning up for sure - DM
+		 */
+		if (ixs->ipsp->ocf_in_use) {
+			switch (ixs->ipsp->ips_encalg) {
+			case ESP_DES:
+			case ESP_3DES:
+				ixs->blocksize = 8;
+				ixs->headroom += ESP_HEADER_LEN + 8 /* ivsize */;
+				break;
+			case ESP_AES:
+				ixs->blocksize = 16;
+				ixs->headroom += ESP_HEADER_LEN + 16 /* ivsize */;
+				break;
+			default:
+				ixs->stats->tx_errors++;
+				return IPSEC_XMIT_ESP_BADALG;
+			}
+		} else
+#endif
+#ifdef CONFIG_KLIPS_ALG
+		if ((ixs->ixt_e=ixs->ipsp->ips_alg_enc)) {
+			ixs->blocksize = ixs->ixt_e->ixt_common.ixt_blocksize;
+			ixs->headroom += ESP_HEADER_LEN + ixs->ixt_e->ixt_common.ixt_support.ias_ivlen/8;
+		} else
+#endif /* CONFIG_KLIPS_ALG */
+		{
 			ixs->stats->tx_errors++;
 			return IPSEC_XMIT_ESP_BADALG;
 		}
+#ifdef CONFIG_KLIPS_OCF
+		if (ixs->ipsp->ocf_in_use) {
+			switch (ixs->ipsp->ips_authalg) {
+			case AH_MD5:
+			case AH_SHA:
+				ixs->authlen = AHHMAC_HASHLEN;
+				break;
+			case AH_NONE:
+				break;
+			}
+		} else
+#endif /* CONFIG_KLIPS_OCF */
+#ifdef CONFIG_KLIPS_ALG
 
-		ixt_a=ixs->ipsp->ips_alg_auth;
-		if (ixt_a) {
-			tailroom += AHHMAC_HASHLEN;
-			authlen = AHHMAC_HASHLEN;
+		ixs->ixt_a=ixs->ipsp->ips_alg_auth;
+		if (ixs->ixt_a) {
+			ixs->tailroom += AHHMAC_HASHLEN;
+			ixs->authlen = AHHMAC_HASHLEN;
 		} else 
+#endif /* CONFIG_KLIPS_ALG */
 		switch(ixs->ipsp->ips_authalg) {
 #ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
 		case AH_MD5:
-			authlen = AHHMAC_HASHLEN;
+			ixs->authlen = AHHMAC_HASHLEN;
 			break;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
 #ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
 		case AH_SHA:
-			authlen = AHHMAC_HASHLEN;
+			ixs->authlen = AHHMAC_HASHLEN;
 			break;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
 		case AH_NONE:
@@ -558,25 +627,22 @@
 			ixs->stats->tx_errors++;
 			return IPSEC_XMIT_ESP_BADALG;
 		}		
-		tailroom += blocksize != 1 ?
-			((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+		ixs->tailroom += ixs->blocksize != 1 ?
+			((ixs->blocksize - ((ixs->pyldsz + 2) % ixs->blocksize)) % ixs->blocksize) + 2 :
 			((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
-		tailroom += authlen;
+		ixs->tailroom += ixs->authlen;
 		break;
-#endif /* CONFIG_KLIPS_ESP */
-
+#endif /* !CONFIG_KLIPS_ESP */
 #ifdef CONFIG_KLIPS_IPIP
 	case IPPROTO_IPIP:
-		headroom += sizeof(struct iphdr);
+		ixs->headroom += sizeof(struct iphdr);
 		ixs->iphlen = sizeof(struct iphdr);
 		break;
 #endif /* !CONFIG_KLIPS_IPIP */
-
 #ifdef CONFIG_KLIPS_IPCOMP
 	case IPPROTO_COMP:
 		break;
 #endif /* CONFIG_KLIPS_IPCOMP */
-
 	default:
 		ixs->stats->tx_errors++;
 		return IPSEC_XMIT_BADPROTO;
@@ -585,306 +651,446 @@
 	KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
 		    "klips_debug:ipsec_xmit_encap_once: "
 		    "pushing %d bytes, putting %d, proto %d.\n", 
-		    headroom, tailroom, ixs->ipsp->ips_said.proto);
-	if(skb_headroom(ixs->skb) < headroom) {
+		    ixs->headroom, ixs->tailroom, ixs->ipsp->ips_said.proto);
+	if(skb_headroom(ixs->skb) < ixs->headroom) {
 		printk(KERN_WARNING
 		       "klips_error:ipsec_xmit_encap_once: "
 		       "tried to skb_push headroom=%d, %d available.  This should never happen, please report.\n",
-		       headroom, skb_headroom(ixs->skb));
+		       ixs->headroom, skb_headroom(ixs->skb));
 		ixs->stats->tx_errors++;
 		return IPSEC_XMIT_ESP_PUSHPULLERR;
 	}
 
-	dat = skb_push(ixs->skb, headroom);
-	ilen = ixs->skb->len - tailroom;
-	if(skb_tailroom(ixs->skb) < tailroom) {
+	ixs->dat = skb_push(ixs->skb, ixs->headroom);
+	ixs->ilen = ixs->skb->len - ixs->tailroom;
+	if(skb_tailroom(ixs->skb) < ixs->tailroom) {
 		printk(KERN_WARNING
 		       "klips_error:ipsec_xmit_encap_once: "
 		       "tried to skb_put %d, %d available.  This should never happen, please report.\n",
-		       tailroom, skb_tailroom(ixs->skb));
+		       ixs->tailroom, skb_tailroom(ixs->skb));
 		ixs->stats->tx_errors++;
 		return IPSEC_XMIT_ESP_PUSHPULLERR;
 	}
-	skb_put(ixs->skb, tailroom);
+	skb_put(ixs->skb, ixs->tailroom);
 	KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
 		    "klips_debug:ipsec_xmit_encap_once: "
 		    "head,tailroom: %d,%d before xform.\n",
 		    skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
-	len = ixs->skb->len;
-	if(len > 0xfff0) {
+	ixs->len = ixs->skb->len;
+	if(ixs->len > 0xfff0) {
 		printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
 		       "tot_len (%d) > 65520.  This should never happen, please report.\n",
-		       len);
+		       ixs->len);
 		ixs->stats->tx_errors++;
 		return IPSEC_XMIT_BADLEN;
 	}
-	memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen);
-	ixs->iph = (struct iphdr *)dat;
+	memmove((void *)ixs->dat, (void *)(ixs->dat + ixs->headroom), ixs->iphlen);
+	ixs->iph = (struct iphdr *)ixs->dat;
 	ixs->iph->tot_len = htons(ixs->skb->len);
 
-	switch(ixs->ipsp->ips_said.proto) {
+	return IPSEC_XMIT_OK;
+}
+
+
+/*
+ * work out which state to proceed to next
+ */
+
+enum ipsec_xmit_value
+ipsec_xmit_encap_select(struct ipsec_xmit_state *ixs)
+{
+	switch (ixs->ipsp->ips_said.proto) {
 #ifdef CONFIG_KLIPS_ESP
 	case IPPROTO_ESP:
-		espp = (struct esphdr *)(dat + ixs->iphlen);
-		espp->esp_spi = ixs->ipsp->ips_said.spi;
-		espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-		
-		if (!ixt_e) {
-			ixs->stats->tx_errors++;
-			return IPSEC_XMIT_ESP_BADALG;
-		}
-		
-		idat = dat + ixs->iphlen + headroom;
-		ilen = len - (ixs->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] = ixs->iph->protocol;
-		ixs->iph->protocol = IPPROTO_ESP;
+		ixs->next_state = IPSEC_XSM_ESP;
+		break;
+#endif
+#ifdef CONFIG_KLIPS_AH
+	case IPPROTO_AH:
+		ixs->next_state = IPSEC_XSM_AH;
+		break;
+#endif
+#ifdef CONFIG_KLIPS_IPIP
+	case IPPROTO_IPIP:
+		ixs->next_state = IPSEC_XSM_IPIP;
+		break;
+#endif
+#ifdef CONFIG_KLIPS_IPCOMP
+	case IPPROTO_COMP:
+		ixs->next_state = IPSEC_XSM_IPCOMP;
+		break;
+#endif
+	default:
+		ixs->stats->tx_errors++;
+		return IPSEC_XMIT_BADPROTO;
+	}
+	return IPSEC_XMIT_OK;
+}
+
+
+#ifdef CONFIG_KLIPS_ESP
+
+enum ipsec_xmit_value
+ipsec_xmit_esp(struct ipsec_xmit_state *ixs)
+{
+	int i;
+	unsigned char *pad;
+	int padlen = 0;
+
+	ixs->espp = (struct esphdr *)(ixs->dat + ixs->iphlen);
+#ifdef NET_21
+	skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->espp));
+#endif /* NET_21 */
+	ixs->espp->esp_spi = ixs->ipsp->ips_said.spi;
+	ixs->espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+	
+	ixs->idat = ixs->dat + ixs->iphlen + ixs->headroom;
+	ixs->ilen = ixs->len - (ixs->iphlen + ixs->headroom + ixs->authlen);
+
+	/* Self-describing padding */
+	pad = &ixs->dat[ixs->len - ixs->tailroom];
+	padlen = ixs->tailroom - 2 - ixs->authlen;
+	for (i = 0; i < padlen; i++) {
+		pad[i] = i + 1; 
+	}
+	ixs->dat[ixs->len - ixs->authlen - 2] = padlen;
+	
+	ixs->dat[ixs->len - ixs->authlen - 1] = ixs->iph->protocol;
+	ixs->iph->protocol = IPPROTO_ESP;
+	
+#ifdef CONFIG_KLIPS_OCF
+	if (ixs->ipsp->ocf_in_use)
+		return(ipsec_ocf_xmit(ixs));
+#endif
+
+#ifdef CONFIG_KLIPS_ALG
+	if (!ixs->ixt_e) {
+		ixs->stats->tx_errors++;
+		return IPSEC_XMIT_ESP_BADALG;
+	}
+	
 #ifdef CONFIG_KLIPS_DEBUG
-		if(debug_tunnel & DB_TN_ENCAP) {
-		        dmp("pre-encrypt", dat, len);
-		}
+	if(debug_tunnel & DB_TN_ENCAP) {
+		dmp("pre-encrypt", ixs->dat, ixs->len);
+	}
 #endif
 
-		/*
-		 * Do all operations here:
-		 * copy IV->ESP, encrypt, update ips IV
-		 *
-		 */
-		{
-			int ret;
-			memcpy(espp->esp_iv, 
-			       ixs->ipsp->ips_iv, 
-			       ixs->ipsp->ips_iv_size);
-			ret=ipsec_alg_esp_encrypt(ixs->ipsp, 
-						  idat, ilen, espp->esp_iv,
-						  IPSEC_ALG_ENCRYPT);
-
-			prng_bytes(&ipsec_prng,
-				   (char *)ixs->ipsp->ips_iv,
-				   ixs->ipsp->ips_iv_size);
-		} 
-		
-		if (ixt_a) {
-			ipsec_alg_sa_esp_hash(ixs->ipsp,
-					(caddr_t)espp, len - ixs->iphlen - authlen,
-					&(dat[len - authlen]), authlen);
+	/*
+	 * Do all operations here:
+	 * copy IV->ESP, encrypt, update ips IV
+	 *
+	 */
+	{
+		int ret;
+		memcpy(ixs->espp->esp_iv, 
+			   ixs->ipsp->ips_iv, 
+			   ixs->ipsp->ips_iv_size);
+		ret=ipsec_alg_esp_encrypt(ixs->ipsp, 
+					  ixs->idat, ixs->ilen, ixs->espp->esp_iv,
+					  IPSEC_ALG_ENCRYPT);
+
+		prng_bytes(&ipsec_prng,
+			   (char *)ixs->ipsp->ips_iv,
+			   ixs->ipsp->ips_iv_size);
+	} 
+	return IPSEC_XMIT_OK;
+#else
+	return IPSEC_XMIT_ESP_BADALG;
+#endif /*  CONFIG_KLIPS_ALG */
+}
 
-		} else
-		switch(ixs->ipsp->ips_authalg) {
+
+enum ipsec_xmit_value
+ipsec_xmit_esp_ah(struct ipsec_xmit_state *ixs)
+{
+#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
+	__u8 hash[AH_AMAX];
+#endif
+#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
+	union {
 #ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
-		case AH_MD5:
-			dmp("espp", (char*)espp, len - ixs->iphlen - authlen);
-			tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-			dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen);
-			dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Final(hash, &tctx.md5);
-			dmp("ictx hash", (char*)&hash, sizeof(hash));
-			tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-			dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
-			dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Final(hash, &tctx.md5);
-			dmp("octx hash", (char*)&hash, sizeof(hash));
-			memcpy(&(dat[len - authlen]), hash, authlen);
-			
-			/* paranoid */
-			memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-			memset((caddr_t)hash, 0, sizeof(*hash));
-			break;
+		MD5_CTX md5;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
 #ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
-		case AH_SHA:
-			tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-			SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen);
-			SHA1Final(hash, &tctx.sha1);
-			tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-			SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-			SHA1Final(hash, &tctx.sha1);
-			memcpy(&(dat[len - authlen]), hash, authlen);
-			
-			/* paranoid */
-			memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-			memset((caddr_t)hash, 0, sizeof(*hash));
-			break;
+		SHA1_CTX sha1;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
-		case AH_NONE:
-			break;
-		default:
-			ixs->stats->tx_errors++;
-			return IPSEC_XMIT_AH_BADALG;
-		}
-#ifdef NET_21
-		/*ixs->skb->h.raw = (unsigned char*)espp;*/
-		skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, espp));
-#endif /* NET_21 */
-		break;
-#endif /* !CONFIG_KLIPS_ESP */
-#ifdef CONFIG_KLIPS_AH
-	case IPPROTO_AH:
-		ahp = (struct ahhdr *)(dat + ixs->iphlen);
-		ahp->ah_spi = ixs->ipsp->ips_said.spi;
-		ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-		ahp->ah_rv = 0;
-		ahp->ah_nh = ixs->iph->protocol;
-		ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
-		ixs->iph->protocol = IPPROTO_AH;
-		dmp("ahp", (char*)ahp, sizeof(*ahp));
+	} tctx;
+#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1) */
+
+#ifdef CONFIG_KLIPS_OCF
+	if (ixs->ipsp->ocf_in_use) {
+		/* we should never be here using OCF */
+		ixs->stats->tx_errors++;
+		return IPSEC_XMIT_AH_BADALG;
+	} else
+#endif
+#ifdef CONFIG_KLIPS_ALG
+	if (ixs->ixt_a) {
+		ipsec_alg_sa_esp_hash(ixs->ipsp,
+				(caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen,
+				&(ixs->dat[ixs->len - ixs->authlen]), ixs->authlen);
+
+	} else
+#endif /* CONFIG_KLIPS_ALG */
+	switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
+	case AH_MD5:
+		dmp("espp", (char*)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
+		tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+		dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, (caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
+		dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Final(hash, &tctx.md5);
+		dmp("ictx hash", (char*)&hash, sizeof(hash));
+		tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+		dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
+		dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Final(hash, &tctx.md5);
+		dmp("octx hash", (char*)&hash, sizeof(hash));
+		memcpy(&(ixs->dat[ixs->len - ixs->authlen]), hash, ixs->authlen);
 		
-		ipo = *ixs->iph;
-		ipo.tos = 0;
-		ipo.frag_off = 0;
-		ipo.ttl = 0;
-		ipo.check = 0;
-		dmp("ipo", (char*)&ipo, sizeof(ipo));
+		/* paranoid */
+		memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+		memset((caddr_t)hash, 0, sizeof(*hash));
+		break;
+#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
+#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
+	case AH_SHA:
+		tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+		SHA1Update(&tctx.sha1, (caddr_t)ixs->espp, ixs->len - ixs->iphlen - ixs->authlen);
+		SHA1Final(hash, &tctx.sha1);
+		tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+		SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+		SHA1Final(hash, &tctx.sha1);
+		memcpy(&(ixs->dat[ixs->len - ixs->authlen]), hash, ixs->authlen);
 		
-		switch(ixs->ipsp->ips_authalg) {
+		/* paranoid */
+		memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+		memset((caddr_t)hash, 0, sizeof(*hash));
+		break;
+#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
+	case AH_NONE:
+		break;
+	default:
+		ixs->stats->tx_errors++;
+		return IPSEC_XMIT_AH_BADALG;
+	}
+	return IPSEC_XMIT_OK;
+}
+
+#endif /* CONFIG_KLIPS_ESP */
+
+
+
+#ifdef CONFIG_KLIPS_AH
+
+enum ipsec_xmit_value
+ipsec_xmit_ah(struct ipsec_xmit_state *ixs)
+{
+	struct iphdr ipo;
+	struct ahhdr *ahp;
+#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
+	__u8 hash[AH_AMAX];
+#endif
+#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)
+	union {
 #ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
-		case AH_MD5:
-			tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-			dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
-			dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
-			dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-			dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5,  dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
-			dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Final(hash, &tctx.md5);
-			dmp("ictx hash", (char*)&hash, sizeof(hash));
-			tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-			dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
-			dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-			osMD5Final(hash, &tctx.md5);
-			dmp("octx hash", (char*)&hash, sizeof(hash));
-					
-			memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-					
-			/* paranoid */
-			memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-			memset((caddr_t)hash, 0, sizeof(*hash));
-			break;
+		MD5_CTX md5;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
 #ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
-		case AH_SHA:
-			tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-			SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
-			SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
-			SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-			SHA1Update(&tctx.sha1,  dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
-			SHA1Final(hash, &tctx.sha1);
-			tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-			SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-			SHA1Final(hash, &tctx.sha1);
-					
-			memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-					
-			/* paranoid */
-			memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-			memset((caddr_t)hash, 0, sizeof(*hash));
-			break;
+		SHA1_CTX sha1;
 #endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
-		default:
-			ixs->stats->tx_errors++;
-			return IPSEC_XMIT_AH_BADALG;
-		}
+	} tctx;
+#endif /* defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMAC_SHA1) */
+
+	ahp = (struct ahhdr *)(ixs->dat + ixs->iphlen);
 #ifdef NET_21
-		skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ahp));
+	skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ahp));
 #endif /* NET_21 */
+	ahp->ah_spi = ixs->ipsp->ips_said.spi;
+	ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
+	ahp->ah_rv = 0;
+	ahp->ah_nh = ixs->iph->protocol;
+	ahp->ah_hl = (ixs->headroom >> 2) - sizeof(__u64)/sizeof(__u32);
+	ixs->iph->protocol = IPPROTO_AH;
+	dmp("ahp", (char*)ahp, sizeof(*ahp));
+	
+#ifdef CONFIG_KLIPS_OCF
+	if (ixs->ipsp->ocf_in_use)
+		return(ipsec_ocf_xmit(ixs));
+#endif
+
+	ipo = *ixs->iph;
+	ipo.tos = 0;
+	ipo.frag_off = 0;
+	ipo.ttl = 0;
+	ipo.check = 0;
+	dmp("ipo", (char*)&ipo, sizeof(ipo));
+	
+	switch(ixs->ipsp->ips_authalg) {
+#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
+	case AH_MD5:
+		tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+		dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
+		dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, (unsigned char *)ahp, ixs->headroom - sizeof(ahp->ah_data));
+		dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+		dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5,  ixs->dat + ixs->iphlen + ixs->headroom, ixs->len - ixs->iphlen - ixs->headroom);
+		dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Final(hash, &tctx.md5);
+		dmp("ictx hash", (char*)&hash, sizeof(hash));
+		tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
+		dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Update(&tctx.md5, hash, AHMD596_ALEN);
+		dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
+		osMD5Final(hash, &tctx.md5);
+		dmp("octx hash", (char*)&hash, sizeof(hash));
+				
+		memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+				
+		/* paranoid */
+		memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
+		memset((caddr_t)hash, 0, sizeof(*hash));
+		break;
+#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
+#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
+	case AH_SHA:
+		tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
+		SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
+		SHA1Update(&tctx.sha1, (unsigned char *)ahp, ixs->headroom - sizeof(ahp->ah_data));
+		SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
+		SHA1Update(&tctx.sha1,  ixs->dat + ixs->iphlen + ixs->headroom, ixs->len - ixs->iphlen - ixs->headroom);
+		SHA1Final(hash, &tctx.sha1);
+		tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
+		SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
+		SHA1Final(hash, &tctx.sha1);
+				
+		memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
+				
+		/* paranoid */
+		memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
+		memset((caddr_t)hash, 0, sizeof(*hash));
 		break;
+#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
+	default:
+		ixs->stats->tx_errors++;
+		return IPSEC_XMIT_AH_BADALG;
+	}
+	return IPSEC_XMIT_OK;
+}
+
 #endif /* CONFIG_KLIPS_AH */
+
+
 #ifdef CONFIG_KLIPS_IPIP
-	case IPPROTO_IPIP:
-		ixs->iph->version  = 4;
-		switch(sysctl_ipsec_tos) {
-		case 0:
+
+enum ipsec_xmit_value
+ipsec_xmit_ipip(struct ipsec_xmit_state *ixs)
+{
+	ixs->iph->version  = 4;
+	switch(sysctl_ipsec_tos) {
+	case 0:
 #ifdef NET_21
-			ixs->iph->tos = ip_hdr(ixs->skb)->tos;
+		ixs->iph->tos = ip_hdr(ixs->skb)->tos;
 #else /* NET_21 */
-			ixs->iph->tos = ixs->skb->ip_hdr->tos;
+		ixs->iph->tos = ixs->skb->ip_hdr->tos;
 #endif /* NET_21 */
-			break;
-		case 1:
-			ixs->iph->tos = 0;
-			break;
-		default:
-			break;
-		}
-		ixs->iph->ttl      = SYSCTL_IPSEC_DEFAULT_TTL;
-		ixs->iph->frag_off = 0;
-		ixs->iph->saddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
-		ixs->iph->daddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
-		ixs->iph->protocol = IPPROTO_IPIP;
-		ixs->iph->ihl      = sizeof(struct iphdr) >> 2;
+		break;
+	case 1:
+		ixs->iph->tos = 0;
+		break;
+	default:
+		break;
+	}
+	ixs->iph->ttl      = SYSCTL_IPSEC_DEFAULT_TTL;
+	ixs->iph->frag_off = 0;
+	ixs->iph->saddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
+	ixs->iph->daddr    = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
+	ixs->iph->protocol = IPPROTO_IPIP;
+	ixs->iph->ihl      = sizeof(struct iphdr) >> 2;
 
-		KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
+	KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
 
-		ixs->newdst = (__u32)ixs->iph->daddr;
-		ixs->newsrc = (__u32)ixs->iph->saddr;
-		
+	ixs->newdst = (__u32)ixs->iph->daddr;
+	ixs->newsrc = (__u32)ixs->iph->saddr;
+	
 #ifdef NET_21
-		skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ip_hdr(ixs->skb)));
+	skb_set_transport_header(ixs->skb, ipsec_skb_offset(ixs->skb, ip_hdr(ixs->skb)));
 #endif /* NET_21 */
-		break;
-#endif /* !CONFIG_KLIPS_IPIP */
+	return IPSEC_XMIT_OK;
+}
+
+#endif /* CONFIG_KLIPS_IPIP */
+
+
 #ifdef CONFIG_KLIPS_IPCOMP
-	case IPPROTO_COMP:
-	{
-		unsigned int flags = 0;
+
+enum ipsec_xmit_value
+ipsec_xmit_ipcomp(struct ipsec_xmit_state *ixs)
+{
+#ifdef CONFIG_KLIPS_DEBUG
+	unsigned int old_tot_len;
+#endif
+	int flags = 0;
+
 #ifdef CONFIG_KLIPS_DEBUG
-		unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
+	old_tot_len = ntohs(ixs->iph->tot_len);
 #endif /* CONFIG_KLIPS_DEBUG */
-		ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
 
-		ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
+	ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
+	ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
 
 #ifdef NET_21
-		ixs->iph = ip_hdr(ixs->skb);
+	ixs->iph = ip_hdr(ixs->skb);
 #else /* NET_21 */
-		ixs->iph = ixs->skb->ip_hdr;
+	ixs->iph = ixs->skb->ip_hdr;
 #endif /* NET_21 */
 
-		ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
+	ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
 
 #ifdef CONFIG_KLIPS_DEBUG
-		if (debug_tunnel & DB_TN_CROUT)
-		{
-			if (old_tot_len > ntohs(ixs->iph->tot_len))
-				KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-					    "klips_debug:ipsec_xmit_encap_once: "
-					    "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
-					    old_tot_len, ntohs(ixs->iph->tot_len),
-					    ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
-					    ntohl(ixs->ipsp->ips_said.spi),
-					    (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
-			else
-				KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-					    "klips_debug:ipsec_xmit_encap_once: "
-					    "packet did not compress (flags = %d).\n",
-					    flags);
-		}
-#endif /* CONFIG_KLIPS_DEBUG */
+	if (debug_tunnel & DB_TN_CROUT)
+	{
+		if (old_tot_len > ntohs(ixs->iph->tot_len))
+			KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+					"klips_debug:ipsec_xmit_encap_once: "
+					"packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
+					old_tot_len, ntohs(ixs->iph->tot_len),
+					ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
+					ntohl(ixs->ipsp->ips_said.spi),
+					(__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
+		else
+			KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
+					"klips_debug:ipsec_xmit_encap_once: "
+					"packet did not compress (flags = %d).\n",
+					flags);
 	}
-	break;
+#endif /* CONFIG_KLIPS_DEBUG */
+	return IPSEC_XMIT_OK;
+}
+
 #endif /* CONFIG_KLIPS_IPCOMP */
-	default:
-		ixs->stats->tx_errors++;
-		return IPSEC_XMIT_BADPROTO;
-	}
-			
+
+
+
+/*
+ * upon entry to this function, ixs->skb should be setup
+ * as follows:
+ *
+ *   data   = beginning of IP packet   <- differs from ipsec_rcv().
+ *   nh.raw = beginning of IP packet.
+ *   h.raw  = data after the IP packet.
+ *
+ */
+enum ipsec_xmit_value
+ipsec_xmit_cont(struct ipsec_xmit_state *ixs)
+{
 #ifdef NET_21
 	skb_set_network_header(ixs->skb, ipsec_skb_offset(ixs->skb, ixs->skb->data));
-
 #else /* NET_21 */
 	ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
 #endif /* NET_21 */
@@ -898,8 +1104,8 @@
 		    ixs->sa_len ? ixs->sa_txt : " (error)");
 	KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
  			
-	ixs->ipsp->ips_life.ipl_bytes.ipl_count += len;
-	ixs->ipsp->ips_life.ipl_bytes.ipl_last = len;
+	ixs->ipsp->ips_life.ipl_bytes.ipl_count += ixs->len;
+	ixs->ipsp->ips_life.ipl_bytes.ipl_last = ixs->len;
 
 	if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
 		ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
@@ -908,10 +1114,17 @@
 	ixs->ipsp->ips_life.ipl_packets.ipl_count++; 
 
 	ixs->ipsp = ixs->ipsp->ips_onext;
-			
+
+	/*
+	 * start again if we have more work to do
+	 */
+	if (ixs->ipsp)
+		ixs->next_state = IPSEC_XSM_ENCAP_INIT;
+
 	return IPSEC_XMIT_OK;
 }
 
+
 /*
  * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
  * source and destination ports to those from the TCP/UDP header.
@@ -1049,24 +1262,15 @@
 	return (error == 0);
 }
 
-/*
- * upon entry to this function, ixs->skb should be setup
- * as follows:
- *
- *   data   = beginning of IP packet   <- differs from ipsec_rcv().
- *   nh.raw = beginning of IP packet.
- *   h.raw  = data after the IP packet.
- *
- */
 enum ipsec_xmit_value
-ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs)
+ipsec_xmit_init(struct ipsec_xmit_state *ixs)
 {
-#ifdef CONFIG_KLIPS_ALG
-	struct ipsec_alg_enc *ixt_e = NULL;
-	struct ipsec_alg_auth *ixt_a = NULL;
-	int blocksize = 8;
-#endif
 	enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
+#ifdef CONFIG_KLIPS_ALG
+	ixs->blocksize = 8;
+	ixs->ixt_e = NULL;
+	ixs->ixt_a = NULL;
+#endif /* CONFIG_KLIPS_ALG */
  
 	ixs->newdst = ixs->orgdst = ixs->iph->daddr;
 	ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
@@ -1104,7 +1308,6 @@
 				    "klips_debug:ipsec_xmit_encap_bundle: "
 				    "PASS: calling dev_queue_xmit\n");
 			return IPSEC_XMIT_PASS;
-			goto cleanup;
 				
 		case SPI_HOLD:
 			KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
@@ -1181,14 +1384,14 @@
 					 * the eroute while we are using and
 					 * updating it.
 					 */
-					spin_lock(&eroute_lock);
+					spin_lock_bh(&eroute_lock);
 					ixs->eroute = ipsec_findroute(&ixs->matcher);
 					if(ixs->eroute) {
 						ixs->eroute->er_said.spi = htonl(SPI_HOLD);
 						ixs->eroute->er_first = ixs->skb;
 						ixs->skb = NULL;
 					}
-					spin_unlock(&eroute_lock);
+					spin_unlock_bh(&eroute_lock);
 				} else if (create_hold_eroute(ixs->eroute,
 							      ixs->skb,
 							      ixs->iph,
@@ -1207,20 +1410,6 @@
 		return IPSEC_XMIT_STOLEN;
 	} /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
 	
-	/*
-	  The spinlock is to prevent any other process from
-	  accessing or deleting the ipsec_sa hash table or any of the
-	  ipsec_sa s while we are using and updating them.
-		  
-	  This is not optimal, but was relatively straightforward
-	  at the time.  A better way to do it has been planned for
-	  more than a year, to lock the hash table and put reference
-	  counts on each ipsec_sa instead.  This is not likely to happen
-	  in KLIPS1 unless a volunteer contributes it, but will be
-	  designed into KLIPS2.
-	*/
-	spin_lock(&tdb_lock);
-
 	ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
 	ixs->sa_len = KLIPS_SATOT(debug_tunnel, &ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt));
 
@@ -1338,22 +1527,59 @@
 			ixs->headroom += sizeof(struct ahhdr);
 			break;
 #endif /* CONFIG_KLIPS_AH */
+
 #ifdef CONFIG_KLIPS_ESP
 		case IPPROTO_ESP:
-			ixt_e=ixs->ipsp->ips_alg_enc;
-			if (ixt_e) {
-				blocksize = ixt_e->ixt_common.ixt_blocksize;
-				ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;
-			}
-			else {
+#ifdef CONFIG_KLIPS_OCF
+			/*
+			 * this needs cleaning up for sure - DM
+			 */
+			if (ixs->ipsp->ocf_in_use) {
+				switch (ixs->ipsp->ips_encalg) {
+				case ESP_DES:
+				case ESP_3DES:
+					ixs->blocksize = 8;
+					ixs->headroom += ESP_HEADER_LEN + 8 /* ivsize */;
+					break;
+				case ESP_AES:
+					ixs->blocksize = 16;
+					ixs->headroom += ESP_HEADER_LEN + 16 /* ivsize */;
+					break;
+				default:
+					ixs->stats->tx_errors++;
+					bundle_stat = IPSEC_XMIT_ESP_BADALG;
+					goto cleanup;
+				}
+			} else
+#endif /* CONFIG_KLIPS_OCF */
+#ifdef CONFIG_KLIPS_ALG
+			if ((ixs->ixt_e=ixs->ipsp->ips_alg_enc)) {
+				ixs->blocksize = ixs->ixt_e->ixt_common.ixt_blocksize;
+				ixs->headroom += ESP_HEADER_LEN + ixs->ixt_e->ixt_common.ixt_support.ias_ivlen/8;
+			} else
+#endif /* CONFIG_KLIPS_ALG */
+			{
 				ixs->stats->tx_errors++;
 				bundle_stat = IPSEC_XMIT_ESP_BADALG;
 				goto cleanup;
 			}
-
-			if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
+#ifdef CONFIG_KLIPS_OCF
+			if (ixs->ipsp->ocf_in_use) {
+				switch (ixs->ipsp->ips_authalg) {
+				case AH_MD5:
+				case AH_SHA:
+					ixs->tailroom += AHHMAC_HASHLEN;
+					break;
+				case AH_NONE:
+					break;
+				}
+			} else
+#endif /* CONFIG_KLIPS_OCF */
+#ifdef CONFIG_KLIPS_ALG
+			if ((ixs->ixt_a=ixs->ipsp->ips_alg_auth)) {
 				ixs->tailroom += AHHMAC_HASHLEN;
 			} else
+#endif /* CONFIG_KLIPS_ALG */
 			switch(ixs->ipsp->ips_authalg) {
 #ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
 			case AH_MD5:
@@ -1372,8 +1598,8 @@
 				bundle_stat = IPSEC_XMIT_AH_BADALG;
 				goto cleanup;
 			}			
-			ixs->tailroom += blocksize != 1 ?
-				((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
+			ixs->tailroom += ixs->blocksize != 1 ?
+				((ixs->blocksize - ((ixs->pyldsz + 2) % ixs->blocksize)) % ixs->blocksize) + 2 :
 				((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
 #ifdef CONFIG_IPSEC_NAT_TRAVERSAL
 		if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
@@ -1402,12 +1628,13 @@
 		}
 #endif
 			break;
-#endif /* !CONFIG_KLIPS_ESP */
+#endif /* CONFIG_KLIPS_ESP */
 #ifdef CONFIG_KLIPS_IPIP
 		case IPPROTO_IPIP:
 			ixs->headroom += sizeof(struct iphdr);
 			break;
 #endif /* !CONFIG_KLIPS_IPIP */
+
 		case IPPROTO_COMP:
 #ifdef CONFIG_KLIPS_IPCOMP
 			/*
@@ -1425,6 +1652,7 @@
 			*/
 			break;
 #endif /* CONFIG_KLIPS_IPCOMP */
+
 		default:
 			ixs->stats->tx_errors++;
 			bundle_stat = IPSEC_XMIT_BADPROTO;
@@ -1438,6 +1666,12 @@
 		ixs->max_headroom += ixs->headroom;
 		ixs->max_tailroom += ixs->tailroom;
 		ixs->pyldsz += (ixs->headroom + ixs->tailroom);
+
+#ifdef CONFIG_KLIPS_DEBUG
+		if(debug_tunnel & DB_TN_ENCAP) {
+			ipsec_print_ip(ixs->iph);
+		}
+#endif
 	}
 	ixs->ipsp = ixs->ipsq;	/* restore the head of the ipsec_sa chain */
 		
@@ -1707,44 +1941,141 @@
 			    "head,tailroom: %d,%d after allocation\n",
 			    skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
 	}
-#ifdef CONFIG_KLIPS_DEBUG		
+
+#ifdef CONFIG_KLIPS_DEBUG
 	if(debug_tunnel & DB_TN_ENCAP) {
 		ipsec_print_ip(ixs->iph);
 	}
 #endif
 
+cleanup:
+	return bundle_stat;
+}
+
+
+/*
+ * here is a state machine to handle encapsulation
+ * basically we keep getting re-entered until processing is
+ * complete.  For the simple case we step down the states and finish.
+ * each state is ideally some logical part of the process.  If a state
+ * can pend (ie., require async processing to complete),  then this
+ * should be the part of last action before it returns IPSEC_RCV_PENDING
+ *
+ * Any particular action may alter the next_state in ixs to move us to
+ * a state other than the preferred "next_state",  but this is the
+ * exception and is highlighted when it is done.
+ *
+ * prototypes for state action
+ */
+
+struct {
+	enum ipsec_xmit_value (*action)(struct ipsec_xmit_state *ixs);
+	int next_state;
+} xmit_state_table[] = {
+	[IPSEC_XSM_INIT]        = {ipsec_xmit_init,        IPSEC_XSM_ENCAP_INIT },
+	[IPSEC_XSM_ENCAP_INIT]  = {ipsec_xmit_encap_init,  IPSEC_XSM_ENCAP_SELECT },
+	[IPSEC_XSM_ENCAP_SELECT]= {ipsec_xmit_encap_select,IPSEC_XSM_DONE },
+
+#ifdef CONFIG_KLIPS_ESP
+	[IPSEC_XSM_ESP]         = {ipsec_xmit_esp,         IPSEC_XSM_ESP_AH },
+	[IPSEC_XSM_ESP_AH]      = {ipsec_xmit_esp_ah,      IPSEC_XSM_CONT },
+#endif
+
+#ifdef CONFIG_KLIPS_AH
+	[IPSEC_XSM_AH]          = {ipsec_xmit_ah,          IPSEC_XSM_CONT },
+#endif
+
+#ifdef CONFIG_KLIPS_IPIP
+	[IPSEC_XSM_IPIP]        = {ipsec_xmit_ipip,        IPSEC_XSM_CONT },
+#endif
+
+#ifdef CONFIG_KLIPS_IPCOMP
+	[IPSEC_XSM_IPCOMP]      = {ipsec_xmit_ipcomp,      IPSEC_XSM_CONT },
+#endif
+
+	[IPSEC_XSM_CONT]        = {ipsec_xmit_cont,        IPSEC_XSM_DONE },
+	[IPSEC_XSM_DONE]        = {NULL,                   IPSEC_XSM_DONE},
+};
+
+
+
+void
+ipsec_xsm(struct ipsec_xmit_state *ixs)
+{
+	enum ipsec_xmit_value stat = IPSEC_XMIT_ENCAPFAIL;
+
+	if (ixs == NULL) {
+		KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xsm: ixs == NULL.\n");
+		return;
+	}
+
 	/*
-	 * Apply grouped transforms to packet
+	 * make sure nothing is removed from underneath us
 	 */
-	while (ixs->ipsp) {
-		enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK;
+	spin_lock_bh(&tdb_lock);
 
-		encap_stat = ipsec_xmit_encap_once(ixs);
-#ifdef CONFIG_KLIPS_DEBUG
-		if(debug_tunnel & DB_TN_ENCAP) {
-			ipsec_print_ip(ixs->iph);
-		}
-#endif
+	/*
+	 * if we have a valid said,  then we must check it here to ensure it
+	 * hasn't gone away while we were waiting for a task to complete
+	 */
 
-		if(encap_stat != IPSEC_XMIT_OK) {
-			KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-				    "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n",
-				    encap_stat);
-				
-			bundle_stat = IPSEC_XMIT_ENCAPFAIL;
-			goto cleanup;
+	if (ixs->ipsp && ipsec_sa_getbyid(&ixs->outgoing_said) == NULL) {
+		KLIPS_PRINT(debug_tunnel,
+			    "klips_debug:ipsec_xsm: "
+			    "no ipsec_sa for SA:%s: outgoing packet with no SA dropped\n",
+			    ixs->sa_len ? ixs->sa_txt : " (error)");
+		if (ixs->stats)
+			ixs->stats->tx_dropped++;
+
+		/* drop through and cleanup */
+		stat = IPSEC_XMIT_SAIDNOTFOUND;
+		ixs->state = IPSEC_XSM_DONE;
+	}
+
+	while (ixs->state != IPSEC_XSM_DONE) {
+
+		ixs->next_state = xmit_state_table[ixs->state].next_state;
+
+		stat = xmit_state_table[ixs->state].action(ixs);
+
+		if (stat == IPSEC_XMIT_OK) {
+			/* some functions change the next state, see the state table */
+			ixs->state = ixs->next_state;
+		} else if (stat == IPSEC_XMIT_PENDING) {
+			/*
+			 * things are on hold until we return here in the next/new state
+			 * we check our SA is valid when we return
+			 */
+			spin_unlock_bh(&tdb_lock);
+			return;
+		} else {
+			/* bad result, force state change to done */
+			KLIPS_PRINT(debug_tunnel,
+					"klips_debug:ipsec_xsm: "
+					"processing completed due to %s.\n",
+					ipsec_xmit_err(stat));
+			ixs->state = IPSEC_XSM_DONE;
 		}
 	}
 
+	/*
+	 * all done with anything needing locks
+	 */
+	spin_unlock_bh(&tdb_lock);
+
 	/* we are done with this SA */
-	ipsec_sa_put(ixs->ipsp); 
+	if (ixs->ipsp) {
+		ipsec_sa_put(ixs->ipsp); 
+		ixs->ipsp = NULL;
+	}
 
-	/* end encapsulation loop here XXX */
- cleanup:
-	spin_unlock(&tdb_lock);
-	return bundle_stat;
+	/*
+	 * let the caller continue with their processing
+	 */
+	ixs->xsm_complete(ixs, stat);
 }
 
+
 /*
  * $Log: ipsec_xmit.c,v $
  * Revision 1.20.2.13  2007-10-30 21:38:56  paul
--- openswan-2.4.13.org/linux/net/ipsec/pfkey_v2.c	2008-06-26 22:48:31.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/pfkey_v2.c	2008-06-27 13:38:04.000000000 +0200
@@ -1514,9 +1514,9 @@
         printk(KERN_INFO "klips_info:pfkey_cleanup: "
 	       "shutting down PF_KEY domain sockets.\n");
 #ifdef VOID_SOCK_UNREGISTER
-		sock_unregister(PF_KEY);
+	sock_unregister(PF_KEY);
 #else
-        sock_unregister(PF_KEY);
+	(void)sock_unregister(PF_KEY);
 #endif
 
 	error |= supported_remove_all(SADB_SATYPE_AH);
--- openswan-2.4.13.org/linux/net/ipsec/pfkey_v2_ext_process.c	2007-11-16 04:42:22.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/pfkey_v2_ext_process.c	2008-06-27 13:38:04.000000000 +0200
@@ -88,6 +88,10 @@
 #include "openswan/ipsec_proto.h"
 #include "openswan/ipsec_alg.h"
 
+#ifdef CONFIG_KLIPS_OCF
+#include "ipsec_ocf.h"
+#endif
+
 #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
 
 int
@@ -139,10 +143,18 @@
 	case IPPROTO_AH:
 		ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
 		ipsp->ips_encalg = SADB_EALG_NONE;
+#ifdef CONFIG_KLIPS_OCF
+		if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, 0))
+		    break;
+#endif
 		break;
 	case IPPROTO_ESP:
 		ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
 		ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
+#ifdef CONFIG_KLIPS_OCF
+		if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, ipsp->ips_encalg))
+		    break;
+#endif
 #ifdef CONFIG_KLIPS_ALG
 		ipsec_alg_sa_init(ipsp);
 #endif
--- openswan-2.4.13.org/linux/net/ipsec/pfkey_v2_parser.c	2007-10-30 22:40:36.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/pfkey_v2_parser.c	2008-06-27 13:38:04.000000000 +0200
@@ -2,6 +2,9 @@
  * @(#) RFC2367 PF_KEYv2 Key management API message parser
  * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs <rgb@freeswan.org>
  * 
+ * OCF support written by David McCullough <dmccullough@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -87,6 +90,8 @@
 
 #include "openswan/ipsec_kern24.h"
 
+#include "ipsec_ocf.h"
+
 #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
 
 struct sklist_t {
@@ -184,7 +189,6 @@
 DEBUG_NO_STATIC int
 pfkey_ipsec_sa_init(struct ipsec_sa *ipsp)
 {
-
 	return ipsec_sa_init(ipsp);
 }
 
--- openswan-2.4.13.org/linux/net/ipsec/sysctl_net_ipsec.c	2007-10-30 22:42:25.000000000 +0100
+++ openswan-2.4.13/linux/net/ipsec/sysctl_net_ipsec.c	2008-06-27 13:38:04.000000000 +0200
@@ -73,58 +73,171 @@
 };
 
 static ctl_table ipsec_table[] = {
+
 #ifdef CONFIG_KLIPS_DEBUG
-	{ NET_IPSEC_DEBUG_AH, "debug_ah", &debug_ah,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_ESP, "debug_esp", &debug_esp,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_TUNNEL, "debug_tunnel", &debug_tunnel,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_EROUTE, "debug_eroute", &debug_eroute,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_SPI, "debug_spi", &debug_spi,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_RADIJ, "debug_radij", &debug_radij,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_NETLINK, "debug_netlink", &debug_netlink,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_XFORM, "debug_xform", &debug_xform,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_RCV, "debug_rcv", &debug_rcv,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &debug_pfkey,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_DEBUG_VERBOSE, "debug_verbose",&sysctl_ipsec_debug_verbose,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_AH,
+		.procname     = "debug_ah",
+		.data         = &debug_ah,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_ESP,
+		.procname     = "debug_esp",
+		.data         = &debug_esp,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_TUNNEL,
+		.procname     = "debug_tunnel",
+		.data         = &debug_tunnel,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_EROUTE,
+		.procname     = "debug_eroute",
+		.data         = &debug_eroute,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_SPI,
+		.procname     = "debug_spi",
+		.data         = &debug_spi,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_RADIJ,
+		.procname     = "debug_radij",
+		.data         = &debug_radij,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_NETLINK,
+		.procname     = "debug_netlink",
+		.data         = &debug_netlink,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_XFORM,
+		.procname     = "debug_xform",
+		.data         = &debug_xform,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_RCV,
+		.procname     = "debug_rcv",
+		.data         = &debug_rcv,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_PFKEY,
+		.procname     = "debug_pfkey",
+		.data         = &debug_pfkey,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_VERBOSE,
+		.procname     = "debug_verbose",
+		.data         = &sysctl_ipsec_debug_verbose,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
 #ifdef CONFIG_KLIPS_IPCOMP
-	{ NET_IPSEC_DEBUG_IPCOMP, "debug_ipcomp", &sysctl_ipsec_debug_ipcomp,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
+	{
+		.ctl_name     = NET_IPSEC_DEBUG_IPCOMP,
+		.procname     = "debug_ipcomp",
+		.data         = &sysctl_ipsec_debug_ipcomp,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
 #endif /* CONFIG_KLIPS_IPCOMP */
 
 #ifdef CONFIG_KLIPS_REGRESS
-	{ NET_IPSEC_REGRESS_PFKEY_LOSSAGE, "pfkey_lossage",
-	  &sysctl_ipsec_regress_pfkey_lossage,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},
+	{
+		.ctl_name     = NET_IPSEC_REGRESS_PFKEY_LOSSAGE,
+		.procname     = "pfkey_lossage",
+		.data         = &sysctl_ipsec_regress_pfkey_lossage,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
 #endif /* CONFIG_KLIPS_REGRESS */
 
 #endif /* CONFIG_KLIPS_DEBUG */
-	{ NET_IPSEC_ICMP, "icmp", &sysctl_ipsec_icmp,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_INBOUND_POLICY_CHECK, "inbound_policy_check", &sysctl_ipsec_inbound_policy_check,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{ NET_IPSEC_TOS, "tos", &sysctl_ipsec_tos,
-	  sizeof(int), 0644, NULL, .proc_handler = &proc_dointvec},    
-	{0}
+
+	{
+		.ctl_name     = NET_IPSEC_ICMP,
+		.procname     = "icmp",
+		.data         = &sysctl_ipsec_icmp,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_INBOUND_POLICY_CHECK,
+		.procname     = "inbound_policy_check",
+		.data         = &sysctl_ipsec_inbound_policy_check,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = NET_IPSEC_TOS,
+		.procname     = "tos",
+		.data         = &sysctl_ipsec_tos,
+		.maxlen       = sizeof(int),
+		.mode         = 0644,
+		.proc_handler = &proc_dointvec
+	},
+	{
+		.ctl_name     = 0
+	}
 };
 
 static ctl_table ipsec_net_table[] = {
-        { NET_IPSEC, "ipsec", NULL, 0, 0555, ipsec_table },
-        { 0 }
+	{
+		.ctl_name     = NET_IPSEC,
+		.procname     = "ipsec",
+		.mode         = 0555,
+		.child        = ipsec_table
+	},
+	{
+		.ctl_name     = 0
+	}
 };
  
 static ctl_table ipsec_root_table[] = {
-        { CTL_NET, "net", NULL, 0, 0555, ipsec_net_table },
-        { 0 }
+	{
+		.ctl_name     = CTL_NET,
+		.procname     = "net",
+		.mode         = 0555,
+		.child        = ipsec_net_table
+	},
+	{
+		.ctl_name     = 0
+	}
 };
  
 static struct ctl_table_header *ipsec_table_header;
--- openswan-2.4.13.org/linux/net/ipsec/aes/aes.c	2004-07-10 09:48:40.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/aes/aes.c	2008-06-27 13:38:04.000000000 +0200
@@ -34,6 +34,10 @@
 
 #include "crypto/aes.h"
 
+#ifdef OCF_ASSIST
+#include "crypto/ocf_assist.h"
+#endif
+
 // CONFIGURATION OPTIONS (see also aes.h)
 //
 // 1.  Define UNROLL for full loop unrolling in encryption and decryption.
@@ -965,6 +969,14 @@
     if(!tab_gen) { gen_tabs(); tab_gen = 1; }
 #endif
 
+/* only need to do a special set_key for the cryptodev hw acceleration */
+#ifdef OCF_ASSIST
+	if (ocf_aes_assist() & OCF_PROVIDES_AES) {
+		ocf_aes_set_key(cx, in_key, n_bytes, f);
+		return;
+	}
+#endif
+
     switch(n_bytes) {
     case 32:                    /* bytes */
     case 256:                   /* bits */
--- openswan-2.4.13.org/linux/net/ipsec/aes/aes_cbc.c	2004-07-10 09:48:40.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/aes/aes_cbc.c	2008-06-27 13:38:04.000000000 +0200
@@ -25,13 +25,34 @@
 #endif
 #include "crypto/aes_cbc.h"
 #include "crypto/cbc_generic.h"
+#ifdef OCF_ASSIST
+#include "crypto/ocf_assist.h"
+#endif
 
 /* returns bool success */
 int AES_set_key(aes_context *aes_ctx, const u_int8_t *key, int keysize) {
 	aes_set_key(aes_ctx, key, keysize, 0);
 	return 1;	
 }
+
+#ifdef OCF_ASSIST
+
+CBC_IMPL_BLK16(_AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
+
+int
+AES_cbc_encrypt(aes_context *ctx, const u_int8_t *in, u_int8_t *out, int ilen,
+		const u_int8_t *iv, int encrypt)
+{
+	if (ocf_aes_assist() & OCF_PROVIDES_AES) {
+		return ocf_aes_cbc_encrypt(ctx, in, out, ilen, iv, encrypt);
+	} else {
+		return _AES_cbc_encrypt(ctx, in, out, ilen, iv, encrypt);
+	}
+}
+
+#else
 CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
+#endif
 
 
 /*
--- openswan-2.4.13.org/linux/net/ipsec/alg/Config.in	2004-04-06 04:49:40.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/alg/Config.in	2008-06-27 13:38:04.000000000 +0200
@@ -1,3 +1,3 @@
 #Placeholder
-source net/ipsec/alg/Config.alg_aes.in
-source net/ipsec/alg/Config.alg_cryptoapi.in
+source ../openswan/linux/net/ipsec/alg/Config.alg_aes.in
+source ../openswan/linux/net/ipsec/alg/Config.alg_cryptoapi.in
--- openswan-2.4.13.org/linux/net/ipsec/des/cbc_enc.c	2004-08-05 23:37:33.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/des/cbc_enc.c	2008-06-27 13:38:04.000000000 +0200
@@ -73,6 +73,13 @@
 	DES_LONG tin[2];
 	unsigned char *iv;
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
+		ocf_des_cbc_encrypt(input, output, length, schedule, ivec, enc);
+		return;
+	}
+#endif
+
 	in=(unsigned char *)input;
 	out=(unsigned char *)output;
 	iv=(unsigned char *)ivec;
--- openswan-2.4.13.org/linux/net/ipsec/des/des_enc.c	2004-08-05 23:37:33.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/des/des_enc.c	2008-06-27 13:38:04.000000000 +0200
@@ -72,6 +72,13 @@
 #endif
 	register DES_LONG *s;
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
+		ocf_des_encrypt(data, ks, enc);
+		return;
+	}
+#endif
+
 	r=data[0];
 	l=data[1];
 
@@ -316,6 +323,13 @@
 	DES_LONG tin[2];
 	unsigned char *iv;
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
+		ocf_des_ncbc_encrypt(input, output, length, schedule, ivec, enc);
+		return;
+	}
+#endif 
+
 	in=(unsigned char *)input;
 	out=(unsigned char *)output;
 	iv=(unsigned char *)ivec;
@@ -400,6 +414,14 @@
 	DES_LONG tin[2];
 	unsigned char *iv;
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
+		ocf_des_ede3_cbc_encrypt(input,output,length,ks1,ks2,ks3,ivec,enc);
+		return;
+	}
+#endif
+
+
 	in=(unsigned char *)input;
 	out=(unsigned char *)output;
 	iv=(unsigned char *)ivec;
--- openswan-2.4.13.org/linux/net/ipsec/des/ecb_enc.c	2004-08-04 17:57:22.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/des/ecb_enc.c	2008-06-27 13:38:04.000000000 +0200
@@ -116,6 +116,13 @@
 	register unsigned char *in,*out;
 	DES_LONG ll[2];
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES) {
+		ocf_des_ecb_encrypt(input, output, ks, enc);
+		return;
+	}
+#endif
+
 	in=(unsigned char *)input;
 	out=(unsigned char *)output;
 	c2l(in,l); ll[0]=l;
--- openswan-2.4.13.org/linux/net/ipsec/des/set_key.c	2004-08-04 17:57:22.000000000 +0200
+++ openswan-2.4.13/linux/net/ipsec/des/set_key.c	2008-06-27 13:38:04.000000000 +0200
@@ -176,6 +176,11 @@
 			return(-2);
 		}
 
+#ifdef OCF_ASSIST
+	if (ocf_des_assist() & OCF_PROVIDES_DES_3DES)
+		return(ocf_des_set_key(key, schedule));
+#endif
+
 	k=(DES_LONG *)schedule;
 	in=(unsigned char *)key;
 
--- openswan-2.4.13.org/packaging/makefiles/module.make	2007-10-28 02:06:08.000000000 +0200
+++ openswan-2.4.13/packaging/makefiles/module.make	2008-06-27 13:38:04.000000000 +0200
@@ -37,6 +37,7 @@
 EXTRA_CFLAGS += ${KERNEL_CFLAGS}
 
 EXTRA_CFLAGS += -I${KLIPS_TOP}/include
+EXTRA_CFLAGS += -I${KLIPSSRC}/.
 
 EXTRA_CFLAGS += -I${TOPDIR}/include 
 EXTRA_CFLAGS += -I${LIBZLIBSRCDIR}
--- openswan-2.4.13.org/packaging/makefiles/module26.make	2007-10-28 02:06:08.000000000 +0200
+++ openswan-2.4.13/packaging/makefiles/module26.make	2008-06-27 13:38:04.000000000 +0200
@@ -23,6 +23,7 @@
 EXTRA_CFLAGS += -DDISABLE_UDP_CHECKSUM
 
 EXTRA_CFLAGS += -I${KLIPS_TOP}/include
+EXTRA_CFLAGS += -I${KLIPSSRC}/.
 
 # build version.c using version number from Makefile.ver
 ${BUILDDIR}/version.c:	${KLIPSSRC}/version.in.c ${OPENSWANSRCDIR}/Makefile.ver
--- openswan-2.4.13.org/programs/Makefile.program	2007-06-19 16:49:19.000000000 +0200
+++ openswan-2.4.13/programs/Makefile.program	2008-06-27 13:38:04.000000000 +0200
@@ -156,6 +156,7 @@
 			-e "s:@USE_IPROUTE2@:$(USE_IPROUTE2):" \
 			-e "s:@IPSEC_FIREWALLTYPE@:$(IPSEC_FIREWALLTYPE):" \
 			-e "s:@OE_FLAG@:$(OE_FLAG):" \
+			-e "s:@USE_DEFAULT_CONNS@:$(USE_DEFAULT_CONNS):" \
 			-e "s:@MODPROBE@:$(MODPROBE):" \
 			| cat >$@
 	@if [ -x $< ]; then chmod +x $@; fi
--- openswan-2.4.13.org/programs/_confread/_confread.in	2006-04-12 21:55:42.000000000 +0200
+++ openswan-2.4.13/programs/_confread/_confread.in	2008-06-27 13:38:04.000000000 +0200
@@ -508,6 +508,7 @@
 	if (failed)
 		exit 1
 
+	if ("@USE_DEFAULT_CONNS@" != "no") {
 	# supply default conns if relevant and not found
 	if (type == "conn") {
 		if (jam("packetdefault", "route")) {
@@ -564,6 +565,7 @@
 			output(o_parm, "leftnexthop", "%defaultroute")
 		}
 	}
+	}
 
 	filename = originalfilename
 	unseen = ""
--- openswan-2.4.13.org/programs/_plutorun/_plutorun.in	2006-10-11 18:24:52.000000000 +0200
+++ openswan-2.4.13/programs/_plutorun/_plutorun.in	2008-06-27 13:38:04.000000000 +0200
@@ -227,6 +227,7 @@
 echo "$verb Pluto subsystem..." | logger -p authpriv.error -t ipsec__plutorun
 execdir=${IPSEC_EXECDIR-@IPSEC_EXECDIR@}
 libdir=${IPSEC_LIBDIR-@IPSEC_LIBDIR@}
+ipsecdir=${IPSEC_CONFS-@IPSEC_CONFDDIR@}
 until (
 	if test -s $info
 	then
@@ -234,7 +235,7 @@
 		export defaultroutephys defaultroutevirt defaultrouteaddr defaultroutenexthop
 	fi
 	# eval allows $popts to contain redirection and other magic
-	eval $execdir/pluto --nofork --secretsfile "$IPSEC_SECRETS" --ipsecdir "${IPSEC_CONFS}/ipsec.d" $popts
+	eval $execdir/pluto --nofork --secretsfile "$IPSEC_SECRETS" --ipsecdir $ipsecdir $popts
 	status=$?
 	echo "exit"
 	echo $status
--- openswan-2.4.13.org/programs/pluto/Makefile	2007-11-06 19:56:26.000000000 +0100
+++ openswan-2.4.13/programs/pluto/Makefile	2008-06-27 13:38:04.000000000 +0200
@@ -56,7 +56,7 @@
 
 # -O on Linux makes gcc coredump when compiling sha1.c
 # -Wundef is nice but RHL5.2 compiler doesn't support it
-CFLAGS = -g -Wall -W -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast \
+CFLAGS += -g -Wall -W -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast \
 	-Wcast-qual -Wmissing-declarations -Wwrite-strings \
 	-Wstrict-prototypes # -Wundef
 
@@ -145,7 +145,9 @@
 SMARTCARD_DIST_SRCS=smartcard.c smartcard.h 
 X509_OBJS=${X509_DIST_OBJS}
 X509_SRCS=${X509_DIST_SRCS}
-X509_DEFS=-DX509 
+X509_DEFS=
+HAVE_OCF_DIST_OBJS=ocf_cryptodev.o 
+HAVE_OCF_DIST_SRCS=ocf_cryptodev.c ocf_cryptodev.h
 
 # dynamic LDAP CRL fetching requires OpenLDAP library
 ifeq ($(USE_LDAP),true)
@@ -162,6 +164,19 @@
 HAVE_THREADS_LIBS=-lpthread
 endif
 
+ifeq ($(HAVE_DYNAMICDNS),true)
+HAVE_DYNAMICDNS_DEF=-DDYNAMICDNS
+endif
+
+ifeq ($(HAVE_OCF),true)
+ifeq ($(HAVE_OPENSSL),true)
+HAVE_OCF_OPENSSL_DEFS=-DHAVE_OCF_AND_OPENSSL
+HAVE_OCF_OBJS=${HAVE_OCF_DIST_OBJS}
+HAVE_OCF_SRCS=${HAVE_OCF_DIST_SRCS}
+OPENSSL_LIBS=-lcrypto
+endif
+endif
+
 ifeq ($(USE_SMARTCARD),true)
 # smartcard functions are compiled in whether or not we have -lopensc,
 # but ifndef SMARTCARD, they are dummy functions.
@@ -210,7 +225,7 @@
 endif
 
 ifeq ($(USE_WEAKSTUFF),true)
-WEAK_DEFS=-DUSE_VERYWEAK_DH1=1 #-DUSE_1DES
+WEAK_DEFS=-DUSE_VERYWEAK_DH1=1 -DUSE_1DES
 endif
 
 ifeq ($(USE_EXTRACRYPTO),true)
@@ -220,6 +235,10 @@
 EXTRA_CRYPTO_LIBS=$(LIBBLOWFISH) $(LIBTWOFISH) $(LIBSERPENT) $(LIBSHA2) 
 endif
 
+ifeq ($(USE_SINGLE_CONF_DIR),true)
+SINGLE_CONF_DIR=-DSINGLE_CONF_DIR
+endif
+
 OS=$(shell uname -s | tr 'A-Z' 'a-z')
 SYSDEP_SRC=sysdep_${OS}.c
 SYSDEP_OBJ=sysdep_${OS}.o
@@ -248,6 +267,8 @@
 	${XAUTH_DEFS} ${XAUTHPAM_DEFS} \
 	${NAT_DEFS} ${CURL_DEFS}\
 	${WEAK_DEFS} \
+	${SINGLE_CONF_DIR} ${HAVE_OCF_OPENSSL_DEFS} \
+	${HAVE_DYNAMICDNS_DEF} \
 	${HW_DEFS} \
 	# -DLEAK_DETECTIVE
 
@@ -261,11 +282,14 @@
 # libefence is a free memory allocation debugger
 # Solaris 2 needs -lsocket -lnsl
 LIBSPLUTO =$(OBJSGCRYPT) $(LIBDESLITE) $(LIBAES) $(OPENSWANLIB) 
+LIBSPLUTO+=$(OPENSSL_LIBS)
 LIBSPLUTO+=$(IPSECPOLICY_LIBS) $(X509_LIBS) $(SMARTCARD_LIBS) 
 LIBSPLUTO+=$(HAVE_THREADS_LIBS) ${XAUTHPAM_LIBS}
 LIBSPLUTO+=${CURL_LIBS}  $(EXTRA_LIBS)
 LIBSPLUTO+=${EXTRA_CRYPTO_LIBS}
 LIBSPLUTO+= -lgmp -lresolv # -lefence
+LIBCRYPT ?= -lcrypt
+LIBSPLUTO+= $(LIBCRYPT) #with OCF_ASSIST we can't get a working crypt() in libdes
 
 ifneq ($(LD_LIBRARY_PATH),)
 LDFLAGS+=-L$(LD_LIBRARY_PATH)
@@ -343,7 +367,8 @@
 	adns.c adns.h \
 	whack.c whack.h whackinit.c whacklib.c\
 	${XAUTH_DIST_SRCS} \
-	${AGGRESSIVE_DIST_SRCS} 
+	${AGGRESSIVE_DIST_SRCS} \
+	${HAVE_OCF_DIST_SRCS}
 
 DIST = $(DISTMISC) $(DISTSRC)
 
@@ -371,6 +396,7 @@
 OBJSPLUTO += ${AGGRESSIVE_OBJS}
 OBJSPLUTO += ${SMARTCARD_OBJS} ${X509_OBJS} ${HAVE_THREADS_OBJS}
 OBJSPLUTO += ${OBJSLIBPLUTO}
+OBJSPLUTO += ${HAVE_OCF_OBJS}
 OBJSPLUTO += ${SYSDEP_OBJ} stubs.o
 
 OBJSADNS = adns.o
--- openswan-2.4.13.org/programs/pluto/certs.c	2004-06-27 22:43:41.000000000 +0200
+++ openswan-2.4.13/programs/pluto/certs.c	2008-06-27 13:38:04.000000000 +0200
@@ -88,16 +88,31 @@
 	fseek(fd, 0, SEEK_END );
 	blob->len = ftell(fd);
 	rewind(fd);
+
+	if (blob->len <= 0) {
+#ifndef SINGLE_CONF_DIR /* too verbose in single conf mode */
+	    /* no point barfing on this */
+	    openswan_log("  empty file, discarded");
+#endif
+	    return FALSE;
+	}
+
 	blob->ptr = alloc_bytes(blob->len, type);
 	bytes = fread(blob->ptr, 1, blob->len, fd);
 	fclose(fd);
+#ifndef SINGLE_CONF_DIR /* too verbose in single conf mode */
+#define	LF()
 	openswan_log("  loaded %s file '%s' (%d bytes)", type, filename, bytes);
+#else
+#define	LF() openswan_log("  loaded %s file '%s' (%d bytes)", type, filename, bytes)
+#endif
 
 	*pgp = FALSE;
 
 	/* try DER format */
 	if (is_asn1(*blob))
 	{
+		LF();
 	    DBG(DBG_PARSING,
 		DBG_log("  file coded in DER format");
 	    )
@@ -111,6 +126,7 @@
 	{
 	    if (*pgp)
 	    {
+                LF();
                 DBG(DBG_PARSING,
                     DBG_log("  file coded in armored PGP format");
                 )
@@ -118,6 +134,7 @@
 	    }
 	    if (is_asn1(*blob))
 	    {
+		LF();
 		DBG(DBG_PARSING,
 		    DBG_log("  file coded in PEM format");
 		)
@@ -126,8 +143,10 @@
 	    ugh = "file coded in unknown format, discarded";
 	}
 
+#ifndef SINGLE_CONF_DIR /* too verbose in single conf mode */
 	/* a conversion error has occured */
 	openswan_log("  %s", ugh);
+#endif
 	pfree(blob->ptr);
 	*blob = empty_chunk;
     }
@@ -136,6 +155,9 @@
 	openswan_log("  could not open %s file '%s'", type, filename);
     }
     return FALSE;
+#ifdef SINGLE_CONF_DIR
+#undef LF
+#endif
 }
 
 /*
--- openswan-2.4.13.org/programs/pluto/connections.c	2008-04-24 20:49:17.000000000 +0200
+++ openswan-2.4.13/programs/pluto/connections.c	2008-06-27 13:56:48.000000000 +0200
@@ -334,6 +334,68 @@
 	*ep = (e)->enext; \
     }
 
+#ifdef DYNAMICDNS
+/* update the host pairs with the latest DNS ip address */
+static void
+update_host_pairs(struct connection *c)
+{
+    struct connection *d = NULL, *conn_next_tmp = NULL, *conn_list = NULL;
+    struct host_pair *p = NULL, *hp_next_tmp;
+    ip_address new_addr;
+    char *dnshostname;
+
+    d = c->host_pair->connections;
+    p = c->host_pair;
+
+    if (d == NULL
+    	|| p == NULL
+	|| d->dnshostname == NULL
+	|| ttoaddr(d->dnshostname, 0, d->addr_family, &new_addr) != NULL
+	|| sameaddr(&new_addr, &p->him.addr)) 
+	    return;
+
+    /* remember this dnshostname */
+    dnshostname = c->dnshostname;
+
+    for (; d != NULL; d = hp_next_tmp)
+    {
+	hp_next_tmp = d->hp_next;
+	if (d->dnshostname && strcmp(d->dnshostname, dnshostname) == 0)
+	{
+	      /* 
+	      * If there is a dnshostname and it is the same as the one that has changed, then 
+	      * change the connection's remote host address and remove the connection from the host pair.
+	      */
+	      d->spd.that.host_addr = new_addr;
+	      list_rm(struct connection, hp_next, d, d->host_pair->connections);
+
+	      d->hp_next = conn_list;
+	      conn_list = d;
+	}
+    }
+
+    if (conn_list)
+    {
+	d = conn_list;
+	for (; d != NULL; d = conn_next_tmp)
+	{
+	    /* 
+	    * connect the connection to the new host_pair
+	    */
+	    conn_next_tmp = d->hp_next;
+	    connect_to_host_pair(d);
+	}
+    }
+
+    if (p->connections == NULL)
+    {
+	passert(p->pending == NULL);	/* ??? must deal with this! */
+	list_rm(struct host_pair, next, p, host_pairs);
+	pfree(p);
+    }
+}
+#endif /* DYNAMICDNS */
+
 static void
 delete_end(struct connection *c UNUSED, struct spd_route *sr UNUSED, struct end *e)
 {
@@ -437,6 +499,9 @@
     set_debugging(old_cur_debugging);
 #endif
     pfreeany(c->name);
+#ifdef DYNAMICDNS
+    pfreeany(c->dnshostname);
+#endif /* DYNAMICDNS */
 
     sr = &c->spd;
     while(sr) {
@@ -853,6 +918,9 @@
 unshare_connection_strings(struct connection *c)
 {
     c->name = clone_str(c->name, "connection name");
+#ifdef DYNAMICDNS
+    c->dnshostname = clone_str(c->dnshostname, "connection dnshostname");
+#endif /* DYNAMICDNS */
 
     unshare_id_content(&c->spd.this.id);
     c->spd.this.updown = clone_str(c->spd.this.updown, "updown");
@@ -1233,6 +1301,10 @@
 
 	same_rightca = same_leftca = FALSE;
 	c->name = wm->name;
+#ifdef DYNAMICDNS
+	if (wm->dnshostname)
+		c->dnshostname = wm->dnshostname;
+#endif /* DYNAMICDNS */
 
 	c->policy = wm->policy;
 
@@ -2159,6 +2231,47 @@
     close_any(whackfd);
 }
 
+void restart_connections_by_peer(struct connection *c)
+{
+    struct connection *d;
+
+    d = c->host_pair->connections;
+    for (; d != NULL; d = d->hp_next) {
+	   if (
+#ifdef DYNAMICDNS
+	       (c->dnshostname && d->dnshostname && (strcmp(c->dnshostname, d->dnshostname) == 0))
+	   	|| (c->dnshostname == NULL && d->dnshostname == NULL && 
+#endif /* DYNAMICDNS */
+									sameaddr(&d->spd.that.host_addr, &c->spd.that.host_addr)
+#ifdef DYNAMICDNS
+																)
+#endif /* DYNAMICDNS */
+																 )
+	       terminate_connection(d->name);
+    }
+
+#ifdef DYNAMICDNS
+    update_host_pairs(c);
+#endif /* DYNAMICDNS */
+
+    if (c->host_pair == NULL)
+    	   return;
+    d = c->host_pair->connections;
+    for (; d != NULL; d = d->hp_next) {
+    	   if (
+#ifdef DYNAMICDNS
+	       (c->dnshostname && d->dnshostname && (strcmp(c->dnshostname, d->dnshostname) == 0))
+	   	|| (c->dnshostname == NULL && d->dnshostname == NULL && 
+#endif /* DYNAMICDNS */
+									sameaddr(&d->spd.that.host_addr, &c->spd.that.host_addr)
+#ifdef DYNAMICDNS
+																)
+#endif /* DYNAMICDNS */
+																 )
+	       initiate_connection(d->name, NULL_FD, 0, pcim_demand_crypto);
+    }
+}
+
 /* (Possibly) Opportunistic Initiation:
  * Knowing clients (single IP addresses), try to build an tunnel.
  * This may involve discovering a gateway and instantiating an
@@ -3396,6 +3509,9 @@
 	    if (d->kind >= CK_PERMANENT
  	    && same_id(&c->spd.this.id, &d->spd.this.id)
 	    && same_id(&c->spd.that.id, &d->spd.that.id)
+#ifdef DYNAMICDNS
+            && !(c->dnshostname && d->dnshostname && (strcmp(c->dnshostname, d->dnshostname) == 0))
+#endif /* DYNAMICDNS */	    
 	    && (!sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr)
 		|| (c->spd.that.host_port != d->spd.that.host_port)))
 	    {
@@ -4601,8 +4717,17 @@
 	    p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES|PHASE1_INITIATOR_STATES);
 	    
 	    /* arrange to rekey the phase 1 */
+#ifdef DYNAMICDNS
+	    if (c->dnshostname != NULL)
+		  restart_connections_by_peer(c);
+	    else 
+	    {
+#endif /* DYNAMICDNS */
 	    delete_event(p1st);
 	    event_schedule(EVENT_SA_REPLACE, 0, p1st);
+#ifdef DYNAMICDNS
+	    }
+#endif /* DYNAMICDNS */
 	}
     }
 }
--- openswan-2.4.13.org/programs/pluto/connections.h	2008-04-24 20:49:17.000000000 +0200
+++ openswan-2.4.13/programs/pluto/connections.h	2008-06-27 13:38:04.000000000 +0200
@@ -239,6 +239,9 @@
 #ifdef XAUTH_USEPAM
     pam_handle_t  *pamh;		/*  PAM handle for that connection  */
 #endif
+#ifdef DYNAMICDNS
+    char *dnshostname;
+#endif /* DYNAMICDNS */
 };
 
 #define oriented(c) ((c).interface != NULL)
@@ -262,6 +265,7 @@
 				, int whackfd
 				, lset_t moredebug
 				, enum crypto_importance importance);
+extern void restart_connections_by_peer(struct connection *c);
 extern void initiate_opportunistic(const ip_address *our_client
     , const ip_address *peer_client, int transport_proto, bool held, int whackfd, err_t why);
 extern void terminate_connection(const char *nm);
--- openswan-2.4.13.org/programs/pluto/crypt_ke.c	2006-03-20 14:32:03.000000000 +0100
+++ openswan-2.4.13/programs/pluto/crypt_ke.c	2008-06-27 13:38:04.000000000 +0200
@@ -14,6 +14,10 @@
  *
  * This code was developed with the support of IXIA communications.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * RCSID $Id: crypt_ke.c,v 1.11.2.3 2006-03-20 13:32:03 paul Exp $
  */
 
@@ -46,6 +50,15 @@
 #include "log.h"
 #include "timer.h"
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "id.h"
+#include "pgp.h"
+#include "x509.h"
+#include "certs.h"
+#include "keys.h"
+#include "ocf_cryptodev.h"
+#endif
+
 void calc_ke(struct pluto_crypto_req *r)
 {
     MP_INT mp_g;
@@ -53,6 +66,9 @@
     const struct oakley_group_desc *group;
     chunk_t gi;
     struct pcr_kenonce *kn = &r->pcr_d.kn;
+#ifdef HAVE_OCF_AND_OPENSSL
+    BIGNUM r0;
+#endif
     
     group = lookup_group(kn->oakley_group);
     
@@ -65,7 +81,13 @@
     n_to_mpz(&secret, wire_chunk_ptr(kn, &(kn->secret)), LOCALSECRETSIZE);
     
     mpz_init(&mp_g);
+#ifdef HAVE_OCF_AND_OPENSSL
+    BN_init(&r0);
+    cryptodev.mod_exp(&r0, &groupgenerator, &secret, group->modulus);
+    bn2mp(&r0, (MP_INT *) &mp_g);
+#else
     mpz_powm(&mp_g, &groupgenerator, &secret, group->modulus);
+#endif
     
     gi = mpz_to_n(&mp_g, group->bytes);
     
@@ -84,8 +106,11 @@
 	DBG_dump_chunk("Public DH value sent:\n", gi));
 
     /* clean up after ourselves */
+#ifdef HAVE_OCF_AND_OPENSSL
+    BN_free(&r0);
+#else
     mpz_clear(&mp_g);
-    mpz_clear(&secret);
+#endif
     freeanychunk(gi);
 }
 
--- openswan-2.4.13.org/programs/pluto/demux.c	2008-06-16 03:03:04.000000000 +0200
+++ openswan-2.4.13/programs/pluto/demux.c	2008-06-27 13:38:04.000000000 +0200
@@ -1650,6 +1650,7 @@
 #ifdef MODECFG	
 	    if(st->st_state == STATE_MODE_CFG_R2)   /* Have we just give an IP address to peer? */
 	    {
+		log_state_chg(st, STATE_MAIN_R3);
 		st->st_state = STATE_MAIN_R3;	    /* ISAKMP is up... */
 	    }
 #endif
@@ -1818,6 +1819,7 @@
 	       && IS_PHASE1(st->st_state))	/* Switch from Phase1 to Mode Config */
 	    {
 		openswan_log("We were in phase 1, with no state, so we went to XAUTH_R0");
+		log_state_chg(st, STATE_XAUTH_R0);
 		st->st_state = STATE_XAUTH_R0;
 	    }
 
@@ -2452,6 +2454,8 @@
 	    openswan_log("transition from state %s to state %s"
                  , enum_name(&state_names, from_state)
                  , enum_name(&state_names, smc->next_state));
+	    
+		log_state_chg(st, smc->next_state);
 	    st->st_state = smc->next_state;
 
 	    /* Delete previous retransmission event.
@@ -2834,6 +2838,7 @@
 	       && !st->hidden_variables.st_modecfg_vars_set 
 	       && !(st->st_connection->policy & POLICY_MODECFG_PULL))
 	    {
+		    log_state_chg(st, STATE_MODE_CFG_R1);
 		    st->st_state = STATE_MODE_CFG_R1;
 		    set_cur_state(st);
 		    openswan_log("Sending MODE CONFIG set");
@@ -2847,6 +2852,7 @@
 		&& IS_MODE_CFG_ESTABLISHED(st->st_state)
 		&& (st->st_seen_vendorid & LELEM(VID_NORTEL))) 
 	    {
+		log_state_chg(st, STATE_MAIN_R3);
 		st->st_state = STATE_MAIN_R3;	    /* ISAKMP is up... */
 	        set_cur_state(st);
 	        quick_outI1(st->st_whack_sock, st, st->st_connection, st->st_connection->policy, 1, SOS_NOBODY);
--- openswan-2.4.13.org/programs/pluto/dpd.c	2006-11-24 05:21:42.000000000 +0100
+++ openswan-2.4.13/programs/pluto/dpd.c	2008-06-27 13:38:04.000000000 +0200
@@ -534,7 +534,9 @@
     /* probably wrong thing to assert here */
     passert(action == DPD_ACTION_HOLD
 	    || action == DPD_ACTION_CLEAR
-	    || action == DPD_ACTION_RESTART);
+	    || action == DPD_ACTION_RESTART
+	    || action == DPD_ACTION_RESTART_BY_PEER
+	    );
         
     /** delete the state, which is probably in phase 2 */
     set_cur_connection(c);
@@ -586,6 +588,12 @@
 
 	break;
 
+    case DPD_ACTION_RESTART_BY_PEER:
+	/** dpdaction=restart_by_peer - immediately renegotiate connections to the same peer. */
+	openswan_log("DPD: Restarting all connections that share this peer");
+
+        restart_connections_by_peer(c);
+	break;
     }
     reset_cur_connection();
 }
--- openswan-2.4.13.org/programs/pluto/ike_alg.c	2006-11-24 18:58:23.000000000 +0100
+++ openswan-2.4.13/programs/pluto/ike_alg.c	2008-06-27 13:38:04.000000000 +0200
@@ -570,9 +570,11 @@
 						 (ike_info->ike_eklen==key_len)) &&
 						(ike_info->ike_halg == aalg) &&
 						(ike_info->ike_modp == group)) {
+#ifndef USE_1DES
 					if (ealg_insecure) 
 						loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!"
 								, enum_name(&oakley_enc_names, ealg));
+#endif
 					return TRUE;
 				}
 			}
--- openswan-2.4.13.org/programs/pluto/ipsec_doi.c	2008-06-26 22:56:44.000000000 +0200
+++ openswan-2.4.13/programs/pluto/ipsec_doi.c	2008-06-27 13:58:18.000000000 +0200
@@ -13,6 +13,10 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * RCSID $Id: ipsec_doi.c,v 1.304.2.18 2008-06-26 20:56:44 paul Exp $
  */
 
@@ -87,6 +91,10 @@
 #include "dpd.h"
 #include "x509more.h"
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "ocf_cryptodev.h"
+#endif
+
 /*
 * tools for sending Pluto Vendor ID.
  */
@@ -1367,14 +1375,25 @@
     {
 	chunk_t temp_s;
 	mpz_t c;
+#ifdef HAVE_OCF_AND_OPENSSL
+	BIGNUM r0;
+#endif
 
 	n_to_mpz(c, sig_val, sig_len);
+#ifdef HAVE_OCF_AND_OPENSSL
+	BN_init(&r0);
+	cryptodev.mod_exp(&r0, c, &k->e, &k->n);
+	bn2mp(&r0, (MP_INT *) c);
+#else
 	mpz_powm(c, c, &k->e, &k->n);
+#endif
 
 	temp_s = mpz_to_n(c, sig_len);	/* back to octets */
 	memcpy(s, temp_s.ptr, sig_len);
 	pfree(temp_s.ptr);
+#ifndef HAVE_OCF_AND_OPENSSL
 	mpz_clear(c);
+#endif
     }
 
     /* sanity check on signature: see if it matches
--- openswan-2.4.13.org/programs/pluto/kernel.c	2008-02-15 18:00:01.000000000 +0100
+++ openswan-2.4.13/programs/pluto/kernel.c	2008-06-27 13:38:04.000000000 +0200
@@ -43,6 +43,11 @@
 #include "kameipsec.h"
 #endif /* KLIPS */
 
+#include <linux/autoconf.h>
+#ifdef CONFIG_LEDMAN
+#include <linux/ledman.h>
+#endif /* !CONFIG_LEDMAN */
+
 #include "constants.h"
 #include "oswlog.h"
 
@@ -1289,7 +1294,7 @@
         struct eroute_info *p = orphaned_holds;
 
         orphaned_holds = p->next;
-        pfree(orphaned_holds);
+        pfree(p);
     }
 
     /* decode the /proc file.  Don't do anything strenuous to it
@@ -2585,6 +2590,10 @@
 #endif /* !KLIPS */
 }
 
+#ifdef CONFIG_LEDMAN
+static int num_ipsec_sa = 0;
+#endif /* !CONFIG_LEDMAN */
+
 bool
 install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS)
 {
@@ -2637,6 +2646,12 @@
             }
         }
     }
+
+#ifdef CONFIG_LEDMAN
+    num_ipsec_sa++;
+    ledman_cmd(LEDMAN_CMD_ON, LEDMAN_VPN);
+#endif /* !CONFIG_LEDMAN */
+
 #else /* !KLIPS */
     DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s"
         , inbound_also? "inbound and oubound" : "outbound only"));
@@ -2712,6 +2727,13 @@
         (void) teardown_half_ipsec_sa(st, FALSE);
     }
     (void) teardown_half_ipsec_sa(st, TRUE);
+
+#ifdef CONFIG_LEDMAN
+	num_ipsec_sa--;
+	if (num_ipsec_sa == 0)
+	    ledman_cmd(LEDMAN_CMD_OFF, LEDMAN_VPN);    
+#endif /* !CONFIG_LEDMAN */
+
 #else /* !KLIPS */
     DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()"));
 #endif /* !KLIPS */
--- openswan-2.4.13.org/programs/pluto/keys.c	2005-08-19 19:52:42.000000000 +0200
+++ openswan-2.4.13/programs/pluto/keys.c	2008-06-27 13:38:04.000000000 +0200
@@ -11,6 +11,10 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * RCSID $Id: keys.c,v 1.102.2.1 2005-08-19 17:52:42 ken Exp $
  */
 
@@ -60,6 +64,10 @@
 #include "fetch.h"
 #include "x509more.h"
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "ocf_cryptodev.h"
+#endif
+
 /* Maximum length of filename and passphrase buffer */
 #define BUF_LEN		256
 
@@ -211,9 +219,16 @@
     , u_char *sig_val, size_t sig_len)
 {
     chunk_t ch;
+#ifdef HAVE_OCF_AND_OPENSSL
+    mpz_t t1;
+#else
     mpz_t t1, t2;
+#endif
     size_t padlen;
     u_char *p = sig_val;
+#ifdef HAVE_OCF_AND_OPENSSL
+    BIGNUM r0;
+#endif
 
     DBG(DBG_CONTROL | DBG_CRYPT,
 	DBG_log("signing hash with RSA Key *%s", k->pub.keyid)
@@ -236,6 +251,11 @@
      * There are two methods, depending on the form of the private key.
      * We use the one based on the Chinese Remainder Theorem.
      */
+#ifdef HAVE_OCF_AND_OPENSSL
+    BN_init(&r0);
+    cryptodev.rsa_mod_exp_crt(k, &t1, &r0);
+    bn2mp(&r0, (MP_INT *) &t1);
+#else
     mpz_init(t2);
 
     mpz_powm(t2, t1, &k->dP, &k->p);	/* m1 = c^dP mod p */
@@ -250,13 +270,16 @@
     mpz_mul(t2, t2, &k->q);	/* m = m2 + h q */
     mpz_add(t1, t1, t2);
 
+#endif
     /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */
     ch = mpz_to_n(t1, sig_len);
     memcpy(sig_val, ch.ptr, sig_len);
     pfree(ch.ptr);
+#ifndef HAVE_OCF_AND_OPENSSL
 
     mpz_clear(t1);
     mpz_clear(t2);
+#endif
 }
 
 const char *shared_secrets_file = SHARED_SECRETS_FILE;
@@ -357,6 +380,28 @@
     pfree(pk);
 }
 
+static bool
+match_any_id(const struct id *id, const struct id *any_id)
+{
+    struct id test_id = empty_id;
+    if (id->kind != any_id->kind)
+	return 0;
+    test_id.kind = any_id->kind;
+    switch (test_id.kind) {
+    case ID_IPV4_ADDR:
+	anyaddr(AF_INET, &test_id.ip_addr);
+	break;
+    case ID_IPV6_ADDR:
+	anyaddr(AF_INET6, &test_id.ip_addr);
+	break;
+    default:
+	return 0;
+    }
+    if (same_id(any_id, &test_id))
+	return 1;
+    return 0;
+}
+
 struct secret *secrets = NULL;
 
 /* find the struct secret associated with the combination of
@@ -368,8 +413,9 @@
 {
     enum {	/* bits */
 	match_default = 01,
-	match_him = 02,
-	match_me = 04
+	match_me_any = 02,
+	match_him = 04,
+	match_me = 010
     };
     unsigned char idstr1[IDTOA_BUF], idme[IDTOA_BUF]
 	, idhim[IDTOA_BUF], idhim2[IDTOA_BUF];
@@ -484,6 +530,8 @@
 
 		    if (same_id(my_id, &i->id))
 			match |= match_me;
+		    else if (match_any_id(my_id, &i->id))
+			match |= match_me_any;
 
 		    if (same_id(his_id, &i->id))
 			match |= match_him;
@@ -516,6 +564,7 @@
 	    case match_default:	/* default all */
 	    case match_me | match_default:	/* default peer */
 	    case match_me | match_him:	/* explicit */
+	    case match_me_any | match_him:	/* %defaultroute/%any */
 		if (match == best_match)
 		{
 		    /* two good matches are equally good:
@@ -1159,6 +1208,37 @@
 			id.kind = ID_IPV6_ADDR;
 			ugh = anyaddr(AF_INET6, &id.ip_addr);
 		    }
+		    else if (*tok == '$')
+		    {
+			char *val = getenv(tok + 1);
+			ugh = atoid(val ? val : tok, &id, FALSE);
+		    }
+		    else if (*tok == '`' && tok[1] && tok[1] != '`' &&
+					strchr(tok, '`')) {
+			FILE *fp;
+			char *val, *cp, out[128];
+
+			ugh = atoid(tok, &id, FALSE);
+
+			/* copy and remove executable quotes */
+			val = strdup(tok + 1);
+			cp = strchr(val, '`');
+			if (cp) {
+			    *cp = '\0';
+
+			    fp = popen(val, "r");
+			    if (fp) {
+				if (fgets(out, sizeof(out), fp)) {
+				    cp = strchr(out, '\n');
+				    if (cp)
+					*cp = '\0';
+				    ugh = atoid(out, &id, FALSE);
+				}
+				pclose(fp);
+			    }
+			    free(val);
+			}
+		    }
 		    else
 		    {
 			ugh = atoid(tok, &id, FALSE);
--- openswan-2.4.13.org/programs/pluto/log.c	2005-07-18 21:40:15.000000000 +0200
+++ openswan-2.4.13/programs/pluto/log.c	2008-06-27 13:38:04.000000000 +0200
@@ -865,6 +865,7 @@
 {
     size_t baselen = strlen(basedir) + 2;
 
+#ifndef SINGLE_CONF_DIR
     verify_path_space(&plutopaths.acerts, baselen + sizeof("acerts"), "acert path");
     snprintf(plutopaths.acerts.path, plutopaths.acerts.path_space, "%s/acerts", basedir);
 
@@ -885,8 +886,171 @@
 
     verify_path_space(&plutopaths.ocspcerts, baselen + sizeof("ocspcerts"), "ocspcerts path");
     snprintf(plutopaths.ocspcerts.path, plutopaths.certs.path_space, "%s/ocspcerts", basedir);
+#else
+    verify_path_space(&plutopaths.acerts, baselen + sizeof(""), "");
+    snprintf(plutopaths.acerts.path, plutopaths.acerts.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.cacerts, baselen + sizeof(""), "");
+    snprintf(plutopaths.cacerts.path, plutopaths.cacerts.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.crls, baselen + sizeof(""), "");
+    snprintf(plutopaths.crls.path, plutopaths.crls.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.private, baselen + sizeof(""), "");
+    snprintf(plutopaths.private.path, plutopaths.private.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.certs, baselen + sizeof(""), "");
+    snprintf(plutopaths.certs.path, plutopaths.certs.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.aacerts, baselen + sizeof(""), "");
+    snprintf(plutopaths.aacerts.path, plutopaths.certs.path_space, "%s", basedir);
+
+    verify_path_space(&plutopaths.ocspcerts, baselen + sizeof(""), "");
+    snprintf(plutopaths.ocspcerts.path, plutopaths.certs.path_space, "%s", basedir);
+#endif
+
+}
+
+#ifdef EXTERNAL_STATE_LOGGING
+/*
+ * we store runtime info for stats/status this way,
+ * you may be able to do something similar using these hooks
+ */
+
+struct log_conn_info {
+	struct connection *conn;
+	struct state *ignore;		/* ignore this state */
+
+	/* best completed state of connection */
+
+	enum {
+		tun_down=0,
+		tun_phase1,
+		tun_phase1up,
+		tun_phase15,
+		tun_phase2,
+		tun_up
+	} tunnel;
+
+	/* best uncompleted state info for each phase */
+
+	enum {
+		p1_none=0,
+		p1_init,
+		p1_encrypt,
+		p1_auth
+	} phase1;
+
+	enum {
+		p2_none=0,
+		p2_neg
+	} phase2;
+};
+
+static void
+connection_state(struct state *st, void *data)
+{
+	struct log_conn_info *lc = data;
+
+	if (!st || st == lc->ignore || st->st_connection != lc->conn)
+		return;
+
+	/* ignore undefined states (ie., just deleted) */
+	if (st->st_state == STATE_UNDEFINED)
+		return;
+
+	if (IS_PHASE1(st->st_state)) {
+		if (lc->tunnel < tun_phase1)
+			lc->tunnel = tun_phase1;
+		if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) {
+			if (lc->tunnel < tun_phase1up)
+				lc->tunnel = tun_phase1up;
+		} else {
+			if (lc->phase1 < p1_init)
+				lc->phase1 = p1_init;
+			if (IS_ISAKMP_ENCRYPTED(st->st_state) && lc->phase1 < p1_encrypt)
+				lc->phase1 = p1_encrypt;
+			if (IS_ISAKMP_AUTHENTICATED(st->st_state) && lc->phase1 < p1_auth)
+				lc->phase1 = p1_auth;
+		}
+	}
+
+
+	if (IS_PHASE15(st->st_state)) {
+		if (lc->tunnel < tun_phase15)
+			lc->tunnel = tun_phase15;
+	}
+
+	if (IS_QUICK(st->st_state)) {
+		if (lc->tunnel < tun_phase2)
+			lc->tunnel = tun_phase2;
+		if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) {
+		   	if (lc->tunnel < tun_up)
+				lc->tunnel = tun_up;
+		} else {
+		   	if (lc->phase2 < p2_neg)
+				lc->phase2 = p2_neg;
+		}
+	}
 }
 
+void
+_log_state(struct state *st, enum state_kind state)
+{
+	char buf[1024];
+	struct log_conn_info lc;
+	struct connection *conn;
+	char *tun = NULL, *p1 = NULL, *p2 = NULL;
+	enum state_kind save_state;
+
+	if (!st || !st->st_connection || !st->st_connection->name)
+		return;
+
+	conn = st->st_connection;
+
+	memset(&lc, 0, sizeof(lc));
+	lc.conn = conn;
+	save_state = st->st_state;
+	st->st_state = state;
+	for_each_state((void *)connection_state, &lc);
+	st->st_state = save_state;
+
+	switch (lc.tunnel) {
+	case tun_phase1:  tun = "phase1";  break;
+	case tun_phase1up:tun = "phase1up";break;
+	case tun_phase15: tun = "phase15"; break;
+	case tun_phase2:  tun = "phase2";  break;
+	case tun_up:      tun = "up";      break;
+	default: break;
+	}
+
+	switch (lc.phase1) {
+	case p1_init:     p1  = "init";    break;
+	case p1_encrypt:  p1  = "encrypt"; break;
+	case p1_auth:     p1  = "auth";    break;
+	default: break;
+	}
+
+	switch (lc.phase2) {
+	case p2_neg:      p2  = "neg";     break;
+	default: break;
+	}
+
+	snprintf(buf, sizeof(buf), "/bin/statsd "
+			"%s ipsec-tunnel-%s if_stats /proc/net/dev/%s \\; "
+			"%s ipsec-tunnel-%s tunnel %s \\; "
+			"%s ipsec-tunnel-%s phase1 %s \\; "
+			"%s ipsec-tunnel-%s phase2 %s",
+			conn->interface ? "push" : "drop", conn->name,
+		   			conn->interface ? conn->interface->ip_dev->id_vname : "",
+			tun ? "push" : "drop", conn->name, tun ? tun : "",
+			p1  ? "push" : "drop", conn->name, p1  ? p1  : "",
+			p2  ? "push" : "drop", conn->name, p2  ? p2  : "");
+	system(buf);
+}
+
+#endif
+
 /*
  * Local Variables:
  * c-basic-offset:4
--- openswan-2.4.13.org/programs/pluto/log.h	2004-10-21 21:13:37.000000000 +0200
+++ openswan-2.4.13/programs/pluto/log.h	2008-06-27 13:38:04.000000000 +0200
@@ -72,6 +72,19 @@
 			 , const char *file_str
 			 , unsigned long line_no) NEVER_RETURNS;
 
+/*
+ * for pushing state to other subsystems
+ */
+#ifdef EXTERNAL_STATE_LOGGING
+#define log_state(st) _log_state(st, st->st_state)
+#define log_state_chg(st,ns) if (ns != st->st_state) {_log_state(st, ns); } else
+extern void _log_state(struct state *st, enum state_kind state);
+#else
+#define log_state(st)
+#define log_state_chg(st, ns)
+#define _log_state(st, kind)
+#endif
+
 #ifdef DEBUG
 
   extern void extra_debugging(const struct connection *c);
--- openswan-2.4.13.org/programs/pluto/ocf_cryptodev.c	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/programs/pluto/ocf_cryptodev.c	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,419 @@
+/* 
+ * Interface to the Open Cryptographic Framework (OCF) 
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
+ * The code was developed with source from the file: hw_cryptodev.c
+ * in the openssl package, and the file: ipsec_doi.c from the 
+ * openswan package.
+ * 
+ * hw_cryptodev.c, openssl package:
+ * Copyright (c) 2002 Bob Beck <beck@openbsd.org>
+ * Copyright (c) 2002 Theo de Raadt
+ * Copyright (c) 2002 Markus Friedl
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ * ipsec_doi.c, openswan package:
+ * Copyright (C) 1997 Angelos D. Keromytis.
+ * Copyright (C) 1998-2002  D. Hugh Redelmeier.
+ * Copyright (C) 2003 Michael Richardson <mcr@xelerance.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+
+#include <sys/types.h>
+#include <crypto/cryptodev.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <linux/errno.h>
+
+#include <openswan.h>
+#include <openswan/ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "pgp.h"
+#include "x509.h"
+#include "certs.h"
+#include "keys.h"
+#include "log.h"
+#include "ocf_cryptodev.h"
+
+static u_int32_t cryptodev_asymfeat = 0;
+struct cryptodev_meth cryptodev;
+
+#undef DEBUG
+
+/*
+ * Convert a BIGNUM to the representation that /dev/crypto needs.
+ */
+static int
+bn2crparam(const BIGNUM *a, struct crparam *crp)
+{
+	int i, j, k;
+	ssize_t bytes, bits;
+	u_char *b;
+
+	crp->crp_p = NULL;
+	crp->crp_nbits = 0;
+
+	bits = BN_num_bits(a);
+	bytes = (bits + 7) / 8;
+
+	b = malloc(bytes);
+	if (b == NULL)
+		return (1);
+	memset(b, 0, bytes);
+
+	crp->crp_p = b;
+	crp->crp_nbits = bits;
+
+	for (i = 0, j = 0; i < a->top; i++) {
+		for (k = 0; k < BN_BITS2 / 8; k++) {
+			if ((j + k) >= bytes)
+				return (0);
+			b[j + k] = a->d[i] >> (k * 8);
+		}
+		j += BN_BITS2 / 8;
+	}
+	return (0);
+}
+
+/* Convert a /dev/crypto parameter to a BIGNUM */
+static int
+crparam2bn(struct crparam *crp, BIGNUM *a)
+{
+	u_int8_t *pd;
+	int i, bytes;
+
+	bytes = (crp->crp_nbits + 7) / 8;
+
+	if (bytes == 0)
+		return (-1);
+
+	if ((pd = (u_int8_t *) malloc(bytes)) == NULL)
+		return (-1);
+
+	for (i = 0; i < bytes; i++)
+		pd[i] = crp->crp_p[bytes - i - 1];
+
+	BN_bin2bn(pd, bytes, a);
+	free(pd);
+
+	return (0);
+}
+
+static void
+zapparams(struct crypt_kop *kop)
+{
+	int i;
+
+	for (i = 0; i < kop->crk_iparams + kop->crk_oparams; i++) {
+		if (kop->crk_param[i].crp_p)
+			free(kop->crk_param[i].crp_p);
+		kop->crk_param[i].crp_p = NULL;
+		kop->crk_param[i].crp_nbits = 0;
+	}
+}
+
+/* Convert from MP_INT to BIGNUM */
+static int
+mp2bn(const MP_INT *mp, BIGNUM *a)
+{
+	a->dmax = mp->_mp_alloc;
+	if (mp->_mp_size < 0) {
+		a->top = -(mp->_mp_size);
+		a->neg = 1;
+	} else {
+		a->top = mp->_mp_size;
+		a->neg = 0;
+	}
+	a->d = mp->_mp_d;
+	return 1;
+}
+
+/* Convert from BIGNUM to MP_INT */
+int
+bn2mp(const BIGNUM *a, MP_INT *mp)
+{
+	mp->_mp_alloc = a->dmax;
+	if (a->neg == 1) {
+		mp->_mp_size = -(a->top);
+	} else {
+		mp->_mp_size = a->top;
+	}
+	mp->_mp_d = a->d;
+	return 1;
+}
+
+/*
+ * Return a fd if /dev/crypto seems usable, 0 otherwise.
+ */
+static int
+open_dev_crypto(void)
+{
+	static int fd = -1;
+
+	if (fd == -1) {
+		if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1)
+			return (-1);
+		/* close on exec */
+		if (fcntl(fd, F_SETFD, 1) == -1) {
+			close(fd);
+			fd = -1;
+			return (-1);
+		}
+	}
+	return (fd);
+}
+
+/*
+ * Get a /dev/crypto file descriptor
+ */
+static int
+get_dev_crypto(void)
+{
+	int fd, retfd;
+
+	if ((fd = open_dev_crypto()) == -1)
+		return (-1);
+	if (ioctl(fd, CRIOGET, &retfd) == -1)
+		return (-1);
+
+	/* close on exec */
+	if (fcntl(retfd, F_SETFD, 1) == -1) {
+		close(retfd);
+		return (-1);
+	}
+	return (retfd);
+}
+
+/* Caching version for asym operations */
+static int
+get_asym_dev_crypto(void)
+{
+	static int fd = -1;
+
+	if (fd == -1)
+		fd = get_dev_crypto();
+	return fd;
+}
+
+/*
+ * Perform the ioctl 
+ */
+static int
+cryptodev_asym(struct crypt_kop *kop, int rlen, BIGNUM *r, int slen, BIGNUM *s)
+{
+	int fd, ret = -1;
+
+	if ((fd = get_asym_dev_crypto()) < 0)
+		return (ret);
+
+	if (r) {
+		kop->crk_param[kop->crk_iparams].crp_p = calloc(rlen, sizeof(char));
+		kop->crk_param[kop->crk_iparams].crp_nbits = rlen * 8;
+		kop->crk_oparams++;
+	}
+	if (s) {
+		kop->crk_param[kop->crk_iparams+1].crp_p = calloc(slen, sizeof(char));
+		kop->crk_param[kop->crk_iparams+1].crp_nbits = slen * 8;
+		kop->crk_oparams++;
+	}
+
+	if (ioctl(fd, CIOCKEY, kop) == 0) {
+		if (r) {
+			crparam2bn(&kop->crk_param[kop->crk_iparams], r);
+		} if (s)
+			crparam2bn(&kop->crk_param[kop->crk_iparams+1], s);
+		ret = 0;
+	}
+
+	return (ret);
+}
+
+/*
+ * Set up the modular exponentiation operation.
+ */
+static int
+cryptodev_mod_exp_setup(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+    const BIGNUM *m, BN_CTX *ctx)
+{
+	struct crypt_kop kop;
+	int ret = 1;
+
+	/* Currently, we know we can do mod exp iff we can do any
+	 * asymmetric operations at all.
+	 */
+	if (cryptodev_asymfeat == 0) {
+		ret = BN_mod_exp(r, a, p, m, ctx);
+		return (ret);
+	}
+
+	memset(&kop, 0, sizeof kop);
+	kop.crk_op = CRK_MOD_EXP;
+
+	/* inputs: a^p % m */
+	if (bn2crparam(a, &kop.crk_param[0]))
+		goto err;
+	if (bn2crparam(p, &kop.crk_param[1]))
+		goto err;
+	if (bn2crparam(m, &kop.crk_param[2]))
+		goto err;
+	kop.crk_iparams = 3;
+
+	if (cryptodev_asym(&kop, BN_num_bytes(m), r, 0, NULL) == -1) {
+
+		/* TODO need to do it in software */
+	}
+
+err:
+	zapparams(&kop);
+	return (ret);
+}
+
+/*
+ * Do the modular exponentiatin without Chinese Remainder Theorem in hardware
+ */
+static int cryptodev_rsa_mod_exp_nocrt(const struct RSA_private_key *k, mpz_t *t1, BIGNUM *r0)
+{
+	BIGNUM I, d, n;
+	BN_CTX *ctx; 
+	int r;
+
+	ctx = BN_CTX_new();
+	mp2bn((MP_INT *) t1, &I);
+	mp2bn(&k->d, &d);
+	mp2bn(&k->pub.n, &n);
+	r = cryptodev_mod_exp_setup(r0, &I, &d, &n, ctx);
+	BN_CTX_free(ctx);
+
+	return (r);
+}
+
+/*
+ * Do the modular exponentiation with Chinese Remainder Theorem in sofware
+ */
+static int cryptodev_rsa_mod_exp_crt_sw(const struct RSA_private_key *k, mpz_t *t1, BIGNUM *r0)
+{
+	mpz_t t2;
+
+	mpz_init(t2);
+
+	mpz_powm(t2, *t1, &k->dP, &k->p);    /* m1 = c^dP mod p */
+
+	mpz_powm(*t1, *t1, &k->dQ, &k->q);    /* m2 = c^dQ mod Q */
+
+	mpz_sub(t2, t2, *t1);	    /* h = qInv (m1 - m2) mod p */
+	mpz_mod(t2, t2, &k->p);
+	mpz_mul(t2, t2, &k->qInv);
+	mpz_mod(t2, t2, &k->p);
+
+	mpz_mul(t2, t2, &k->q);     /* m = m2 + h q */
+	mpz_add(*t1, *t1, t2);
+	mp2bn((MP_INT *) t1, r0);
+	mpz_clear(t2);
+	return 1;
+}
+
+/*
+ * Compute mod exp in software
+ */
+static int
+cryptodev_mod_exp_sw(BIGNUM *r0, MP_INT *mp_g, MP_INT *secret, MP_INT *modulus)
+{
+	mpz_t shared;
+	
+	mpz_init(shared);
+	mpz_powm(shared, mp_g, secret, modulus);
+	mp2bn((MP_INT *) shared, r0);
+	return 1;
+}
+
+/*
+ * Compute mod exp in hardware
+ */
+static int
+cryptodev_mod_exp(BIGNUM *r0, MP_INT *mp_g, MP_INT *secret, MP_INT *modulus)
+{
+
+	BIGNUM a, p, m;
+	int r;
+	BN_CTX *ctx;
+	
+	ctx = BN_CTX_new();
+	mp2bn(mp_g, &a);
+	mp2bn(secret, &p);
+	mp2bn(modulus, &m);
+	r = cryptodev_mod_exp_setup(r0, &a, &p, &m, ctx);
+	BN_CTX_free(ctx);
+
+	return (r);
+}
+
+/*
+ * Find out what we can support and use it.
+ */
+void load_cryptodev(void)
+{
+	int fd;
+
+	cryptodev.rsa_mod_exp_crt = cryptodev_rsa_mod_exp_crt_sw;
+	cryptodev.mod_exp = cryptodev_mod_exp_sw;
+
+	if((fd = get_dev_crypto()) < 0) {
+		return;
+	}
+
+	/* find out what asymmetric crypto algorithms we support */
+	if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) {
+		close(fd);
+		return;
+	}
+	close(fd);
+
+	if (cryptodev_asymfeat & CRF_MOD_EXP) {
+		/* Use modular exponentiation */
+		cryptodev.mod_exp = cryptodev_mod_exp;
+		cryptodev.rsa_mod_exp_crt = cryptodev_rsa_mod_exp_nocrt;
+		openswan_log("Performing modular exponentiation acceleration in hardware");
+	}
+}
--- openswan-2.4.13.org/programs/pluto/ocf_cryptodev.h	1970-01-01 01:00:00.000000000 +0100
+++ openswan-2.4.13/programs/pluto/ocf_cryptodev.h	2008-06-27 13:38:04.000000000 +0200
@@ -0,0 +1,67 @@
+/* 
+ * Interface to the Open Cryptographic Framework (OCF) 
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
+ * The code was developed with source from the openssl package,
+ * file: hw_cryptodev.c
+ *
+ * Copyright (c) 2002 Bob Beck <beck@openbsd.org>
+ * Copyright (c) 2002 Theo de Raadt
+ * Copyright (c) 2002 Markus Friedl
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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.
+ *
+ */
+
+/* yuck */
+#define NO_ASN1_TYPEDEFS 1
+#include <openssl/bn.h>
+/* yuck yuck !*/
+#undef NO_ASN1_TYPEDEFS
+#undef ASN1_INTEGER
+#undef ASN1_ENUMERATED
+#undef ASN1_BIT_STRING
+#undef ASN1_OCTET_STRING
+#undef ASN1_PRINTABLESTRING
+#undef ASN1_T61STRING
+#undef ASN1_IA5STRING
+#undef ASN1_UTCTIME
+#undef ASN1_GENERALIZEDTIME
+#undef ASN1_TIME
+#undef ASN1_GENERALSTRING
+#undef ASN1_UNIVERSALSTRING
+#undef ASN1_BMPSTRING
+#undef ASN1_VISIBLESTRING
+#undef ASN1_UTF8STRING
+#undef ASN1_BOOLEAN
+#undef ASN1_NULL
+
+struct cryptodev_meth {
+	int (*rsa_mod_exp_crt)(const struct RSA_private_key *k, mpz_t *t1, BIGNUM *r0);
+	int (*mod_exp)(BIGNUM *r0, MP_INT *mp_g, MP_INT *secret, MP_INT *modulus);
+};
+
+extern struct cryptodev_meth cryptodev;
+
+extern void load_cryptodev(void);
+extern int bn2mp(const BIGNUM *a, MP_INT *mp);
--- openswan-2.4.13.org/programs/pluto/pluto_constants.c	2006-11-07 16:55:52.000000000 +0100
+++ openswan-2.4.13/programs/pluto/pluto_constants.c	2008-06-27 13:38:04.000000000 +0200
@@ -65,10 +65,11 @@
   "action:clear",
   "action:hold",
   "action:restart",
+  "action:restart_by_peer",
 };
 
 enum_names dpd_action_names =
-    { EVENT_NULL, DPD_ACTION_RESTART, dpd_action_name, NULL };
+    { EVENT_NULL, DPD_ACTION_RESTART_BY_PEER, dpd_action_name, NULL };
 
 /* Timer events */
 static const char *const timer_event_name[] = {
--- openswan-2.4.13.org/programs/pluto/pluto_crypt.c	2008-02-15 22:06:09.000000000 +0100
+++ openswan-2.4.13/programs/pluto/pluto_crypt.c	2008-06-27 14:00:16.000000000 +0200
@@ -12,6 +12,10 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * This code was developed with the support of IXIA communications.
  *
  * RCSID $Id: pluto_crypt.c,v 1.19.2.4 2008-02-15 21:06:09 paul Exp $
@@ -45,6 +49,15 @@
 #include "rnd.h"
 #include "pluto_crypt.h"
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "id.h"
+#include "pgp.h"
+#include "x509.h"
+#include "certs.h"
+#include "keys.h"
+#include "ocf_cryptodev.h"
+#endif
+
 struct pluto_crypto_worker {
     int   pcw_helpernum;
     pid_t pcw_pid;
@@ -666,6 +679,9 @@
 	
 	pluto_init_log();
 	init_rnd_pool();
+#ifdef HAVE_OCF_AND_OPENSSL
+	load_cryptodev();
+#endif
 	free_preshared_secrets();
 	openswan_passert_fail = helper_passert_fail;
 	debug_prefix='!';
--- openswan-2.4.13.org/programs/pluto/plutoalg.c	2007-07-06 02:02:15.000000000 +0200
+++ openswan-2.4.13/programs/pluto/plutoalg.c	2008-06-27 13:38:04.000000000 +0200
@@ -536,9 +536,11 @@
 						((esp_info->esp_ealg_keylen==0) || (key_len==0) ||
 						 (esp_info->esp_ealg_keylen==key_len)) &&
 						(esp_info->esp_aalg_id == aalg)) {
+#ifndef USE_1DES
 					if (ealg_insecure) 
 						loglog(RC_LOG_SERIOUS, "You should NOT use insecure ESP algorithms [%s (%d)]!"
 								, enum_name(&esp_transformid_names, ealg), key_len);
+#endif
 					return TRUE;
 				}
 			}
--- openswan-2.4.13.org/programs/pluto/plutomain.c	2007-04-06 19:10:37.000000000 +0200
+++ openswan-2.4.13/programs/pluto/plutomain.c	2008-06-27 13:38:04.000000000 +0200
@@ -13,6 +13,10 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * RCSID $Id: plutomain.c,v 1.102.2.7 2007-04-06 17:10:37 paul Exp $
  */
 
@@ -79,6 +83,10 @@
 #include "nat_traversal.h"
 #endif
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "ocf_cryptodev.h"
+#endif
+
 #ifndef IPSECDIR
 #define IPSECDIR "/etc/ipsec.d"
 #endif
@@ -760,6 +768,9 @@
     init_connections();
     init_crypto();
     init_crypto_helpers(nhelpers);
+#ifdef HAVE_OCF_AND_OPENSSL
+    load_cryptodev();
+#endif
     init_demux();
     init_kernel();
     init_adns();
--- openswan-2.4.13.org/programs/pluto/state.c	2006-11-24 05:21:42.000000000 +0100
+++ openswan-2.4.13/programs/pluto/state.c	2008-06-27 13:38:04.000000000 +0200
@@ -259,6 +259,8 @@
      */
     if (st->st_event == NULL)
 	event_schedule(EVENT_SO_DISCARD, 0, st);
+
+	log_state(st);
 }
 
 /* unlink a state object from the hash table, but don't free it
@@ -317,6 +319,7 @@
 
     DBG(DBG_CONTROL, DBG_log("deleting state #%lu", st->st_serialno));
 
+	log_state_chg(st, STATE_UNDEFINED);
     set_cur_state(st);
 
     /* If DPD is enabled on this state object, clear any pending events */
--- openswan-2.4.13.org/programs/pluto/timer.c	2005-08-12 19:03:02.000000000 +0200
+++ openswan-2.4.13/programs/pluto/timer.c	2008-06-27 13:38:04.000000000 +0200
@@ -294,8 +294,18 @@
 			, "%s: retransmission; will wait %lus for response"
 			, enum_name(&state_names, st->st_state)
 			, (unsigned long)delay);
+#ifdef DYNAMICDNS
+			if (st->st_retransmit == 6
+			    && (st->st_state == STATE_MAIN_I1 || st->st_state == STATE_AGGR_I1)
+			    && st->st_connection->dnshostname != NULL)
+			    restart_connections_by_peer(st->st_connection);
+			else {
+#endif /* DYNAMICDNS */
 		    send_packet(st, "EVENT_RETRANSMIT", TRUE);
 		    event_schedule(EVENT_RETRANSMIT, delay, st);
+#ifdef DYNAMICDNS
+			}
+#endif /* DYNAMICDNS */
 		}
 		else
 		{
@@ -357,6 +367,13 @@
 			    /* no whack: just log to syslog */
 			    openswan_log("%s", story);
 			}
+#ifdef DYNAMICDNS
+			if (st->st_connection->dnshostname != NULL)
+			{
+			    restart_connections_by_peer(st->st_connection);
+			    break;
+			} else 
+#endif /* DYNAMICDNS */
 			ipsecdoi_replace(st, try);
 		    }
 		    delete_state(st);
--- openswan-2.4.13.org/programs/pluto/whack.c	2006-10-27 22:05:09.000000000 +0200
+++ openswan-2.4.13/programs/pluto/whack.c	2008-06-27 13:38:04.000000000 +0200
@@ -139,7 +139,7 @@
 	    " [--aggrmode]"
             " [--dpddelay <seconds> --dpdtimeout <seconds>]"
             " \\\n   "
-            " [--dpdaction (clear|hold|restart)]"
+            " [--dpdaction (clear|hold|restart|restart_by_peer)]"
 	    " [--forceencaps]"
 
 
@@ -700,6 +700,11 @@
     { 0,0,0,0 }
 };
 
+#ifdef DYNAMICDNS
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz"
+				"ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+#endif /* DYNAMICDNS */
+
 struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };
 
 /* helper variables and function to encode strings from whack message */
@@ -927,6 +932,9 @@
     clear_end(&msg.right);	/* left set from this after --to */
 
     msg.name = NULL;
+#ifdef DYNAMICDNS
+    msg.dnshostname = NULL;
+#endif /* DYNAMICDNS */
     msg.keyid = NULL;
     msg.keyval.ptr = NULL;
     msg.esp = NULL;
@@ -1254,6 +1262,24 @@
 	    }
 	    else
 	    {
+#ifdef DYNAMICDNS
+                if (msg.left.id != NULL) {
+		    int strlength = 0;
+		    int n = 0;
+		    const char *cp;
+		    int dnshostname = 0;
+
+		    strlength = strlen(optarg);
+		    for (cp = optarg, n = strlength; n > 0; cp++, n--) {
+			    if (strchr(namechars, *cp) != NULL) {
+				    dnshostname = 1;
+				    break;
+			    }
+		    }
+		    if (dnshostname)
+		    	msg.dnshostname = optarg;
+		}
+#endif /* DYNAMICDNS */
 		diagq(ttoaddr(optarg, 0, msg.addr_family
 		    , &msg.right.host_addr), optarg);
 	    }
@@ -1511,6 +1537,9 @@
             if( strcmp(optarg, "restart") == 0) {
                     msg.dpd_action = DPD_ACTION_RESTART;
             }
+            if( strcmp(optarg, "restart_by_peer") == 0) {
+                    msg.dpd_action = DPD_ACTION_RESTART_BY_PEER;
+            }
             continue;
 
 	case CD_IKE:	/* --ike <ike_alg1,ike_alg2,...> */
@@ -1768,8 +1797,9 @@
             diag("dpddelay specified, but dpdtimeout is zero, both should be specified");
     if(!msg.dpd_delay && msg.dpd_timeout)
             diag("dpdtimeout specified, but dpddelay is zero, both should be specified");
-    if(msg.dpd_action != DPD_ACTION_CLEAR && msg.dpd_action != DPD_ACTION_HOLD && msg.dpd_action != DPD_ACTION_RESTART) {
-            diag("dpdaction can only be \"clear\", \"hold\" or \"restart\", defaulting to \"hold\"");
+    if(msg.dpd_action != DPD_ACTION_CLEAR && msg.dpd_action != DPD_ACTION_HOLD 
+	  && msg.dpd_action != DPD_ACTION_RESTART && msg.dpd_action != DPD_ACTION_RESTART_BY_PEER) {
+            diag("dpdaction can only be \"clear\", \"hold\", \"restart\" or \"restart_by_peer\", defaulting to \"hold\"");
             msg.dpd_action = DPD_ACTION_HOLD;
     }
 
@@ -1806,6 +1836,9 @@
     || !pack_str(&msg.myid)		/* string 13 */
     || !pack_str(&msg.ike)		/* string 14 */
     || !pack_str(&msg.esp)		/* string 15 */
+#ifdef DYNAMICDNS
+    || !pack_str(&msg.dnshostname)	/* string 16 */
+#endif
     || str_roof - next_str < (ptrdiff_t)msg.keyval.len)    /* chunk (sort of string 5) */
 	diag("too many bytes of strings to fit in message to pluto");
 
--- openswan-2.4.13.org/programs/pluto/whack.h	2004-12-16 02:22:44.000000000 +0100
+++ openswan-2.4.13/programs/pluto/whack.h	2008-06-27 13:38:04.000000000 +0200
@@ -86,6 +86,9 @@
     /* name is used in connection and initiate */
     size_t name_len;	/* string 1 */
     char *name;
+#ifdef DYNAMICDNS
+    char *dnshostname;
+#endif /* DYNAMICDNS */
 
     /* for WHACK_OPTIONS: */
 
--- openswan-2.4.13.org/programs/pluto/whacklib.c	2004-12-16 02:21:59.000000000 +0100
+++ openswan-2.4.13/programs/pluto/whacklib.c	2008-06-27 13:38:04.000000000 +0200
@@ -128,7 +128,12 @@
 	|| !pack_str(wp, &wp->msg->myid)        /* string 15 */
     	|| !pack_str(wp, &wp->msg->ike)         /* string 16 */
     	|| !pack_str(wp, &wp->msg->esp)         /* string 17 */
+#ifdef DYNAMICDNS
+    	|| !pack_str(wp, &wp->msg->dnshostname) /* string 18 */
+	|| wp->str_roof - wp->str_next < (ptrdiff_t)wp->msg->keyval.len)    /* chunk (sort of string 17) */
+#else
 	|| wp->str_roof - wp->str_next < (ptrdiff_t)wp->msg->keyval.len)    /* chunk (sort of string 16) */
+#endif
     {
 	ugh = "too many bytes of strings to fit in message to pluto";
 	return ugh;
@@ -181,6 +186,9 @@
 	|| !unpack_str(wp, &wp->msg->myid)        /* string 15 */
     	|| !unpack_str(wp, &wp->msg->ike)         /* string 16 */
     	|| !unpack_str(wp, &wp->msg->esp)         /* string 17 */
+#ifdef DYNAMICDNS
+    	|| !unpack_str(wp, &wp->msg->dnshostname)         /* string 18 */
+#endif
 
        || wp->str_roof - wp->str_next != (ptrdiff_t)wp->msg->keyval.len)	/* check chunk */
     {
--- openswan-2.4.13.org/programs/pluto/x509.c	2006-04-27 17:48:13.000000000 +0200
+++ openswan-2.4.13/programs/pluto/x509.c	2008-06-27 13:38:04.000000000 +0200
@@ -14,6 +14,10 @@
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
  *
+ * Modifications to use OCF interface written by
+ * Daniel Djamaludin <ddjamaludin@cyberguard.com>
+ * Copyright (C) 2004-2005 Intel Corporation.  All Rights Reserved.
+ *
  * RCSID $Id: x509.c,v 1.23.18.4 2006-04-27 15:48:13 paul Exp $
  */
 
@@ -56,6 +60,10 @@
 #include "x509more.h"
 #include "paths.h"
 
+#ifdef HAVE_OCF_AND_OPENSSL
+#include "ocf_cryptodev.h"
+#endif
+
 /* chained lists of X.509 host/user and ca certificates and crls */
 
 static x509cert_t *x509certs   = NULL;
@@ -1672,6 +1680,10 @@
 	    mpz_t s;
 	    mpz_t e;
 	    mpz_t n;
+#ifdef HAVE_OCF_AND_OPENSSL
+	    BIGNUM r0;
+	    BN_init(&r0);
+#endif
 
 	    n_to_mpz(s, sig.ptr, sig.len);
 	    n_to_mpz(e, issuer_cert->publicExponent.ptr,
@@ -1680,7 +1692,12 @@
 			issuer_cert->modulus.len);
 
 	    /* decrypt the signature s = s^e mod n */
+#ifdef HAVE_OCF_AND_OPENSSL
+	    cryptodev.mod_exp(&r0, s, e, n);
+	    bn2mp(&r0, (MP_INT *) s);
+#else
 	    mpz_powm(s, s, e, n);
+#endif
 	    /* convert back to bytes */
 	    decrypted = mpz_to_n(s, issuer_cert->modulus.len);
 	    DBG(DBG_PARSING,
@@ -1695,7 +1712,9 @@
 
 	    /* free memory */
 	    pfree(decrypted.ptr);
+#ifndef HAVE_OCF_AND_OPENSSL
 	    mpz_clear(s);
+#endif
 	    mpz_clear(e);
 	    mpz_clear(n);
 	    return TRUE;
--- openswan-2.4.13.org/programs/pluto/xauth.c	2007-09-06 01:02:19.000000000 +0200
+++ openswan-2.4.13/programs/pluto/xauth.c	2008-06-27 13:38:04.000000000 +0200
@@ -472,6 +472,7 @@
 	/* set up reply */
 	init_pbs(&reply, buf, sizeof(buf), "ModecfgR1");
 
+	log_state_chg(st, STATE_MODE_CFG_R1);
 	st->st_state = STATE_MODE_CFG_R1;
 	/* HDR out */
 	{
@@ -554,6 +555,7 @@
 
     /* this is the beginning of a new exchange */
     st->st_msgid_phase15 = generate_msgid(st);
+    log_state_chg(st, STATE_XAUTH_R0);
     st->st_state = STATE_XAUTH_R0;
 
     /* HDR out */
@@ -644,6 +646,7 @@
 
     /* this is the beginning of a new exchange */
     st->st_msgid_phase15 = generate_msgid(st);
+    log_state_chg(st, STATE_MODE_CFG_I1);
     st->st_state = STATE_MODE_CFG_I1;
 
     /* HDR out */
@@ -807,6 +810,7 @@
 
     send_packet(st, "XAUTH: status", TRUE);
 
+    log_state_chg(st, STATE_XAUTH_R1);
     st->st_state = STATE_XAUTH_R1;
 
     return STF_OK;
@@ -1059,6 +1063,7 @@
          *  and reset state to XAUTH_R0 */
         openswan_log("XAUTH: User %s: Authentication Failed: Incorrect Username or Password", arg->name.ptr);
         xauth_send_status(st,0);	
+        log_state_chg(st, STATE_XAUTH_R0);
         st->st_state = STATE_XAUTH_R0;        
     }   
     
@@ -2247,6 +2252,7 @@
     {
 	/* oops, something seriously wrong */
 	openswan_log("did not get status attribute in xauth_inI1, looking for new challenge.");
+        log_state_chg(st, STATE_XAUTH_I0);
 	st->st_state = STATE_XAUTH_I0;
 	return xauth_inI0(md);
     }
--- openswan-2.4.13.org/programs/setup/Makefile	2004-12-18 19:13:43.000000000 +0100
+++ openswan-2.4.13/programs/setup/Makefile	2008-06-27 13:38:04.000000000 +0200
@@ -19,7 +19,7 @@
 # this dance is because setup has to get installed as /etc/rc.d/init.d/ipsec
 # not as /etc/rc.d/init.d/setup.
 PROGRAMDIR=$(RCDIR)
-PROGRAM=
+PROGRAM=setup
 EXTRA8MAN=setup.8
 
 include ${srcdir}../Makefile.program
