diff -uNr -x CVS linux-2.5.43/include/linux/ip.h linux25.43-ipsec/include/linux/ip.h
--- linux-2.5.43/include/linux/ip.h	2002-10-16 12:27:49.000000000 +0900
+++ linux25.43-ipsec/include/linux/ip.h	2002-10-16 15:27:44.000000000 +0900
@@ -113,6 +113,23 @@
   unsigned char __data[0];
 };
 
+#ifdef CONFIG_IP_IPSEC
+struct ip_auth_hdr {
+	__u8  nexthdr;
+	__u8  hdrlen;      /* This one is measured in 32 bit units! */
+	__u16 reserved;
+	__u32 spi;
+	__u32 seq_no;      /* Sequence number */
+	__u8  auth_data[4];     /* Length variable but >=4. Mind the 64 bit alignment! */
+};
+
+struct ip_esp_hdr {
+	__u32 spi;
+	__u32 seq_no;      /* Sequence number */
+	__u8  enc_data[8];      /* Length variable but >=8. Mind the 64 bit alignment! */
+};
+#endif /* CONFIG_IP_IPSEC */
+
 #define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
 
 struct inet_opt {
diff -uNr -x CVS linux-2.5.43/include/linux/ipsec.h linux25.43-ipsec/include/linux/ipsec.h
--- linux-2.5.43/include/linux/ipsec.h	2002-10-16 12:27:16.000000000 +0900
+++ linux25.43-ipsec/include/linux/ipsec.h	2002-10-16 15:27:44.000000000 +0900
@@ -16,7 +16,12 @@
 #include <linux/config.h>
 #include <linux/socket.h>
 #include <net/sock.h>
+#include <net/route.h>
 #include <linux/skbuff.h>
+#ifdef CONFIG_IP_IPSEC
+#include <net/sadb.h>
+#include <net/spd.h>
+#endif
 
 /* Values for the set/getsockopt calls */
 
@@ -65,5 +70,57 @@
 }
 #endif /* CONFIG */
 
+/* return value for ipsec[46]_output_check() -mk */
+#define IPSEC_ACTION_BYPASS		0x0
+#define IPSEC_ACTION_AUTH		0x1
+#define IPSEC_ACTION_ESP		0x2
+#define IPSEC_ACTION_COMP		0x4
+#define IPSEC_ACTION_DROP		0x8
+
+#ifdef CONFIG_SYSCTL
+extern  int sysctl_ipsec_replay_window;
+#ifdef CONFIG_IPSEC_DEBUG
+extern	int sysctl_ipsec_debug_ipv4;
+extern  int sysctl_ipsec_debug_ipv6;
+extern  int sysctl_ipsec_debug_pfkey;
+extern  int sysctl_ipsec_debug_sadb;
+extern  int sysctl_ipsec_debug_spd;
+#endif /* CONFIG_IPSEC_DEBUG */
+#endif /* CONFIG_SYSCTL */
+
+#ifdef CONFIG_IP_IPSEC
+int ipsec4_out_ah_calc(struct iphdr *iph, struct ip_auth_hdr *authhdr, struct ipsec_sp *policy);
+
+int ipsec4_out_get_ahsize(struct ipsec_sp *policy);
+int ipsec4_out_get_espsize(struct ipsec_sp *policy);
+static inline int ipsec4_out_get_hdrsize(struct ipsec_sp *policy)
+{
+	return ipsec4_out_get_ahsize(policy) + ipsec4_out_get_espsize(policy);
+}
+
+void ipsec4_out_enc(const void *data, unsigned length, u8 proto,
+		void **newdata, unsigned *newlength, struct ipsec_sp *policy);
+void ipsec4_out_finish(struct ipsec_sp *policy_ptr);
+
+int ipsec4_input_check(struct sk_buff **skb); 
+int ipsec4_output_check(struct sock *sk, struct rtable *rt, struct ipsec_sp **policy_ptr);
+
+#ifdef CONFIG_IPSEC_DEBUG
+# ifdef CONFIG_SYSCTL
+#  define IPSEC4_DEBUG(fmt, args...) 					\
+do {									\
+	if (sysctl_ipsec_debug_ipv4) {					\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args);	\
+	}								\
+} while(0)
+# else
+#  define IPSEC4_DEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# endif /* CONFIG_SYSCTL */
+#else
+#  define IPSEC4_DEBUG(fmt, args...)
+#endif
+#endif /* CONFIG_IP_IPSEC */
+
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_IPSEC_H */
diff -uNr -x CVS linux-2.5.43/include/linux/ipsec6.h linux25.43-ipsec/include/linux/ipsec6.h
--- linux-2.5.43/include/linux/ipsec6.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/include/linux/ipsec6.h	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,153 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *      Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI Project
+ *      Mitsuru KANDA <mk@linux-ipv6.org> / USAGI Project
+ *      YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> / USAGI Project
+ */
+#ifndef _LINUX_IPSEC6_H
+#define _LINUX_IPSEC6_H
+
+#include <linux/skbuff.h>
+#include <net/ipv6.h>
+#include <net/spd.h>
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_IPSEC_DEBUG
+# ifdef CONFIG_SYSCTL
+#  define IPSEC6_DEBUG(fmt, args...) 					\
+do {									\
+	if (sysctl_ipsec_debug_ipv6) {					\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args);	\
+	}								\
+} while(0)
+# else
+#  define IPSEC6_DEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# endif /* CONFIG_SYSCTL */
+#else
+#  define IPSEC6_DEBUG(fmt, args...)
+#endif
+
+/* Set all mutable/unpredictable fields to zero. */
+static int inline zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
+{
+	u8 *opt = (u8*)opthdr;
+	int len = ipv6_optlen(opthdr);
+	int off = 0;
+	int optlen;
+
+	off += 2;
+	len -= 2;
+
+	while(len > 0) {
+		switch(opt[off]) {
+		case IPV6_TLV_PAD0:
+			optlen = 1;
+			break;
+		default:
+			if (len < 2)
+				goto bad;
+			optlen = opt[off+1]+2;
+			if (len < optlen)
+				goto bad;
+			if (opt[off] & 0x20)	/* mutable check */
+				memset(&opt[off+2], 0, opt[off+1]);
+			break;
+		}
+		off += optlen;
+		len -= optlen;
+	}
+	if (len == 0)
+		return 1;
+bad:
+	return 0;
+}
+
+/* Set all mutable/predictable fields to the destination state, and all
+   mutable/unpredictable fields to zero. */
+static void inline zero_out_for_ah(struct inet6_skb_parm *parm, char* packet) 
+{
+	struct ipv6hdr *hdr = (struct ipv6hdr*)packet;
+
+	/* Main header */
+	hdr->priority=0;
+	hdr->flow_lbl[0]=0;
+	hdr->flow_lbl[1]=0;
+	hdr->flow_lbl[2]=0;
+	hdr->hop_limit=0;
+	/* Mutable/unpredictable Option headers */
+	/* AH header */
+
+	if (parm->auth) {
+		struct ipv6_auth_hdr* authhdr =
+			(struct ipv6_auth_hdr*)(packet + parm->auth);
+		int len = ((authhdr->hdrlen - 1)  << 2);
+		memset(authhdr->auth_data,0,len);
+	}
+
+	if (parm->hop) {
+		struct ipv6_hopopt_hdr* hopopthdr =
+			(struct ipv6_hopopt_hdr*)(packet + parm->hop);
+		if (!zero_out_mutable_opts(hopopthdr))
+			printk(KERN_WARNING
+				"overrun when muting hopopts\n");
+	}
+
+	if (parm->dst0) {
+		struct ipv6_destopt_hdr* destopthdr0 =
+			(struct ipv6_destopt_hdr*)(packet + parm->dst0);
+		if (!zero_out_mutable_opts(destopthdr0))
+			printk(KERN_WARNING
+				"overrun when muting destopt\n");
+	}
+
+	if (parm->dst1) {
+		struct ipv6_destopt_hdr* destopthdr1 =
+			(struct ipv6_destopt_hdr*)(packet + parm->dst1);
+		if (!zero_out_mutable_opts(destopthdr1))
+			printk(KERN_WARNING
+				"overrun when muting destopt\n");
+	}
+}
+
+int ipsec6_out_get_ahsize(struct ipsec_sp *policy);
+int ipsec6_out_get_espsize(struct ipsec_sp *policy);
+static inline int ipsec6_out_get_hdrsize(struct ipsec_sp *policy)
+{
+	return ipsec6_out_get_ahsize(policy) + ipsec6_out_get_espsize(policy);
+}
+
+struct ipv6_txoptions *ipsec6_out_get_newopt(struct ipv6_txoptions *opt, struct ipsec_sp *policy);
+int ipsec6_out_ah_calc(const void *data, unsigned length, 
+		inet_getfrag_t getfrag, struct sk_buff *skb, 
+		struct ipv6_auth_hdr *authhdr, struct ipsec_sp *policy);
+void ipsec6_out_enc(const void *data, unsigned length, u8 proto, struct ipv6_txoptions *opt,
+		void **newdata, unsigned *newlength, struct ipsec_sp *policy);
+void ipsec6_out_finish(struct ipv6_txoptions *opt, struct ipsec_sp *policy_ptr);
+int ipsec6_input_check_ah(struct sk_buff **skb, struct ipv6_auth_hdr* authhdr);
+int ipsec6_input_check_esp(struct sk_buff **skb, struct ipv6_esp_hdr *esphdr, u8 *nexthdr);
+
+int ipsec6_input_check(struct sk_buff **skb, u8 *nexthdr);
+int ipsec6_output_check(struct sock *sk, struct flowi *fl, const u8* data, struct ipsec_sp **policy_ptr);
+int ipsec6_ndisc_check(struct in6_addr *saddr, struct in6_addr *daddr, struct ipsec_sp **policy_ptr);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_IPSEC6_H */
diff -uNr -x CVS linux-2.5.43/include/linux/ipv6.h linux25.43-ipsec/include/linux/ipv6.h
--- linux-2.5.43/include/linux/ipv6.h	2002-10-16 12:28:30.000000000 +0900
+++ linux25.43-ipsec/include/linux/ipv6.h	2002-10-16 15:27:44.000000000 +0900
@@ -73,6 +73,22 @@
 #define rt0_type		rt_hdr.type;
 };
 
+/* IPsec6 header */
+struct ipv6_auth_hdr {
+	__u8  nexthdr;
+	__u8  hdrlen;           /* This one is measured in 32 bit units! */
+	__u16 reserved;
+	__u32 spi;
+	__u32 seq_no;           /* Sequence number */
+	__u8  auth_data[4];     /* Length variable but >=4. Mind the 64 bit alignment! */
+};
+
+struct ipv6_esp_hdr {
+	__u32 spi;
+	__u32 seq_no;           /* Sequence number */
+	__u8  enc_data[8];      /* Length variable but >=8. Mind the 64 bit alignment! */
+};
+
 /*
  *	IPv6 fixed header
  *
@@ -120,6 +136,7 @@
 	__u16			dst0;
 	__u16			srcrt;
 	__u16			dst1;
+	__u32			espspi; /* not offset */
 };
 
 struct ipv6_pinfo {
diff -uNr -x CVS linux-2.5.43/include/linux/pfkey.h linux25.43-ipsec/include/linux/pfkey.h
--- linux-2.5.43/include/linux/pfkey.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/include/linux/pfkey.h	2002-10-16 15:27:46.000000000 +0900
@@ -0,0 +1,326 @@
+/*
+ * FreeS/WAN specific PF_KEY headers
+ * Copyright (C) 1999  Richard Guy Briggs.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey.h,v 1.1.1.1 2001/05/22 06:13:35 miyazawa Exp $
+ */
+
+#ifndef __NET_IPSEC_PF_KEY_H
+#define __NET_IPSEC_PF_KEY_H
+#ifdef __KERNEL__
+extern void pfkey_proto_init(struct net_proto *pro);
+extern struct proto_ops pfkey_proto_ops;
+typedef struct sock pfkey_sock;
+extern int debug_pfkey;
+
+extern /* void */ int pfkey_init(void);
+extern /* void */ int pfkey_cleanup(void);
+
+extern struct sock *pfkey_sock_list;
+struct socket_list
+{
+	struct socket *socketp;
+	struct socket_list *next;
+};
+
+extern int pfkey_list_insert_socket(struct socket*, struct socket_list**);
+extern int pfkey_list_remove_socket(struct socket*, struct socket_list**);
+extern struct socket_list *pfkey_open_sockets;
+extern struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+extern rwlock_t pfkey_sk_lock;
+
+struct sockaddr_key
+{
+	uint16_t	key_family;	/* PF_KEY */
+	uint16_t	key_pad;	/* not used */
+	uint32_t	key_pid;	/* process ID */
+};
+
+struct pfkey_extracted_data
+{
+	struct tdb* tdb;
+	struct tdb* tdb2;
+	struct eroute *eroute;
+};
+
+extern int pfkey_upmsg(struct socket *, struct sadb_msg *);
+extern int pfkey_expire(struct tdb *, int);
+extern int pfkey_acquire(struct tdb *);
+#endif /* __KERNEL__ */
+
+extern uint8_t satype2proto(uint8_t satype);
+extern uint8_t proto2satype(uint8_t proto);
+extern char* satype2name(uint8_t satype);
+extern char* proto2name(uint8_t proto);
+
+struct key_opt
+{
+	uint32_t	key_pid;	/* process ID */
+	struct sock	*sk;
+};
+
+#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid
+
+#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
+#define BITS_PER_OCTET 8
+#define OCTETBITS 8
+#define PFKEYBITS 64
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
+
+#define PFKEYv2_MAX_MSGSIZE 4096
+
+/*
+ * PF_KEYv2 permitted and required extensions in and out bitmaps
+ */
+
+extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/];
+#define EXT_BITS_IN 0
+#define EXT_BITS_OUT 1
+#define EXT_BITS_PERM 0
+#define EXT_BITS_REQ 1
+
+extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
+extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
+
+extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+			   int (*ext_parsers[])(struct sadb_ext* ),
+			   struct sadb_ext **extensions,
+			   int dir);
+
+/*
+ * PF_KEYv2 build function prototypes
+ */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext**	pfkey_ext,
+		    uint8_t		msg_type,
+		    uint8_t		satype,
+		    uint8_t		msg_errno,
+		    uint32_t		seq,
+		    uint32_t		pid);
+
+int
+pfkey_sa_build(struct sadb_ext **	pfkey_ext,
+	       uint16_t			exttype,
+	       uint32_t			spi, /* in network order */
+	       uint8_t			replay_window,
+	       uint8_t			sa_state,
+	       uint8_t			auth,
+	       uint8_t			encrypt,
+	       uint32_t			flags);
+
+int
+pfkey_lifetime_build(struct sadb_ext **	pfkey_ext,
+		     uint16_t		exttype,
+		     uint32_t		allocations,
+		     uint64_t		bytes,
+		     uint64_t		addtime,
+		     uint64_t		usetime);
+
+int
+pfkey_address_build(struct sadb_ext**	pfkey_ext,
+		    uint16_t		exttype,
+		    uint8_t		proto,
+		    uint8_t		prefixlen,
+		    struct sockaddr*	address);
+
+int
+pfkey_key_build(struct sadb_ext**	pfkey_ext,
+		uint16_t		exttype,
+		uint16_t		key_bits,
+		char*			key);
+
+int
+pfkey_ident_build(struct sadb_ext**	pfkey_ext,
+		  uint16_t		exttype,
+		  uint16_t		ident_type,
+		  uint64_t		ident_id,
+		  char*			ident_string);
+
+int
+pfkey_sens_build(struct sadb_ext**	pfkey_ext,
+		 uint32_t		dpd,
+		 uint8_t		sens_level,
+		 uint8_t		sens_len,
+		 uint64_t*		sens_bitmap,
+		 uint8_t		integ_level,
+		 uint8_t		integ_len,
+		 uint64_t*		integ_bitmap);
+
+int
+pfkey_prop_build(struct sadb_ext**	pfkey_ext,
+		 uint8_t		replay,
+		 unsigned int		comb_num,
+		 struct sadb_comb*	comb);
+
+int
+pfkey_supported_build(struct sadb_ext**	pfkey_ext,
+		      uint16_t		exttype,
+		      unsigned int	alg_num,
+		      struct sadb_alg*	alg);
+
+int
+pfkey_spirange_build(struct sadb_ext**	pfkey_ext,
+		     uint16_t		exttype,
+		     uint32_t		min,
+		     uint32_t		max);
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext**	pfkey_ext);
+
+int
+pfkey_x_satype_build(struct sadb_ext**	pfkey_ext,
+		     uint8_t		satype);
+
+int
+pfkey_x_debug_build(struct sadb_ext**	pfkey_ext,
+		    uint32_t            tunnel,
+		    uint32_t		netlink,
+		    uint32_t		xform,
+		    uint32_t		eroute,
+		    uint32_t		spi,
+		    uint32_t		radij,
+		    uint32_t		esp,
+		    uint32_t		ah,
+		    uint32_t		rcv,
+		    uint32_t            pfkey,
+		    uint32_t            ipcomp,
+		    uint32_t            verbose);
+
+int
+pfkey_msg_build(struct sadb_msg**	pfkey_msg,
+		struct sadb_ext*	extensions[],
+		int			dir);
+
+#endif /* __NET_IPSEC_PF_KEY_H */
+
+/*
+ * $Log: pfkey.h,v $
+ * Revision 1.1.1.1  2001/05/22 06:13:35  miyazawa
+ * kernel for ipsec without FS
+ *
+ * Revision 1.30  2001/02/27 07:04:52  rgb
+ * Added satype2name prototype.
+ *
+ * Revision 1.29  2001/02/26 19:59:33  rgb
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ *
+ * Revision 1.28  2000/10/10 20:10:19  rgb
+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
+ *
+ * Revision 1.27  2000/09/21 04:20:45  rgb
+ * Fixed array size off-by-one error.  (Thanks Svenning!)
+ *
+ * Revision 1.26  2000/09/12 03:26:05  rgb
+ * Added pfkey_acquire prototype.
+ *
+ * Revision 1.25  2000/09/08 19:21:28  rgb
+ * Fix pfkey_prop_build() parameter to be only single indirection.
+ *
+ * Revision 1.24  2000/09/01 18:46:42  rgb
+ * Added a supported algorithms array lists, one per satype and registered
+ * existing algorithms.
+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
+ * list.
+ *
+ * Revision 1.23  2000/08/27 01:55:26  rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.22  2000/08/20 21:39:23  rgb
+ * Added kernel prototypes for kernel funcitions pfkey_upmsg() and
+ * pfkey_expire().
+ *
+ * Revision 1.21  2000/08/15 17:29:23  rgb
+ * Fixes from SZI to untested pfkey_prop_build().
+ *
+ * Revision 1.20  2000/05/10 20:14:19  rgb
+ * Fleshed out sensitivity, proposal and supported extensions.
+ *
+ * Revision 1.19  2000/03/16 14:07:23  rgb
+ * Renamed ALIGN macro to avoid fighting with others in kernel.
+ *
+ * Revision 1.18  2000/01/22 23:24:06  rgb
+ * Added prototypes for proto2satype(), satype2proto() and proto2name().
+ *
+ * Revision 1.17  2000/01/21 06:26:59  rgb
+ * Converted from double tdb arguments to one structure (extr)
+ * containing pointers to all temporary information structures.
+ * Added klipsdebug switching capability.
+ * Dropped unused argument to pfkey_x_satype_build().
+ *
+ * Revision 1.16  1999/12/29 21:17:41  rgb
+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
+ * parameter for cleaner manipulation of extensions[] and to guard
+ * against potential memory leaks.
+ * Changed the I/F to pfkey_msg_free() for the same reason.
+ *
+ * Revision 1.15  1999/12/09 23:12:54  rgb
+ * Added macro for BITS_PER_OCTET.
+ * Added argument to pfkey_sa_build() to do eroutes.
+ *
+ * Revision 1.14  1999/12/08 20:33:25  rgb
+ * Changed sa_family_t to uint16_t for 2.0.xx compatibility.
+ *
+ * Revision 1.13  1999/12/07 19:53:40  rgb
+ * Removed unused first argument from extension parsers.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ * Added function prototypes for pfkey message and extensions
+ * initialisation and cleanup.
+ *
+ * Revision 1.12  1999/12/01 22:19:38  rgb
+ * Change pfkey_sa_build to accept an SPI in network byte order.
+ *
+ * Revision 1.11  1999/11/27 11:55:26  rgb
+ * Added extern sadb_satype2proto to enable moving protocol lookup table
+ * to lib/pfkey_v2_parse.c.
+ * Delete unused, moved typedefs.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ *
+ * Revision 1.10  1999/11/23 22:29:21  rgb
+ * This file has been moved in the distribution from klips/net/ipsec to
+ * lib.
+ * Add macros for dealing with alignment and rounding up more opaquely.
+ * The uint<n>_t type defines have been moved to freeswan.h to avoid
+ * chicken-and-egg problems.
+ * Add macros for dealing with alignment and rounding up more opaque.
+ * Added prototypes for using extention header bitmaps.
+ * Added prototypes of all the build functions.
+ *
+ * Revision 1.9  1999/11/20 21:59:48  rgb
+ * Moved socketlist type declarations and prototypes for shared use.
+ * Slightly modified scope of sockaddr_key declaration.
+ *
+ * Revision 1.8  1999/11/17 14:34:25  rgb
+ * Protect sa_family_t from being used in userspace with GLIBC<2.
+ *
+ * Revision 1.7  1999/10/27 19:40:35  rgb
+ * Add a maximum PFKEY packet size macro.
+ *
+ * Revision 1.6  1999/10/26 16:58:58  rgb
+ * Created a sockaddr_key and key_opt socket extension structures.
+ *
+ * Revision 1.5  1999/06/10 05:24:41  rgb
+ * Renamed variables to reduce confusion.
+ *
+ * Revision 1.4  1999/04/29 15:21:11  rgb
+ * Add pfkey support to debugging.
+ * Add return values to init and cleanup functions.
+ *
+ * Revision 1.3  1999/04/15 17:58:07  rgb
+ * Add RCSID labels.
+ *
+ */
diff -uNr -x CVS linux-2.5.43/include/linux/pfkeyv2.h linux25.43-ipsec/include/linux/pfkeyv2.h
--- linux-2.5.43/include/linux/pfkeyv2.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/include/linux/pfkeyv2.h	2002-10-16 15:27:46.000000000 +0900
@@ -0,0 +1,368 @@
+/*
+ * RCSID $Id: pfkeyv2.h,v 1.2 2001/05/26 10:10:17 mk Exp $
+ */
+
+/*
+RFC 2367               PF_KEY Key Management API               July 1998
+
+
+Appendix D: Sample Header File
+
+This file defines structures and symbols for the PF_KEY Version 2
+key management interface. It was written at the U.S. Naval Research
+Laboratory. This file is in the public domain. The authors ask that
+you leave this credit intact on any copies of this file.
+*/
+#ifndef __PFKEY_V2_H
+#define __PFKEY_V2_H 1
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_IPSEC_DEBUG
+# ifdef CONFIG_SYSCTL
+#  define PFKEY_DEBUG(fmt, args...)				\
+do {								\
+	if (sysctl_ipsec_debug_pfkey) {				\
+	printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args);	\
+	}							\
+} while(0)
+# else
+#  define PFKEY_DEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#endif /* CONFIG_SYSCTL */
+#else
+#  define PFKEY_DEBUG(fmt, args...)
+#endif
+
+#endif /* __KERNEL__ */
+
+#define PF_KEY_V2 2
+#define PFKEYV2_REVISION        199806L
+
+#define SADB_RESERVED    0
+#define SADB_GETSPI      1
+#define SADB_UPDATE      2
+#define SADB_ADD         3
+#define SADB_DELETE      4
+#define SADB_GET         5
+#define SADB_ACQUIRE     6
+#define SADB_REGISTER    7
+#define SADB_EXPIRE      8
+#define SADB_FLUSH       9
+#define SADB_DUMP       10
+#define SADB_X_PROMISC  11
+#define SADB_X_PCHANGE  12
+#define SADB_X_GRPSA    13
+#define SADB_X_ADDFLOW	14
+#define SADB_X_DELFLOW	15
+#define SADB_X_DEBUG	16
+#define SADB_X_FLUSH_SP 17
+#define SADB_MAX        17
+
+struct sadb_msg {
+  uint8_t sadb_msg_version;
+  uint8_t sadb_msg_type;
+  uint8_t sadb_msg_errno;
+  uint8_t sadb_msg_satype;
+  uint16_t sadb_msg_len;
+  uint16_t sadb_msg_reserved;
+  uint32_t sadb_msg_seq;
+  uint32_t sadb_msg_pid;
+};
+
+struct sadb_ext {
+  uint16_t sadb_ext_len;
+  uint16_t sadb_ext_type;
+};
+
+struct sadb_sa {
+  uint16_t sadb_sa_len;
+  uint16_t sadb_sa_exttype;
+  uint32_t sadb_sa_spi;
+  uint8_t sadb_sa_replay;
+  uint8_t sadb_sa_state;
+  uint8_t sadb_sa_auth;
+  uint8_t sadb_sa_encrypt;
+  uint32_t sadb_sa_flags;
+};
+
+struct sadb_lifetime {
+  uint16_t sadb_lifetime_len;
+  uint16_t sadb_lifetime_exttype;
+  uint32_t sadb_lifetime_allocations;
+  uint64_t sadb_lifetime_bytes;
+  uint64_t sadb_lifetime_addtime;
+  uint64_t sadb_lifetime_usetime;
+};
+
+struct sadb_address {
+  uint16_t sadb_address_len;
+  uint16_t sadb_address_exttype;
+  uint8_t sadb_address_proto;
+  uint8_t sadb_address_prefixlen;
+  uint16_t sadb_address_reserved;
+};
+
+struct sadb_key {
+  uint16_t sadb_key_len;
+  uint16_t sadb_key_exttype;
+  uint16_t sadb_key_bits;
+  uint16_t sadb_key_reserved;
+};
+
+struct sadb_ident {
+  uint16_t sadb_ident_len;
+  uint16_t sadb_ident_exttype;
+  uint16_t sadb_ident_type;
+  uint16_t sadb_ident_reserved;
+  uint64_t sadb_ident_id;
+};
+
+struct sadb_sens {
+  uint16_t sadb_sens_len;
+  uint16_t sadb_sens_exttype;
+  uint32_t sadb_sens_dpd;
+  uint8_t sadb_sens_sens_level;
+  uint8_t sadb_sens_sens_len;
+  uint8_t sadb_sens_integ_level;
+  uint8_t sadb_sens_integ_len;
+  uint32_t sadb_sens_reserved;
+};
+
+struct sadb_prop {
+  uint16_t sadb_prop_len;
+  uint16_t sadb_prop_exttype;
+  uint8_t sadb_prop_replay;
+  uint8_t sadb_prop_reserved[3];
+};
+
+struct sadb_comb {
+  uint8_t sadb_comb_auth;
+  uint8_t sadb_comb_encrypt;
+  uint16_t sadb_comb_flags;
+  uint16_t sadb_comb_auth_minbits;
+  uint16_t sadb_comb_auth_maxbits;
+  uint16_t sadb_comb_encrypt_minbits;
+  uint16_t sadb_comb_encrypt_maxbits;
+  uint32_t sadb_comb_reserved;
+  uint32_t sadb_comb_soft_allocations;
+  uint32_t sadb_comb_hard_allocations;
+  uint64_t sadb_comb_soft_bytes;
+  uint64_t sadb_comb_hard_bytes;
+  uint64_t sadb_comb_soft_addtime;
+  uint64_t sadb_comb_hard_addtime;
+  uint64_t sadb_comb_soft_usetime;
+  uint64_t sadb_comb_hard_usetime;
+};
+
+struct sadb_supported {
+  uint16_t sadb_supported_len;
+  uint16_t sadb_supported_exttype;
+  uint32_t sadb_supported_reserved;
+};
+
+struct sadb_alg {
+  uint8_t sadb_alg_id;
+  uint8_t sadb_alg_ivlen;
+  uint16_t sadb_alg_minbits;
+  uint16_t sadb_alg_maxbits;
+  uint16_t sadb_alg_reserved;
+};
+
+struct sadb_spirange {
+  uint16_t sadb_spirange_len;
+  uint16_t sadb_spirange_exttype;
+  uint32_t sadb_spirange_min;
+  uint32_t sadb_spirange_max;
+  uint32_t sadb_spirange_reserved;
+};
+
+struct sadb_x_kmprivate {
+  uint16_t sadb_x_kmprivate_len;
+  uint16_t sadb_x_kmprivate_exttype;
+  uint32_t sadb_x_kmprivate_reserved;
+};
+
+struct sadb_x_satype {
+  uint16_t sadb_x_satype_len;
+  uint16_t sadb_x_satype_exttype;
+  uint8_t sadb_x_satype_satype;
+  uint8_t sadb_x_satype_reserved[3];
+};
+  
+struct sadb_x_debug {
+  uint16_t sadb_x_debug_len;
+  uint16_t sadb_x_debug_exttype;
+  uint32_t sadb_x_debug_tunnel;
+  uint32_t sadb_x_debug_netlink;
+  uint32_t sadb_x_debug_xform;
+  uint32_t sadb_x_debug_eroute;
+  uint32_t sadb_x_debug_spi;
+  uint32_t sadb_x_debug_radij;
+  uint32_t sadb_x_debug_esp;
+  uint32_t sadb_x_debug_ah;
+  uint32_t sadb_x_debug_rcv;
+  uint32_t sadb_x_debug_pfkey;
+  uint32_t sadb_x_debug_ipcomp;
+  uint32_t sadb_x_debug_verbose;
+  uint8_t sadb_x_debug_reserved[4];
+};
+  
+#define SADB_EXT_RESERVED             0
+#define SADB_EXT_SA                   1
+#define SADB_EXT_LIFETIME_CURRENT     2
+#define SADB_EXT_LIFETIME_HARD        3
+#define SADB_EXT_LIFETIME_SOFT        4
+#define SADB_EXT_ADDRESS_SRC          5
+#define SADB_EXT_ADDRESS_DST          6
+#define SADB_EXT_ADDRESS_PROXY        7
+#define SADB_EXT_KEY_AUTH             8
+#define SADB_EXT_KEY_ENCRYPT          9
+#define SADB_EXT_IDENTITY_SRC         10
+#define SADB_EXT_IDENTITY_DST         11
+#define SADB_EXT_SENSITIVITY          12
+#define SADB_EXT_PROPOSAL             13
+#define SADB_EXT_SUPPORTED_AUTH       14
+#define SADB_EXT_SUPPORTED_ENCRYPT    15
+#define SADB_EXT_SPIRANGE             16
+#define SADB_X_EXT_KMPRIVATE          17
+#define SADB_X_EXT_SATYPE2            18
+#define SADB_X_EXT_SA2                19
+#define SADB_X_EXT_ADDRESS_DST2       20
+#define SADB_X_EXT_ADDRESS_SRC_FLOW   21
+#define SADB_X_EXT_ADDRESS_DST_FLOW   22
+#define SADB_X_EXT_ADDRESS_SRC_MASK   23
+#define SADB_X_EXT_ADDRESS_DST_MASK   24
+#define SADB_X_EXT_DEBUG              25
+#define SADB_EXT_MAX                  25
+
+/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
+#define SADB_X_EXT_ADDRESS_DELFLOW \
+	( (1<<SADB_X_EXT_ADDRESS_SRC_FLOW) \
+	| (1<<SADB_X_EXT_ADDRESS_DST_FLOW) \
+	| (1<<SADB_X_EXT_ADDRESS_SRC_MASK) \
+	| (1<<SADB_X_EXT_ADDRESS_DST_MASK))
+
+#define SADB_SATYPE_UNSPEC    0
+#define SADB_SATYPE_AH        2
+#define SADB_SATYPE_ESP       3
+#define SADB_SATYPE_RSVP      5
+#define SADB_SATYPE_OSPFV2    6
+#define SADB_SATYPE_RIPV2     7
+#define SADB_SATYPE_MIP       8
+#define SADB_X_SATYPE_IPIP    9
+#define SADB_X_SATYPE_COMP    10
+#define SADB_X_SATYPE_INT     11
+#define SADB_SATYPE_MAX       11
+
+#define SADB_SASTATE_LARVAL   0
+#define SADB_SASTATE_MATURE   1
+#define SADB_SASTATE_DYING    2
+#define SADB_SASTATE_DEAD     3
+#define SADB_SASTATE_MAX      3
+
+#define SADB_SAFLAGS_PFS		1
+#define SADB_X_SAFLAGS_REPLACEFLOW	2
+#define SADB_X_SAFLAGS_CLEARFLOW	4
+#define SADB_X_SAFLAGS_TUNNEL		8
+
+#define SADB_AALG_NONE        0
+#define SADB_AALG_MD5HMAC     2
+#define SADB_AALG_SHA1HMAC    3
+#define SADB_AALG_MAX         3
+
+#define SADB_EALG_NONE        0
+#define SADB_EALG_DES_IV64    1  /* N/A */
+#define SADB_EALG_DESCBC      2 
+#define SADB_EALG_3DESCBC     3
+#define SADB_EALG_RC5         4  /* N/A */
+#define SADB_EALG_IDEA        5  /* N/A */
+#define SADB_EALG_CAST        6  /* N/A */
+#define SADB_EALG_BLOWFISH    7  /* N/A */
+#define SADB_EALG_3IDEA       8  /* N/A */
+#define SADB_EALG_DES_IV32    9  /* N/A */
+#define SADB_EALG_ESP_RC4     10 /* N/A */
+#define SADB_EALG_NULL        11
+#define SADB_EALG_AES         12 /* N/A */
+#define SADB_EALG_MAX         12
+
+#define SADB_X_CALG_NONE          0
+#define SADB_X_CALG_OUI           1
+#define SADB_X_CALG_DEFLATE       2
+#define SADB_X_CALG_LZS           3
+#define SADB_X_CALG_V42BIS        4
+#define SADB_X_CALG_LZJH          4
+#define SADB_X_CALG_MAX           4
+
+#define SADB_X_TALG_NONE          0
+#define SADB_X_TALG_IPv4_in_IPv4  1
+#define SADB_X_TALG_IPv6_in_IPv4  2
+#define SADB_X_TALG_IPv4_in_IPv6  3
+#define SADB_X_TALG_IPv6_in_IPv6  4
+#define SADB_X_TALG_MAX           4
+
+
+#define SADB_IDENTTYPE_RESERVED   0
+#define SADB_IDENTTYPE_PREFIX     1
+#define SADB_IDENTTYPE_FQDN       2
+#define SADB_IDENTTYPE_USERFQDN   3
+#define SADB_IDENTTYPE_MAX        3
+
+#define SADB_KEY_FLAGS_MAX     0
+#endif /* __PFKEY_V2_H */
+
+/*
+ * $Log: pfkeyv2.h,v $
+ * Revision 1.2  2001/05/26 10:10:17  mk
+ * rename ah_utils.h to ipsec6_utils.h
+ *
+ * Revision 1.1.1.1  2001/05/22 06:13:33  miyazawa
+ * kernel for ipsec without FS
+ *
+ * Revision 1.15  2001/02/26 20:00:43  rgb
+ * Added internal IP protocol 61 for magic SAs.
+ *
+ * Revision 1.14  2001/02/08 18:51:05  rgb
+ * Include RFC document title and appendix subsection title.
+ *
+ * Revision 1.13  2000/10/10 20:10:20  rgb
+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
+ *
+ * Revision 1.12  2000/09/15 06:41:50  rgb
+ * Added V42BIS constant.
+ *
+ * Revision 1.11  2000/09/12 22:35:37  rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.10  2000/09/12 18:50:09  rgb
+ * Added IPIP tunnel types as algo support.
+ *
+ * Revision 1.9  2000/08/21 16:47:19  rgb
+ * Added SADB_X_CALG_* macros for IPCOMP.
+ *
+ * Revision 1.8  2000/08/09 20:43:34  rgb
+ * Fixed bitmask value for SADB_X_SAFLAGS_CLEAREROUTE.
+ *
+ * Revision 1.7  2000/01/21 06:28:37  rgb
+ * Added flow add/delete message type macros.
+ * Added flow address extension type macros.
+ * Tidied up spacing.
+ * Added klipsdebug switching capability.
+ *
+ * Revision 1.6  1999/11/27 11:56:08  rgb
+ * Add SADB_X_SATYPE_COMP for compression, eventually.
+ *
+ * Revision 1.5  1999/11/23 22:23:16  rgb
+ * This file has been moved in the distribution from klips/net/ipsec to
+ * lib.
+ *
+ * Revision 1.4  1999/04/29 15:23:29  rgb
+ * Add GRPSA support.
+ * Add support for a second SATYPE, SA and DST_ADDRESS.
+ * Add IPPROTO_IPIP support.
+ *
+ * Revision 1.3  1999/04/15 17:58:08  rgb
+ * Add RCSID labels.
+ *
+ */
diff -uNr -x CVS linux-2.5.43/include/linux/socket.h linux25.43-ipsec/include/linux/socket.h
--- linux-2.5.43/include/linux/socket.h	2002-10-16 12:28:33.000000000 +0900
+++ linux25.43-ipsec/include/linux/socket.h	2002-10-16 15:27:46.000000000 +0900
@@ -25,6 +25,24 @@
 };
 
 /*
+ * Desired design of maximum size and alignment
+ */
+#define _SS_MAXSIZE    128                      /* Implementation specific max size */
+#define _SS_ALIGNSIZE  (sizeof (int64_t))       /* Implementation specific desired alignment */
+/* 
+ * Definitions used for sockaddr_storage structure paddings design.
+ */
+#define _SS_PAD1SIZE   (_SS_ALIGNSIZE - sizeof (sa_family_t))
+#define _SS_PAD2SIZE   (_SS_MAXSIZE - (sizeof (sa_family_t)+ _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+	sa_family_t  ss_family; 
+	char      __ss_pad1[_SS_PAD1SIZE];
+	int64_t   __ss_align; 
+	char      __ss_pad2[_SS_PAD2SIZE];
+};
+
+/*
  *	As we do 4.4BSD message passing we use a 4.4BSD message passing
  *	system, not 4.3. Thus msg_accrights(len) are now missing. They
  *	belong in an obscure libc emulation or the bin.
diff -uNr -x CVS linux-2.5.43/include/linux/sysctl.h linux25.43-ipsec/include/linux/sysctl.h
--- linux-2.5.43/include/linux/sysctl.h	2002-10-16 12:27:08.000000000 +0900
+++ linux25.43-ipsec/include/linux/sysctl.h	2002-10-16 15:27:46.000000000 +0900
@@ -177,6 +177,7 @@
 	NET_DECNET=15,
 	NET_ECONET=16,
 	NET_SCTP=17, 
+	NET_IPSEC=18
 };
 
 /* /proc/sys/kernel/random */
@@ -385,6 +386,16 @@
 	NET_IPV6_RTR_SOLICIT_DELAY=10
 };
 
+/* /proc/net/ipsec */
+enum {
+	NET_IPSEC_REPLAY_WINDOW=1,
+	NET_IPSEC_DEBUG_IPV4=4,
+	NET_IPSEC_DEBUG_IPV6=5,
+	NET_IPSEC_DEBUG_PFKEY=6,
+	NET_IPSEC_DEBUG_SADB=7,
+	NET_IPSEC_DEBUG_SPD=8,
+};
+
 /* /proc/sys/net/<protocol>/neigh/<dev> */
 enum {
 	NET_NEIGH_MCAST_SOLICIT=1,
diff -uNr -x CVS linux-2.5.43/include/net/ipv6.h linux25.43-ipsec/include/net/ipv6.h
--- linux-2.5.43/include/net/ipv6.h	2002-10-16 12:28:34.000000000 +0900
+++ linux25.43-ipsec/include/net/ipv6.h	2002-10-16 15:27:46.000000000 +0900
@@ -185,7 +185,7 @@
 
 extern int			ipv6_parse_hopopts(struct sk_buff *skb, int);
 
-extern int			ipv6_parse_exthdrs(struct sk_buff **skb, int);
+extern int			ipv6_parse_exthdrs(struct sk_buff **skb, int, u8* nexthdr);
 
 extern struct ipv6_txoptions *  ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
 
diff -uNr -x CVS linux-2.5.43/include/net/sadb.h linux25.43-ipsec/include/net/sadb.h
--- linux-2.5.43/include/net/sadb.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/include/net/sadb.h	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,230 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/* IPsec Security Association Implementation */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SADB_H
+#define __SADB_H
+
+#include <linux/types.h>
+#include <linux/socket.h>	/* sockaddr_storage */
+#include <linux/list.h>		/* list_entry */
+#include <linux/spinlock.h>	/* rw_lock_t */
+#include <linux/crypto.h>
+#include <asm/atomic.h>
+
+/* internally reserved SPI values */
+#define IPSEC_SPI_BYPASS	256
+#define IPSEC_SPI_DROP		257
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_IPSEC_DEBUG
+# ifdef CONFIG_SYSCTL
+#  define SADB_DEBUG(fmt, args...)					\
+do {									\
+	if (sysctl_ipsec_debug_sadb) {					\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args);	\
+	}								\
+} while(0)
+# else
+#  define SADB_DEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# endif /* CONFIG_SYSCTL */
+#else
+# define SADB_DEBUG(fmt, args...)
+#endif
+
+
+#define KEY_LEN_MAX      24
+#define AUTH_KEY_LEN_MAX 20         /* enough for HMAC SHA1 key length */
+#define ESP_KEY_LEN_MAX  384        /* enough for 3DES key length */
+#define ESP_IV_LEN_MAX   16
+#define IPSEC_SPI_ANY    0xFFFFFFFF
+
+extern struct list_head sadb_list;
+extern rwlock_t sadb_lock; 
+
+/* The sa_replay_window holds information for a replay window.*/
+struct sa_replay_window{
+	__u8	overflow;
+	__u8	size;
+	__u32   seq_num;
+	__u32	last_seq;
+	__u32	bitmap;
+};
+
+/* The sa_lifetime holds lifetime for a specific SA. */
+struct sa_lifetime{
+	__u64	bytes;
+	__u64	addtime;
+	__u64	usetime;
+	__u32	allocations;
+};
+
+/* We use kerneli transformation. */
+struct auth_algo_info{
+	__u8	algo;
+	__u8	*key;
+	__u16	key_len; /* key length in byte */
+	__u16	digest_len;
+	struct digest_context *dx;
+	
+};
+
+struct esp_algo_info{
+	__u8	algo;
+	__u8	*key;
+	__u16	key_len; /* key length in byte */
+	__u8	*iv;
+	struct cipher_context *cx;
+};
+
+/* Security Association (SA)
+ *
+ * RFC2401 ch4.4 says
+ * 
+ *    Each interface for which IPsec is enabled requires nominally separate
+ *    inbound vs. outbound databases (SAD and SPD), because of the
+ *    directionality of many of the fields that are used as selectors.
+ *
+ * But we don't care whether SA is inbound or outbound.
+ * Because it is enough to check src/dst address pair of SA. */
+struct ipsec_sa {
+
+	/* Never touch entry without lock sadb_lock */
+	struct list_head entry;
+
+	/* list entry for temporary work */
+	struct list_head tmp_entry;
+
+	/* reference count describes the number of sa_index_t */
+	atomic_t refcnt;
+
+	/* This lock only affect elements except for entry */
+	rwlock_t lock;
+
+	/* The sadb_address_proto field is normally zero,
+	   which MUST be filled with the transport protocol's number. */
+	__u8 proto;
+
+	/* SA status */
+	__u8 state;
+
+	/* tunnel mode */
+	__u8 tunnel_mode;
+
+	/* ipsec protocol like AH, ESP, IPCOMP */
+	__u8 ipsec_proto;
+
+	/* SPI: Security Parameter Index (network byte order) 
+	 * or 
+	 * CPI: Compression Prameter Index 
+	 *      IPcomp algorithm(CPI): deflate=2, (lhz=3, lzjh) (network byte order) 
+	 *      in case of CPI, we use lower u16 as CPI. */ 
+	__u32 spi;
+	 
+	/* SA destination address */
+	struct sockaddr_storage dst;
+
+	/* SA source address */
+	struct sockaddr_storage src;
+
+	/* SA proxy address (RFC specified but we don't use) */
+	/* struct sockaddr_storage pxy; */
+
+	/* SA source address prefix len */
+	__u8 prefixlen_s;
+
+	/* SA dst address prefix len */
+	__u8 prefixlen_d;
+
+	/* SA proxy address prefix len (not use) */
+	/* __u8 prefixlen_p; */
+
+	/* replay window */
+	struct sa_replay_window replay_window;
+
+	/* liftetime for this SA, giving an upper limit
+	   for the sequence number */
+	struct sa_lifetime lifetime_s; /* soft lifetime */
+	struct sa_lifetime lifetime_h; /* hard lifetime */
+	struct sa_lifetime lifetime_c; /* current lifetime */
+	/* internal use, because uint64 and jiffies are different unit */
+	unsigned long init_time;       /* initial time (unit: jiffies) */
+	unsigned long fuse_time;       /* first use time (unit: jiffies) */
+
+	struct timer_list timer;
+
+	/* algo is the number of the algorithm in use */
+	struct auth_algo_info auth_algo;
+	struct esp_algo_info esp_algo;
+};
+
+struct sa_index{
+
+        struct list_head entry;
+
+	/* SA doesn't always exist. 
+	 * If SA is null, it means suitable SA doesn't exist 
+	 * in SA list(it consists of struct ipsec_sa_t). */
+        struct ipsec_sa *sa;
+
+	struct sockaddr_storage dst;
+	__u32  spi;
+	__u8	prefixlen_d;
+	__u8	ipsec_proto;
+};
+
+int sadb_init(void);
+int sadb_cleanup(void);
+
+/* The function sadb_append copies entry to own list. */
+/* It is able to free the parameter entry. */
+struct ipsec_sa* ipsec_sa_kmalloc(void);
+int ipsec_sa_init(struct ipsec_sa *sa);
+void ipsec_sa_kfree(struct ipsec_sa *sa);
+int ipsec_sa_copy(struct ipsec_sa *dst, struct ipsec_sa *src);
+void ipsec_sa_lifetime_check(unsigned long data);
+void ipsec_sa_put(struct ipsec_sa *sa);
+static inline void ipsec_sa_hold(struct ipsec_sa *sa)
+{
+	if(sa) atomic_inc(&sa->refcnt);
+};
+
+int sadb_append(struct ipsec_sa *sa);
+void sadb_remove(struct ipsec_sa *sa);
+void sadb_clear_db(void);
+int sadb_flush_sa(int satype);
+
+/* These functions expect the parameter SA has been allocated. */
+struct ipsec_sa* sadb_find_by_sa_index(struct sa_index *sa_index);
+int sadb_find_by_address_proto_spi(struct sockaddr *src, __u8 prefixlen_s, 
+					struct sockaddr *dst, __u8 prefixlen_d,
+					__u8 ipsec_proto, __u32 spi, struct ipsec_sa **sa);
+
+/* The struct sa_index is a glue between SA and Policy */
+struct sa_index* sa_index_kmalloc(void);
+int sa_index_init(struct sa_index *sa);
+void sa_index_kfree(struct sa_index *sa);
+int sa_index_compare(struct sa_index *sa_idx1, struct sa_index *sa_idx2);
+int sa_index_copy(struct sa_index *dst, struct sa_index *src);
+void ipsec_sa_mod_timer(struct ipsec_sa *sa);
+
+#endif /* __KERNEL__ */
+#endif /* __SADB_H */
+
diff -uNr -x CVS linux-2.5.43/include/net/spd.h linux25.43-ipsec/include/net/spd.h
--- linux-2.5.43/include/net/spd.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/include/net/spd.h	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,117 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/* IPsec Security Policy Implementation */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SPD_H
+#define __SPD_H
+
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/spinlock.h>
+#include <net/sadb.h>
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_IPSEC_DEBUG
+# ifdef CONFIG_SYSCTL
+#  define SPD_DEBUG(fmt, args...)					\
+do {									\
+	if (sysctl_ipsec_debug_spd) {					\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args);	\
+	}								\
+} while(0)
+# else
+#  define SPD_DEBUG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+# endif /* CONFIG_SYSCTL */
+#else
+#  define SPD_DEBUG(fmt, args...)
+#endif
+
+extern struct list_head spd_list;
+extern rwlock_t spd_lock;
+
+/* Selector for SPD 
+ *
+ * Now Selector realy consist of a pair of source and destination address. */
+struct selector{
+	/* TODO: It should be better to hold elements as reference(pointer) */
+	struct sockaddr_storage src;
+	struct sockaddr_storage dst;
+	__u8 prefixlen_s;
+	__u8 prefixlen_d;
+	__u8 proto;
+#ifdef CONFIG_IPSEC_TUNNEL
+	__u8 mode;
+#endif
+};
+
+/* IPsec Policy */
+struct ipsec_sp{
+	/* Never touch entry without locking spd_lock */
+	struct list_head entry;
+
+	/* This lock only affects elements except for entry. */
+	rwlock_t lock;	
+	atomic_t refcnt;
+	struct selector selector;
+	struct sa_index* auth_sa_idx;
+	struct sa_index* esp_sa_idx;
+	struct sa_index* comp_sa_idx;
+	__u8 policy_action;
+};
+
+struct ipsec_sp* ipsec_sp_kmalloc(void);
+int ipsec_sp_init(struct ipsec_sp *policy);
+void ipsec_sp_kfree(struct ipsec_sp *policy);
+int ipsec_sp_copy(struct ipsec_sp *dst, struct ipsec_sp *src);
+int ipsec_sp_put(struct ipsec_sp *policy);
+void ipsec_sp_release_invalid_sa(struct ipsec_sp *policy, struct ipsec_sa *sa);
+
+static inline void ipsec_sp_hold(struct ipsec_sp *policy)
+{
+	if (policy) atomic_inc(&policy->refcnt);
+}
+
+int spd_append(struct ipsec_sp *entry);
+int spd_remove(struct selector *selector);
+int spd_find_by_selector(struct selector *selector, struct ipsec_sp **policy);
+
+static inline struct ipsec_sp* spd_get(struct selector *selector)
+{
+	struct ipsec_sp *policy = NULL;
+	spd_find_by_selector(selector, &policy);
+	return policy;
+}
+
+void spd_clear_db(void);
+
+int spd_init(void);
+int spd_cleanup(void);
+
+#define IPSEC_POLICY_APPLY	0
+#define IPSEC_POLICY_BYPASS	1
+#define IPSEC_POLICY_DROP	2
+
+#ifdef CONFIG_IPSEC_TUNNEL
+#define IPSEC_MODE_TRANSPORT	0
+#define IPSEC_MODE_TUNNEL	1
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* __SPD_H */
diff -uNr -x CVS linux-2.5.43/net/Config.in linux25.43-ipsec/net/Config.in
--- linux-2.5.43/net/Config.in	2002-10-16 12:27:22.000000000 +0900
+++ linux25.43-ipsec/net/Config.in	2002-10-16 15:27:47.000000000 +0900
@@ -18,6 +18,14 @@
 tristate 'Unix domain sockets' CONFIG_UNIX
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_CRYPTO" = "y" ]; then
+         bool '  The IPsec protocol (EXPERIMENTAL)' CONFIG_IPSEC
+         if [ "$CONFIG_IPSEC" != "n" ]; then
+            source net/key/Config.in
+         fi
+      fi
+   fi
    source net/ipv4/Config.in
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 #   IPv6 as module will cause a CRASH if you try to unload it
diff -uNr -x CVS linux-2.5.43/net/Makefile linux25.43-ipsec/net/Makefile
--- linux-2.5.43/net/Makefile	2002-10-16 12:27:55.000000000 +0900
+++ linux25.43-ipsec/net/Makefile	2002-10-16 15:27:47.000000000 +0900
@@ -35,6 +35,7 @@
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
+obj-$(CONFIG_IPSEC)		+= key/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_MODULES)		+= netsyms.o
diff -uNr -x CVS linux-2.5.43/net/ipv4/Config.help linux25.43-ipsec/net/ipv4/Config.help
--- linux-2.5.43/net/ipv4/Config.help	2002-10-16 12:27:54.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/Config.help	2002-10-16 15:27:48.000000000 +0900
@@ -277,3 +277,7 @@
   gated-5). This routing protocol is not used widely, so say N unless
   you want to play with it.
 
+CONFIG_IP_IPSEC
+
+  IPsec for IPv4 support.  You also need to say Y to "The IPsec Protocol."
+  If unsure, say N.
diff -uNr -x CVS linux-2.5.43/net/ipv4/Config.in linux25.43-ipsec/net/ipv4/Config.in
--- linux-2.5.43/net/ipv4/Config.in	2002-10-16 12:27:14.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/Config.in	2002-10-16 15:27:48.000000000 +0900
@@ -41,6 +41,12 @@
 fi
 bool '  IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN
 bool '  IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKIES
+# --- IPsec ---
+if [ "$CONFIG_EXPERIMENTAL" = "y" ] ; then
+   if [ "$CONFIG_IPSEC" != "n" ] ; then
+      bool '  IP: IP Security Support (EXPERIMENTAL) ' CONFIG_IP_IPSEC
+   fi
+fi
 if [ "$CONFIG_NETFILTER" != "n" ]; then
    source net/ipv4/netfilter/Config.in
 fi
diff -uNr -x CVS linux-2.5.43/net/ipv4/Makefile linux25.43-ipsec/net/ipv4/Makefile
--- linux-2.5.43/net/ipv4/Makefile	2002-10-16 12:27:23.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/Makefile	2002-10-16 15:27:48.000000000 +0900
@@ -16,6 +16,7 @@
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
+obj-$(CONFIG_IP_IPSEC) += ipsec4_output.o ipsec4_input.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 include $(TOPDIR)/Rules.make
diff -uNr -x CVS linux-2.5.43/net/ipv4/ip_input.c linux25.43-ipsec/net/ipv4/ip_input.c
--- linux-2.5.43/net/ipv4/ip_input.c	2002-10-16 12:27:12.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/ip_input.c	2002-10-16 15:27:48.000000000 +0900
@@ -143,6 +143,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#include <linux/ipsec.h>
 
 /*
  *	SNMP management statistics
@@ -197,6 +198,9 @@
 static inline int ip_local_deliver_finish(struct sk_buff *skb)
 {
 	int ihl = skb->nh.iph->ihl*4;
+#ifdef CONFIG_IP_IPSEC
+	int result;
+#endif
 
 #ifdef CONFIG_NETFILTER_DEBUG
 	nf_debug_ip_local_deliver(skb);
@@ -214,6 +218,13 @@
         /* Point into the IP datagram, just past the header. */
         skb->h.raw = skb->data;
 
+#ifdef CONFIG_IP_IPSEC
+	result = ipsec4_input_check(&skb);
+	if (result < 0) {
+		kfree_skb(skb);
+		return result;
+	}
+#endif
 	{
 		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
 		int protocol = skb->nh.iph->protocol;
diff -uNr -x CVS linux-2.5.43/net/ipv4/ip_output.c linux25.43-ipsec/net/ipv4/ip_output.c
--- linux-2.5.43/net/ipv4/ip_output.c	2002-10-16 12:29:05.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/ip_output.c	2002-10-16 15:27:48.000000000 +0900
@@ -77,6 +77,7 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#include <linux/ipsec.h>
 
 /*
  *      Shall we try to damage output packets if routing dev changes?
@@ -125,6 +126,38 @@
 	struct inet_opt *inet = inet_sk(sk);
 	struct rtable *rt = (struct rtable *)skb->dst;
 	struct iphdr *iph;
+#ifdef CONFIG_IP_IPSEC
+	struct ip_auth_hdr *authhdr = NULL;
+	int ah_len;
+	struct ipsec_sp *policy_ptr = NULL;
+	int ipsec_action =  0;
+	u8 protocol = sk->protocol;
+
+	ipsec_action = ipsec4_output_check(sk, rt, &policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *encdata = NULL;
+		unsigned int enclength = 0;
+		unsigned int encaddsize = 0;
+		struct ip_esp_hdr *esphdr = NULL;
+
+		ipsec4_out_enc(skb->data, skb->len, protocol, &encdata, &enclength, policy_ptr);
+		encaddsize = enclength - skb->len;
+		esphdr = (struct ip_esp_hdr*) skb_push(skb, encaddsize);
+		memcpy(esphdr, encdata, enclength);
+		protocol = IPPROTO_ESP;
+		if (encdata) kfree(encdata);
+	}
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		ah_len = ipsec4_out_get_ahsize(policy_ptr);
+		authhdr = (struct ip_auth_hdr*) skb_push(skb, ah_len);
+		authhdr->nexthdr = protocol;
+		authhdr->hdrlen  = (ah_len >> 2) -2;
+		authhdr->reserved = 0;
+		protocol = IPPROTO_AH;
+	}
+#endif
 
 	/* Build the IP header. */
 	if (opt)
@@ -142,7 +175,11 @@
 	iph->ttl      = inet->ttl;
 	iph->daddr    = rt->rt_dst;
 	iph->saddr    = rt->rt_src;
+#ifdef CONFIG_IP_IPSEC
+	iph->protocol = protocol;
+#else
 	iph->protocol = sk->protocol;
+#endif
 	iph->tot_len  = htons(skb->len);
 	ip_select_ident(iph, &rt->u.dst, sk);
 	skb->nh.iph   = iph;
@@ -151,6 +188,10 @@
 		iph->ihl += opt->optlen>>2;
 		ip_options_build(skb, opt, daddr, rt, 0);
 	}
+#ifdef CONFIG_IP_IPSEC
+	ipsec4_out_ah_calc(skb->nh.iph, authhdr, policy_ptr);
+	ipsec4_out_finish(policy_ptr);
+#endif
 	ip_send_check(iph);
 
 	/* Send it out. */
@@ -319,8 +360,9 @@
 				skb_shinfo(skb)->tso_size - 1;
 	}
 
+#ifndef CONFIG_IP_IPSEC
 	ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);
-
+#endif
 	/* Add an IP checksum. */
 	ip_send_check(iph);
 
@@ -354,7 +396,13 @@
 	struct ip_options *opt = inet->opt;
 	struct rtable *rt;
 	struct iphdr *iph;
-
+#ifdef CONFIG_IP_IPSEC
+	struct ipsec_sp *policy_ptr = NULL;
+	struct ip_auth_hdr *authhdr = NULL;
+	int ah_len = 0;
+	int ipsec_action =  0;
+	u8 protocol = sk->protocol;
+#endif
 	/* Skip all of this if the packet is already routed,
 	 * f.e. by something like SCTP.
 	 */
@@ -392,9 +440,38 @@
 	skb->dst = dst_clone(&rt->u.dst);
 
 packet_routed:
+
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto no_route;
 
+#ifdef CONFIG_IP_IPSEC
+	ipsec_action = ipsec4_output_check(sk, rt, &policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *encdata = NULL;
+		unsigned int enclength = 0;
+		unsigned int encaddsize = 0;
+		struct ip_esp_hdr *esphdr = NULL;
+
+		ipsec4_out_enc(skb->data, skb->len, protocol, &encdata, &enclength, policy_ptr);
+		encaddsize = enclength - skb->len;
+		esphdr = (struct ip_esp_hdr*) skb_push(skb, encaddsize);
+		memcpy(esphdr, encdata, enclength);
+		protocol = IPPROTO_ESP;
+		if (encdata) kfree(encdata);
+	}
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		ah_len = ipsec4_out_get_ahsize(policy_ptr);
+		authhdr = (struct ip_auth_hdr*)skb_push(skb, ah_len);
+		authhdr->nexthdr  = protocol;
+		authhdr->hdrlen   = (ah_len >> 2) - 2;
+		authhdr->reserved = 0;
+		protocol = IPPROTO_AH;
+	}
+#endif
+
+
 	/* OK, we know where to send it, allocate and build IP header. */
 	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
 	*((__u16 *)iph)	= htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
@@ -404,7 +481,12 @@
 	else
 		iph->frag_off = 0;
 	iph->ttl      = inet->ttl;
+#ifdef CONFIG_IP_IPSEC
+	iph->protocol = protocol;
+	ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);
+#else
 	iph->protocol = sk->protocol;
+#endif
 	iph->saddr    = rt->rt_src;
 	iph->daddr    = rt->rt_dst;
 	skb->nh.iph   = iph;
@@ -414,16 +496,30 @@
 		iph->ihl += opt->optlen >> 2;
 		ip_options_build(skb, opt, inet->daddr, rt, 0);
 	}
-
+#ifdef CONFIG_IP_IPSEC
+	ipsec4_out_ah_calc(skb->nh.iph, authhdr, policy_ptr);
+#endif
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 		       ip_queue_xmit2);
 
+#ifdef CONFIG_IP_IPSEC
+	ipsec4_out_finish(policy_ptr);
+#endif
+
 no_route:
 	IP_INC_STATS(IpOutNoRoutes);
 	kfree_skb(skb);
 	return -EHOSTUNREACH;
 }
 
+#ifdef CONFIG_IP_IPSEC
+static int ipsec4_getfrag(const void *data, char *buff, unsigned int offset, unsigned int len)
+{
+        memcpy(buff, ((char*)data)+offset, len);
+        return 0;
+}
+#endif
+
 /*
  *	Build and send a packet, with as little as one copy
  *
@@ -453,7 +549,13 @@
 		  unsigned length,
 		  struct ipcm_cookie *ipc,
 		  struct rtable *rt,
-		  int flags)
+		  int flags
+#ifdef CONFIG_IP_IPSEC
+		,struct ipsec_sp *policy_ptr
+		,int ipsec_action
+		,int protocol
+#endif
+)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	unsigned int fraglen, maxfraglen, fragheaderlen;
@@ -467,12 +569,63 @@
 	struct ip_options *opt = ipc->opt;
 	int df = 0;
 
+#if CONFIG_IP_IPSEC
+	struct ip_auth_hdr *authhdr = NULL;
+	char* tmpdata = NULL;
+#endif
+
 	mtu = rt->u.dst.pmtu;
 	if (ip_dont_fragment(sk, &rt->u.dst))
 		df = htons(IP_DF);
 
 	length -= sizeof(struct iphdr);
 
+#if CONFIG_IP_IPSEC
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		struct inet_opt *inet = inet_sk(sk);
+		struct iphdr *iph = NULL;
+		int ah_len = ipsec4_out_get_ahsize(policy_ptr);
+		int tot_len = sizeof(struct iphdr) + ah_len + length;
+		if (opt)
+			tot_len += opt->optlen;
+
+		tmpdata = kmalloc(tot_len, GFP_ATOMIC);
+		if (!tmpdata) {
+				return -ENOMEM;
+		}
+			
+		iph = (struct iphdr*)tmpdata;
+		iph->version=4;
+		iph->ihl=5 + (opt ? opt->optlen : 0);
+		iph->tos=inet->tos;
+		iph->tot_len = htons(tot_len);
+		iph->frag_off = htons(IP_MF) | df;
+		if (rt->rt_type != RTN_MULTICAST)
+			iph->ttl=inet->ttl;
+		iph->protocol=protocol;
+		iph->saddr=rt->rt_src;
+		iph->daddr=rt->rt_dst;
+		iph->check=0;
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+		iph->ttl=inet->mc_ttl;
+		authhdr = (struct ip_auth_hdr*)(tmpdata + iph->ihl*4);
+		authhdr->nexthdr  = protocol;
+		authhdr->hdrlen   = (ah_len >> 2) - 2;
+		authhdr->reserved = 0;
+		iph->protocol = IPPROTO_AH;
+
+		err = getfrag(frag, tmpdata+iph->ihl*4+ah_len, 0, length); 
+		if (err) {
+			goto error;
+		}
+
+		getfrag = ipsec4_getfrag;
+		frag = authhdr;
+		length += ah_len;
+		protocol = IPPROTO_AH;
+	}
+#endif
+
 	if (opt) {
 		fragheaderlen = sizeof(struct iphdr) + opt->optlen;
 		maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
@@ -601,12 +754,22 @@
 				 *	Any further fragments will have MF set.
 				 */
 				mf = htons(IP_MF);
+#ifdef CONFIG_IP_IPSEC
+				if (ipsec_action & IPSEC_ACTION_AUTH) {
+					((struct iphdr *)tmpdata)->id = id;
+					ipsec4_out_ah_calc((struct iphdr*)tmpdata, authhdr, policy_ptr);
+				}
+#endif
 			}
 			if (rt->rt_type == RTN_MULTICAST)
 				iph->ttl = inet->mc_ttl;
 			else
 				iph->ttl = inet->ttl;
+#ifdef CONFIG_IP_IPSEC
+			iph->protocol = protocol;
+#else
 			iph->protocol = sk->protocol;
+#endif
 			iph->check = 0;
 			iph->saddr = rt->rt_src;
 			iph->daddr = rt->rt_dst;
@@ -639,12 +802,21 @@
 		}
 	} while (offset >= 0);
 
+#if CONFIG_IP_IPSEC
+	if (tmpdata)
+		kfree(tmpdata);
+#endif
+
 	if (nfrags>1)
 		ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates += nfrags;
 out:
 	return 0;
 
 error:
+#if CONFIG_IP_IPSEC
+	if (tmpdata) 
+		kfree(tmpdata);
+#endif
 	IP_INC_STATS(IpOutDiscards);
 	if (nfrags>1)
 		ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates += nfrags;
@@ -670,7 +842,83 @@
 	struct sk_buff *skb;
 	int df;
 	struct iphdr *iph;
+	u16 ah_len = 0;
+#if CONFIG_IP_IPSEC
+	u8  protocol = sk->protocol;
+	void *newdata = NULL;
+	char *dummyhdr = NULL;
+	unsigned int newlength = 0;
+	int ipsec_action =  0;
+	struct ipsec_sp *policy_ptr = NULL;
+	struct ip_auth_hdr *authhdr = NULL;
+
+	ipsec_action = ipsec4_output_check(sk, rt, &policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *olddata = NULL;
+		olddata = kmalloc(length, GFP_ATOMIC);
+		if (!olddata) {
+			err = -ENOMEM;
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Could not get memory for ESP (olddata)\n");
+			goto out;
+		}
+
+		err = getfrag(frag, olddata, 0, length);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Could nog get data for ESP (olddata)\n");
+			kfree(olddata);
+			goto out;
+		}
+
+		if(!inet->hdrincl) {
+			ipsec4_out_enc(olddata, length, protocol, &newdata, &newlength, policy_ptr);
+			if (newdata) {
+				frag = newdata;
+				length = newlength;
+				getfrag = ipsec4_getfrag; /* needs this function for Ipv4 */
+				protocol = IPPROTO_ESP;
+			} else {
+				kfree(olddata);
+				goto out;
+			}
+		} else {
+			int hdrlen = ((struct iphdr*)olddata)->ihl * 4;
+			protocol = ((struct iphdr*)olddata)->protocol;
+			ipsec4_out_enc(olddata + hdrlen, length - hdrlen, protocol, &newdata, &newlength, policy_ptr);
+			if (newdata) {
+				char* tmpdata = kmalloc(hdrlen + newlength, GFP_ATOMIC);
+				if (!tmpdata) {
+					kfree(olddata);
+					kfree(newdata);
+					goto out;
+				}
+				memcpy(tmpdata, olddata, hdrlen);
+				memcpy(tmpdata + hdrlen, newdata, newlength);
 
+				((struct iphdr*)tmpdata)->protocol = IPPROTO_ESP;
+				((struct iphdr*)tmpdata)->tot_len = htons(hdrlen + newlength);
+				ip_send_check((struct iphdr*)tmpdata);
+
+				frag = tmpdata;
+				length = hdrlen + newlength;
+				getfrag = ipsec4_getfrag; /* needs this function for Ipv4 */
+				kfree(newdata);
+				newdata = tmpdata;
+			} else {
+				kfree(olddata);
+				goto out;
+			}
+		}
+
+		kfree(olddata);
+	}
+
+	if (ipsec_action & IPSEC_ACTION_AUTH)
+		ah_len = ipsec4_out_get_ahsize(policy_ptr);
+
+#endif
 	/*
 	 *	Try the simple case first. This leaves fragmented frames, and by
 	 *	choice RAW frames within 20 bytes of maximum size(rare) to the long path
@@ -683,7 +931,12 @@
 		 * 	Check for slow path.
 		 */
 		if (length > rt->u.dst.pmtu || ipc->opt != NULL)  
+#ifdef CONFIG_IP_IPSEC
+			return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags,
+					policy_ptr, ipsec_action, protocol);
+#else
 			return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags); 
+#endif
 	} else {
 		if (length > rt->u.dst.dev->mtu) {
 			ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport,
@@ -707,7 +960,7 @@
 	{
 	int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 
-	skb = sock_alloc_send_skb(sk, length+hh_len+15,
+	skb = sock_alloc_send_skb(sk, length+hh_len+15+ah_len,
 				  flags&MSG_DONTWAIT, &err);
 	if(skb==NULL)
 		goto error; 
@@ -717,6 +970,10 @@
 	skb->priority = sk->priority;
 	skb->dst = dst_clone(&rt->u.dst);
 
+#ifdef CONFIG_IP_IPSEC
+	if (ipsec_action & IPSEC_ACTION_AUTH)
+		dummyhdr = skb_put(skb, ah_len);
+#endif
 	skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
 
 	if (!inet->hdrincl) {
@@ -729,16 +986,43 @@
 		ip_select_ident(iph, &rt->u.dst, sk);
 		if (rt->rt_type != RTN_MULTICAST)
 			iph->ttl = inet->ttl;
+#ifdef CONFIG_IP_IPSEC
+		iph->protocol=protocol;
+#else
 		iph->protocol=sk->protocol;
+#endif
 		iph->saddr=rt->rt_src;
 		iph->daddr=rt->rt_dst;
 		iph->check=0;
 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 		err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
 	}
-	else
+	else {
 		err = getfrag(frag, (void *)iph, 0, length);
 
+		if (err)
+			goto error_fault;
+#ifdef CONFIG_IP_IPSEC
+		protocol = iph->protocol;
+#endif
+	}
+
+#ifdef CONFIG_IP_IPSEC
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		protocol = iph->protocol;
+		iph->protocol = IPPROTO_AH;
+		memcpy(dummyhdr, iph, iph->ihl * 4);
+		authhdr = (struct ip_auth_hdr*)(((char*)dummyhdr) + iph->ihl * 4);
+		skb->nh.iph = iph = (struct iphdr*)dummyhdr;
+		authhdr->nexthdr = protocol;
+		authhdr->hdrlen = (ah_len >> 2) - 2;
+		authhdr->reserved = 0;
+		iph->tot_len = htons(ntohs(iph->tot_len) + ah_len);
+		ipsec4_out_ah_calc(skb->nh.iph, authhdr, policy_ptr);
+		ip_send_check(iph);
+	}
+#endif
+
 	if (err)
 		goto error_fault;
 
@@ -749,6 +1033,10 @@
 	if (err)
 		goto error;
 out:
+#ifdef CONFIG_IP_IPSEC
+	ipsec4_out_finish(policy_ptr);
+	if (newdata) kfree(newdata);
+#endif
 	return 0;
 
 error_fault:
diff -uNr -x CVS linux-2.5.43/net/ipv4/ipsec4_input.c linux25.43-ipsec/net/ipv4/ipsec4_input.c
--- linux-2.5.43/net/ipv4/ipsec4_input.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/ipsec4_input.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,622 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysctl.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/smp.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+#include <net/addrconf.h>
+#include <net/snmp.h>  
+#include <linux/in.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h> /* sa proto type */
+#include <linux/pfkey.h>
+
+/* XXX must insert window size  sa_replay_window member */
+static int check_replay_window(struct sa_replay_window *rw, __u32 hdrseq)
+{	
+	__u32 diff;
+	__u32 seq = ntohl(hdrseq);
+
+	if (!sysctl_ipsec_replay_window) {
+		IPSEC4_DEBUG("disable replay window check, skip!\n");
+		return 1;
+	}
+
+	IPSEC4_DEBUG("overflow: %u\n" 
+		     "    size: %u\n" 
+		     " seq_num: %x\n" 
+		     "last_seq: %x\n" 
+		     "  bitmap: %08x\n" 
+		     " curr seq: %x\n",
+			rw->overflow, rw->size, rw->seq_num, rw->last_seq, rw->bitmap, seq);
+	if (seq == 0) {
+		return 0; /* first == 0 or wrapped */
+	}
+
+	if (seq > rw->last_seq) return 1; /* larger is good */
+
+	diff = rw->last_seq - seq;
+
+	if (diff >= rw->size) {
+		return 0; /* too old or wrapped */
+	}
+
+	if ( rw->bitmap & ((u_long)1 << diff) ) {
+		return 0; /* already seen */
+	}
+
+	return 1; /* out of order but good */
+}
+
+static void update_replay_window(struct sa_replay_window *rw, __u32 hdrseq)
+{
+	__u32 diff;
+	__u32 seq = ntohl(hdrseq);
+
+	if (!sysctl_ipsec_replay_window) {
+		IPSEC4_DEBUG("disable replay window check, skip!\n");
+		return;
+	}
+
+	if (seq == 0) return;
+
+	if (seq > rw->last_seq) { /* new larger sequence number */
+		diff = seq - rw->last_seq;
+		if (diff < rw->size) {  /* In window */
+			rw->bitmap <<= diff;
+			rw->bitmap |= 1; /* set bit for this packet */
+		} else {
+			rw->bitmap = 1; /* This packet has a "way larger" */
+		}
+
+		rw->last_seq = seq;
+	}
+
+	diff = rw->last_seq - seq;
+	rw->bitmap |= ((u_long)1 << diff); /* mark as seen */
+}
+
+static int ipsec4_input_check_ah(struct sk_buff **skb, struct ip_auth_hdr *authhdr, struct sa_index *sa_idx, u8 *nexthdr)
+{
+	int rtn = 0;
+	__u8* authdata;
+	size_t authsize;
+	char *packet;
+	int offset;
+	struct ip_auth_hdr *pseudo_authhdr = NULL;
+
+	IPSEC4_DEBUG("start auth header processing\n");
+
+	if (!((*skb)&&authhdr)) {
+		IPSEC4_DEBUG("parameters is invalid\n");
+		rtn = -EINVAL;
+		goto finish;
+	}
+
+	/* Check SPI */
+	IPSEC4_DEBUG("authhdr->spi is 0x%x\n", ntohl(authhdr->spi));
+
+	sa_index_init(sa_idx);
+	((struct sockaddr_in *)&sa_idx->dst)->sin_addr.s_addr = (*skb)->nh.iph->daddr;
+	((struct sockaddr_in *)&sa_idx->dst)->sin_family = AF_INET;
+	sa_idx->prefixlen_d = 32;
+	sa_idx->ipsec_proto = SADB_SATYPE_AH;
+	sa_idx->spi = authhdr->spi;
+
+	sa_idx->sa = sadb_find_by_sa_index(sa_idx);
+
+	if (!sa_idx->sa) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d AH %d): Can't find SA\n",
+			       NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr),
+			       ntohs(sa_idx->spi));
+		}
+		rtn = -EINVAL;
+		goto finish;
+	}
+
+	write_lock_bh(&sa_idx->sa->lock);
+
+	if (sa_idx->sa->auth_algo.algo == SADB_AALG_NONE ) {
+		if (net_ratelimit())
+			IPSEC4_DEBUG("not found auth algo.\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	if (!check_replay_window(&sa_idx->sa->replay_window, authhdr->seq_no)) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d AH %d): Replay check error\n",
+				NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr), 
+				ntohs(sa_idx->spi));
+		}
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	authsize = ntohs((*skb)->nh.iph->tot_len);
+
+	if (authsize > (*skb)->len + ((char*)(*skb)->data - (char*)(*skb)->nh.iph)) {
+		if (net_ratelimit())
+			IPSEC4_DEBUG("the packet length is wrong\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	packet = kmalloc(((authsize + 3) & ~3) + 
+			sa_idx->sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+	if (!packet) {
+		if (net_ratelimit())
+			IPSEC4_DEBUG("can't get memory for pakcet\n");
+		rtn = -ENOMEM;
+		goto unlock_finish;
+	}
+	authdata = packet + ((authsize + 3) & ~3);
+
+	offset = (char *)((*skb)->nh.iph) - (char *)((*skb)->data);
+
+	if (skb_copy_bits(*skb, offset, packet, authsize)) {
+		if (net_ratelimit())
+			IPSEC4_DEBUG("packet copy failed\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	((struct iphdr*)packet)->tos      = 0;
+	((struct iphdr*)packet)->frag_off = 0;
+	((struct iphdr*)packet)->ttl      = 0;
+	((struct iphdr*)packet)->check    = 0;
+
+	pseudo_authhdr = (struct ip_auth_hdr*)(packet + (((char*)authhdr) - ((char*)(*skb)->nh.iph)));
+	memset(&pseudo_authhdr->auth_data[0], 0, ((authhdr->hdrlen - 1) << 2));
+
+	sa_idx->sa->auth_algo.dx->di->hmac_atomic(sa_idx->sa->auth_algo.dx,
+			sa_idx->sa->auth_algo.key,
+			sa_idx->sa->auth_algo.key_len,
+			packet, authsize, authdata);	 
+
+	/* Originally, IABG uses "for" loop for matching authentication data.	*/
+	/* I change it into memcmp routine.					*/
+	if (memcmp(authdata, authhdr->auth_data, sa_idx->sa->auth_algo.digest_len)) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d AH %d): Invalid checksum\n",
+			       NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr), 
+			       ntohs(sa_idx->spi));
+		}
+		kfree(packet);
+		rtn = IPSEC_ACTION_DROP;
+		goto unlock_finish;
+	}
+	kfree(packet);
+
+	rtn = IPSEC_ACTION_AUTH;
+	*nexthdr = authhdr->nexthdr;
+	update_replay_window(&sa_idx->sa->replay_window, authhdr->seq_no);
+
+	(*skb)->security |= RCV_AUTH; /* ? we must rewrite linux/ipsec.h */
+	{
+		int authhdrlen = (authhdr->hdrlen + 2) << 2;
+		int payloadlen = (*skb)->len - (*skb)->data_len - authhdrlen;
+		IPSEC4_DEBUG("authhdrlen=%d, payloadlen=%d\n", authhdrlen, payloadlen);
+		if (payloadlen > 0) {
+			memmove(authhdr, ((char*)authhdr) + authhdrlen, payloadlen);
+			(*skb)->len -= authhdrlen;
+			(*skb)->nh.iph->protocol = *nexthdr;
+			(*skb)->nh.iph->tot_len = htons(ntohs((*skb)->nh.iph->tot_len) - authhdrlen);			
+			(*skb)->nh.iph->check = ip_fast_csum((unsigned char*)((*skb)->nh.iph), (*skb)->nh.iph->ihl);
+		} else {
+			rtn = -EINVAL;
+			goto unlock_finish;
+		}
+	}
+
+
+	if (!sa_idx->sa->fuse_time) {
+		sa_idx->sa->fuse_time = jiffies;
+		sa_idx->sa->lifetime_c.usetime = (sa_idx->sa->fuse_time) / HZ;
+		ipsec_sa_mod_timer(sa_idx->sa);
+		IPSEC4_DEBUG("set fuse_time = %lu\n", sa_idx->sa->fuse_time);
+	}
+	sa_idx->sa->lifetime_c.bytes += (*skb)->tail - (*skb)->head;
+	IPSEC4_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa_idx->sa->lifetime_c.bytes) >> 32), (__u32)(sa_idx->sa->lifetime_c.bytes));
+	if (sa_idx->sa->lifetime_c.bytes >= sa_idx->sa->lifetime_s.bytes && sa_idx->sa->lifetime_s.bytes) {
+		sa_idx->sa->state = SADB_SASTATE_DYING;
+		IPSEC4_DEBUG("change sa state DYING\n");
+	}
+	if (sa_idx->sa->lifetime_c.bytes >= sa_idx->sa->lifetime_h.bytes && sa_idx->sa->lifetime_h.bytes) {
+		sa_idx->sa->state = SADB_SASTATE_DEAD;
+		IPSEC4_DEBUG("change sa state DEAD\n");
+	}
+
+unlock_finish:
+	write_unlock_bh(&sa_idx->sa->lock);  /* unlock SA */
+	ipsec_sa_put(sa_idx->sa);
+finish:
+	return rtn;
+}
+
+static int ipsec4_input_check_esp(struct sk_buff **skb, struct ip_esp_hdr* esphdr, struct sa_index *sa_idx, u8 *nexthdr)
+{
+	int len = 0;
+	int rtn = IPSEC_ACTION_DROP;
+	u8 *authdata = NULL;
+	u8 *srcdata = NULL;
+	int srcsize = 0, totalsize = 0, hashsize = 0, encsize = 0;
+
+	IPSEC4_DEBUG("start esp processing\n");
+	if (!(*skb&&esphdr)) {
+		printk(KERN_ERR "ipsec4_input_check_esp: parameters are invalid\n");
+		goto finish;
+	}	
+
+	if (skb_is_nonlinear(*skb)) {
+		u16 offset = ((char*)esphdr) - (char*)((*skb)->nh.raw);
+		if (!skb_linearize(*skb, GFP_ATOMIC)) {
+			esphdr = (struct ip_esp_hdr*)((*skb)->nh.raw + offset);
+		} else {
+			printk(KERN_ERR "ipsec4_input_check_esp: counld not linearize skb\n");
+			rtn = -EINVAL;
+			goto finish;
+		} 
+	}
+
+	/* Check SPI */
+	IPSEC4_DEBUG("esphdr->spi is 0x%x\n", ntohl(esphdr->spi));
+
+	sa_index_init(sa_idx);
+	((struct sockaddr_in *)&sa_idx->dst)->sin_addr.s_addr = (*skb)->nh.iph->daddr;
+	((struct sockaddr_in *)&sa_idx->dst)->sin_family = AF_INET;
+	sa_idx->prefixlen_d = 32;
+	sa_idx->ipsec_proto = SADB_SATYPE_ESP;
+	sa_idx->spi = esphdr->spi;
+
+	sa_idx->sa = sadb_find_by_sa_index(sa_idx);
+
+	if (!sa_idx->sa) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: (%d.%d.%d.%d ESP %d) Can't find SA\n",
+			       NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr), 
+			       sa_idx->spi);
+		}
+		rtn = -EINVAL;
+		goto finish;
+	}
+
+	write_lock_bh(&sa_idx->sa->lock);
+
+	if ( sa_idx->sa->esp_algo.algo == SADB_EALG_NONE ) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec4_input_check_esp: not found encryption algorithm in SA!\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	len = ntohs((*skb)->nh.iph->tot_len);
+
+	if (len > (*skb)->len + ((char*)(*skb)->data - (char*)(*skb)->nh.iph)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec4_input_check_esp: received packet length is wrong\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	totalsize = len - (((char*)esphdr) - ((char*)(*skb)->nh.iph));
+
+	if (!(sa_idx->sa->esp_algo.cx->ci)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec4_input_check_esp: not found esp algo\n");
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	if ( !check_replay_window(&sa_idx->sa->replay_window, esphdr->seq_no) ) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d ESP %d): Replay check error\n",
+			       NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr),
+			       sa_idx->spi);
+		}
+		kfree(srcdata);
+		rtn = -EINVAL;
+		goto unlock_finish;
+	}
+
+	encsize = totalsize - sa_idx->sa->esp_algo.cx->ci->ivsize - 8;
+							/* 8 = SPI + Sequence Number */	
+
+	if ( sa_idx->sa->auth_algo.algo != SADB_AALG_NONE ) {
+		/* Calculate size */
+		/* The tail of payload does not have to be aligned		*/
+		/* with a multiple number of 64 bit.				*/
+		/* 64 bit alignment is adapted to the position of top of header.*/
+		hashsize = sa_idx->sa->auth_algo.digest_len;
+		encsize -= hashsize;
+		authdata=kmalloc(sa_idx->sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+		sa_idx->sa->auth_algo.dx->di->hmac_atomic(sa_idx->sa->auth_algo.dx,
+			sa_idx->sa->auth_algo.key,
+			sa_idx->sa->auth_algo.key_len,
+			(char*)esphdr, totalsize - hashsize, authdata);	 
+		/* Originally, IABG uses "for" loop for matching authentication data. */
+		/* I change it into memcmp routine. */
+
+		if (memcmp(authdata, &((char*)esphdr)[totalsize - hashsize],
+				sa_idx->sa->auth_algo.digest_len )) {
+			if (net_ratelimit()) {
+				printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d ESP %d): Invalid checksum\n",
+				       NIPQUAD(((struct sockaddr_in*)&sa_idx->dst)->sin_addr), sa_idx->spi);
+			}
+			kfree(authdata);
+			rtn = IPSEC_ACTION_DROP;
+			goto unlock_finish;
+		}
+		kfree(authdata);
+		authdata = NULL;
+	}
+
+	/* Decrypt data */
+	srcdata = kmalloc(encsize, GFP_ATOMIC);
+	if (!srcdata) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec4_input_check_esp: can't allocate memory for decrypt\n");
+		rtn = -ENOMEM;
+		goto unlock_finish;
+	}
+
+	IPSEC4_DEBUG("len=%d, totalsize=%d, encsize=%d\n",
+			len, totalsize, encsize);
+
+	if (!(sa_idx->sa->esp_algo.iv)) { /* first packet */
+		sa_idx->sa->esp_algo.iv = kmalloc(sa_idx->sa->esp_algo.cx->ci->ivsize, GFP_ATOMIC);
+	}
+
+	memcpy(sa_idx->sa->esp_algo.iv, esphdr->enc_data, sa_idx->sa->esp_algo.cx->ci->ivsize);
+	sa_idx->sa->esp_algo.cx->ci->decrypt_atomic_iv(sa_idx->sa->esp_algo.cx,
+			((u8 *)(esphdr->enc_data)) + sa_idx->sa->esp_algo.cx->ci->ivsize,
+			srcdata, encsize, sa_idx->sa->esp_algo.iv);
+
+	/* encsize - (pad_len + next_hdr) - pad_len */
+	srcsize = encsize - 2 - srcdata[encsize-2];
+	IPSEC4_DEBUG("Original data is srcsize=%d, padlength=%d\n", srcsize, srcdata[encsize-2]);
+	if (srcsize <= 0) {
+		if (net_ratelimit()) {
+			printk(KERN_ERR "IPSEC: SA(%d.%d.%d.%d ESP %d):Decrypted packet contains garbage\n",
+			       NIPQUAD(((struct sockaddr_in *)&sa_idx->dst)->sin_addr), sa_idx->spi);
+		}
+		kfree(srcdata);
+		rtn = IPSEC_ACTION_DROP;
+		goto unlock_finish;
+	}
+
+	update_replay_window(&sa_idx->sa->replay_window, esphdr->seq_no);
+
+	memcpy(esphdr, srcdata, srcsize);
+
+	(*skb)->nh.iph->protocol = *nexthdr = srcdata[encsize-1];
+	(*skb)->nh.iph->tot_len = htons(ntohs((*skb)->nh.iph->tot_len) - 10 - srcdata[encsize]);			
+							/* 10 = sizeof(struct ip_esp_hdr) - 8 + 2 */
+	(*skb)->nh.iph->check = ip_fast_csum((unsigned char*)((*skb)->nh.iph), (*skb)->nh.iph->ihl);
+
+	skb_trim(*skb, (*skb)->len +  srcsize - totalsize);
+	(*skb)->nh.iph->tot_len = htons(((char *)esphdr - (char *)((*skb)->nh.iph)) + srcsize);
+
+	kfree(srcdata);
+	srcdata = NULL;
+
+	rtn = IPSEC_ACTION_ESP;
+
+	/* Otherwise checksum of fragmented udp packets fails (udp.c, csum_fold) */
+	(*skb)->ip_summed = CHECKSUM_UNNECESSARY; 
+	(*skb)->security |= RCV_CRYPT;
+
+	if (!sa_idx->sa->fuse_time) {
+		sa_idx->sa->fuse_time = jiffies;
+		sa_idx->sa->lifetime_c.usetime = (sa_idx->sa->fuse_time) / HZ;
+		ipsec_sa_mod_timer(sa_idx->sa);
+		IPSEC4_DEBUG("set fuse_time = %lu\n", (sa_idx->sa->fuse_time));
+	}
+	sa_idx->sa->lifetime_c.bytes += totalsize;
+	IPSEC4_DEBUG("sa->bytes=%-9u %-9u\n",			/* XXX: %-18Lu */
+			(__u32)((sa_idx->sa->lifetime_c.bytes) >> 32), (__u32)(sa_idx->sa->lifetime_c.bytes));
+	if (sa_idx->sa->lifetime_c.bytes >= sa_idx->sa->lifetime_s.bytes && sa_idx->sa->lifetime_s.bytes) {
+		sa_idx->sa->state = SADB_SASTATE_DYING;
+		IPSEC4_DEBUG("change sa state DYING\n");
+	}
+	if (sa_idx->sa->lifetime_c.bytes >= sa_idx->sa->lifetime_h.bytes && sa_idx->sa->lifetime_h.bytes) {
+		sa_idx->sa->state = SADB_SASTATE_DEAD;
+		IPSEC4_DEBUG("change sa state DEAD\n");
+	}
+
+
+unlock_finish:
+	write_unlock_bh(&sa_idx->sa->lock); /* unlock SA */
+	ipsec_sa_put(sa_idx->sa);
+		
+finish:
+	return rtn;
+}
+
+int ipsec4_input_check(struct sk_buff **skb)
+{
+	int rtn = 0;
+	int result = IPSEC_ACTION_BYPASS;
+	u8 nexthdr = (*skb)->nh.iph->protocol;
+	struct sa_index auth_sa_idx;
+	struct sa_index esp_sa_idx;
+	struct selector selector;
+	struct ipsec_sp *policy = NULL;
+	struct iphdr *hdr = (*skb)->nh.iph;
+
+	IPSEC4_DEBUG("called\n");
+#ifdef CONFIG_IPSEC_DEBUG
+	IPSEC4_DEBUG("src addr: %d.%d.%d.%d\n", NIPQUAD(hdr->saddr));
+	IPSEC4_DEBUG("dst addr: %d.%d.%d.%d\n", NIPQUAD(hdr->daddr));
+	IPSEC4_DEBUG("hdr->tot_len is %d\n", ntohs(hdr->tot_len)); 
+#endif /* CONFIG_IPSEC_DEBUG */
+	
+	if ( hdr->protocol == IPPROTO_UDP ) { /* IKE */
+		if (pskb_may_pull(*skb, (*skb)->h.raw - (*skb)->data + sizeof(struct udphdr))) {
+			if ((*skb)->h.uh->source == __constant_htons(500)
+				 && (*skb)->h.uh->dest == __constant_htons(500)) {
+					IPSEC4_DEBUG("received IKE packet. skip!\n");
+					goto finish;
+			}
+		}
+	}
+
+
+	if (nexthdr == IPPROTO_AH) {
+		result |= ipsec4_input_check_ah(skb, (struct ip_auth_hdr*)((*skb)->h.raw), &auth_sa_idx, &nexthdr);
+	}
+
+	if (nexthdr == IPPROTO_ESP) {
+		result |= ipsec4_input_check_esp(skb, (struct ip_esp_hdr*)((*skb)->h.raw), &esp_sa_idx, &nexthdr);
+	}
+
+	if (result&IPSEC_ACTION_DROP) {
+		IPSEC4_DEBUG("result is drop.\n");
+		rtn = -EINVAL;
+		goto finish;
+	}
+
+	/* copy selector XXX port */
+	memset(&selector, 0, sizeof(struct selector));
+	
+#if 0	/* ipsec4 tunnel mode: not yet */
+	if (nexthdr == IPPROTO_IPIP)
+		selector.mode = IPSEC_MODE_TUNNEL;
+#endif
+	selector.proto = nexthdr;
+
+	IPSEC4_DEBUG("nexthdr = %u\n", nexthdr);
+
+	((struct sockaddr_in *)&selector.src)->sin_family = AF_INET;
+	((struct sockaddr_in *)&selector.src)->sin_addr.s_addr = (*skb)->nh.iph->saddr;
+	((struct sockaddr_in *)&selector.dst)->sin_family = AF_INET;
+	((struct sockaddr_in *)&selector.dst)->sin_addr.s_addr = (*skb)->nh.iph->daddr;
+	selector.prefixlen_d = 32;
+	selector.prefixlen_s = 32;
+
+	/* beggining of matching check selector and policy */
+	IPSEC4_DEBUG("start match check SA and policy.\n");
+
+#ifdef CONFIG_IPSEC_DEBUG
+	IPSEC4_DEBUG("selector dst addr: %d.%d.%d.%d\n", 
+		     NIPQUAD(((struct sockaddr_in *)&selector.dst)->sin_addr));
+	IPSEC4_DEBUG("selector src addr: %d.%d.%d.%d\n", 
+		     NIPQUAD(((struct sockaddr_in *)&selector.src)->sin_addr));
+#endif /* CONFIG_IPSEC_DEBUG */
+	policy = spd_get(&selector);
+		
+	if (policy) {
+
+		read_lock_bh(&policy->lock);
+
+		/* non-ipsec packet processing: If this packet doesn't
+		 * have any IPSEC headers, then consult policy to see
+		 * what to do with packet. If policy says to apply IPSEC,
+		 * and there is an SA, then pass packet to netxt layer,
+		 * if ther isn't an SA, then drop the packet.
+		 */
+		if (policy->policy_action == IPSEC_POLICY_DROP) {
+			rtn = -EINVAL;
+			read_unlock_bh(&policy->lock);
+			IPSEC4_DEBUG("a policy is drop, drop packet!\n"); 
+			goto finish;
+		}
+
+		if (policy->policy_action == IPSEC_POLICY_BYPASS) {
+			rtn = 0;
+			read_unlock_bh(&policy->lock);
+			IPSEC4_DEBUG("a policy is bypass, through!\n"); 
+			goto finish;
+		}
+
+		if (policy->policy_action == IPSEC_POLICY_APPLY) {
+			if (result&IPSEC_ACTION_AUTH) {
+				if (policy->auth_sa_idx) {
+					if (sa_index_compare(&auth_sa_idx, policy->auth_sa_idx)) {
+						rtn = -EINVAL;
+					}
+				} else {
+					rtn = -EINVAL;
+				}
+			} else {
+				if (policy->auth_sa_idx) {
+					rtn = -EINVAL;
+				}
+			}
+
+			if (result&IPSEC_ACTION_ESP) {
+				if (policy->esp_sa_idx) {
+					if (sa_index_compare(&esp_sa_idx, policy->esp_sa_idx)) {
+						rtn = -EINVAL;
+					}
+				} else {
+					rtn = -EINVAL;
+				}
+			} else {
+				if (policy->esp_sa_idx) {
+					rtn = -EINVAL;
+				}
+			}
+			IPSEC4_DEBUG("matching piar of SA and policy, through=%d\n", rtn); 
+		}
+
+		read_unlock_bh(&policy->lock);
+		ipsec_sp_put(policy);
+	} else {
+		if (!result) {
+			rtn = 0;
+		} else {
+			IPSEC4_DEBUG("matching pair of SA and policy not found, through!\n"); 
+			rtn = -EINVAL;
+			goto finish;		
+		}
+	}
+
+	IPSEC4_DEBUG("end match check SA and policy.\n");
+	/* end of matching check selector and policy */
+
+
+finish:
+
+	return rtn;
+}
+
diff -uNr -x CVS linux-2.5.43/net/ipv4/ipsec4_output.c linux25.43-ipsec/net/ipv4/ipsec4_output.c
--- linux-2.5.43/net/ipv4/ipsec4_output.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/ipsec4_output.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,673 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysctl.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/smp.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <net/ipv6.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+#include <net/addrconf.h>
+#include <net/snmp.h>  
+#include <linux/in.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h> /* sa proto type */
+#include <linux/pfkey.h>
+
+/*
+	We assume iph and authder is on continuous buffer. 
+*/
+int ipsec4_out_ah_calc(struct iphdr *iph, struct ip_auth_hdr *authhdr, struct ipsec_sp *policy)
+{
+	struct ipsec_sa *sa = NULL;
+	struct ip_auth_hdr *pseudo_authhdr = NULL;
+	char* pseudo_packet = NULL;
+	int packetlen = 0;
+	__u8* authdata = NULL;
+	
+	IPSEC4_DEBUG("called.\n");
+	if(!policy){
+		return -EINVAL;
+	}
+
+	if (!iph) {
+		IPSEC4_DEBUG("iph is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (!authhdr) {
+		authhdr = (struct ip_auth_hdr*)(((char*)iph) + iph->ihl*4);
+	}
+
+	read_lock_bh(&policy->lock);
+
+	if (!policy->auth_sa_idx || !policy->auth_sa_idx->sa) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(ah) SA missing.\n", __FUNCTION__);
+		read_unlock_bh(&policy->lock);
+		return -EINVAL;
+	}
+
+	ipsec_sa_hold(policy->auth_sa_idx->sa);
+	sa = policy->auth_sa_idx->sa;
+
+	read_unlock_bh(&policy->lock);
+
+	packetlen = ntohs(iph->tot_len);
+
+	pseudo_packet = kmalloc(packetlen,GFP_ATOMIC);
+	if (!pseudo_packet) {
+		ipsec_sa_put(sa);
+		return -ENOMEM;
+	}
+
+	pseudo_authhdr = (struct ip_auth_hdr*)(pseudo_packet + (((char*)authhdr) - ((char*)iph)));
+
+	authdata=kmalloc((sa->auth_algo.dx)->di->blocksize, GFP_ATOMIC);
+	if (!authdata) {
+		kfree(pseudo_packet);
+		ipsec_sa_put(sa);
+		return -ENOMEM;
+	}
+
+	write_lock_bh(&sa->lock);
+
+	/* authhdr->spi = htonl(sa->spi); */
+	IPSEC4_DEBUG("spi is 0x%x\n", ntohl(sa->spi));
+	authhdr->spi = sa->spi; /* -mk */
+	authhdr->seq_no = htonl(++sa->replay_window.seq_num);
+
+	memcpy(pseudo_packet,iph,packetlen);
+	memset(&pseudo_authhdr->auth_data[0], 0, (authhdr->hdrlen -1) << 2);
+
+	pseudo_authhdr->spi = authhdr->spi;
+	pseudo_authhdr->seq_no = authhdr->seq_no;
+
+	((struct iphdr*)pseudo_packet)->tos      = 0;
+	((struct iphdr*)pseudo_packet)->frag_off = 0;
+	((struct iphdr*)pseudo_packet)->ttl      = 0;
+	((struct iphdr*)pseudo_packet)->check    = 0;
+
+	sa->auth_algo.dx->di->hmac_atomic(sa->auth_algo.dx,
+			sa->auth_algo.key,
+			sa->auth_algo.key_len,
+			pseudo_packet, packetlen, authdata);
+
+	memcpy(authhdr->auth_data, authdata, sa->auth_algo.digest_len);
+	
+	if (!sa->fuse_time) {
+		sa->fuse_time = jiffies;
+		sa->lifetime_c.usetime = (sa->fuse_time)/HZ;
+		ipsec_sa_mod_timer(sa);
+		IPSEC4_DEBUG("set fuse_time = %lu\n", sa->fuse_time);
+	}
+
+	sa->lifetime_c.bytes += packetlen;
+	IPSEC4_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa->lifetime_c.bytes) >> 32), (__u32)(sa->lifetime_c.bytes));
+
+	if (sa->lifetime_c.bytes >= sa->lifetime_s.bytes && sa->lifetime_s.bytes) {
+		IPSEC4_DEBUG("change sa state DYING\n");
+		sa->state = SADB_SASTATE_DYING;
+	} 
+
+	if (sa->lifetime_c.bytes >= sa->lifetime_h.bytes && sa->lifetime_h.bytes) {
+		sa->state = SADB_SASTATE_DEAD;
+		IPSEC4_DEBUG("change sa state DEAD\n");
+	}
+
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+
+	kfree(authdata);
+	kfree(pseudo_packet); 
+	return 0;
+}
+
+int ipsec4_out_get_ahsize(struct ipsec_sp *policy)
+{
+	int result = 0;
+	struct ipsec_sa *sa_ah = NULL;
+
+	IPSEC4_DEBUG("called.\n");
+
+	if (!policy) return 0;
+
+	write_lock_bh(&policy->lock);
+	if (policy->auth_sa_idx && policy->auth_sa_idx->sa) {
+		ipsec_sa_hold(policy->auth_sa_idx->sa);
+		sa_ah = policy->auth_sa_idx->sa;
+	}
+
+	write_unlock_bh(&policy->lock);
+
+	if (sa_ah) {
+		read_lock_bh(&sa_ah->lock);
+		if ( sa_ah->auth_algo.algo != SADB_AALG_NONE) {
+			result += (offsetof(struct ip_auth_hdr, auth_data) + 
+					sa_ah->auth_algo.digest_len + 7) & ~7;	/* 64 bit alignment */
+		}
+		read_unlock_bh(&sa_ah->lock);
+		ipsec_sa_put(sa_ah);
+	}
+
+	IPSEC4_DEBUG("Calculated size is %d.\n", result);
+	return result;
+}
+
+int ipsec4_out_get_espsize(struct ipsec_sp *policy)
+{
+	int result = 0;
+	struct ipsec_sa *sa_esp = NULL;
+
+	IPSEC4_DEBUG("called.\n");
+
+	if (!policy) return 0;
+
+	write_lock_bh(&policy->lock);
+
+	if (policy->esp_sa_idx && policy->esp_sa_idx->sa) {
+		ipsec_sa_hold(policy->esp_sa_idx->sa);
+		sa_esp = policy->esp_sa_idx->sa;
+	}
+	write_unlock_bh(&policy->lock);
+
+	if (sa_esp) {
+		read_lock_bh(&sa_esp->lock);
+		if ( sa_esp->esp_algo.algo != SADB_EALG_NONE){
+			result += sizeof(struct ip_esp_hdr) - 8;
+			result += sa_esp->esp_algo.cx->ci->ivsize;
+			result += (sa_esp->esp_algo.cx->ci->blocksize + 3) & ~3;
+			result += 4;	/* included pad_len and next_hdr  32 bit align */
+		}else{
+			read_unlock_bh(&sa_esp->lock);
+			ipsec_sa_put(sa_esp);
+			return 0;
+		}
+		if ( sa_esp->auth_algo.algo != SADB_AALG_NONE) {
+			result += (sa_esp->auth_algo.digest_len + 3) & ~3;	/* 32 bit alignment */
+		}
+		read_unlock_bh(&sa_esp->lock);
+		ipsec_sa_put(sa_esp);
+	}
+	IPSEC4_DEBUG("Calculated size is %d.\n", result);
+	return result;
+}
+
+/*** ESP ***/
+
+void ipsec4_out_enc(const void *data, unsigned length, u8 proto,
+		void **newdata, unsigned *newlength, struct ipsec_sp *policy)
+{
+	struct ipsec_sa *sa = NULL;
+	struct ip_esp_hdr *esphdr = NULL;
+	u8* srcdata = NULL;
+	u8* authdata = NULL;
+	int encblocksize = 0;
+	int encsize = 0, hashsize = 0, totalsize = 0;
+	int i;
+
+	IPSEC4_DEBUG("called.\nData ptr is %p, data length is %d.\n",data,length);
+
+	if (!policy) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s; ipsec policy is NULL\n", __FUNCTION__);
+		return;
+	}
+
+	read_lock_bh(&policy->lock);
+	if (!policy->esp_sa_idx || !policy->esp_sa_idx->sa) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) SA missing.\n", __FUNCTION__);
+		read_unlock_bh(&policy->lock);
+		return;
+	}
+	ipsec_sa_hold(policy->esp_sa_idx->sa);
+	sa = policy->esp_sa_idx->sa;
+	read_unlock_bh(&policy->lock);
+
+	write_lock_bh(&sa->lock);
+	/* Get algorithms */
+	if (sa->esp_algo.algo == SADB_EALG_NONE) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) encryption algorithm not present.\n", __FUNCTION__);
+		goto unlock_finish;
+		return;
+	}
+
+
+	if (!(sa->esp_algo.cx->ci)){
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) cipher_implementation not present.\n", __FUNCTION__);
+		goto unlock_finish;
+		return;
+	}
+
+	/* Calculate size */
+
+
+	encblocksize = (sa->esp_algo.cx->ci->blocksize + 3) & ~3;
+	encsize = length + 2 + (encblocksize - 1);
+	encsize -= encsize % encblocksize;
+
+	/* The tail of payload does not have to be aligned with a multiple number of 64 bit.	*/
+	/* 64 bit alignment is adapted to the position of top of header. 			*/
+
+	if (sa->auth_algo.algo != SADB_AALG_NONE)
+		hashsize = sa->auth_algo.digest_len;
+
+
+	totalsize = sizeof(struct ip_esp_hdr) - 8 + sa->esp_algo.cx->ci->ivsize + encsize + hashsize;
+	IPSEC4_DEBUG("IV size=%d, enc size=%d hash size=%d, total size=%d\n",
+			 sa->esp_algo.cx->ci->ivsize, encsize, hashsize, totalsize);
+	
+	/* Get memory */
+	esphdr = kmalloc(totalsize, GFP_ATOMIC);
+	srcdata = kmalloc(encsize, GFP_ATOMIC);
+	if (!esphdr || !srcdata) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ipsec6_enc: Out of memory.\n");
+		if (esphdr) kfree(esphdr);
+		if (srcdata) kfree(srcdata);
+		goto unlock_finish;
+		return;
+	}
+
+	memset(esphdr, 0, totalsize);
+	memset(srcdata, 0, encsize);
+	/* Handle sequence number and fill in header fields */
+	esphdr->spi = sa->spi;
+	esphdr->seq_no = htonl(++sa->replay_window.seq_num);
+
+	/* Get source data, fill in padding and trailing fields */
+
+	memcpy(srcdata, data, length);
+	for (i = length; i < encsize-2; i++) 
+		srcdata[i] = (u8)(i-length+1);
+	srcdata[encsize-2] = (encsize-2)-length;
+	IPSEC4_DEBUG("length=%d, encsize=%d\n", length, encsize);
+	IPSEC4_DEBUG("encsize-2=%d\n", srcdata[encsize-2]);
+
+	srcdata[encsize-1] = proto;
+
+	/* Do encryption */
+
+	if (!(sa->esp_algo.iv)) { /* first packet */
+		sa->esp_algo.iv = kmalloc(sa->esp_algo.cx->ci->ivsize, GFP_ATOMIC); /* kfree at SA removed */
+		get_random_bytes(sa->esp_algo.iv, sa->esp_algo.cx->ci->ivsize);
+		IPSEC4_DEBUG("IV initilized.\n");
+	}  /* else, had inserted a stored iv (last packet block) */
+
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		int i;
+		IPSEC4_DEBUG("IV is 0x");
+		if (sysctl_ipsec_debug_ipv6) {
+			for (i=0; i < sa->esp_algo.cx->ci->ivsize ; i++) {
+				printk(KERN_DEBUG "%x", (u8)(sa->esp_algo.iv[i]));
+			}
+		}
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+	sa->esp_algo.cx->ci->encrypt_atomic_iv(sa->esp_algo.cx, srcdata,
+					(u8 *)&esphdr->enc_data + sa->esp_algo.cx->ci->ivsize, encsize, sa->esp_algo.iv);
+	memcpy(esphdr->enc_data, sa->esp_algo.iv, sa->esp_algo.cx->ci->ivsize);
+	kfree(srcdata);
+	srcdata=NULL;
+	/* copy last block for next IV (src: enc_data + ivsize + encsize - ivsize) */
+	memcpy(sa->esp_algo.iv, esphdr->enc_data + encsize, sa->esp_algo.cx->ci->ivsize);
+	/* if CONFIG_IPSEC_DEBUG isn't defined here is finish of encryption process */
+
+	if(sa->auth_algo.algo){
+		authdata = kmalloc(sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+		if (!authdata) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "ipsec6_enc: Out of memory.\n");
+			kfree(esphdr);
+			goto unlock_finish;
+			return;
+		}
+		memset(authdata, 0, sa->auth_algo.dx->di->blocksize);
+		sa->auth_algo.dx->di->hmac_atomic(sa->auth_algo.dx,
+				sa->auth_algo.key,
+				sa->auth_algo.key_len,
+				(char*)esphdr, totalsize-hashsize, authdata);
+		memcpy(&((char*)esphdr)[8 + sa->esp_algo.cx->ci->ivsize + encsize],
+			authdata, sa->auth_algo.digest_len);
+
+		kfree(authdata);
+	}	
+
+	if (!sa->fuse_time) {
+		sa->fuse_time = jiffies;
+		sa->lifetime_c.usetime = (sa->fuse_time)/HZ;
+		ipsec_sa_mod_timer(sa);
+		IPSEC4_DEBUG("set fuse_time = %lu\n", sa->fuse_time);
+	}
+	sa->lifetime_c.bytes += totalsize;
+	IPSEC4_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa->lifetime_c.bytes) >> 32), (__u32)(sa->lifetime_c.bytes));
+	if (sa->lifetime_c.bytes >= sa->lifetime_s.bytes && sa->lifetime_s.bytes) {
+		sa->state = SADB_SASTATE_DYING;
+		IPSEC4_DEBUG("change sa state DYING\n");
+	} 
+	if (sa->lifetime_c.bytes >= sa->lifetime_h.bytes && sa->lifetime_h.bytes) {
+		sa->state = SADB_SASTATE_DEAD;
+		IPSEC4_DEBUG("change sa state DEAD\n");
+	}
+
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+
+	authdata = NULL;
+	/* Set return values */
+	*newdata = esphdr;
+	*newlength = totalsize;
+	return;
+
+unlock_finish:
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+	return;
+}
+
+void ipsec4_out_finish(struct ipsec_sp *policy)
+{
+	if (policy) {
+		ipsec_sp_put(policy);
+	}
+}
+
+static int ipsec4_output_check_core(struct selector *selector, struct ipsec_sp **policy_ptr)
+{
+	int error = 0;
+	struct ipsec_sp *policy = NULL;
+	int result = IPSEC_ACTION_BYPASS; 	/* default */
+
+	IPSEC4_DEBUG("called\n");
+
+	if (!selector) {
+		IPSEC4_DEBUG("selector is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	policy = spd_get(selector);
+	if (!policy) { /* not match ! */
+		IPSEC4_DEBUG("no policy exists.\n");
+		result = IPSEC_ACTION_BYPASS;
+		goto err;
+	}
+
+	read_lock_bh(&policy->lock);
+	if (policy->policy_action == IPSEC_POLICY_DROP) {
+		result = IPSEC_ACTION_DROP;
+		read_unlock_bh(&policy->lock);
+		goto err;
+	}  else if (policy->policy_action == IPSEC_POLICY_BYPASS) {
+		result = IPSEC_ACTION_BYPASS;
+		read_unlock_bh(&policy->lock);
+		goto err;
+	}
+	
+	/* policy must then be to apply ipsec */
+	if (policy->auth_sa_idx) {
+		if (policy->auth_sa_idx->sa) {
+			struct ipsec_sa *sa = NULL;
+			ipsec_sa_hold(policy->auth_sa_idx->sa);
+			sa = policy->auth_sa_idx->sa;
+			read_unlock_bh(&policy->lock);
+
+			read_lock_bh(&sa->lock);
+			switch (sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_AUTH;
+				break;
+			default:
+				result = IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&sa->lock);
+			ipsec_sa_put(sa);
+		} else {
+			/* copy sa_idx in policy to avoid to lock SADB and SPD at the same time */
+			struct sa_index sa_idx;
+			sa_index_init(&sa_idx);
+			sa_index_copy(&sa_idx, policy->auth_sa_idx);
+			read_unlock_bh(&policy->lock);
+
+			sa_idx.sa = sadb_find_by_sa_index(&sa_idx);
+			if (sa_idx.sa) {
+				write_lock_bh(&policy->lock);
+				policy->auth_sa_idx->sa = sa_idx.sa;
+				ipsec_sa_hold(policy->auth_sa_idx->sa);
+				write_unlock_bh(&policy->lock);
+				ipsec_sa_put(sa_idx.sa);
+				result |= IPSEC_ACTION_AUTH;
+			} else {
+				/* SADB_ACQUIRE message should be thrown up to KMd */
+				result = IPSEC_ACTION_DROP;
+			}
+		}
+	} else {
+		read_unlock_bh(&policy->lock);
+	}
+
+	read_lock_bh(&policy->lock);
+	if (policy->esp_sa_idx) {
+		if (policy->esp_sa_idx->sa) {
+			struct ipsec_sa *sa = NULL;
+			ipsec_sa_hold(policy->esp_sa_idx->sa);
+			sa = policy->esp_sa_idx->sa;
+			read_unlock_bh(&policy->lock);
+
+			read_lock_bh(&sa->lock);
+			switch (sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_ESP;
+				break;
+			default:
+				result = IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&sa->lock);
+			ipsec_sa_put(sa);
+		} else {
+			/* copy sa_idx in policy to avoid to lock SADB and SPD at the same time */
+			struct sa_index sa_idx;
+			sa_index_init(&sa_idx);
+			sa_index_copy(&sa_idx, policy->esp_sa_idx);
+			read_unlock_bh(&policy->lock);
+
+			sa_idx.sa = sadb_find_by_sa_index(&sa_idx);
+			if (sa_idx.sa) {
+				write_lock_bh(&policy->lock);
+				policy->esp_sa_idx->sa = sa_idx.sa;
+				ipsec_sa_hold(policy->esp_sa_idx->sa);
+				write_unlock_bh(&policy->lock);
+				ipsec_sa_put(sa_idx.sa);
+				result |= IPSEC_ACTION_ESP;
+			} else {
+				/* SADB_ACQUIRE message should be thrown up to KMd */
+				result = IPSEC_ACTION_DROP;
+			}
+		}
+	} else {
+		read_unlock_bh(&policy->lock);
+	}
+
+	read_lock_bh(&policy->lock);
+	if (policy->comp_sa_idx) {
+		if (policy->comp_sa_idx->sa) {
+			struct ipsec_sa *sa = NULL;
+			ipsec_sa_hold(policy->comp_sa_idx->sa);
+			sa = policy->comp_sa_idx->sa;
+			read_unlock_bh(&policy->lock);
+
+			read_lock_bh(&sa->lock);
+			switch (sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_COMP;
+				break;
+			default:
+				result |= IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&sa->lock);
+			ipsec_sa_put(sa);
+		} else {
+			/* copy sa_idx in policy to avoid to lock SADB and SPD at the same time */
+			struct sa_index sa_idx;
+			sa_index_init(&sa_idx);
+			sa_index_copy(&sa_idx, policy->comp_sa_idx);
+			read_unlock_bh(&policy->lock);
+
+			sa_idx.sa = sadb_find_by_sa_index(&sa_idx);
+			if (sa_idx.sa) {
+				write_lock_bh(&policy->lock);
+				policy->comp_sa_idx->sa = sa_idx.sa;
+				ipsec_sa_hold(policy->comp_sa_idx->sa);
+				write_unlock_bh(&policy->lock);
+				ipsec_sa_put(sa_idx.sa);
+				result |= IPSEC_ACTION_COMP;
+			} else {
+				/* SADB_ACUIRE message should be thrown up to KMd */
+				result |= IPSEC_ACTION_DROP;
+			}
+		}
+	} else {
+		read_unlock_bh(&policy->lock);
+	}
+
+	*policy_ptr= policy;
+
+	IPSEC4_DEBUG("end\n");	
+
+err:
+	return result;
+}
+
+int ipsec4_output_check(struct sock *sk,  struct rtable *rt, struct ipsec_sp **policy_ptr)
+{
+	struct inet_opt *inet = inet_sk(sk);
+	struct in_addr saddr,daddr;
+	u16 sport,dport;
+	unsigned char proto;
+	struct selector selector;
+	int result = IPSEC_ACTION_BYPASS; 	/* default */
+
+	IPSEC4_DEBUG("called\n");
+	if (!sk) {
+		printk(KERN_ERR "flowi and sock are NULL\n");
+		result = -EINVAL;
+		goto err;
+	}
+	
+	if (rt) {
+		saddr.s_addr = rt->rt_src;
+	}else if (sk) {
+		saddr.s_addr = inet->saddr;
+	} else {
+		result = -EINVAL;
+		goto err;
+	}
+
+	if (rt) {
+		daddr.s_addr = rt->rt_dst;
+	} else if (sk) {
+		daddr.s_addr = inet->daddr;
+	} else { 
+		result = -EINVAL;
+		goto err;
+	}
+
+	if (sk) {
+		sport=inet->sport;
+		dport=inet->dport;
+		proto=sk->protocol;
+	} else {
+		result = -EINVAL;
+		goto err;
+	}
+
+	/* for ISKAMP see RFC2408 */
+	if (proto == IPPROTO_UDP && 
+	    sport == __constant_htons(500) && dport == __constant_htons(500)) {
+		result = IPSEC_ACTION_BYPASS; 	/* default */
+		goto err;
+	}
+
+	if (proto == IPPROTO_ICMP) {
+		sport = 0;
+		dport = 0;
+	}
+
+	memset(&selector, 0, sizeof(struct selector));
+
+	((struct sockaddr_in *)&selector.src)->sin_family = AF_INET;
+	((struct sockaddr_in *)&selector.src)->sin_addr = saddr;
+	((struct sockaddr_in *)&selector.dst)->sin_family = AF_INET;
+	((struct sockaddr_in *)&selector.dst)->sin_addr = daddr;
+	selector.proto = proto;
+	selector.prefixlen_d = 32;
+	selector.prefixlen_s = 32;
+
+	((struct sockaddr_in *)&selector.src)->sin_port = sport;	
+	((struct sockaddr_in *)&selector.dst)->sin_port = dport;	
+
+#ifdef CONFIG_IPSEC_DEBUG
+	IPSEC4_DEBUG("original src addr: %d.%d.%d.%d\n", NIPQUAD(saddr));
+	IPSEC4_DEBUG("original src port: %u\n", ntohs(sport));
+	IPSEC4_DEBUG("original dst addr: %d.%d.%d.%d\n", NIPQUAD(daddr));
+	IPSEC4_DEBUG("original dst port: %u\n", ntohs(dport));
+
+	IPSEC4_DEBUG("selector src addr: %d.%d.%d.%d\n", 
+			NIPQUAD(((struct sockaddr_in *)&selector.src)->sin_addr));
+	IPSEC4_DEBUG("selector src port: %u\n", 
+			ntohs(((struct sockaddr_in *)&selector.src)->sin_port));
+	IPSEC4_DEBUG("selector dst addr: %d.%d.%d.%d\n", 
+			NIPQUAD(((struct sockaddr_in *)&selector.dst)->sin_addr));
+	IPSEC4_DEBUG("selector dst port: %u\n", 
+			ntohs(((struct sockaddr_in *)&selector.dst)->sin_port));
+	IPSEC4_DEBUG("selector proto: %u\n", selector.proto);
+#endif /* CONFIG_IPSEC_DEBUG */
+
+	result = ipsec4_output_check_core(&selector, policy_ptr);
+
+ err:
+		return result;
+}
+
diff -uNr -x CVS linux-2.5.43/net/ipv4/tcp_ipv4.c linux25.43-ipsec/net/ipv4/tcp_ipv4.c
--- linux-2.5.43/net/ipv4/tcp_ipv4.c	2002-10-16 12:27:50.000000000 +0900
+++ linux25.43-ipsec/net/ipv4/tcp_ipv4.c	2002-10-16 15:27:49.000000000 +0900
@@ -817,6 +817,17 @@
 	tp->ext_header_len = 0;
 	if (inet->opt)
 		tp->ext_header_len = inet->opt->optlen;
+#ifdef CONFIG_IP_IPSEC
+	{
+		struct ipsec_sp *policy_ptr = NULL;
+		int action = ipsec4_output_check(sk, NULL, &policy_ptr);
+
+		if (action != IPSEC_ACTION_DROP) {
+			tp->ext_header_len += ipsec4_out_get_hdrsize(policy_ptr);
+		}
+		ipsec4_out_finish(policy_ptr);
+	}
+#endif /* CONFIG_IP_IPSEC */
 
 	tp->mss_clamp = 536;
 
@@ -1577,6 +1588,17 @@
 	newtp->ext_header_len = 0;
 	if (newinet->opt)
 		newtp->ext_header_len = newinet->opt->optlen;
+#ifdef CONFIG_IP_IPSEC
+	{
+		struct ipsec_sp *policy_ptr = NULL;
+		int action = ipsec4_output_check(sk, NULL, &policy_ptr);
+
+		if (action != IPSEC_ACTION_DROP) {
+			newtp->ext_header_len += ipsec4_out_get_hdrsize(policy_ptr);
+		}
+		ipsec4_out_finish(policy_ptr);
+	}
+#endif /* CONFIG_IP_IPSEC */
 	newinet->id = newtp->write_seq ^ jiffies;
 
 	tcp_sync_mss(newsk, dst->pmtu);
diff -uNr -x CVS linux-2.5.43/net/ipv6/Config.help linux25.43-ipsec/net/ipv6/Config.help
--- linux-2.5.43/net/ipv6/Config.help	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/Config.help	2002-10-16 15:27:49.000000000 +0900
@@ -0,0 +1,5 @@
+CONFIG_IPV6_IPSEC
+
+  IPsec for IPv6 support.  You also need to say Y to "The IPsec Protocol."
+  Since IPsec is mandatory feature of IPv6, you probably want to say
+  Y here.  If unsure, say N.
diff -uNr -x CVS linux-2.5.43/net/ipv6/Config.in linux25.43-ipsec/net/ipv6/Config.in
--- linux-2.5.43/net/ipv6/Config.in	2002-10-16 12:28:22.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/Config.in	2002-10-16 15:27:49.000000000 +0900
@@ -5,3 +5,13 @@
 if [ "$CONFIG_NETFILTER" != "n" ]; then
    source net/ipv6/netfilter/Config.in
 fi
+
+# -- IPsec --
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   if [ "$CONFIG_IPSEC" != "n" ] ; then
+      bool '    IPv6: IP Security Support (EXPERIMENTAL)' CONFIG_IPV6_IPSEC 
+   fi
+   if [ "$CONFIG_IPSEC_TUNNEL" != "n" ]; then
+      define_bool CONFIG_IPV6_IPSEC_TUNNEL y
+   fi
+fi
diff -uNr -x CVS linux-2.5.43/net/ipv6/Makefile linux25.43-ipsec/net/ipv6/Makefile
--- linux-2.5.43/net/ipv6/Makefile	2002-10-16 12:28:33.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/Makefile	2002-10-16 15:43:04.000000000 +0900
@@ -12,6 +12,7 @@
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
 		ip6_flowlabel.o ipv6_syms.o
 
+obj-$(CONFIG_IPV6_IPSEC) += ipsec6_input.o ipsec6_output.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 include $(TOPDIR)/Rules.make
diff -uNr -x CVS linux-2.5.43/net/ipv6/exthdrs.c linux25.43-ipsec/net/ipv6/exthdrs.c
--- linux-2.5.43/net/ipv6/exthdrs.c	2002-10-16 12:27:09.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/exthdrs.c	2002-10-16 15:27:50.000000000 +0900
@@ -43,6 +43,10 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec6.h>
+#endif
+
 /*
  *	Parsing inbound headers.
  *
@@ -402,7 +406,7 @@
 	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
 		goto fail;
 
-	len = (skb->h.raw[1]+1)<<2;
+	len = (skb->h.raw[1]+2)<<2;
 
 	if (len&7)
 		goto fail;
@@ -410,6 +414,12 @@
 	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
 		goto fail;
 
+#ifdef CONFIG_IPV6_IPSEC
+	if (ipsec6_input_check_ah(skb_ptr,
+		(struct ipv6_auth_hdr*)((*skb_ptr)->h.raw)) <= 0)
+		goto fail;
+#endif /* CONFIG_IPV6_IPSEC */  
+
 	opt->auth = skb->h.raw - skb->nh.raw;
 	skb->h.raw += len;
 	return opt->auth;
@@ -419,6 +429,22 @@
 	return -1;
 }
 
+#ifdef CONFIG_IPV6_IPSEC
+static int ipv6_esp_hdr(struct sk_buff **skb_ptr, int nhoff, u8 *nexthdr)
+{
+	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)(*skb_ptr)->cb;
+
+	u32 espspi = ipsec6_input_check_esp(skb_ptr, 
+			(struct ipv6_esp_hdr*)(*skb_ptr)->h.raw, nexthdr);
+	if (ntohl(espspi) >0 ) {
+		opt->espspi = espspi;
+		return nhoff;
+	} else {
+		return -1;
+	}
+}
+#endif
+
 /* This list MUST NOT contain entry for NEXTHDR_HOP.
    It is parsed immediately after packet received
    and if it occurs somewhere in another place we must
@@ -437,20 +463,28 @@
 	{-1,			NULL}
 };
 
-int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
+int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff, u8 *nexthdr)
 {
 	struct hdrtype_proc *hdrt;
-	u8 nexthdr = (*skb_in)->nh.raw[nhoff];
 
 restart:
 	for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
-		if (hdrt->type == nexthdr) {
+		if (hdrt->type == *nexthdr) {
 			if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
-				nexthdr = (*skb_in)->nh.raw[nhoff];
+				*nexthdr = (*skb_in)->nh.raw[nhoff];
 				goto restart;
 			}
 			return -1;
 		}
+#ifdef CONFIG_IPV6_IPSEC
+		if (*nexthdr == NEXTHDR_ESP) {
+			if ((nhoff = ipv6_esp_hdr(skb_in, nhoff, nexthdr)) >= 0) {
+				goto restart;
+			}
+			return -1;
+		}
+#endif
+
 	}
 	return nhoff;
 }
@@ -539,6 +573,7 @@
 static u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
 		     struct ipv6_rt_hdr *opt, struct in6_addr *addr)
 {
+	struct inet6_skb_parm *parm = (struct inet6_skb_parm*)skb->cb;
 	struct rt0_hdr *phdr, *ihdr;
 	int hops;
 
@@ -557,26 +592,30 @@
 
 	phdr->rt_hdr.nexthdr = *prev_hdr;
 	*prev_hdr = NEXTHDR_ROUTING;
+	parm->srcrt = (unsigned char*)phdr - skb->nh.raw;
 	return &phdr->rt_hdr.nexthdr;
 }
 
-static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
+static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt, __u16 *optoff)
 {
 	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
 
 	memcpy(h, opt, ipv6_optlen(opt));
 	h->nexthdr = *prev_hdr;
 	*prev_hdr = type;
+	*optoff = (unsigned char*)h - skb->nh.raw;
 	return &h->nexthdr;
 }
 
 static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
 {
+	struct inet6_skb_parm *parm = (struct inet6_skb_parm*)skb->cb;
 	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
 
 	memcpy(h, opt, (opt->hdrlen+2)<<2);
 	h->nexthdr = *prev_hdr;
 	*prev_hdr = NEXTHDR_AUTH;
+	parm->auth = (unsigned char*)h - skb->nh.raw;
 	return &h->nexthdr;
 }
 
@@ -584,10 +623,11 @@
 u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
 			  struct in6_addr *daddr, u32 jumbolen)
 {
+	struct inet6_skb_parm *parm = (struct inet6_skb_parm*)skb->cb;
 	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
 
 	if (opt && opt->hopopt)
-		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
+		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt, &parm->hop);
 
 	if (jumbolen) {
 		u8 *jumboopt = (u8 *)skb_put(skb, 8);
@@ -610,7 +650,7 @@
 	}
 	if (opt) {
 		if (opt->dst0opt)
-			prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
+			prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt, &parm->dst0);
 		if (opt->srcrt)
 			prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
 	}
@@ -619,21 +659,23 @@
 
 u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
 {
+	struct inet6_skb_parm *parm = (struct inet6_skb_parm*)skb->cb;
+
 	if (opt->auth)
 		prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
 	if (opt->dst1opt)
-		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
+		prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt, &parm->dst1);
 	return prev_hdr;
 }
 
 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
-			    struct ipv6_rt_hdr *opt,
+			    struct ipv6_rt_hdr **opt,
 			    struct in6_addr **addr_p)
 {
 	struct rt0_hdr *phdr, *ihdr;
 	int hops;
 
-	ihdr = (struct rt0_hdr *) opt;
+	ihdr = (struct rt0_hdr *) *opt;
 	
 	phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
 	memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
@@ -649,24 +691,36 @@
 
 	phdr->rt_hdr.nexthdr = *proto;
 	*proto = NEXTHDR_ROUTING;
+
+#ifdef CONFIG_IPV6_IPSEC
+	*opt = (struct ipv6_rt_hdr*)phdr;
+#endif
 }
 
-static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
+static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr **opt)
 {
-	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
+	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(*opt));
 
-	memcpy(h, opt, ipv6_optlen(opt));
+	memcpy(h, *opt, ipv6_optlen(*opt));
 	h->nexthdr = *proto;
 	*proto = type;
+
+#ifdef CONFIG_IPV6_IPSEC
+	*opt = h;
+#endif
 }
 
-static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
+static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr **opt)
 {
-	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
+	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ((*opt)->hdrlen+2)<<2);
 
-	memcpy(h, opt, (opt->hdrlen+2)<<2);
+	memcpy(h, *opt, ((*opt)->hdrlen+2)<<2);
 	h->nexthdr = *proto;
 	*proto = NEXTHDR_AUTH;
+
+#ifdef CONFIG_IPV6_IPSEC
+	*opt = h;
+#endif
 }
 
 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
@@ -674,19 +728,19 @@
 			  struct in6_addr **daddr)
 {
 	if (opt->srcrt)
-		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
+		ipv6_push_rthdr(skb, proto, &opt->srcrt, daddr);
 	if (opt->dst0opt)
-		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
+		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, &opt->dst0opt);
 	if (opt->hopopt)
-		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
+		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, &opt->hopopt);
 }
 
 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
 {
 	if (opt->dst1opt)
-		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
+		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, &opt->dst1opt);
 	if (opt->auth)
-		ipv6_push_authhdr(skb, proto, opt->auth);
+		ipv6_push_authhdr(skb, proto, &opt->auth);
 }
 
 struct ipv6_txoptions *
@@ -726,6 +780,7 @@
 		 (nexthdr == NEXTHDR_ROUTING)	||
 		 (nexthdr == NEXTHDR_FRAGMENT)	||
 		 (nexthdr == NEXTHDR_AUTH)	||
+		 (nexthdr == NEXTHDR_ESP)       ||
 		 (nexthdr == NEXTHDR_NONE)	||
 		 (nexthdr == NEXTHDR_DEST) );
 }
diff -uNr -x CVS linux-2.5.43/net/ipv6/ip6_input.c linux25.43-ipsec/net/ipv6/ip6_input.c
--- linux-2.5.43/net/ipv6/ip6_input.c	2002-10-16 12:28:32.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ip6_input.c	2002-10-16 15:27:50.000000000 +0900
@@ -40,6 +40,10 @@
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#endif /* CONFIG_IPV6_IPSEC */
 
 
 static inline int ip6_rcv_finish( struct sk_buff *skb) 
@@ -125,7 +129,8 @@
 	struct inet6_protocol *ipprot;
 	struct sock *raw_sk;
 	int nhoff;
-	int nexthdr;
+	u8 nexthdr;
+	int found = 0;
 	u8 hash;
 
 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
@@ -149,10 +154,10 @@
 	   which are missing with probability of 200%
 	 */
 	if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
-		nhoff = ipv6_parse_exthdrs(&skb, nhoff);
+		nexthdr = skb->nh.raw[nhoff];
+		nhoff = ipv6_parse_exthdrs(&skb, nhoff, &nexthdr);
 		if (nhoff < 0)
 			return 0;
-		nexthdr = skb->nh.raw[nhoff];
 		hdr = skb->nh.ipv6h;
 	}
 
@@ -163,6 +168,14 @@
 		skb->csum = csum_sub(skb->csum,
 				     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
 
+#ifdef CONFIG_IPV6_IPSEC 
+	IPSEC6_DEBUG("called\n");
+	if (ipsec6_input_check(&skb, &nexthdr)) {       
+		if (net_ratelimit())
+			printk(KERN_DEBUG "ip6_input_finish: (ipsec) dropping packet\n");
+		goto discard;
+	}
+#endif /* CONFIG_IPV6_IPSEC */
 resubmit:
 	raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
 	if (raw_sk)
diff -uNr -x CVS linux-2.5.43/net/ipv6/ip6_output.c linux25.43-ipsec/net/ipv6/ip6_output.c
--- linux-2.5.43/net/ipv6/ip6_output.c	2002-10-16 12:27:12.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ip6_output.c	2002-10-16 15:27:50.000000000 +0900
@@ -51,6 +51,13 @@
 #include <net/rawv6.h>
 #include <net/icmp.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#else
+struct ipsec_sp;        /* to suppress warning */
+#endif /* CONFIG_IPV6_IPSEC */
+
 static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
 {
 	static u32 ipv6_fragmentation_id = 1;
@@ -191,14 +198,67 @@
 	u8  proto = fl->proto;
 	int seg_len = skb->len;
 	int hlimit;
+        int retval = 0;
+	void *encdata = NULL;
+#ifdef CONFIG_IPV6_IPSEC
+	unsigned enclength = 0;
+	struct ipsec_sp *policy_ptr = NULL;
+	int ipsec_action = 0;
+	struct ipv6_txoptions *newopt = NULL;
+	struct ipv6_txoptions *opt2 = NULL;
+#endif /* CONFIG_IPV6_IPSEC */
+
+#ifdef CONFIG_IPV6_IPSEC
+	IPSEC6_DEBUG("call ipsec6_output_check\n");
+	ipsec_action = ipsec6_output_check(sk, fl, NULL, &policy_ptr);
+	IPSEC6_DEBUG("ipsec_action is %d\n", ipsec_action);
+	if (ipsec_action == IPSEC_ACTION_DROP) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "ip6_xmit: (ipsec) dropping packet.\n");
+		return -EFAULT;
+	}
 
-	if (opt) {
-		int head_room;
+	if (opt && opt->auth) {
+		ipsec_action &= ~IPSEC_ACTION_AUTH;
+		printk(KERN_DEBUG "ip6_xmit: AH header is duplicated!\n"); 
+	}
+
+        /* Get a copy of opt for IPsec */
+	if (ipsec_action & (IPSEC_ACTION_AUTH | IPSEC_ACTION_ESP)) {
+		newopt = ipsec6_out_get_newopt(opt, policy_ptr);
+		if (newopt) 
+			opt = newopt;
+	}
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		ipsec6_out_enc(skb->data, skb->len, fl->proto, opt, &encdata, &enclength, policy_ptr);
+		if (!encdata) { 
+			if (net_ratelimit())
+				printk(KERN_DEBUG "ip6_xmit: encrypt failed\n");
+			retval = -EFAULT;
+			goto out;
+		}
+	}
+#endif /* CONFIG_IPV6_IPSEC */
+
+	if (opt || encdata) {
+#ifdef CONFIG_IPV6_IPSEC
+		int encaddsize = 0;
+#endif
+		int head_room = 0;
 
 		/* First: exthdrs may take lots of space (~8K for now)
 		   MAX_HEADER is not enough.
 		 */
-		head_room = opt->opt_nflen + opt->opt_flen;
+		if (opt) 
+			head_room += opt->opt_nflen + opt->opt_flen;
+#ifdef CONFIG_IPV6_IPSEC
+		if (encdata) {
+			encaddsize = enclength - skb->len;
+			head_room += encaddsize+4;
+		}
+#endif
+
 		seg_len += head_room;
 		head_room += sizeof(struct ipv6hdr) + ((dst->dev->hard_header_len + 15)&~15);
 
@@ -206,15 +266,40 @@
 			struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
 			kfree_skb(skb);
 			skb = skb2;
-			if (skb == NULL)
-				return -ENOBUFS;
+			if (skb == NULL) {
+				retval = -ENOBUFS;
+				goto out;
+			}
 			if (sk)
 				skb_set_owner_w(skb, sk);
 		}
-		if (opt->opt_flen)
-			ipv6_push_frag_opts(skb, opt, &proto);
-		if (opt->opt_nflen)
-			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+#ifdef CONFIG_IPV6_IPSEC
+		if (encdata) {
+			skb->h.raw = skb_push(skb,encaddsize+4); 
+			memcpy(skb->h.raw,encdata,enclength);
+			seg_len -= 4; 
+			skb_trim(skb,enclength);
+			fl->proto = NEXTHDR_ESP;
+			proto = fl->proto;
+		}
+		/* ipv6_push_[n}frag_opts overwrites opt. */
+		if (opt) {
+			opt2 = kmalloc(sizeof(struct ipv6_txoptions), GFP_ATOMIC);
+			memcpy(opt2, opt, sizeof(struct ipv6_txoptions));
+
+			if (opt2->opt_flen)
+				ipv6_push_frag_opts(skb, opt2, &proto);
+			if (opt2->opt_nflen)
+				ipv6_push_nfrag_opts(skb, opt2, &proto, &first_hop);
+		}
+#else
+		if (opt) {
+			if (opt->opt_flen)
+				ipv6_push_frag_opts(skb, opt, &proto);
+			if (opt->opt_nflen)
+				ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+		}
+#endif
 	}
 
 	hdr = skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6hdr));
@@ -237,16 +322,46 @@
 	ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
 	ipv6_addr_copy(&hdr->daddr, first_hop);
 
+#ifdef CONFIG_IPV6_IPSEC
+	if (opt && opt2 && opt2->auth) {
+		struct inet6_skb_parm *parm = (struct inet6_skb_parm*)skb->cb;
+
+		parm->auth = (char*)(opt2->auth) - (char*)(skb->nh.raw);
+
+		if (opt2->hopopt)
+			parm->hop  = (char*)(opt2->hopopt) - (char*)(skb->nh.raw);
+		if (opt2->dst0opt)
+			parm->dst0 = (char*)(opt2->dst0opt) - (char*)(skb->nh.raw);
+		if (opt2->dst1opt)
+			parm->dst1 = (char*)(opt2->dst1opt) - (char*)(skb->nh.raw);
+		if ( (ipsec_action & IPSEC_ACTION_AUTH) ) {
+			IPSEC6_DEBUG("call ipsec6_out_calc_ah\n");
+			ipsec6_out_ah_calc(NULL, 0, NULL, skb, NULL, policy_ptr);
+		}
+		kfree(opt2);
+	} 
+#endif /* CONFIG_IPV6_IPSEC */
+
 	if (skb->len <= dst->pmtu) {
 		IP6_INC_STATS(Ip6OutRequests);
-		return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
+		retval = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
+		goto out;
 	}
 
 	if (net_ratelimit())
 		printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
 	icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
 	kfree_skb(skb);
-	return -EMSGSIZE;
+	retval =  -EMSGSIZE;
+
+out:
+#ifdef CONFIG_IPV6_IPSEC
+        if (newopt) ipsec6_out_finish(newopt, policy_ptr);
+	if (encdata) kfree(encdata);
+	policy_ptr=NULL;
+#endif /* CONFIG_IPV6_IPSEC */
+
+	return retval;
 }
 
 /*
@@ -323,7 +438,8 @@
 			 const void *data, struct dst_entry *dst,
 			 struct flowi *fl, struct ipv6_txoptions *opt,
 			 struct in6_addr *final_dst,
-			 int hlimit, int flags, unsigned length, int mtu)
+			 int hlimit, int flags, unsigned length, int mtu,
+			 int ipsec_action, struct ipsec_sp *policy_ptr)
 {
 	struct ipv6hdr *hdr;
 	struct sk_buff *last_skb;
@@ -425,6 +541,38 @@
 	if (opt && opt->opt_nflen)
 		prev_hdr = ipv6_build_nfrag_opts(last_skb, prev_hdr, opt, final_dst, 0);
 
+#ifdef CONFIG_IPV6_IPSEC
+	if ( (ipsec_action & IPSEC_ACTION_AUTH) && opt && opt->auth) {
+		struct sk_buff *skb = NULL;
+		u8 *skb_prev_hdr = NULL;
+		int prev_hdr_offset;
+
+                /* The nfrag headers and the ip header are in last_skb. Copy it, and add the
+		 * fragmentable headers. So we can build an unfragmented version of the
+		 * packet, which is necessary for AH calculation. */
+		skb = skb_copy(last_skb, sk->allocation);
+		if (skb) {
+			prev_hdr_offset = prev_hdr - (u8*)hdr;
+			skb_prev_hdr = ((u8*)skb->nh.ipv6h) + prev_hdr_offset;
+
+			if (opt && opt->opt_flen)
+				ipv6_build_frag_opts(skb, skb_prev_hdr, opt);
+
+			/* Calculate payload length */
+			if (opt) /* This should always be true :-) */
+				skb->nh.ipv6h->payload_len = htons(length + opt->opt_flen + opt->opt_nflen);
+			else
+				skb->nh.ipv6h->payload_len = htons(length);
+
+			/* Calculate AH and free memory */
+			ipsec6_out_ah_calc(data, length, getfrag, skb,
+					(struct ipv6_auth_hdr*)opt->auth, policy_ptr);
+			kfree_skb(skb);
+		} else
+			printk(KERN_WARNING "Could not allocate memory for AH calculation!\n");
+	}
+#endif /* CONFIG_IPV6_IPSEC */
+
 	prev_hdr = ipv6_build_fraghdr(last_skb, prev_hdr, frag_off);
 	fhdr_dist = prev_hdr - last_skb->data;
 
@@ -498,6 +646,15 @@
 	return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
 }
 
+#ifdef CONFIG_IPV6_IPSEC
+static int ipsec6_getfrag(const void *data, struct in6_addr *saddr, 
+			 char *buff, unsigned int offset, unsigned int len)
+{
+	memcpy(buff, ((char*)data)+offset, len);
+	return 0;
+}
+#endif /* CONFIG_IPV6_IPSEC */
+
 int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
 		   struct flowi *fl, unsigned length,
 		   struct ipv6_txoptions *opt, int hlimit, int flags)
@@ -506,6 +663,13 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct in6_addr *final_dst = NULL;
 	struct dst_entry *dst;
+	struct ipsec_sp *policy_ptr = NULL;
+	int ipsec_action = 0;
+#ifdef CONFIG_IPV6_IPSEC
+	struct ipv6_txoptions *newopt = NULL;
+	void *newdata = NULL;
+	unsigned int newlength = 0;
+#endif /* CONFIG_IPV6_IPSEC */
 	int err = 0;
 	unsigned int pktlength, jumbolen, mtu;
 	struct in6_addr saddr;
@@ -572,6 +736,76 @@
 		}
 		fl->fl6_src = &saddr;
 	}
+
+#ifdef CONFIG_IPV6_IPSEC
+	IPSEC6_DEBUG("call ipsec6_output_check\n");
+	ipsec_action = ipsec6_output_check(sk, fl, data, &policy_ptr);
+	if (ipsec_action == IPSEC_ACTION_DROP) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "ip6_build_xmit: (ipsec) dropping packet.\n");
+		return -EFAULT;
+	}
+	if (opt && opt->auth) { /* why ? */
+		ipsec_action &= ~IPSEC_ACTION_AUTH;
+		printk(KERN_DEBUG "ip6_build_xmit: AH is duplicated!\n"); 
+	}
+
+	/* Get a copy of opt for IPsec */
+	if (ipsec_action & (IPSEC_ACTION_AUTH | IPSEC_ACTION_ESP)) {
+		newopt = ipsec6_out_get_newopt(opt, policy_ptr);
+		if (newopt) 
+			opt = newopt;
+	}
+
+        /* Check for encryption */
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *olddata;
+		struct in6_addr dummyaddr;
+
+		IPSEC6_DEBUG("IPsec6: action ESP selected.\n");
+		if (fl->fl6_src == NULL) {
+			dst = __sk_dst_check(sk, np->dst_cookie);
+			err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
+			if (err) {
+				if (net_ratelimit())
+					printk(KERN_DEBUG "ip6_build_xmit: no availiable source address (olddata)\n");
+				goto out;
+			}
+			fl->fl6_src = &saddr;
+		}
+		ipv6_addr_copy(&dummyaddr, fl->nl_u.ip6_u.saddr);
+		olddata = kmalloc(length, GFP_ATOMIC);
+		if (!olddata) {
+			err = -ENOMEM;
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Could not get memory for ESP (olddata)\n");
+			goto out;
+		}
+		err = getfrag(data, &dummyaddr, (char*)olddata, 0, length);
+		if (err) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "Could not get data for ESP (olddata)\n");
+			kfree(olddata);
+			goto out;
+		}
+
+		ipsec6_out_enc(olddata, length, fl->proto, opt, &newdata, &newlength, policy_ptr);
+
+		if (newdata) {
+			data = newdata;
+			length = newlength;
+			fl->proto = NEXTHDR_ESP;
+			getfrag = ipsec6_getfrag;
+		} else {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "ip6_build_xmit: encrypt failed\n");
+			kfree(olddata);
+			err = -EFAULT;
+			goto out;
+		}
+		kfree(olddata);
+	}
+#endif /* CONFIG_IPV6_IPSEC */
 	pktlength = length;
 
 	if (hlimit < 0) {
@@ -663,6 +897,11 @@
 			      0, length);
 
 		if (!err) {
+#ifdef CONFIG_IPV6_IPSEC
+			if ( (ipsec_action & IPSEC_ACTION_AUTH) && opt && opt->auth) {
+				ipsec6_out_ah_calc(NULL, 0, NULL, skb, NULL, policy_ptr);
+			}
+#endif /* CONFIG_IPV6_IPSEC */
 			IP6_INC_STATS(Ip6OutRequests);
 			err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
 		} else {
@@ -677,8 +916,44 @@
 			goto out;
 		}
 
+#ifdef CONFIG_IPV6_IPSEC
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+		if (policy_ptr && policy_ptr->selector.mode == IPSEC_MODE_TUNNEL) {
+			struct sk_buff *skb;
+			struct ipv6hdr *hdr;
+			struct net_device *dev = dst->dev;
+			unsigned int pmtu = mtu - sizeof(struct ipv6hdr) - ipsec6_out_get_hdrsize(policy_ptr);
+
+			skb = sock_alloc_send_skb(sk, pktlength + 15 + 
+					dev->hard_header_len, 
+					flags & MSG_DONTWAIT, &err);
+
+			if (skb == NULL) {
+				IP6_INC_STATS(Ip6OutDiscards);
+				goto out;
+			}
+
+			skb->dst = dst_clone(dst);
+
+			skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+			hdr = (struct ipv6hdr *) skb->tail;
+			skb->nh.ipv6h = hdr;
+
+			skb_put(skb, length);
+			err = getfrag(data, &hdr->saddr, (char *) hdr, 0, length);
+
+			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, 
+					(pmtu > IPV6_MIN_MTU ? pmtu : IPV6_MIN_MTU), dev);
+			IP6_INC_STATS_BH(Ip6InTooBigErrors);
+
+			goto out;
+		}
+#endif /* CONFIG_IPV6_IPSEC_TUNNEL */
+#endif /* CONFIG_IPV6_IPSEC */
+
 		err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, final_dst, hlimit,
-				    flags, length, mtu);
+				    flags, length, mtu, ipsec_action, policy_ptr);
 	}
 
 	/*
@@ -688,6 +963,13 @@
 	ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
 	if (err > 0)
 		err = np->recverr ? net_xmit_errno(err) : 0;
+
+#ifdef CONFIG_IPV6_IPSEC
+	if (newopt) ipsec6_out_finish(newopt, policy_ptr);
+	if (newdata) kfree(newdata);
+	policy_ptr=NULL;
+#endif /* CONFIG_IPV6_IPSEC */
+
 	return err;
 }
 
diff -uNr -x CVS linux-2.5.43/net/ipv6/ipsec6_input.c linux25.43-ipsec/net/ipv6/ipsec6_input.c
--- linux-2.5.43/net/ipv6/ipsec6_input.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ipsec6_input.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,699 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysctl.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/smp.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <net/ipv6.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/snmp.h>  
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#include <linux/pfkeyv2.h> /* sa proto type */
+#include <linux/pfkey.h>
+#ifdef CONFIG_IPV6_IPCOMP
+#include <net/ipcomp.h>
+#endif /* CONFIG_IPV6_IPCOMP */
+
+/* XXX: should move this function to net/ipv6/utils.c */
+static char* in6_ntop(const struct in6_addr *in6, char *buf){
+	if (!buf)
+		return NULL;
+	sprintf(buf,
+		"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+		ntohs(in6->s6_addr16[0]), ntohs(in6->s6_addr16[1]),
+		ntohs(in6->s6_addr16[2]), ntohs(in6->s6_addr16[3]),
+		ntohs(in6->s6_addr16[4]), ntohs(in6->s6_addr16[5]),
+		ntohs(in6->s6_addr16[6]), ntohs(in6->s6_addr16[7]));
+	return buf;
+}
+
+static int check_replay_window(struct sa_replay_window *rw, __u32 hdrseq)
+{	
+	__u32 diff;
+	__u32 seq = ntohl(hdrseq);
+
+	if (!sysctl_ipsec_replay_window) {
+		IPSEC6_DEBUG("disable replay window check, skip!\n");
+		return 1;
+	}
+
+	IPSEC6_DEBUG("overflow: %u\n" 
+		     "    size: %u\n" 
+		     " seq_num: %x\n" 
+		     "last_seq: %x\n" 
+		     "  bitmap: %08x\n" 
+		     " curr seq: %x\n",
+			rw->overflow, rw->size, rw->seq_num, rw->last_seq, rw->bitmap, seq);
+	if (seq == 0) {
+		return 0; /* first == 0 or wrapped */
+	}
+
+	if (seq > rw->last_seq) return 1; /* larger is good */
+
+	diff = rw->last_seq - seq;
+
+	if (diff >= rw->size) {
+		return 0; /* too old or wrapped */
+	}
+
+	if ( rw->bitmap & ((u_long)1 << diff) ) {
+		return 0; /* already seen */
+	}
+
+	return 1; /* out of order but good */
+}
+
+static void update_replay_window(struct sa_replay_window *rw, __u32 hdrseq)
+{
+	__u32 diff;
+	__u32 seq = ntohl(hdrseq);
+
+	if (!sysctl_ipsec_replay_window) {
+		IPSEC6_DEBUG("disable replay window check, skip!\n");
+		return;
+	}
+
+	if (seq == 0) return;
+
+	if (seq > rw->last_seq) { /* new larger sequence number */
+		diff = seq - rw->last_seq;
+		if (diff < rw->size) {  /* In window */
+			rw->bitmap <<= diff;
+			rw->bitmap |= 1; /* set bit for this packet */
+		} else {
+			rw->bitmap = 1; /* This packet has a "way larger" */
+		}
+
+		rw->last_seq = seq;
+	}
+
+	diff = rw->last_seq - seq;
+	rw->bitmap |= ((u_long)1 << diff); /* mark as seen */
+}
+
+static void ipsec6_input_get_offset(u8 *packet, u32 packet_len, 
+				    struct inet6_skb_parm* opt)
+{
+	u16 offset = sizeof(struct ipv6hdr);
+	u8 nexthdr = ((struct ipv6hdr*)packet)->nexthdr;
+	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(packet + offset);
+
+	while (offset + 1 < packet_len) {
+
+		switch (nexthdr) {
+
+		case NEXTHDR_HOP:
+			opt->hop = offset;
+			offset += ipv6_optlen(exthdr);
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
+			break;
+
+		case NEXTHDR_ROUTING:
+			if (opt->dst1) {
+				opt->dst0 = opt->dst1;
+				opt->dst1 = 0;
+			}
+			opt->srcrt = offset;
+			offset += ipv6_optlen(exthdr);
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
+			break;
+
+		case NEXTHDR_DEST:
+			opt->dst1 = offset;
+			offset += ipv6_optlen(exthdr);
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
+			break;
+
+		case NEXTHDR_AUTH:
+			opt->auth = offset;
+			offset += (exthdr->hdrlen + 2) <<2;
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
+			break;
+
+		default :
+			return;
+		}
+	}
+
+	return;
+}
+
+
+int ipsec6_input_check_ah(struct sk_buff **skb, struct ipv6_auth_hdr *authhdr)
+{
+	int rtn = 0;
+	__u8* authdata;
+	size_t authsize;
+	char *packet;
+	int offset;
+	struct sa_index sa_idx;
+	struct inet6_skb_parm opt;
+
+	IPSEC6_DEBUG("start auth header processing\n");
+
+	if (!((*skb)&&authhdr)) {
+		IPSEC6_DEBUG("parameters is invalid\n");
+		goto finish;
+	}
+
+	/* Check SPI */
+	IPSEC6_DEBUG("authhdr->spi is 0x%x\n", ntohl(authhdr->spi));
+
+	sa_index_init(&sa_idx);
+	ipv6_addr_copy(&((struct sockaddr_in6 *)&sa_idx.dst)->sin6_addr,
+	       &(*skb)->nh.ipv6h->daddr);
+	((struct sockaddr_in6 *)&sa_idx.dst)->sin6_family = AF_INET6;
+	sa_idx.prefixlen_d = 128;
+	sa_idx.ipsec_proto = SADB_SATYPE_AH;
+	sa_idx.spi = authhdr->spi;
+
+	sa_idx.sa = sadb_find_by_sa_index(&sa_idx);
+
+	if (!sa_idx.sa) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_ah: not found SA for ah\n");
+		goto finish;
+	}
+
+	write_lock_bh(&sa_idx.sa->lock);
+
+	if (sa_idx.sa->auth_algo.algo == SADB_AALG_NONE ) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec_input_calc_ah: not found auth algo.\n");
+		goto unlock_finish;
+	}
+
+	if (!check_replay_window(&sa_idx.sa->replay_window, authhdr->seq_no)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_ah: replay check err!\n");
+		goto unlock_finish;
+	}
+
+	authsize = ntohs((*skb)->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+
+	if (authsize > (*skb)->len + ((char*)(*skb)->data - (char*)(*skb)->nh.ipv6h)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_ah: the packet length is wrong\n");
+		goto unlock_finish;
+	}
+
+	packet = kmalloc(((authsize + 3) & ~3) + 
+			sa_idx.sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+
+	if (!packet) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_ah: can't get memory for pakcet\n");
+		goto unlock_finish;
+	}
+	authdata = packet + ((authsize + 3) & ~3);
+
+	offset = (char *)((*skb)->nh.ipv6h) - (char *)((*skb)->data);
+
+	if (skb_copy_bits(*skb, offset, packet, authsize)) {
+		IPSEC6_DEBUG("packet copy failed\n");
+		goto unlock_finish;
+	}
+
+	memset(&opt, 0, sizeof(struct inet6_skb_parm));
+	ipsec6_input_get_offset(packet, authsize, &opt);
+
+	zero_out_for_ah(&opt, packet);
+
+	sa_idx.sa->auth_algo.dx->di->hmac_atomic(sa_idx.sa->auth_algo.dx,
+			sa_idx.sa->auth_algo.key,
+			sa_idx.sa->auth_algo.key_len,
+			packet, authsize, authdata);	 
+
+	/* Originally, IABG uses "for" loop for matching authentication data.	*/
+	/* I change it into memcmp routine.					*/
+	if (memcmp(authdata, authhdr->auth_data, sa_idx.sa->auth_algo.digest_len)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_ah: invalid checksum in AH.\n");
+		kfree(packet);
+		goto unlock_finish;
+	}
+	kfree(packet);
+
+	rtn = 1;
+
+	(*skb)->security |= RCV_AUTH; /* ? we must rewrite linux/ipsec.h */
+
+	update_replay_window(&sa_idx.sa->replay_window, authhdr->seq_no);
+
+	if (!sa_idx.sa->fuse_time) {
+		sa_idx.sa->fuse_time = jiffies;
+		sa_idx.sa->lifetime_c.usetime = (sa_idx.sa->fuse_time) / HZ;
+		ipsec_sa_mod_timer(sa_idx.sa);
+		IPSEC6_DEBUG("set fuse_time = %lu\n", sa_idx.sa->fuse_time);
+	}
+	sa_idx.sa->lifetime_c.bytes += (*skb)->tail - (*skb)->head;
+	IPSEC6_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa_idx.sa->lifetime_c.bytes) >> 32), (__u32)(sa_idx.sa->lifetime_c.bytes));
+	if (sa_idx.sa->lifetime_c.bytes >= sa_idx.sa->lifetime_s.bytes && sa_idx.sa->lifetime_s.bytes) {
+		sa_idx.sa->state = SADB_SASTATE_DYING;
+		IPSEC6_DEBUG("change sa state DYING\n");
+	}
+	if (sa_idx.sa->lifetime_c.bytes >= sa_idx.sa->lifetime_h.bytes && sa_idx.sa->lifetime_h.bytes) {
+		sa_idx.sa->state = SADB_SASTATE_DEAD;
+		IPSEC6_DEBUG("change sa state DEAD\n");
+	}
+
+unlock_finish:
+	write_unlock_bh(&sa_idx.sa->lock);  /* unlock SA */
+	ipsec_sa_put(sa_idx.sa);
+finish:
+	return rtn;
+}
+
+int ipsec6_input_check_esp(struct sk_buff **skb, struct ipv6_esp_hdr* esphdr, u8 *nexthdr)
+{
+	int len = 0;
+	int rtn = 0;
+	struct sa_index sa_idx;
+	u8 *authdata = NULL;
+	u8 *srcdata = NULL;
+	int srcsize = 0, totalsize = 0, hashsize = 0, encsize = 0;
+
+	IPSEC6_DEBUG("start esp processing\n");
+	if (!(*skb&&esphdr)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: parameters are invalid\n");
+		goto finish;
+	}	
+
+	if (skb_is_nonlinear(*skb)) {
+		u16 offset = ((char*)esphdr) - (char*)((*skb)->nh.raw);
+		if (!skb_linearize(*skb, GFP_ATOMIC)) {
+			esphdr = (struct ipv6_esp_hdr*)((*skb)->nh.raw + offset);
+		} else {
+			if (net_ratelimit())
+				printk(KERN_ERR "ipsec6_input_check_esp: counld not linearize skb\n");
+			rtn = -EINVAL;
+			goto finish;
+		} 
+	}
+
+	/* Check SPI */
+	IPSEC6_DEBUG("esphdr->spi is 0x%x\n", ntohl(esphdr->spi));
+
+	sa_index_init(&sa_idx);
+	ipv6_addr_copy(&((struct sockaddr_in6 *)&sa_idx.dst)->sin6_addr,
+	       &(*skb)->nh.ipv6h->daddr);
+	((struct sockaddr_in6 *)&sa_idx.dst)->sin6_family = AF_INET6;
+	sa_idx.prefixlen_d = 128;
+	sa_idx.ipsec_proto = SADB_SATYPE_ESP;
+	sa_idx.spi = esphdr->spi;
+
+	sa_idx.sa = sadb_find_by_sa_index(&sa_idx);
+
+	if (!sa_idx.sa) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: not found SA for esp\n");
+		goto finish;
+	}
+
+	write_lock_bh(&sa_idx.sa->lock);
+
+	if ( sa_idx.sa->esp_algo.algo == SADB_EALG_NONE ) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: not found encryption algorithm in SA!\n");
+		goto unlock_finish;
+	}
+
+	len = ntohs((*skb)->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+
+	if (len > (*skb)->len + ((char*)(*skb)->data - (char*)(*skb)->nh.ipv6h)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: received packet length is wrong\n");
+		goto unlock_finish;
+	}
+
+	totalsize = len - ((((char*)esphdr) - ((char*)(*skb)->nh.ipv6h)));
+
+	if (!(sa_idx.sa->esp_algo.cx->ci)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: not found esp algo\n");
+		goto unlock_finish;
+	}
+
+	if ( !check_replay_window(&sa_idx.sa->replay_window, esphdr->seq_no) ) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: replay check err!\n");
+		kfree(srcdata);
+		goto unlock_finish;
+	}
+
+	encsize = totalsize - sa_idx.sa->esp_algo.cx->ci->ivsize - 8;
+							/* 8 = SPI + Sequence Number */	
+
+	if ( sa_idx.sa->auth_algo.algo != SADB_AALG_NONE ) {
+		/* Calculate size */
+		/* The tail of payload does not have to be aligned		*/
+		/* with a multiple number of 64 bit.				*/
+		/* 64 bit alignment is adapted to the position of top of header.*/
+		hashsize = sa_idx.sa->auth_algo.digest_len;
+		encsize -= hashsize;
+		authdata=kmalloc(sa_idx.sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+		sa_idx.sa->auth_algo.dx->di->hmac_atomic(sa_idx.sa->auth_algo.dx,
+			sa_idx.sa->auth_algo.key,
+			sa_idx.sa->auth_algo.key_len,
+			(char*)esphdr, totalsize - hashsize, authdata);	 
+		/* Originally, IABG uses "for" loop for matching authentication data. */
+		/* I change it into memcmp routine. */
+
+		if (memcmp(authdata, &((char*)esphdr)[totalsize - hashsize],
+				sa_idx.sa->auth_algo.digest_len )) {
+			if (net_ratelimit())
+				printk(KERN_ERR "ipsec6_input_check_esp: invalid checksum in ESP\n");
+			kfree(authdata);
+			goto unlock_finish;
+		}
+		kfree(authdata);
+		authdata = NULL;
+	}
+
+	/* Decrypt data */
+	srcdata = kmalloc(encsize, GFP_ATOMIC);
+	if (!srcdata) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: can't allocate memory for decrypt\n");
+		goto unlock_finish;
+	}
+
+	IPSEC6_DEBUG("len=%d, totalsize=%d, encsize=%d\n",
+			len, totalsize, encsize);
+
+	if (!(sa_idx.sa->esp_algo.iv)) { /* first packet */
+		sa_idx.sa->esp_algo.iv = kmalloc(sa_idx.sa->esp_algo.cx->ci->ivsize, GFP_ATOMIC);
+	}
+
+	memcpy(sa_idx.sa->esp_algo.iv, esphdr->enc_data, sa_idx.sa->esp_algo.cx->ci->ivsize);
+	sa_idx.sa->esp_algo.cx->ci->decrypt_atomic_iv(sa_idx.sa->esp_algo.cx,
+			((u8 *)(esphdr->enc_data)) + sa_idx.sa->esp_algo.cx->ci->ivsize,
+			srcdata, encsize, sa_idx.sa->esp_algo.iv);
+
+	/* encsize - (pad_len + next_hdr) - pad_len */
+	srcsize = encsize - 2 - srcdata[encsize-2];
+	IPSEC6_DEBUG("Original data is srcsize=%d, padlength=%d\n", srcsize, srcdata[encsize-2]);
+	if (srcsize <= 0) {
+		if (net_ratelimit())
+			printk(KERN_ERR "ipsec6_input_check_esp: Encrypted packet contains garbage(Size of decrypted packet < 0).\n");
+		kfree(srcdata);
+		goto unlock_finish;
+	}
+
+	update_replay_window(&sa_idx.sa->replay_window, esphdr->seq_no);
+
+	*nexthdr = srcdata[encsize-1];
+	IPSEC6_DEBUG("nexthdr = %u\n", *nexthdr);
+	memcpy(esphdr, srcdata, srcsize);
+
+	skb_trim(*skb, (*skb)->len +  srcsize - totalsize);
+	(*skb)->nh.ipv6h->payload_len = htons(((char *)esphdr - (char *)((*skb)->nh.ipv6h))  - sizeof(struct ipv6hdr) + srcsize);
+	/* ok ? -mk */
+
+	kfree(srcdata);
+	srcdata = NULL;
+
+	rtn = sa_idx.spi;
+
+	/* Otherwise checksum of fragmented udp packets fails (udp.c, csum_fold) */
+	(*skb)->ip_summed = CHECKSUM_UNNECESSARY; 
+	(*skb)->security |= RCV_CRYPT;
+
+	if (!sa_idx.sa->fuse_time) {
+		sa_idx.sa->fuse_time = jiffies;
+		sa_idx.sa->lifetime_c.usetime = (sa_idx.sa->fuse_time) / HZ;
+		ipsec_sa_mod_timer(sa_idx.sa);
+		IPSEC6_DEBUG("set fuse_time = %lu\n", (sa_idx.sa->fuse_time));
+	}
+	sa_idx.sa->lifetime_c.bytes += totalsize;
+	IPSEC6_DEBUG("sa->bytes=%-9u %-9u\n",			/* XXX: %-18Lu */
+			(__u32)((sa_idx.sa->lifetime_c.bytes) >> 32), (__u32)(sa_idx.sa->lifetime_c.bytes));
+	if (sa_idx.sa->lifetime_c.bytes >= sa_idx.sa->lifetime_s.bytes && sa_idx.sa->lifetime_s.bytes) {
+		sa_idx.sa->state = SADB_SASTATE_DYING;
+		IPSEC6_DEBUG("change sa state DYING\n");
+	}
+	if (sa_idx.sa->lifetime_c.bytes >= sa_idx.sa->lifetime_h.bytes && sa_idx.sa->lifetime_h.bytes) {
+		sa_idx.sa->state = SADB_SASTATE_DEAD;
+		IPSEC6_DEBUG("change sa state DEAD\n");
+	}
+
+
+unlock_finish:
+	write_unlock_bh(&sa_idx.sa->lock); /* unlock SA */
+	ipsec_sa_put(sa_idx.sa);
+		
+finish:
+	return rtn;
+}
+
+int ipsec6_input_check(struct sk_buff **skb, __u8 *nexthdr)
+{
+	int rtn = 0;
+	struct inet6_skb_parm *opt = NULL;
+	int result = IPSEC_ACTION_BYPASS;
+	struct sa_index auth_sa_idx;
+	struct sa_index esp_sa_idx;
+#ifdef CONFIG_IPV6_IPCOMP
+#if 0
+	struct sa_index comp_sa_idx;
+#endif
+#endif /* CONFIG_IPV6_IPCOMP */
+	struct selector selector;
+	struct ipsec_sp *policy = NULL;
+	int addr_type = 0;
+	struct ipv6hdr *hdr = (*skb)->nh.ipv6h;
+
+	IPSEC6_DEBUG("called\n");
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		char buf[64];
+		IPSEC6_DEBUG("dst addr: %s\n", 
+				in6_ntop( &hdr->daddr, buf));
+		IPSEC6_DEBUG("src addr: %s\n", 
+				in6_ntop( &hdr->saddr, buf));
+		IPSEC6_DEBUG("hdr->payload_len is %d\n", 
+			     ntohs(hdr->payload_len)); 
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+	/* XXX */
+	addr_type = ipv6_addr_type(&hdr->daddr);
+	if (addr_type & IPV6_ADDR_MULTICAST) {
+		IPSEC6_DEBUG("address type multicast skip!\n");
+		goto finish;
+	}
+	
+	if ( *nexthdr == NEXTHDR_UDP ) { /* IKE */
+		if (pskb_may_pull(*skb, (*skb)->h.raw - (*skb)->data + sizeof(struct udphdr))) {
+			if ((*skb)->h.uh->source == htons(500) &&
+			    (*skb)->h.uh->dest == htons(500)) {
+					IPSEC6_DEBUG("received IKE packet. skip!\n");
+					goto finish;
+			}
+		}
+	}
+
+	opt = (struct inet6_skb_parm*)((*skb)->cb);
+
+	if (opt->auth) {
+		sa_index_init(&auth_sa_idx);
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&auth_sa_idx.dst)->sin6_addr,
+		       &(*skb)->nh.ipv6h->daddr);
+		((struct sockaddr_in6 *)&auth_sa_idx.dst)->sin6_family = AF_INET6;
+		auth_sa_idx.prefixlen_d = 128;
+		auth_sa_idx.ipsec_proto = SADB_SATYPE_AH;
+		auth_sa_idx.spi = ((struct ipv6_auth_hdr*)((*skb)->nh.raw + opt->auth))->spi;
+		result |= IPSEC_ACTION_AUTH;
+		opt->auth=0;
+	}
+
+	if (opt->espspi) {
+		sa_index_init(&esp_sa_idx);
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&esp_sa_idx.dst)->sin6_addr,
+		       &(*skb)->nh.ipv6h->daddr);
+		((struct sockaddr_in6 *)&esp_sa_idx.dst)->sin6_family = AF_INET6;
+		esp_sa_idx.prefixlen_d = 128;
+		esp_sa_idx.ipsec_proto = SADB_SATYPE_ESP;
+		esp_sa_idx.spi = opt->espspi;
+		result |= IPSEC_ACTION_ESP;
+		opt->espspi=0;
+	}
+
+	if (result&IPSEC_ACTION_DROP) {
+		IPSEC6_DEBUG("result is drop.\n");
+		rtn = -EINVAL;
+		goto finish;
+	}
+
+	/* copy selector XXX port */
+	memset(&selector, 0, sizeof(struct selector));
+	
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	if (*nexthdr == NEXTHDR_IPV6) {
+		selector.mode = IPSEC_MODE_TUNNEL;
+	}
+#endif
+	selector.proto = *nexthdr;
+
+	IPSEC6_DEBUG("nexthdr = %u\n", *nexthdr);
+
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	if (selector.mode == IPSEC_MODE_TUNNEL) {
+		struct ipv6hdr *h = NULL;
+		if (pskb_may_pull(*skb, (*skb)->h.raw - (*skb)->data + sizeof(struct ipv6hdr))) {
+			h = (struct ipv6hdr*) (*skb)->h.raw;
+
+			((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
+			ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
+				       &h->saddr);
+			((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
+			ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
+				       &h->daddr);
+		} else {
+			rtn = -EINVAL;
+			goto finish;
+		}
+	} else {
+#endif
+		((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
+			       &(*skb)->nh.ipv6h->saddr);
+		((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
+			       &(*skb)->nh.ipv6h->daddr);
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	}
+#endif
+	selector.prefixlen_d = 128;
+	selector.prefixlen_s = 128;
+
+	/* beggining of matching check selector and policy */
+	IPSEC6_DEBUG("start match check SA and policy.\n");
+
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		char buf[64];
+		IPSEC6_DEBUG("selector dst addr: %s\n", 
+			  in6_ntop( &((struct sockaddr_in6 *)&selector.dst)->sin6_addr, buf));
+		IPSEC6_DEBUG("selector src addr: %s\n", 
+			  in6_ntop( &((struct sockaddr_in6 *)&selector.src)->sin6_addr, buf));
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+	policy = spd_get(&selector);
+		
+	if (policy) {
+
+		read_lock_bh(&policy->lock);
+
+		/* non-ipsec packet processing: If this packet doesn't
+		 * have any IPSEC headers, then consult policy to see
+		 * what to do with packet. If policy says to apply IPSEC,
+		 * and there is an SA, then pass packet to netxt layer,
+		 * if ther isn't an SA, then drop the packet.
+		 */
+		if (policy->policy_action == IPSEC_POLICY_DROP) {
+			rtn = -EINVAL;
+			read_unlock_bh(&policy->lock);
+			goto finish;
+		}
+
+		if (policy->policy_action == IPSEC_POLICY_BYPASS) {
+			rtn = 0;
+			read_unlock_bh(&policy->lock);
+			goto finish;
+		}
+
+		if (policy->policy_action == IPSEC_POLICY_APPLY) {
+			if (result&IPSEC_ACTION_AUTH) {
+				if (policy->auth_sa_idx) {
+					if (sa_index_compare(&auth_sa_idx, 
+							     policy->auth_sa_idx)) {
+						rtn = -EINVAL;
+					}
+				} else {
+					rtn = -EINVAL;
+				}
+			} else {
+				if (policy->auth_sa_idx) rtn = -EINVAL;
+			}
+
+			if (result&IPSEC_ACTION_ESP) {
+				if (policy->esp_sa_idx) {
+					if (sa_index_compare(&esp_sa_idx, 
+							     policy->esp_sa_idx)) {
+						rtn = -EINVAL;
+					}
+				} else {
+					rtn = -EINVAL;
+				}
+			} else {
+				if (policy->esp_sa_idx) rtn = -EINVAL;
+			}
+		}
+
+		read_unlock_bh(&policy->lock);
+		ipsec_sp_put(policy);
+	} else {
+		if (!result) {
+			rtn = 0;
+		} else {
+			IPSEC6_DEBUG("matching pair of SA and policy not found, through!\n"); 
+			rtn = -EINVAL;
+			goto finish;		
+		}
+	}
+
+
+	IPSEC6_DEBUG("end match check SA and policy.\n");
+	/* end of matching check selector and policy */
+		
+
+finish:
+
+	return rtn;
+}
+
diff -uNr -x CVS linux-2.5.43/net/ipv6/ipsec6_output.c linux25.43-ipsec/net/ipv6/ipsec6_output.c
--- linux-2.5.43/net/ipv6/ipsec6_output.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ipsec6_output.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,851 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ *
+ * Authors:
+ *   Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysctl.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/smp.h>
+#include <linux/list.h>
+#include <linux/random.h>
+#include <asm/uaccess.h>
+#include <net/ipv6.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/snmp.h>  
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#include <linux/pfkeyv2.h> /* sa proto type */
+#include <linux/pfkey.h>
+
+/* XXX: should move this function to net/ipv6/utils.c */
+static char* in6_ntop(const struct in6_addr *in6, char *buf){
+	if (!buf)
+		return NULL;
+	sprintf(buf,
+		"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+		ntohs(in6->s6_addr16[0]), ntohs(in6->s6_addr16[1]),
+		ntohs(in6->s6_addr16[2]), ntohs(in6->s6_addr16[3]),
+		ntohs(in6->s6_addr16[4]), ntohs(in6->s6_addr16[5]),
+		ntohs(in6->s6_addr16[6]), ntohs(in6->s6_addr16[7]));
+	return buf;
+}
+
+int ipsec6_out_ah_calc(const void *data, unsigned length, inet_getfrag_t getfrag, 
+		struct sk_buff *skb, struct ipv6_auth_hdr *authhdr, struct ipsec_sp *policy)
+{
+	struct ipsec_sa *sa = NULL;
+	char* pseudo_packet;
+	int packetlen;
+	struct inet6_skb_parm* parm;
+	struct ipv6_auth_hdr *pseudo_authhdr = NULL;
+	__u8* authdata = NULL;
+	
+	IPSEC6_DEBUG("called.\n");
+	if(!policy){
+		return -EINVAL;
+	}
+
+	if (!data) length=0;
+	if (!skb) {
+		IPSEC6_DEBUG("skb is NULL!\n");
+		return -EINVAL;
+	}
+
+	parm = (struct inet6_skb_parm*)skb->cb;
+
+	if (!authhdr) {
+		if (parm->auth) {
+			authhdr = (struct ipv6_auth_hdr*)(skb->nh.raw + parm->auth);
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	read_lock_bh(&policy->lock);
+
+	if (!policy->auth_sa_idx || !policy->auth_sa_idx->sa) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(ah) SA missing.\n", __FUNCTION__);
+		read_unlock_bh(&policy->lock);
+		return -EINVAL;
+	}
+
+	ipsec_sa_hold(policy->auth_sa_idx->sa);
+	sa = policy->auth_sa_idx->sa;
+
+	read_unlock_bh(&policy->lock);
+
+	packetlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+
+	pseudo_packet = kmalloc(packetlen,GFP_ATOMIC);
+	if (!pseudo_packet) {
+		ipsec_sa_put(sa);
+		return -ENOMEM;
+	}
+
+	if (length>0) {
+		struct in6_addr *addr;
+		addr=&skb->nh.ipv6h->saddr;
+		getfrag(data,addr,&pseudo_packet[skb->len],0,length);
+	}
+
+	pseudo_authhdr = (struct ipv6_auth_hdr*)(pseudo_packet + parm->auth);
+
+	authdata=kmalloc((sa->auth_algo.dx)->di->blocksize, GFP_ATOMIC);
+	if (!authdata) {
+		kfree(pseudo_packet);
+		ipsec_sa_put(sa);
+		return -ENOMEM;
+	}
+
+	write_lock_bh(&sa->lock);
+
+	/* authhdr->spi = htonl(sa->spi); */
+	IPSEC6_DEBUG("spi is 0x%x\n", ntohl(sa->spi));
+	authhdr->spi = sa->spi; /* -mk */
+	authhdr->seq_no = htonl(++sa->replay_window.seq_num);
+
+	memcpy(pseudo_packet,skb->nh.ipv6h,skb->len);
+
+	pseudo_authhdr->spi = authhdr->spi;
+	pseudo_authhdr->seq_no = authhdr->seq_no;
+
+	zero_out_for_ah(parm, pseudo_packet);
+
+	sa->auth_algo.dx->di->hmac_atomic(sa->auth_algo.dx,
+			sa->auth_algo.key,
+			sa->auth_algo.key_len,
+			pseudo_packet, packetlen, authdata);
+
+	memcpy(authhdr->auth_data, authdata, sa->auth_algo.digest_len);
+	
+	if (!sa->fuse_time) {
+		sa->fuse_time = jiffies;
+		sa->lifetime_c.usetime = (sa->fuse_time)/HZ;
+		ipsec_sa_mod_timer(sa);
+		IPSEC6_DEBUG("set fuse_time = %lu\n", sa->fuse_time);
+	}
+
+	sa->lifetime_c.bytes += packetlen;
+	IPSEC6_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa->lifetime_c.bytes) >> 32), 
+			(__u32)(sa->lifetime_c.bytes));
+
+	if (sa->lifetime_c.bytes >= sa->lifetime_s.bytes && 
+	    sa->lifetime_s.bytes) {
+		IPSEC6_DEBUG("change sa state DYING\n");
+		sa->state = SADB_SASTATE_DYING;
+	} 
+	if (sa->lifetime_c.bytes >= sa->lifetime_h.bytes && 
+	    sa->lifetime_h.bytes) {
+		sa->state = SADB_SASTATE_DEAD;
+		IPSEC6_DEBUG("change sa state DEAD\n");
+	}
+
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+
+	kfree(authdata);
+	kfree(pseudo_packet); 
+	return 0;
+
+}
+
+int ipsec6_out_get_ahsize(struct ipsec_sp *policy)
+{
+	int result = 0;
+	struct ipsec_sa *sa_ah = NULL;
+
+	IPSEC6_DEBUG("called.\n");
+
+	if (!policy) return 0;
+
+	write_lock_bh(&policy->lock);
+	if (policy->auth_sa_idx && policy->auth_sa_idx->sa) {
+		ipsec_sa_hold(policy->auth_sa_idx->sa);
+		sa_ah = policy->auth_sa_idx->sa;
+	}
+
+	write_unlock_bh(&policy->lock);
+
+	if (sa_ah) {
+		read_lock_bh(&sa_ah->lock);
+		if ( sa_ah->auth_algo.algo != SADB_AALG_NONE) {
+			result += (offsetof(struct ipv6_auth_hdr, auth_data) + 
+					sa_ah->auth_algo.digest_len + 7) & ~7;	/* 64 bit alignment */
+		}
+		read_unlock_bh(&sa_ah->lock);
+		ipsec_sa_put(sa_ah);
+	}
+
+	IPSEC6_DEBUG("Calculated size is %d.\n", result);
+	return result;
+}
+
+int ipsec6_out_get_espsize(struct ipsec_sp *policy)
+{
+	int result = 0;
+	struct ipsec_sa *sa_esp = NULL;
+
+	IPSEC6_DEBUG("called.\n");
+
+	if (!policy) return 0;
+
+	write_lock_bh(&policy->lock);
+
+	if (policy->esp_sa_idx && policy->esp_sa_idx->sa) {
+		ipsec_sa_hold(policy->esp_sa_idx->sa);
+		sa_esp = policy->esp_sa_idx->sa;
+	}
+	write_unlock_bh(&policy->lock);
+
+	if (sa_esp) {
+		read_lock_bh(&sa_esp->lock);
+		if ( sa_esp->esp_algo.algo != SADB_EALG_NONE){
+			result += sizeof(struct ipv6_esp_hdr) - 8;
+			result += sa_esp->esp_algo.cx->ci->ivsize;
+			result += (sa_esp->esp_algo.cx->ci->blocksize + 3) & ~3;
+			result += 4;	/* included pad_len and next_hdr  32 bit align */
+		}else{
+			read_unlock_bh(&sa_esp->lock);
+			ipsec_sa_put(sa_esp);
+			return 0;
+		}
+		if ( sa_esp->auth_algo.algo != SADB_AALG_NONE) {
+			result += (sa_esp->auth_algo.digest_len + 3) & ~3;	/* 32 bit alignment */
+		}
+		read_unlock_bh(&sa_esp->lock);
+		ipsec_sa_put(sa_esp);
+	}
+	IPSEC6_DEBUG("Calculated size is %d.\n", result);
+	return result;
+}
+
+struct ipv6_txoptions *ipsec6_out_get_newopt(struct ipv6_txoptions *opt, struct ipsec_sp *policy)
+{
+	struct ipv6_txoptions *newopt = NULL;
+	struct ipsec_sa *sa = NULL;
+	int ah_len = 0;
+
+	IPSEC6_DEBUG("called.\n");
+
+	
+	if (!policy) {
+		if (net_ratelimit())
+			printk(KERN_INFO "ipsec6_out_get_newopt: ipsec6_ptr/policy is NULL.\n");
+		return NULL;
+	}
+
+	read_lock_bh(&policy->lock);
+
+	if (policy->auth_sa_idx && policy->auth_sa_idx->sa) {
+
+		ipsec_sa_hold(policy->auth_sa_idx->sa);
+		sa = policy->auth_sa_idx->sa;
+		read_unlock_bh(&policy->lock);
+	
+		read_lock_bh(&sa->lock);
+	
+		if ( sa->auth_algo.algo == SADB_AALG_NONE ) {
+			if (net_ratelimit())
+				printk(KERN_INFO "ipsec6_out_get_newopt: Hash algorithm %d not present.\n",
+					sa->auth_algo.algo);
+			read_unlock_bh(&sa->lock);
+			ipsec_sa_put(sa);
+			return NULL;
+		}
+	
+		ah_len = (offsetof(struct ipv6_auth_hdr, auth_data) +
+				sa->auth_algo.digest_len + 7) & ~7;
+	
+		IPSEC6_DEBUG("ah_len=%d hash_size=%d\n", ah_len, sa->auth_algo.digest_len);
+		read_unlock_bh(&sa->lock);
+		ipsec_sa_put(sa);
+	
+	} else {
+		read_unlock_bh(&policy->lock);
+	}
+
+	if (opt) {
+		IPSEC6_DEBUG("There have already been opt.\n");
+		newopt = (struct ipv6_txoptions*)kmalloc(opt->tot_len + ah_len, GFP_ATOMIC);
+		if (!newopt) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "Couldn't allocate newopt - out of memory.\n");
+			return NULL;
+		}
+		memset(newopt, 0, opt->tot_len + ah_len);
+		memcpy(newopt, opt, sizeof(struct ipv6_txoptions));
+
+		if (ah_len)
+			newopt->auth = (struct ipv6_opt_hdr*)((char*)newopt + opt->tot_len);
+
+
+	} else if (ah_len) {
+
+		IPSEC6_DEBUG("There is not opt.\n");
+		newopt = (struct ipv6_txoptions*) kmalloc(sizeof(struct ipv6_txoptions) + ah_len, GFP_ATOMIC);
+		if (!newopt) {
+			if (net_ratelimit()) {
+				printk(KERN_INFO "ipsec6_out_get_newopt: could not allocate newopt.\n");
+				return NULL;
+			}
+		}
+		memset(newopt, 0, sizeof(struct ipv6_txoptions) + ah_len);
+		newopt->auth = (struct ipv6_opt_hdr*)((char*)newopt + sizeof(struct ipv6_txoptions));
+		newopt->tot_len = sizeof(struct ipv6_txoptions);
+	}
+
+	if (ah_len) {
+		newopt->tot_len += ah_len;
+		newopt->opt_flen += ah_len;
+		newopt->auth->hdrlen = (ah_len >> 2) - 2;
+	}
+
+	return newopt;
+}
+
+/*** ESP ***/
+
+void ipsec6_out_enc(const void *data, unsigned length, u8 proto, struct ipv6_txoptions *opt,
+		void **newdata, unsigned *newlength, struct ipsec_sp *policy)
+{
+	struct ipsec_sa *sa = NULL;
+	struct ipv6_esp_hdr *esphdr = NULL;
+	u8* srcdata = NULL;
+	u8* authdata = NULL;
+	int encblocksize = 0;
+	int encsize = 0, hashsize = 0, totalsize = 0;
+	int dstoptlen = 0;
+	int i;
+
+	IPSEC6_DEBUG("called.\nData ptr is %p, data length is %d.\n",data,length);
+
+	if (!policy) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s; ipsec policy is NULL\n", __FUNCTION__);
+		return;
+	}
+
+	read_lock_bh(&policy->lock);
+	if (!policy->esp_sa_idx || !policy->esp_sa_idx->sa) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) SA missing.\n", __FUNCTION__);
+		read_unlock_bh(&policy->lock);
+		return;
+	}
+	ipsec_sa_hold(policy->esp_sa_idx->sa);
+	sa = policy->esp_sa_idx->sa;
+	read_unlock_bh(&policy->lock);
+
+	write_lock_bh(&sa->lock);
+	/* Get algorithms */
+	if (sa->esp_algo.algo == SADB_EALG_NONE) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) encryption algorithm not present.\n", __FUNCTION__);
+		goto unlock_finish;
+		return;
+	}
+
+
+	if (!(sa->esp_algo.cx->ci)){
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: ipsec(esp) cipher_implementation not present.\n", __FUNCTION__);
+		goto unlock_finish;
+		return;
+	}
+
+	/* Calculate size */
+
+	if (opt && opt->dst1opt) 
+		dstoptlen = ipv6_optlen(opt->dst1opt);
+
+	encblocksize = (sa->esp_algo.cx->ci->blocksize + 3) & ~3;
+	encsize = dstoptlen + length + 2 + (encblocksize - 1);
+	encsize -= encsize % encblocksize;
+
+	/* The tail of payload does not have to be aligned with a multiple number of 64 bit.	*/
+	/* 64 bit alignment is adapted to the position of top of header. 			*/
+
+	if (sa->auth_algo.algo != SADB_AALG_NONE)
+		hashsize = sa->auth_algo.digest_len;
+
+
+	totalsize = sizeof(struct ipv6_esp_hdr) - 8 + sa->esp_algo.cx->ci->ivsize + encsize + hashsize;
+	IPSEC6_DEBUG("IV size=%d, enc size=%d hash size=%d, total size=%d\n",
+			 sa->esp_algo.cx->ci->ivsize, encsize, hashsize, totalsize);
+	
+	/* Get memory */
+	esphdr = kmalloc(totalsize, GFP_ATOMIC);
+	srcdata = kmalloc(encsize, GFP_ATOMIC);
+	if (!esphdr || !srcdata) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ipsec6_out_enc: Out of memory.\n");
+		if (esphdr) kfree(esphdr);
+		if (srcdata) kfree(srcdata);
+		goto unlock_finish;
+		return;
+	}
+
+	memset(esphdr, 0, totalsize);
+	memset(srcdata, 0, encsize);
+	/* Handle sequence number and fill in header fields */
+	esphdr->spi = sa->spi;
+	esphdr->seq_no = htonl(++sa->replay_window.seq_num);
+
+	/* Get source data, fill in padding and trailing fields */
+	if (opt && opt->dst1opt) 
+		memcpy(srcdata, opt->dst1opt, dstoptlen);
+
+	memcpy(srcdata + dstoptlen, data, length);
+	for (i = length + dstoptlen; i < encsize-2; i++) 
+		srcdata[i] = (u8)(i-length+dstoptlen+1);
+	srcdata[encsize-2] = (encsize-2)-length-dstoptlen;
+	IPSEC6_DEBUG("length=%d, encsize=%d\n", length+dstoptlen, encsize);
+	IPSEC6_DEBUG("encsize-2=%d\n", srcdata[encsize-2]);
+
+	if (opt && opt->dst1opt) {
+		/* ((struct ipv6_opt_hdr*)srcdata)->nexthdr = proto; */
+		srcdata[0] = proto;
+		opt->dst1opt = NULL;
+		opt->opt_flen -= dstoptlen;
+		srcdata[encsize-1] = NEXTHDR_DEST;
+	} else {
+		srcdata[encsize-1] = proto;
+	}
+
+	/* Do encryption */
+
+	if (!(sa->esp_algo.iv)) { /* first packet */
+		sa->esp_algo.iv = kmalloc(sa->esp_algo.cx->ci->ivsize, GFP_ATOMIC); /* kfree at SA removed */
+		get_random_bytes(sa->esp_algo.iv, sa->esp_algo.cx->ci->ivsize);
+		IPSEC6_DEBUG("IV initilized.\n");
+	}  /* else, had inserted a stored iv (last packet block) */
+
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		int i;
+		IPSEC6_DEBUG("IV is 0x");
+		if (sysctl_ipsec_debug_ipv6) {
+			for (i=0; i < sa->esp_algo.cx->ci->ivsize ; i++) {
+				printk(KERN_DEBUG "%x", (u8)(sa->esp_algo.iv[i]));
+			}
+		}
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+	sa->esp_algo.cx->ci->encrypt_atomic_iv(sa->esp_algo.cx, srcdata,
+					(u8 *)&esphdr->enc_data + sa->esp_algo.cx->ci->ivsize, encsize, sa->esp_algo.iv);
+	memcpy(esphdr->enc_data, sa->esp_algo.iv, sa->esp_algo.cx->ci->ivsize);
+	kfree(srcdata);
+	srcdata=NULL;
+	/* copy last block for next IV (src: enc_data + ivsize + encsize - ivsize) */
+	memcpy(sa->esp_algo.iv, esphdr->enc_data + encsize, sa->esp_algo.cx->ci->ivsize);
+	/* if CONFIG_IPSEC_DEBUG isn't defined here is finish of encryption process */
+
+	if(sa->auth_algo.algo){
+		authdata = kmalloc(sa->auth_algo.dx->di->blocksize, GFP_ATOMIC);
+		if (!authdata) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "ipsec6_out_enc: Out of memory.\n");
+			kfree(esphdr);
+			goto unlock_finish;
+			return;
+		}
+		memset(authdata, 0, sa->auth_algo.dx->di->blocksize);
+		sa->auth_algo.dx->di->hmac_atomic(sa->auth_algo.dx,
+				sa->auth_algo.key,
+				sa->auth_algo.key_len,
+				(char*)esphdr, totalsize-hashsize, authdata);
+		memcpy(&((char*)esphdr)[8 + sa->esp_algo.cx->ci->ivsize + encsize],
+			authdata, sa->auth_algo.digest_len);
+
+		kfree(authdata);
+	}	
+
+	if (!sa->fuse_time) {
+		sa->fuse_time = jiffies;
+		sa->lifetime_c.usetime = (sa->fuse_time)/HZ;
+		ipsec_sa_mod_timer(sa);
+		IPSEC6_DEBUG("set fuse_time = %lu\n", sa->fuse_time);
+	}
+	sa->lifetime_c.bytes += totalsize;
+	IPSEC6_DEBUG("sa->lifetime_c.bytes=%-9u %-9u\n",	/* XXX: %-18Lu */
+			(__u32)((sa->lifetime_c.bytes) >> 32), (__u32)(sa->lifetime_c.bytes));
+	if (sa->lifetime_c.bytes >= sa->lifetime_s.bytes && sa->lifetime_s.bytes) {
+		sa->state = SADB_SASTATE_DYING;
+		IPSEC6_DEBUG("change sa state DYING\n");
+	} 
+	if (sa->lifetime_c.bytes >= sa->lifetime_h.bytes && sa->lifetime_h.bytes) {
+		sa->state = SADB_SASTATE_DEAD;
+		IPSEC6_DEBUG("change sa state DEAD\n");
+	}
+
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+
+	authdata = NULL;
+	/* Set return values */
+	*newdata = esphdr;
+	*newlength = totalsize;
+	return;
+
+unlock_finish:
+	write_unlock_bh(&sa->lock);
+	ipsec_sa_put(sa);
+	return;
+}
+
+void ipsec6_out_finish(struct ipv6_txoptions *opt, struct ipsec_sp *policy)
+{
+
+	if (opt) {
+		kfree(opt);
+	}
+
+	if (policy) {
+		ipsec_sp_put(policy);
+	}
+}
+
+static int ipsec6_output_check_core(struct selector *selector, struct ipsec_sp **policy_ptr)
+{
+	int error = 0;
+	struct ipsec_sp *policy = NULL;
+	int result = IPSEC_ACTION_BYPASS; 	/* default */
+
+	IPSEC6_DEBUG("called\n");
+
+	if (!selector) {
+		IPSEC6_DEBUG("selector is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+	
+	policy = spd_get(selector);
+	if (!policy) { /* not match ! */
+		IPSEC6_DEBUG("no policy exists.\n");
+		result = IPSEC_ACTION_BYPASS;
+		goto err;
+	}
+
+	read_lock_bh(&policy->lock);
+	if (policy->policy_action == IPSEC_POLICY_DROP) {
+		result = IPSEC_ACTION_DROP;
+		read_unlock_bh(&policy->lock);
+		goto err;
+	}  else if (policy->policy_action == IPSEC_POLICY_BYPASS) {
+		result = IPSEC_ACTION_BYPASS;
+		read_unlock_bh(&policy->lock);
+		goto err;
+	}
+	
+	/* policy must then be to apply ipsec */
+	if (policy->auth_sa_idx) {
+		if (policy->auth_sa_idx->sa) {
+			read_lock_bh(&policy->auth_sa_idx->sa->lock);
+			switch (policy->auth_sa_idx->sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_AUTH;
+				break;
+			default:
+				result = IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&policy->auth_sa_idx->sa->lock);
+		} else {
+			read_unlock_bh(&policy->lock);
+			write_lock_bh(&policy->lock);
+			/* check and see if another process attached an sa to
+			 * the policy while we were acquiring the write lock.
+			 * Note: refcnt guarantees policy is still in memory.
+			 */
+			if (!policy->auth_sa_idx->sa)
+				policy->auth_sa_idx->sa = sadb_find_by_sa_index(policy->auth_sa_idx);
+			write_unlock_bh(&policy->lock); 
+			read_lock_bh(&policy->lock);
+			if (policy->auth_sa_idx->sa) 
+				result |= IPSEC_ACTION_AUTH;
+		 	else 
+				/* SADB_ACQUIRE message should be thrown up to KMd */
+				result = IPSEC_ACTION_DROP;
+		}
+	}
+
+	if (policy->esp_sa_idx) {
+		if (policy->esp_sa_idx->sa) {
+			read_lock_bh(&policy->esp_sa_idx->sa->lock);
+			switch (policy->esp_sa_idx->sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_ESP;
+				break;
+			default:
+				result = IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&policy->esp_sa_idx->sa->lock);
+		} else {
+			read_unlock_bh(&policy->lock);
+			write_lock_bh(&policy->lock);
+			/* check and see if another process attached an sa to
+			 * the policy while we were acquiring the write lock.
+			 * Note: refcnt guarantees policy is still in memory.
+			 */
+			if (!policy->esp_sa_idx->sa)
+				policy->esp_sa_idx->sa = sadb_find_by_sa_index(policy->esp_sa_idx);
+			write_unlock_bh(&policy->lock);
+			read_lock_bh(&policy->lock);
+			if (policy->esp_sa_idx->sa) 
+				result |= IPSEC_ACTION_ESP;
+			 else 
+				/* SADB_ACQUIRE message should be thrown up to KMd */
+				result = IPSEC_ACTION_DROP;
+		}
+	}
+
+	if (policy->comp_sa_idx) {
+		if (policy->comp_sa_idx->sa) {
+			read_lock_bh(&policy->comp_sa_idx->sa->lock);
+			switch (policy->comp_sa_idx->sa->state) {
+			case SADB_SASTATE_MATURE:
+			case SADB_SASTATE_DYING:
+				result |= IPSEC_ACTION_COMP;
+				break;
+			default:
+				result |= IPSEC_ACTION_DROP;
+			}
+			read_unlock_bh(&policy->comp_sa_idx->sa->lock);
+		} else {
+			read_unlock_bh(&policy->lock);
+			write_lock_bh(&policy->lock);
+			/* check and see if another process attached an sa to
+			 * the policy while we were acquiring the write lock.
+			 * Note: refcnt guarantees policy is still in memory.
+			 */
+			if (!policy->comp_sa_idx->sa)
+				policy->comp_sa_idx->sa = sadb_find_by_sa_index(policy->comp_sa_idx);
+			write_unlock_bh(&policy->lock);
+			read_lock_bh(&policy->lock);
+			if (policy->comp_sa_idx->sa) 
+				result |= IPSEC_ACTION_COMP;
+			else 
+				/* SADB_ACUIRE message should be thrown up to KMd */
+				result |= IPSEC_ACTION_DROP;
+		}
+	}
+
+	*policy_ptr= policy;
+	read_unlock_bh(&policy->lock);
+	IPSEC6_DEBUG("end\n");	
+
+err:
+	return result;
+}
+
+int ipsec6_output_check(struct sock *sk, struct flowi *fl, const u8 *data, struct ipsec_sp **policy_ptr)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct inet_opt *inet = inet_sk(sk);
+	struct in6_addr *saddr,*daddr;
+	u16 sport,dport;
+	unsigned char proto;
+	struct selector selector;
+	int result = IPSEC_ACTION_BYPASS; 	/* default */
+
+	IPSEC6_DEBUG("called\n");
+	if (!sk && !fl) {
+		printk(KERN_ERR "flowi and sock are NULL\n");
+		result = -EINVAL;
+		goto err;
+	}
+	
+	if (fl && fl->fl6_src) {
+		saddr = fl->fl6_src; 
+	} else {
+		if (sk) {
+			saddr = &np->saddr;
+		} else {
+			result = -EINVAL;
+			printk(KERN_ERR "sock is null\n");
+			goto err;
+		}
+	}
+
+	if (fl && fl->fl6_dst) {
+		daddr = fl->fl6_dst; 
+	} else {
+		if (sk) {
+			daddr = &np->daddr;
+		} else { 
+			result = -EINVAL;
+			printk(KERN_ERR "flowi and sock are NULL\n");
+			goto err;
+		}
+	}
+
+	if (fl) { 
+		sport=fl->uli_u.ports.sport;
+		dport=fl->uli_u.ports.dport;
+		proto=fl->proto;
+	} else if (sk) {
+		sport=inet->sport;
+		dport=inet->dport;
+		proto=sk->protocol;
+	} else {
+		result = -EINVAL;
+		printk(KERN_ERR "flowi and sock are NULL\n");
+		goto err;
+	}
+
+	/* for ISKAMP see RFC2408 */
+	if (proto == IPPROTO_UDP && 
+	    sport == htons(500) && dport == htons(500)) {
+		result = IPSEC_ACTION_BYPASS; 	/* default */
+		goto err;
+	}
+
+	/* XXX have to decide to the policy of ICMP messages -mk*/
+	if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
+		sport = 0;
+		dport = 0;
+	}
+
+	/* XXX config  port policy */
+	memset(&selector, 0, sizeof(struct selector));
+
+
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	if (proto == IPPROTO_IPV6) {
+		selector.mode = IPSEC_MODE_TUNNEL;
+	} else {
+#endif
+		((struct sockaddr_in6 *)&selector.src)->sin6_port = sport;	
+		((struct sockaddr_in6 *)&selector.dst)->sin6_port = dport;	
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	}
+	selector.proto = proto;
+
+	if (selector.mode == IPSEC_MODE_TUNNEL) {
+		struct ipv6hdr *h = (struct ipv6hdr*) data;
+		((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
+			       &h->saddr);
+		((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
+			       &h->daddr);
+	} else { /* IPSEC_MODE_TRANSPORT */
+#endif
+		((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
+			       saddr);
+		((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
+		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
+			       daddr);
+#ifdef CONFIG_IPV6_IPSEC_TUNNEL
+	}
+#endif
+
+	selector.prefixlen_d = 128;
+	selector.prefixlen_s = 128;
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		char buf[64];
+		IPSEC6_DEBUG("original src addr: %s\n", in6_ntop(saddr, buf));
+		IPSEC6_DEBUG("original src port: %u\n", ntohs(sport));
+		IPSEC6_DEBUG("original dst addr: %s\n", in6_ntop(daddr, buf));
+		IPSEC6_DEBUG("original dst port: %u\n", ntohs(dport));
+
+		IPSEC6_DEBUG("selector src addr: %s\n", 
+				in6_ntop( &((struct sockaddr_in6 *)&selector.src)->sin6_addr, buf));
+		IPSEC6_DEBUG("selector src port: %u\n", 
+				ntohs(((struct sockaddr_in6 *)&selector.src)->sin6_port));
+		IPSEC6_DEBUG("selector dst addr: %s\n", 
+				in6_ntop( &((struct sockaddr_in6 *)&selector.dst)->sin6_addr, buf));
+		IPSEC6_DEBUG("selector dst port: %u\n", 
+				ntohs(((struct sockaddr_in6 *)&selector.dst)->sin6_port));
+		IPSEC6_DEBUG("selector proto: %u\n", selector.proto);
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+	result = ipsec6_output_check_core(&selector, policy_ptr);
+
+ err:
+		return result;
+}
+
+
+int ipsec6_ndisc_check(struct in6_addr *saddr, struct in6_addr *daddr, struct ipsec_sp **policy_ptr)
+{
+	struct selector selector;
+	int result = IPSEC_ACTION_BYPASS; 	/* default */
+
+	IPSEC6_DEBUG("called\n");
+
+
+	/* XXX config  port policy */
+	memset(&selector, 0, sizeof(struct selector));
+
+	((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
+	ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
+		       saddr);
+	((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
+	ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
+		       daddr);
+	selector.proto = IPPROTO_ICMPV6;
+	selector.prefixlen_d = 128;
+	selector.prefixlen_s = 128;
+
+#ifdef CONFIG_IPSEC_DEBUG
+	{
+		char buf[64];
+		IPSEC6_DEBUG("original dst addr: %s\n", in6_ntop(daddr, buf));
+		IPSEC6_DEBUG("original src addr: %s\n", in6_ntop(saddr, buf));
+
+		IPSEC6_DEBUG("selector dst addr: %s\n", 
+				in6_ntop( &((struct sockaddr_in6 *)&selector.dst)->sin6_addr, buf));
+		IPSEC6_DEBUG("selector src addr: %s\n", 
+				in6_ntop( &((struct sockaddr_in6 *)&selector.src)->sin6_addr, buf));
+		IPSEC6_DEBUG("selector proto: %u\n", selector.proto);
+	}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+	result = ipsec6_output_check_core(&selector, policy_ptr);
+
+	return result;
+}
diff -uNr -x CVS linux-2.5.43/net/ipv6/ipv6_sockglue.c linux25.43-ipsec/net/ipv6/ipv6_sockglue.c
--- linux-2.5.43/net/ipv6/ipv6_sockglue.c	2002-10-16 12:27:14.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ipv6_sockglue.c	2002-10-16 15:27:50.000000000 +0900
@@ -51,6 +51,11 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#endif /* CONFIG_IPV6_IPSEC */
+
 struct ipv6_mib ipv6_statistics[NR_CPUS*2];
 
 static struct packet_type ipv6_packet_type =
@@ -284,7 +289,22 @@
 				struct tcp_opt *tp = tcp_sk(sk);
 				if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
 				    && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
+#ifdef CONFIG_IPV6_IPSEC
+					struct ipsec_sp *policy_ptr = NULL;
+					int action = ipsec6_output_check(sk,NULL,NULL,&policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
 					tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
+#ifdef CONFIG_IPV6_IPSEC
+					if (action != IPSEC_ACTION_DROP) {
+						printk(KERN_DEBUG "ipv6_setsockopt: ipsec6_output_check said DROP.\n");
+						if (opt->auth) {
+							action &=! IPSEC_ACTION_AUTH;
+						} else {
+							tp->ext_header_len += ipsec6_out_get_hdrsize(policy_ptr);
+						}
+					}
+					ipsec6_out_finish(NULL, policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
 					tcp_sync_mss(sk, tp->pmtu_cookie);
 				}
 			}
diff -uNr -x CVS linux-2.5.43/net/ipv6/ndisc.c linux25.43-ipsec/net/ipv6/ndisc.c
--- linux-2.5.43/net/ipv6/ndisc.c	2002-10-16 12:28:24.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/ndisc.c	2002-10-16 15:37:23.000000000 +0900
@@ -75,6 +75,11 @@
 #include <net/checksum.h>
 #include <linux/proc_fs.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec.h>
+#include <linux/ipsec6.h>
+#endif
+
 static struct socket *ndisc_socket;
 
 static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
@@ -383,6 +388,37 @@
         int len;
         struct sk_buff *skb;
 	int err;
+	int ipsec_hdrlen = 0;
+	int ipsec_authhdrlen = 0;
+#ifdef CONFIG_IPV6_IPSEC
+	struct in6_addr *src_addr;
+	struct inet6_ifaddr *ifp;
+	u8 *prevhdr;
+	struct ipsec_sp *policy_ptr = NULL;
+	int ipsec_action = IPSEC_ACTION_DROP;
+	struct ipv6_auth_hdr *authhdr = NULL;
+#endif
+
+#ifdef CONFIG_IPV6_IPSEC
+	ifp = ipv6_get_ifaddr(solicited_addr, dev);
+	if (ifp) {
+		src_addr = solicited_addr;
+		in6_ifa_put(ifp);
+	} else {
+		return;
+	}
+
+	ipsec_action = ipsec6_ndisc_check(src_addr, daddr, &policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_DROP || ipsec_action == -EINVAL) 
+		return;
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) 
+		ipsec_hdrlen += ipsec_authhdrlen = ipsec6_out_get_ahsize(policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) 
+		ipsec_hdrlen += ipsec6_out_get_espsize(policy_ptr);
+#endif
 
 	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
@@ -393,23 +429,53 @@
 			inc_opt = 0;
 	}
 
-	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15 + ipsec_hdrlen,
 				  0, &err);
 
 	if (skb == NULL) {
 		ND_PRINTK1("send_na: alloc skb failed\n");
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		return;
 	}
 
-	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
+	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len + ipsec_hdrlen) == 0) {
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		kfree_skb(skb);
 		return;
 	}
 
-	ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len + ipsec_authhdrlen);
 
+#ifdef CONFIG_IPV6_IPSEC
+	prevhdr = &(skb->nh.ipv6h->nexthdr);
+	if (ipsec_authhdrlen) {
+		struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
+		authhdr = (struct ipv6_auth_hdr *)skb_put(skb, ipsec_authhdrlen);
+		memset(authhdr, 0, ipsec_authhdrlen);
+		parm->auth = sizeof(struct ipv6hdr); /* offset of authentication header */
+		*prevhdr = IPPROTO_AH;
+		prevhdr = &(authhdr->nexthdr);
+		authhdr->hdrlen = (ipsec_authhdrlen>>2) - 2;
+		*prevhdr = IPPROTO_ICMPV6;
+	}
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		msg = (struct nd_msg *)kmalloc(len, GFP_ATOMIC);
+		if (!msg) {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree_skb(skb);
+			return;
+		}
+	} else {
+		msg = (struct nd_msg *) skb_put(skb, len);
+	}
+#else
 	msg = (struct nd_msg *) skb_put(skb, len);
-
+#endif
         msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
         msg->icmph.icmp6_code = 0;
         msg->icmph.icmp6_cksum = 0;
@@ -431,6 +497,33 @@
 						 csum_partial((__u8 *) msg, 
 							      len, 0));
 
+#ifdef CONFIG_IPV6_IPSEC
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *encdata = NULL;
+		int enclength = 0;
+		ipsec6_out_enc(msg, len, IPPROTO_ICMPV6, NULL, &encdata, &enclength, policy_ptr);
+		if (encdata) {
+			char *esphdr = skb_put(skb, enclength);
+			memcpy(esphdr, encdata, enclength);
+			*prevhdr = IPPROTO_ESP;
+			skb->nh.ipv6h->payload_len = 
+				htons(ntohs(skb->nh.ipv6h->payload_len) - len + enclength);
+		} else {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree(msg);
+			kfree_skb(skb);
+			return;
+		}
+		kfree(msg);
+	}
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		ipsec6_out_ah_calc(NULL, 0, NULL, skb, authhdr, policy_ptr);
+	}
+	
+	ipsec6_out_finish(NULL, policy_ptr);
+#endif
+
 	dev_queue_xmit(skb);
 
 	ICMP6_INC_STATS(Icmp6OutNeighborAdvertisements);
@@ -448,6 +541,14 @@
         int len;
 	int err;
 	int send_llinfo;
+	int ipsec_hdrlen = 0;
+	int ipsec_authhdrlen = 0;
+#ifdef CONFIG_IPV6_IPSEC
+	u8 *prevhdr;
+	struct ipsec_sp *policy_ptr = NULL;
+	struct ipv6_auth_hdr *authhdr = NULL;
+	int ipsec_action = IPSEC_ACTION_DROP;
+#endif
 
 	if (saddr == NULL) {
 		if (ipv6_get_lladdr(dev, &addr_buf))
@@ -460,21 +561,65 @@
 	if (send_llinfo)
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
-	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+#ifdef CONFIG_IPV6_IPSEC
+	ipsec_action = ipsec6_ndisc_check(saddr, daddr, &policy_ptr);
+
+	if (ipsec_action == IPSEC_ACTION_DROP || ipsec_action == -EINVAL) 
+		return;
+
+	if (ipsec_action & IPSEC_ACTION_AUTH)
+		ipsec_hdrlen += ipsec_authhdrlen = ipsec6_out_get_ahsize(policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) 
+		ipsec_hdrlen += ipsec6_out_get_espsize(policy_ptr);
+#endif
+
+	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15 + ipsec_hdrlen,
 				  0, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		return;
 	}
 
-	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
+	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len + ipsec_hdrlen) == 0) {
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		kfree_skb(skb);
 		return;
 	}
 
-	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len + ipsec_authhdrlen);
 
+#ifdef CONFIG_IPV6_IPSEC
+	prevhdr = &(skb->nh.ipv6h->nexthdr);
+	if (ipsec_authhdrlen) {
+		struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
+		authhdr = (struct ipv6_auth_hdr *)skb_put(skb, ipsec_authhdrlen);
+		memset(authhdr, 0, ipsec_authhdrlen);
+		parm->auth = sizeof(struct ipv6hdr); /* offset of authentication header */
+		*prevhdr = IPPROTO_AH;
+		prevhdr = &(authhdr->nexthdr);
+		authhdr->hdrlen = (ipsec_authhdrlen>>2) - 2;
+		*prevhdr = IPPROTO_ICMPV6;
+	}
+
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		msg = (struct nd_msg *)kmalloc(len, GFP_ATOMIC);
+		if (!msg) {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree_skb(skb);
+			return;
+		}
+	} else {
+		msg = (struct nd_msg *)skb_put(skb, len);
+	}
+#else
 	msg = (struct nd_msg *)skb_put(skb, len);
+#endif
 	msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
 	msg->icmph.icmp6_code = 0;
 	msg->icmph.icmp6_cksum = 0;
@@ -492,6 +637,35 @@
 						 IPPROTO_ICMPV6,
 						 csum_partial((__u8 *) msg, 
 							      len, 0));
+
+#ifdef CONFIG_IPV6_IPSEC
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *encdata = NULL;
+		int enclength = 0;
+		ipsec6_out_enc(msg, len, IPPROTO_ICMPV6, NULL, &encdata, &enclength, policy_ptr);
+		if (encdata) {
+			char *esphdr = skb_put(skb, enclength);
+			memcpy(esphdr, encdata, enclength);
+			*prevhdr = IPPROTO_ESP;
+
+			skb->nh.ipv6h->payload_len = 
+				htons(ntohs(skb->nh.ipv6h->payload_len) - len + enclength);
+		} else {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree(msg);
+			kfree_skb(skb);
+			return;
+		}
+		kfree(msg);
+	}
+	
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		ipsec6_out_ah_calc(NULL, 0, NULL, skb, authhdr, policy_ptr);
+	}
+
+	ipsec6_out_finish(NULL, policy_ptr);
+#endif
+
 	/* send it! */
 	dev_queue_xmit(skb);
 
@@ -508,26 +682,78 @@
 	__u8 * opt;
         int len;
 	int err;
+	int ipsec_hdrlen = 0;
+	int ipsec_authhdrlen = 0;
+#ifdef CONFIG_IPV6_IPSEC
+	u8 *prevhdr;
+	struct ipsec_sp *policy_ptr = NULL;
+	struct ipv6_auth_hdr *authhdr = NULL;
+	int ipsec_action = ipsec6_ndisc_check(saddr, daddr, &policy_ptr);
+
+#endif
+
+#ifdef CONFIG_IPV6_IPSEC
+	if (ipsec_action == IPSEC_ACTION_DROP || ipsec_action == -EINVAL) 
+		return;
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) 
+		ipsec_hdrlen += ipsec_authhdrlen = ipsec6_out_get_ahsize(policy_ptr);
+
+	if (ipsec_action & IPSEC_ACTION_ESP) 
+		ipsec_hdrlen += ipsec6_out_get_espsize(policy_ptr);
+#endif
 
 	len = sizeof(struct icmp6hdr);
 	if (dev->addr_len)
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
-        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15 + ipsec_hdrlen,
 				  0, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		return;
 	}
 
-	if (ndisc_build_ll_hdr(skb, dev, daddr, NULL, len) == 0) {
+	if (ndisc_build_ll_hdr(skb, dev, daddr, NULL, len + ipsec_hdrlen) == 0) {
+#ifdef CONFIG_IPV6_IPSEC
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif
 		kfree_skb(skb);
 		return;
 	}
 
-	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len + ipsec_authhdrlen);
 
+#ifdef CONFIG_IPV6_IPSEC
+	prevhdr = &(skb->nh.ipv6h->nexthdr);
+
+	if (ipsec_authhdrlen) {
+		struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+		authhdr = (struct ipv6_auth_hdr*)skb_put(skb, ipsec_authhdrlen);
+		memset(authhdr, 0, ipsec_authhdrlen);
+		opt->auth = sizeof(struct ipv6hdr);
+		*prevhdr = IPPROTO_AH;
+		prevhdr = &(authhdr->nexthdr);
+		authhdr->hdrlen = (ipsec_authhdrlen>>2) - 2;
+		*prevhdr = IPPROTO_ICMPV6;
+	}
+	
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		hdr = (struct icmp6hdr *)kmalloc(len, GFP_ATOMIC);
+		if (!hdr) {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree_skb(skb);
+			return;
+		}
+	} else {
+		hdr = (struct icmp6hdr *)skb_put(skb, len);
+	}
+#else
         hdr = (struct icmp6hdr *) skb_put(skb, len);
+#endif
         hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
         hdr->icmp6_code = 0;
         hdr->icmp6_cksum = 0;
@@ -543,6 +769,33 @@
 					   IPPROTO_ICMPV6,
 					   csum_partial((__u8 *) hdr, len, 0));
 
+#ifdef CONFIG_IPV6_IPSEC
+	if (ipsec_action & IPSEC_ACTION_ESP) {
+		void *encdata = NULL;
+		int enclength = 0;
+		ipsec6_out_enc(hdr, len, IPPROTO_ICMPV6, NULL, &encdata, &enclength, policy_ptr);
+		if (encdata) {
+			char *esphdr = skb_put(skb, enclength);
+			memcpy(esphdr, encdata, enclength);
+			*prevhdr = IPPROTO_ESP;
+
+			skb->nh.ipv6h->payload_len =
+				htons(ntohs(skb->nh.ipv6h->payload_len) - len + enclength);
+		} else {
+			ipsec6_out_finish(NULL, policy_ptr);
+			kfree(hdr);
+			kfree_skb(skb);
+			return;
+		}
+	}
+
+	if (ipsec_action & IPSEC_ACTION_AUTH) {
+		ipsec6_out_ah_calc(NULL, 0, NULL, skb, authhdr, policy_ptr);
+	}
+
+	ipsec6_out_finish(NULL, policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
+
 	/* send it! */
 	dev_queue_xmit(skb);
 
diff -uNr -x CVS linux-2.5.43/net/ipv6/reassembly.c linux25.43-ipsec/net/ipv6/reassembly.c
--- linux-2.5.43/net/ipv6/reassembly.c	2002-10-16 12:27:49.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/reassembly.c	2002-10-16 15:27:50.000000000 +0900
@@ -534,12 +534,20 @@
 	nhoff = head->h.raw - head->nh.raw;
 
 	if (payload_len > 65535) {
+#ifdef CONFIG_IPV6_IPSEC
+		if (payload_len > 65535 + 8)
+#else
 		payload_len -= 8;
 		if (payload_len > 65535)
+#endif
 			goto out_oversize;
 		remove_fraghdr = 1;
 	}
 
+#ifdef CONFIG_IPV6_IPSEC
+	remove_fraghdr = 1;
+#endif /* CONFIG_IPV6_IPSEC */
+
 	/* Head of list must not be cloned. */
 	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
 		goto out_oom;
@@ -576,6 +584,9 @@
 		memmove(head->head+8, head->head, (head->data-head->head)-8);
 		head->mac.raw += 8;
 		head->nh.raw += 8;
+#ifdef CONFIG_IPV6_IPSEC
+		payload_len -= 8;
+#endif
 	} else {
 		((struct frag_hdr*)head->h.raw)->frag_off = 0;
 	}
diff -uNr -x CVS linux-2.5.43/net/ipv6/tcp_ipv6.c linux25.43-ipsec/net/ipv6/tcp_ipv6.c
--- linux-2.5.43/net/ipv6/tcp_ipv6.c	2002-10-16 12:28:23.000000000 +0900
+++ linux25.43-ipsec/net/ipv6/tcp_ipv6.c	2002-10-16 15:27:50.000000000 +0900
@@ -51,6 +51,10 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_IPV6_IPSEC
+#include <linux/ipsec6.h>
+#endif /* CONFIG_IPV6_IPSEC */
+
 static void	tcp_v6_send_reset(struct sk_buff *skb);
 static void	tcp_v6_or_send_ack(struct sk_buff *skb, struct open_request *req);
 static void	tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, 
@@ -675,8 +679,24 @@
 	inet->rcv_saddr = LOOPBACK4_IPV6;
 
 	tp->ext_header_len = 0;
-	if (np->opt)
-		tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
+	{
+#ifdef CONFIG_IPV6_IPSEC
+		struct ipsec_sp *policy_ptr = NULL;
+		int action = ipsec6_output_check(sk, &fl, NULL, &policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
+		if (np->opt)
+			tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
+#ifdef CONFIG_IPV6_IPSEC
+		if (action != IPSEC_ACTION_DROP) {
+			if (np->opt && np->opt->auth) {
+				action &= ~IPSEC_ACTION_AUTH;
+			} else {
+				tp->ext_header_len += ipsec6_out_get_hdrsize(policy_ptr);
+			}
+		}
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif /* CONFIG_IPv6_IPSEC */
+	}
 	tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
 	inet->dport = usin->sin6_port;
@@ -1385,10 +1405,25 @@
 	}
 
 	newtp->ext_header_len = 0;
-	if (newnp->opt)
-		newtp->ext_header_len = newnp->opt->opt_nflen +
-					newnp->opt->opt_flen;
-
+	{
+#ifdef CONFIG_IPV6_IPSEC
+		struct ipsec_sp *policy_ptr = NULL;
+		int action = ipsec6_output_check(sk, &fl, NULL, &policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
+		if (newnp->opt)
+			newtp->ext_header_len = newnp->opt->opt_nflen +
+						newnp->opt->opt_flen;
+#ifdef CONFIG_IPV6_IPSEC
+		if (action != IPSEC_ACTION_DROP) {
+			if (np->opt && np->opt->auth) {
+				action &= ~IPSEC_ACTION_AUTH;
+			} else {
+				newtp->ext_header_len += ipsec6_out_get_hdrsize(policy_ptr);
+			}
+		}
+		ipsec6_out_finish(NULL, policy_ptr);
+#endif /* CONFIG_IPV6_IPSEC */
+	}
 	tcp_sync_mss(newsk, dst->pmtu);
 	newtp->advmss = dst->advmss;
 	tcp_initialize_rcv_mss(newsk);
diff -uNr -x CVS linux-2.5.43/net/key/Config.help linux25.43-ipsec/net/key/Config.help
--- linux-2.5.43/net/key/Config.help	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/Config.help	2002-10-16 15:27:50.000000000 +0900
@@ -0,0 +1,27 @@
+CONFIG_IPSEC
+
+  This option enables (extended) PF_KEY(v2) support, which manages 
+  Security Association and Security Policy for IPsec (and IPComp).
+  Say Y here if you want to enable IPsec.  
+  Note: Since IPsec is mandatory feature of IPv6, you probably want
+  to say Y here when you enable IPv6.
+
+  You also need to say Y to Cryptographic API support, ciphers,
+  digest and IPsec for each IP versions, you need.
+
+CONFIG_IPSEC_DEBUG
+
+  Say Y here if you want to get additional messages useful for
+  debugging the IPsec (IPsec6, PFKEY, SADB, SPD) code. 
+
+  You can enable/disable these parameters via sysctl(/proc/net/ipsec/).
+
+CONFIG_IPSEC_DEBUG_DISABLE_DEFAULT
+
+  Normally IPsec debugging messages are activated by default, 
+  if you set CONFIG_IPSEC_DEBUG.
+
+  IPsec debugging messages are activated by default and you will receive 
+  tons of log messages if you enable "IPsec Debug messages" option
+  (CONFIG_IPSEC_DEBUG).  This option turns these debug messages off
+  by default (at the boot time).
diff -uNr -x CVS linux-2.5.43/net/key/Config.in linux25.43-ipsec/net/key/Config.in
--- linux-2.5.43/net/key/Config.in	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/Config.in	2002-10-16 15:27:50.000000000 +0900
@@ -0,0 +1,13 @@
+#comment '  PF_KEY_V2 Configuration'
+
+if [ "$CONFIG_SYSCTL" = "y" ] ; then
+  if [ "$CONFIG_IPSEC" != "n" ]; then
+    bool '    IPsec: IPsec Debug messages' CONFIG_IPSEC_DEBUG
+    if [ "$CONFIG_IPSEC_DEBUG" = "y" ] ; then
+      bool '      IPsec: IPsec debugging off by default' CONFIG_IPSEC_DEBUG_DISABLE_DEFAULT
+    fi
+  fi
+fi
+define_bool CONFIG_IPSEC_TUNNEL y
+
+#endmenu
diff -uNr -x CVS linux-2.5.43/net/key/Makefile linux25.43-ipsec/net/key/Makefile
--- linux-2.5.43/net/key/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/Makefile	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,17 @@
+#
+# Makefile for the IPsec basic part (PF_KEY_V2)
+#
+# $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $
+
+export-objs := key.o
+
+obj-y := af_key.o pfkey_v2_build.o pfkey_v2_ext_bits.o \
+	pfkey_v2_msg.o pfkey_v2_msg_add.o pfkey_v2_msg_delete.o pfkey_v2_msg_get.o \
+	pfkey_v2_msg_getspi.o pfkey_v2_msg_update.o pfkey_v2_msg_flow.o \
+	sa_index.o sadb.o spd.o sockaddr_utils.o 
+
+
+obj-$(CONFIG_SYSCTL) += sysctl_net_ipsec.o
+
+EXTRA_CFLAGS+=-I./
+include $(TOPDIR)/Rules.make
diff -uNr -x CVS linux-2.5.43/net/key/af_key.c linux25.43-ipsec/net/key/af_key.c
--- linux-2.5.43/net/key/af_key.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/af_key.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,884 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/* 
+ * This file derived from FreeS/WAN-1.9 pfkey_v2.c.
+ * But changed a lot from the origin.
+ *
+ * 	Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ * 	Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
+ *
+ * Copyright (C)2001 USAGI/WIDE Project
+ */ 
+/*
+ * RFC2367 PF_KEYv2 Key management API domain socket I/F
+ * Copyright (C) 1999, 2000  Richard Guy Briggs.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+
+/*
+ *		Template from /usr/src/linux-2.0.36/net/unix/af_unix.c.
+ *		Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h> /* struct socket */
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/sock.h> /* struct sock */
+#include <net/af_unix.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#include <linux/types.h>
+ 
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/spd.h>
+
+#include <linux/ipsec.h>
+
+#include "pfkey_v2_msg.h"
+
+
+struct proto_ops SOCKOPS_WRAPPED(pfkey_ops);
+struct sock *pfkey_sock_list = NULL;
+
+struct socket_list *pfkey_open_sockets = NULL;
+struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
+rwlock_t pfkey_sk_lock = RW_LOCK_UNLOCKED;
+
+#ifdef CONFIG_SYSCTL
+extern void ipsec_sysctl_register(void);
+extern void ipsec_sysctl_unregister(void);
+#endif /* CONFIG_SYSCTL */
+
+/* derived from FreeS/WAN-1.9 pfkey_v2_parse.c (mk) */
+int
+pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg)
+{
+	int error = 0;
+	struct sadb_msg *pfkey_reply = NULL;
+	struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1];
+	struct socket_list *pfkey_socketsp = 0;
+
+	if (pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
+		return -EINVAL;
+	}
+	
+	memset(reply_ext_msgs, 0, SADB_EXT_MAX+1);
+
+	switch (pfkey_msg->sadb_msg_type) {
+	case SADB_GETSPI:
+		error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_GETSPI\n");
+		break;
+	case SADB_UPDATE:
+		error = -EINVAL;/* XXX */
+		PFKEY_DEBUG("PF_KEY:interp: SADB_UPDATE\n");
+		break;
+	case SADB_ADD:
+		error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_ADD\n");
+		break;
+	case SADB_DELETE:
+		error = sadb_msg_delete_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_DELETE\n");
+		break;
+	case SADB_FLUSH:
+		error = sadb_msg_flush_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_FLUSH\n");
+		break;
+	case SADB_REGISTER:
+		error = sadb_msg_register_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_REGISTER\n");
+		break;
+	case SADB_X_GRPSA:
+		error =  -EINVAL;/* XXX */
+		PFKEY_DEBUG("PF_KEY:interp: SADB_X_GRPSA\n");
+		break;
+	case SADB_X_ADDFLOW:
+		error = sadb_msg_addflow_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_ADDFLOW\n");
+		break;
+	case SADB_X_DELFLOW:
+		error = sadb_msg_delflow_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PF_KEY:interp: SADB_DELFLOW\n");
+		break;
+
+	case SADB_X_FLUSH_SP:
+		error = sadb_msg_flush_sp_parse(sk, pfkey_msg, &pfkey_reply);
+		PFKEY_DEBUG("PFKEY:interp: SADB_X_FLUSH_SP\n");
+		break;
+	default:
+		error = -EINVAL;
+		break;
+	}
+	
+	if (error) {
+		PFKEY_DEBUG("PFKEY:interp: parse routine return error=%d\n", error);
+		goto err;
+	}
+
+	switch (pfkey_msg->sadb_msg_type) {
+
+	case SADB_GETSPI:
+	case SADB_UPDATE:
+	case SADB_ADD:
+	case SADB_DELETE:
+	case SADB_FLUSH:
+	case SADB_X_ADDFLOW:
+	case SADB_X_DELFLOW:
+	case SADB_X_FLUSH_SP:
+		write_lock_bh(&pfkey_sk_lock);
+		for (pfkey_socketsp = pfkey_open_sockets;
+	    		pfkey_socketsp;
+	    			pfkey_socketsp = pfkey_socketsp->next)
+		{
+			pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
+		}
+		write_unlock_bh(&pfkey_sk_lock);
+		break;
+	case SADB_GET:
+	case SADB_DUMP:
+	case SADB_REGISTER:
+		write_lock_bh(&pfkey_sk_lock);
+		pfkey_upmsg(sk->socket, pfkey_reply);
+		write_unlock_bh(&pfkey_sk_lock);
+		break;
+	case SADB_ACQUIRE:
+		write_lock_bh(&pfkey_sk_lock);
+		for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype];
+			pfkey_socketsp;
+				pfkey_socketsp = pfkey_socketsp->next)
+		{
+			pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
+		}
+		write_unlock_bh(&pfkey_sk_lock);
+		break;
+	default:
+		error = -EINVAL;
+		goto err;
+	}
+
+	if (pfkey_reply)
+		kfree(pfkey_reply);
+
+	return 0;
+err:
+	if (pfkey_reply)
+		kfree(pfkey_reply);
+
+	pfkey_reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
+	if (!pfkey_reply){
+		return -ENOMEM;
+	}
+	memcpy(pfkey_reply, pfkey_msg, sizeof(pfkey_reply));
+	pfkey_reply->sadb_msg_errno = error;
+
+	write_lock_bh(&pfkey_sk_lock);
+	pfkey_upmsg(sk->socket, pfkey_reply);
+	for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype];
+		pfkey_socketsp;
+			pfkey_socketsp = pfkey_socketsp->next)
+	{
+		pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply);
+	}
+	write_unlock_bh(&pfkey_sk_lock);
+
+	if (pfkey_reply) {
+		kfree(pfkey_reply);
+	}
+
+	return error;
+}
+
+int
+pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
+{
+	struct socket_list *socket_listp,*prev;
+
+	PFKEY_DEBUG("called\n");
+	if (!socketp) {
+		return -EINVAL;
+	}
+
+	if (!sockets) {
+		return -EINVAL;
+	}
+
+	socket_listp = *sockets;
+	prev = NULL;
+	
+	while (socket_listp != NULL) {
+		if (socket_listp->socketp == socketp) {
+			if (prev != NULL) {
+				prev->next = socket_listp->next;
+			} else {
+				*sockets = socket_listp->next;
+			}
+			
+			kfree((void*)socket_listp);
+			PFKEY_DEBUG("removed sock=%p\n", socketp);
+			
+			break;
+		}
+		prev = socket_listp;
+		socket_listp = socket_listp->next;
+	}
+	PFKEY_DEBUG("end\n");
+
+	return 0;
+}
+
+int
+pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
+{
+	struct socket_list *socket_listp;
+
+	PFKEY_DEBUG("called\n");
+	if (!socketp) {
+		return -EINVAL;
+	}
+
+	if (!sockets) {
+		return -EINVAL;
+	}
+
+	if ((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	
+	socket_listp->socketp = socketp;
+	socket_listp->next = *sockets;
+	*sockets = socket_listp;
+	PFKEY_DEBUG("inserted sock=%p\n", socketp);
+	PFKEY_DEBUG("end\n");
+
+	return 0;
+}
+  
+static void
+pfkey_insert_socket(struct sock *sk)
+{
+	PFKEY_DEBUG("called\n");
+	write_lock_bh(&pfkey_sk_lock);
+	sk->next=pfkey_sock_list;
+	pfkey_sock_list=sk;
+	write_unlock_bh(&pfkey_sk_lock);
+	PFKEY_DEBUG("end\n");
+}
+
+static void
+pfkey_remove_socket(struct sock *sk)
+{
+	struct sock **s;
+	
+	PFKEY_DEBUG("called\n");
+	s=&pfkey_sock_list;
+
+	while (*s!=NULL) {
+		if (*s==sk) {
+			*s=sk->next;
+			sk->next=NULL;
+			goto final;
+		}
+		s=&((*s)->next);
+	}
+
+	PFKEY_DEBUG("end\n");
+final:
+	return;
+}
+
+static void
+pfkey_destroy_socket(struct sock *sk)
+{
+	struct sk_buff *skb;
+
+	PFKEY_DEBUG("called\n");
+	pfkey_remove_socket(sk);
+
+	while (sk && (skb=skb_dequeue(&sk->receive_queue)) !=NULL ) {
+#if defined(CONFIG_IPSEC_DEBUG) && defined(CONFIG_SYSCTL)
+		if (sysctl_ipsec_debug_pfkey) {
+			printk(KERN_DEBUG "pfkey_destroy_socket: pfkey_skb contents:");
+			printk(" next:%p", skb->next);
+			printk(" prev:%p", skb->prev);
+			printk(" list:%p", skb->list);
+			printk(" sk:%p", skb->sk);
+			printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec);
+			printk(" dev:%p", skb->dev);
+			if (skb->dev) {
+				if (skb->dev->name) {
+					printk(" dev->name:%s", skb->dev->name);
+				} else {
+					printk(" dev->name:NULL?");
+				}
+			} else {
+				printk(" dev:NULL");
+			}
+			printk(" h:%p", skb->h.raw);
+			printk(" nh:%p", skb->nh.raw);
+			printk(" mac:%p", skb->mac.raw);
+			printk(" dst:%p", skb->dst);
+			{
+				int i;
+				
+				printk(" cb");
+				for (i=0; i<48; i++) {
+					printk(":%2x", skb->cb[i]);
+				}
+			}
+			printk(" len:%d", skb->len);
+			printk(" csum:%d", skb->csum);
+			printk(" cloned:%d", skb->cloned);
+			printk(" pkt_type:%d", skb->pkt_type);
+			printk(" ip_summed:%d", skb->ip_summed);
+			printk(" priority:%d", skb->priority);
+			printk(" protocol:%d", skb->protocol);
+			printk(" security:%d", skb->security);
+			printk(" truesize:%d", skb->truesize);
+			printk(" head:%p", skb->head);
+			printk(" data:%p", skb->data);
+			printk(" tail:%p", skb->tail);
+			printk(" end:%p", skb->end);
+			{
+				unsigned int i;
+				printk(" data");
+				for (i=(unsigned int)(skb->head); i<(unsigned int)(skb->end); i++) {
+					printk(":%2x", (unsigned char)(*(char*)(i)));
+				}
+			}
+			printk(" destructor:%p", skb->destructor);
+			printk("\n");
+		}
+#endif /* CONFIG_IPSEC_DEBUG and CONFIG_SYSCTL */
+		PFKEY_DEBUG("skb=%p freed.\n", skb);
+		kfree_skb(skb);
+	}
+
+	sk->dead = 1;
+	sk_free(sk);
+	PFKEY_DEBUG("end\n");
+}
+
+int
+pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
+{
+	int error;
+	struct sk_buff * skb = NULL;
+	struct sock *sk;
+
+	PFKEY_DEBUG("called\n");
+	if (sock == NULL) {
+		return -EINVAL;
+	}
+
+	if (pfkey_msg == NULL) {
+		return -EINVAL;
+	}
+
+	sk = sock->sk;
+
+	if (sk == NULL) {
+		return -EINVAL;
+	}
+
+	if (!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) {
+		return -ENOBUFS;
+	}
+	
+	skb->dev = NULL;
+	
+	if (skb_tailroom(skb) < pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
+		printk(KERN_WARNING "klips_error:pfkey_upmsg: "
+		       "tried to skb_put %ld, %d available.  This should never happen, please report.\n",
+		       (unsigned long int)pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN,
+		       skb_tailroom(skb));
+		kfree_skb(skb);
+
+		return -ENOBUFS;
+	}
+	skb->h.raw = skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+	memcpy(skb->h.raw, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+
+	if ((error = sock_queue_rcv_skb(sk, skb)) < 0) {
+		skb->sk=NULL;
+		kfree_skb(skb);
+		return error;
+	}
+	PFKEY_DEBUG("end\n");
+	return 0;
+}
+
+static int
+pfkey_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	PFKEY_DEBUG("called\n");
+	if (sock == NULL) {
+		return -EINVAL;
+	}
+
+	if (sock->type != SOCK_RAW) {
+		return -ESOCKTNOSUPPORT;
+	}
+
+	if (protocol != PF_KEY_V2) {
+		return -EPROTONOSUPPORT;
+	}
+
+	if ((current->uid != 0)) {
+		return -EACCES;
+	}
+
+	sock->state = SS_UNCONNECTED;
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif /* MODULE */
+
+	if ((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1, NULL)) == NULL)
+	{
+#ifdef MODULE
+		MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+		return -ENOMEM;
+	}
+
+	sock_init_data(sock, sk);
+
+	sk->destruct = NULL;
+	sk->reuse = 1;
+	sock->ops = &SOCKOPS_WRAPPED(pfkey_ops);
+
+	sk->zapped=0;
+	sk->family = PF_KEY;
+	sk->protocol = protocol;
+	key_pid(sk) = current->pid;
+
+	pfkey_insert_socket(sk);
+	pfkey_list_insert_socket(sock, &pfkey_open_sockets);
+
+	PFKEY_DEBUG("end\n");
+	return 0;
+}
+
+static int
+pfkey_release(struct socket *sock)
+{
+	struct sock *sk;
+	int i;
+
+	PFKEY_DEBUG("called\n");
+	if (sock==NULL) {
+		return 0; /* -EINVAL; */
+	}
+		
+	sk=sock->sk;
+	
+	/* May not have data attached */
+	if (sk==NULL) {
+		return 0; /* -EINVAL; */
+	}
+		
+	if (!sk->dead)
+		if (sk->state_change) {
+			sk->state_change(sk);
+		}
+
+	sock->sk = NULL;
+
+	/* Try to flush out this socket. Throw out buffers at least */
+	write_lock_bh(&pfkey_sk_lock);
+	pfkey_destroy_socket(sk);
+	pfkey_list_remove_socket(sock, &pfkey_open_sockets);
+	for (i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
+		pfkey_list_remove_socket(sock, &pfkey_registered_sockets[i]);
+		PFKEY_DEBUG("socket=%p is released, SA type is %d\n", sock, i);
+	}
+	write_unlock_bh(&pfkey_sk_lock);
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+
+	PFKEY_DEBUG("called\n");
+	return 0;
+}
+
+static int
+pfkey_shutdown(struct socket *sock, int mode)
+{
+	struct sock *sk;
+
+	PFKEY_DEBUG("called\n");
+	if (sock == NULL) {
+		return -EINVAL;
+	}
+
+	sk=sock->sk;
+	
+	if (sk == NULL) {
+		return -EINVAL;
+	}
+
+	mode++;
+	
+	if (mode&SEND_SHUTDOWN) {
+		sk->shutdown|=SEND_SHUTDOWN;
+		sk->state_change(sk);
+	}
+
+	if (mode&RCV_SHUTDOWN) {
+		sk->shutdown|=RCV_SHUTDOWN;
+		sk->state_change(sk);
+	}
+	PFKEY_DEBUG("end\n");
+	return 0;
+}
+
+/*
+ *	Send PF_KEY data down.
+ */
+		
+static int
+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+{
+	struct sock *sk;
+	int error = 0;
+	struct sadb_msg *pfkey_msg = NULL;
+
+	PFKEY_DEBUG("called\n");
+	if (sock == NULL) return -EINVAL;
+
+	sk = sock->sk;
+
+	if (sk == NULL) return -EINVAL;
+	
+	if (msg == NULL) return -EINVAL;
+
+	if (sk->err) return sock_error(sk);
+
+	if ((current->uid != 0)) return -EACCES;
+
+	if (msg->msg_control) return -EINVAL;
+		
+	if (sk->shutdown & SEND_SHUTDOWN) {
+		send_sig(SIGPIPE, current, 0);
+		return -EPIPE;
+	}
+	
+	if (len < sizeof(struct sadb_msg)) return -EMSGSIZE;
+
+	if ((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) 
+		return -ENOBUFS;
+
+	memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len);
+
+	if (pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+		kfree((void*)pfkey_msg);
+		return -EINVAL;
+	}
+
+	if (len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) { 
+		kfree((void *)pfkey_msg); 
+		return -EMSGSIZE;
+	}
+
+	if (pfkey_msg->sadb_msg_reserved) {
+		kfree((void *)pfkey_msg); 
+		return -EINVAL;
+	}
+	
+	if ((pfkey_msg->sadb_msg_type > SADB_MAX) || (!pfkey_msg->sadb_msg_type)) {
+		kfree((void *)pfkey_msg); 
+		return -EINVAL;
+	}
+	
+	error = pfkey_msg_interp(sk, pfkey_msg);
+	if (error) {
+		kfree((void *)pfkey_msg); 
+		return -error;
+	}
+	PFKEY_DEBUG("end\n");
+
+	return len;
+}
+
+/*
+ *	Receive PF_KEY data up.
+ */
+		
+static int
+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+{
+	struct sock *sk;
+	int noblock = flags & MSG_DONTWAIT;
+	struct sk_buff *skb;
+	int error;
+
+	PFKEY_DEBUG("called\n");
+	if (sock == NULL)  return -EINVAL;
+
+	sk = sock->sk;
+
+	if (sk == NULL) return -EINVAL;
+
+	if (msg == NULL) return -EINVAL;
+
+	if (flags & ~MSG_PEEK)  return -EOPNOTSUPP;
+		
+	msg->msg_namelen = 0; /* sizeof(*ska); */
+		
+	if (sk->err) return sock_error(sk);
+
+	if ((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) 
+                return error;
+
+	if (size > skb->len) 
+		size = skb->len;
+
+	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
+        sk->stamp=skb->stamp;
+
+	skb_free_datagram(sk, skb);
+	PFKEY_DEBUG("end\n");
+	return size;
+}
+
+struct net_proto_family pfkey_family_ops = {
+	PF_KEY,
+	pfkey_create
+};
+
+struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
+	family:		PF_KEY,
+	release:	pfkey_release,
+	bind:		sock_no_bind,
+	connect:	sock_no_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		sock_no_accept,
+	getname:	sock_no_getname,
+	poll:		datagram_poll,
+	ioctl:		sock_no_ioctl,
+	listen:		sock_no_listen,
+	shutdown:	pfkey_shutdown,
+	setsockopt:	sock_no_setsockopt,
+	getsockopt:	sock_no_getsockopt,
+	sendmsg:	pfkey_sendmsg,
+	recvmsg:	pfkey_recvmsg,
+	mmap:		sock_no_mmap,
+};
+
+#include <linux/smp_lock.h>
+   
+#ifdef CONFIG_PROC_FS
+int
+pfkey_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0;
+	off_t begin=0;
+	int len=0;
+	struct sock *sk=pfkey_sock_list;
+	
+	len+= sprintf(buffer,
+		      "    sock   pid   socket     next     prev e n p sndbf    Flags     Type St\n");
+	
+	while (sk!=NULL) {
+		len+=sprintf(buffer+len,
+			     "%8p %5d %8p %8p %8p %d %d %5d %08lX %8X %2X\n",
+			     sk,
+			     key_pid(sk),
+			     sk->socket,
+			     sk->next,
+			     sk->prev,
+			     sk->err,
+			     sk->protocol,
+			     sk->sndbuf,
+			     sk->socket->flags,
+			     sk->socket->type,
+			     sk->socket->state);
+		pos=begin+len;
+		if (pos<offset) {
+			len=0;
+			begin=pos;
+		}
+		if (pos>offset+length)
+			break;
+		sk=sk->next;
+	}
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if (len>length)
+		len=length;
+	return len;
+}
+
+int
+pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0;
+	off_t begin=0;
+	int len=0;
+	int satype;
+	struct socket_list *pfkey_sockets;
+	
+	len+= sprintf(buffer,
+		      "satype   socket   pid       sk\n");
+	
+	for (satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
+		pfkey_sockets = pfkey_registered_sockets[satype];
+		while (pfkey_sockets) {
+			len+=sprintf(buffer+len,
+				     "    %2d %8p %5d %8p\n",
+				     satype,
+				     pfkey_sockets->socketp,
+				     key_pid(pfkey_sockets->socketp->sk),
+				     pfkey_sockets->socketp->sk);
+			
+			pos=begin+len;
+			if (pos<offset) {
+				len=0;
+				begin=pos;
+			}
+			if (pos>offset+length)
+				break;
+			pfkey_sockets = pfkey_sockets->next;
+		}
+	}
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if (len>length)
+		len=length;
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+int
+pfkey_init(void)
+{
+	int error = 0;
+
+        sock_register(&pfkey_family_ops);
+
+#ifdef CONFIG_PROC_FS
+	proc_net_create ("pf_key", 0, pfkey_get_info);
+	proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info);
+#endif          /* CONFIG_PROC_FS */
+
+
+	error = sadb_init();
+	if (error) {
+		PFKEY_DEBUG("sadb_init failed\n");
+		goto err;
+	}
+	error = spd_init();
+	if (error) {
+		PFKEY_DEBUG("spd_init faild\n");
+		goto err;
+	}
+#ifdef CONFIG_SYSCTL
+	ipsec_sysctl_register();
+#endif /* CONFIG_SYSCTL */
+
+	printk(KERN_INFO "IPsec PF_KEY V2: initialized\n");
+
+err:
+	return error;
+}
+
+int
+pfkey_cleanup(void)
+{
+	int error = 0;
+	
+	error = spd_cleanup();
+	if (error) {
+		PFKEY_DEBUG("spd_cleanup failed\n");
+		goto err;
+	}
+	error = sadb_cleanup();
+	if (error) {
+		PFKEY_DEBUG("sadb_cleanup failed\n");
+		goto err;
+	}
+
+	printk(KERN_INFO "pfkey_cleanup: shutting down PF_KEY domain sockets.\n");
+
+        sock_unregister(PF_KEY);
+
+
+#ifdef CONFIG_PROC_FS
+	proc_net_remove ("pf_key");
+	proc_net_remove ("pf_key_registered");
+#endif          /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_SYSCTL
+	ipsec_sysctl_unregister();
+#endif  
+
+	/* other module unloading cleanup happens here */
+err:
+	return error;
+}
+
+/* XXX: currently not available as a module */
+#ifdef MODULE
+static int __init pfkey_module_init(void)
+{
+	int err = pfkey_init();
+	return err;
+}
+
+static void __exit pfkey_module_cleanup(void)
+{
+	pfkey_cleanup();
+}
+
+module_init(pfkey_module_init);
+module_exit(pfkey_module_cleanup);
+
+#else /* MODULE */
+void
+pfkey_proto_init(struct net_proto *pro)
+{
+	pfkey_init();
+}
+#endif /* MODULE */
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_build.c linux25.43-ipsec/net/key/pfkey_v2_build.c
--- linux-2.5.43/net/key/pfkey_v2_build.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_build.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,915 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/* this file was derived from FreeS/WAN-1.9. (changed a little) */
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999  Richard Guy Briggs.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+
+/*
+ *		Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/sysctl.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <linux/ipv6.h> 
+#endif
+#include <linux/inet.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+#include "sockaddr_utils.h"
+
+#define ADDRTOT_BUF 128
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+void
+pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+	int i;
+	
+	for (i = 0; i != SADB_EXT_MAX + 1; i++) {
+		extensions[i] = NULL;
+	}
+}
+
+void
+pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+	int i;
+	
+	if (!extensions) {
+		return;
+	}
+
+	if (extensions[0]) {
+		memset(extensions[0], 0, sizeof(struct sadb_msg));
+		kfree(extensions[0]);
+		extensions[0] = NULL;
+	}
+	
+	for (i = 1; i != SADB_EXT_MAX + 1; i++) {
+		if (extensions[i]) {
+			memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+			kfree(extensions[i]);
+			extensions[i] = NULL;
+		}
+	}
+}
+
+void
+pfkey_msg_free(struct sadb_msg **pfkey_msg)
+{
+	if (*pfkey_msg) {
+		memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+		kfree(*pfkey_msg);
+		*pfkey_msg = NULL;
+	}
+}
+
+/* Default extension builders taken from the KLIPS code */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext**	pfkey_ext,
+		    uint8_t		msg_type,
+		    uint8_t		satype,
+		    uint8_t		msg_errno,
+		    uint32_t		seq,
+		    uint32_t		pid)
+{
+	int error = 0;
+	struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
+
+	PFKEY_DEBUG("called\n");
+	PFKEY_DEBUG("on_entry &pfkey_ext=%p pfkey_ext=%p *pfkey_ext=%p.\n",
+		&pfkey_ext, pfkey_ext, *pfkey_ext);
+	/* sanity checks... */
+	if (pfkey_msg) {
+		PFKEY_DEBUG("why is pfkey_msg already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (!msg_type) {
+		PFKEY_DEBUG("msg type not set, must be non-zero.\n");
+		SENDERR(EINVAL);
+	}
+
+	if (msg_type > SADB_MAX) {
+		PFKEY_DEBUG("msg type too large:%d.\n", msg_type);
+		SENDERR(EINVAL);
+	}
+
+	if (satype > SADB_SATYPE_MAX) {
+		PFKEY_DEBUG("satype %d > max %d\n", satype, SADB_SATYPE_MAX);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_msg = (struct sadb_msg*)
+	     kmalloc(sizeof(struct sadb_msg), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_msg, 0, sizeof(struct sadb_msg));
+
+	pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+	pfkey_msg->sadb_msg_type = msg_type;
+	pfkey_msg->sadb_msg_satype = satype;
+
+	pfkey_msg->sadb_msg_version = PF_KEY_V2;
+	pfkey_msg->sadb_msg_errno = msg_errno;
+	pfkey_msg->sadb_msg_reserved = 0;
+	pfkey_msg->sadb_msg_seq = seq;
+	pfkey_msg->sadb_msg_pid = pid;
+	PFKEY_DEBUG("on_exit &pfkey_ext=%p pfkey_ext=%p *pfkey_ext=%p.\n",
+		&pfkey_ext, pfkey_ext, *pfkey_ext);
+errlab:
+	return error;
+}	
+
+int
+pfkey_sa_build(struct sadb_ext **	pfkey_ext,
+	       uint16_t			exttype,
+	       uint32_t			spi, /* in network order */
+	       uint8_t			replay_window,
+	       uint8_t			sa_state,
+	       uint8_t			auth,
+	       uint8_t			encrypt,
+	       uint32_t			flags)
+{
+	int error = 0;
+	struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
+
+	PFKEY_DEBUG("spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
+		    ntohl(spi), replay_window, sa_state, auth, encrypt, flags);
+	/* sanity checks... */
+	if (pfkey_sa) {
+		PFKEY_DEBUG("why is pfkey_sa already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (exttype != SADB_EXT_SA &&
+	   exttype != SADB_X_EXT_SA2) {
+		PFKEY_DEBUG("invalid exttype=%d.\n", exttype);
+		SENDERR(EINVAL);
+	}
+
+	if (replay_window > 64) {
+		PFKEY_DEBUG("replay window size: %d -- must be 0 <= size <= 64\n", 
+				replay_window);
+		SENDERR(EINVAL);
+	}
+
+	if (auth > SADB_AALG_MAX) {
+		PFKEY_DEBUG("auth=%d > SADB_AALG_MAX=%d.\n", auth, SADB_AALG_MAX);
+		SENDERR(EINVAL);
+	}
+
+	if (encrypt > SADB_EALG_MAX) {
+		PFKEY_DEBUG("encrypt=%d > SADB_EALG_MAX=%d.\n", encrypt, SADB_EALG_MAX);
+		SENDERR(EINVAL);
+	}
+
+	if (sa_state > SADB_SASTATE_MAX) {
+		PFKEY_DEBUG("sa_state=%d exceeds MAX=%d.\n", sa_state, SADB_SASTATE_MAX);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_sa = (struct sadb_sa*)
+	     kmalloc(sizeof(struct sadb_sa), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_sa, 0, sizeof(struct sadb_sa));
+	
+	pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
+	pfkey_sa->sadb_sa_exttype = exttype;
+	pfkey_sa->sadb_sa_spi = spi;
+	pfkey_sa->sadb_sa_replay = replay_window;
+	pfkey_sa->sadb_sa_state = sa_state;
+	pfkey_sa->sadb_sa_auth = auth;
+	pfkey_sa->sadb_sa_encrypt = encrypt;
+	pfkey_sa->sadb_sa_flags = flags;
+
+errlab:
+	return error;
+}	
+
+int
+pfkey_lifetime_build(struct sadb_ext **	pfkey_ext,
+		     uint16_t		exttype,
+		     uint32_t		allocations,
+		     uint64_t		bytes,
+		     uint64_t		addtime,
+		     uint64_t		usetime)
+{
+	int error = 0;
+	struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
+
+	PFKEY_DEBUG(
+		"pfkey_lifetime_build:\n");
+	/* sanity checks... */
+	if (pfkey_lifetime) {
+		PFKEY_DEBUG("why is pfkey_lifetime already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (exttype != SADB_EXT_LIFETIME_CURRENT &&
+	   exttype != SADB_EXT_LIFETIME_HARD &&
+	   exttype != SADB_EXT_LIFETIME_SOFT) {
+		PFKEY_DEBUG("invalid exttype=%d.\n", exttype);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_lifetime = (struct sadb_lifetime*)
+	     kmalloc(sizeof(struct sadb_lifetime), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
+
+	pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
+	pfkey_lifetime->sadb_lifetime_exttype = exttype;
+	pfkey_lifetime->sadb_lifetime_allocations = allocations;
+	pfkey_lifetime->sadb_lifetime_bytes = bytes;
+	pfkey_lifetime->sadb_lifetime_addtime = addtime;
+	pfkey_lifetime->sadb_lifetime_usetime = usetime;
+
+errlab:
+	return error;
+}
+
+int
+pfkey_address_build(struct sadb_ext**	pfkey_ext,
+		    uint16_t		exttype,
+		    uint8_t		proto,
+		    uint8_t		prefixlen,
+		    struct sockaddr*	address)
+{
+	int error = 0;
+	int saddr_len = 0;
+	char ipaddr_txt[ADDRTOT_BUF];
+	struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
+	
+	PFKEY_DEBUG(
+		"pfkey_address_build: exttype=%d proto=%d prefixlen=%d\n", exttype, proto, prefixlen);
+	/* sanity checks... */
+	if (pfkey_address) {
+		PFKEY_DEBUG("why is pfkey_address already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (!address)  {
+			PFKEY_DEBUG("address is NULL\n");
+			SENDERR(EINVAL);
+	}
+	
+	switch (exttype) {	
+	case SADB_EXT_ADDRESS_SRC:
+	case SADB_EXT_ADDRESS_DST:
+	case SADB_EXT_ADDRESS_PROXY:
+		break;
+	default:
+		PFKEY_DEBUG("unrecognised ext_type=%d.\n", 
+			exttype); 
+		SENDERR(EINVAL); 
+	}
+
+	switch (address->sa_family) {
+	case AF_INET:
+		PFKEY_DEBUG("found address family AF_INET.\n");
+		saddr_len = sizeof(struct sockaddr_in);
+		sockaddrtoa(address, ipaddr_txt, sizeof(ipaddr_txt));
+		break;
+	case AF_INET6:
+		PFKEY_DEBUG("found address family AF_INET6.\n");
+		saddr_len = sizeof(struct sockaddr_in6);
+		sockaddrtoa(address, ipaddr_txt, sizeof(ipaddr_txt));
+		break;
+	default:
+		PFKEY_DEBUG("address->sa_family=%d not supported.\n",
+			address->sa_family);
+		SENDERR(EPFNOSUPPORT);
+	}
+
+	PFKEY_DEBUG("found address=%s.\n", ipaddr_txt);
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_address = (struct sadb_address*)
+	     kmalloc(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_address,
+	       0,
+	       ALIGN_N(sizeof(struct sadb_address) + saddr_len,
+		     IPSEC_PFKEYv2_ALIGN));
+	       
+	pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
+						IPSEC_PFKEYv2_ALIGN);
+	
+	pfkey_address->sadb_address_exttype = exttype;
+	pfkey_address->sadb_address_proto = proto;
+	pfkey_address->sadb_address_prefixlen = prefixlen;
+	pfkey_address->sadb_address_reserved = 0;
+
+	memcpy((char*)pfkey_address + sizeof(struct sadb_address),
+	       address,
+	       saddr_len);
+
+	PFKEY_DEBUG("successful.\n");
+
+ errlab:
+	return error;
+}
+
+int
+pfkey_key_build(struct sadb_ext**	pfkey_ext,
+		uint16_t		exttype,
+		uint16_t		key_bits,
+		char*			key)
+{
+	int error = 0;
+	struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
+
+	PFKEY_DEBUG(
+		"pfkey_key_build:\n");
+	/* sanity checks... */
+	if (pfkey_key) {
+		PFKEY_DEBUG("why is pfkey_key already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (!key_bits) {
+		PFKEY_DEBUG("key_bits is zero, it must be non-zero.\n");
+		SENDERR(EINVAL);
+	}
+
+	if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
+		PFKEY_DEBUG("unsupported extension type=%d.\n", exttype);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_key = (struct sadb_key*)
+	     kmalloc(sizeof(struct sadb_key) +
+				    DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_key,
+	       0,
+	       sizeof(struct sadb_key) +
+	       DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+	
+	pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN +	key_bits,
+					64);
+	pfkey_key->sadb_key_exttype = exttype;
+	pfkey_key->sadb_key_bits = key_bits;
+	pfkey_key->sadb_key_reserved = 0;
+	memcpy((char*)pfkey_key + sizeof(struct sadb_key),
+	       key,
+	       DIVUP(key_bits, 8));
+
+errlab:
+	return error;
+}
+
+int
+pfkey_ident_build(struct sadb_ext**	pfkey_ext,
+		  uint16_t		exttype,
+		  uint16_t		ident_type,
+		  uint64_t		ident_id,
+		  char*			ident_string)
+{
+	int error = 0;
+	struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
+
+	PFKEY_DEBUG(
+		"pfkey_ident_build:\n");
+	/* sanity checks... */
+	if (pfkey_ident) {
+		PFKEY_DEBUG("why is pfkey_ident already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if ( ! ((exttype == SADB_EXT_IDENTITY_SRC) ||
+	       (exttype == SADB_EXT_IDENTITY_DST))) {
+		PFKEY_DEBUG("unsupported extension type=%d.\n", exttype);
+		SENDERR(EINVAL);
+	}
+
+	if ((ident_type == SADB_IDENTTYPE_RESERVED)) {
+		PFKEY_DEBUG("ident_type must be non-zero.\n");
+		SENDERR(EINVAL);
+	}
+
+	if (ident_type > SADB_IDENTTYPE_MAX) {
+		PFKEY_DEBUG("identtype=%d out of range.\n", ident_type);
+		SENDERR(EINVAL);
+	}
+
+	if (((ident_type == SADB_IDENTTYPE_PREFIX) ||
+	    (ident_type == SADB_IDENTTYPE_FQDN)) &&
+	   !ident_string) {
+		PFKEY_DEBUG("string required to allocate size of extension.\n");
+		SENDERR(EINVAL);
+	}
+	
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_ident = (struct sadb_ident*)
+	     kmalloc(ALIGN_N(sizeof(struct sadb_key) + strlen(ident_string), IPSEC_PFKEYv2_ALIGN), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_ident,
+	       0,
+	       ALIGN_N(sizeof(struct sadb_ident) + strlen(ident_string),
+		     IPSEC_PFKEYv2_ALIGN));
+	
+	pfkey_ident->sadb_ident_len = DIVUP(sizeof(struct sadb_ident) + strlen(ident_string),
+					    IPSEC_PFKEYv2_ALIGN);
+	
+	pfkey_ident->sadb_ident_exttype = exttype;
+	pfkey_ident->sadb_ident_type = ident_type;
+	pfkey_ident->sadb_ident_reserved = 0;
+	pfkey_ident->sadb_ident_id = ident_id;
+	memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
+	       ident_string,
+	       strlen(ident_string));
+
+	memset(((char*)pfkey_ident) + sizeof(struct sadb_ident) + strlen(ident_string),
+	       0,
+	       ALIGN_N(sizeof(struct sadb_ident) + strlen(ident_string), IPSEC_PFKEYv2_ALIGN) -
+	       sizeof(struct sadb_ident) + strlen(ident_string));
+
+errlab:
+	return error;
+}
+
+int
+pfkey_sens_build(struct sadb_ext**	pfkey_ext,
+		 uint32_t		dpd,
+		 uint8_t		sens_level,
+		 uint8_t		sens_len,
+		 uint64_t*		sens_bitmap,
+		 uint8_t		integ_level,
+		 uint8_t		integ_len,
+		 uint64_t*		integ_bitmap)
+{
+	int error = 0;
+	struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
+	int i;
+	uint64_t* bitmap;
+
+	PFKEY_DEBUG(
+		"pfkey_sens_build:\n");
+	/* sanity checks... */
+	if (pfkey_sens) {
+		PFKEY_DEBUG("why is pfkey_sens already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	PFKEY_DEBUG("Sorry, I can't build exttype=%d yet.\n", (*pfkey_ext)->sadb_ext_type);
+	SENDERR(EINVAL); /* don't process these yet */
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_sens = (struct sadb_sens*)
+	     kmalloc(sizeof(struct sadb_sens) +
+		    (sens_len + integ_len) * sizeof(uint64_t), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_sens,
+	       0,
+	       sizeof(struct sadb_sens) +
+	       (sens_len + integ_len) * sizeof(uint64_t));
+	
+	pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
+		    (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
+	pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+	pfkey_sens->sadb_sens_dpd = dpd;
+	pfkey_sens->sadb_sens_sens_level = sens_level;
+	pfkey_sens->sadb_sens_sens_len = sens_len;
+	pfkey_sens->sadb_sens_integ_level = integ_level;
+	pfkey_sens->sadb_sens_integ_len = integ_len;
+	pfkey_sens->sadb_sens_reserved = 0;
+
+	bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
+	for (i = 0; i < sens_len; i++) {
+		*bitmap = sens_bitmap[i];
+		bitmap++;
+	}
+	for (i = 0; i < integ_len; i++) {
+		*bitmap = integ_bitmap[i];
+		bitmap++;
+	}
+
+errlab:
+	return error;
+}
+
+int
+pfkey_prop_build(struct sadb_ext**	pfkey_ext,
+		 uint8_t		replay,
+		 unsigned int		comb_num,
+		 struct sadb_comb*	comb)
+{
+	int error = 0;
+	int i;
+	struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
+	struct sadb_comb *combp;
+
+	PFKEY_DEBUG(
+		"pfkey_prop_build:\n");
+	/* sanity checks... */
+	if (pfkey_prop) {
+		PFKEY_DEBUG("why is pfkey_prop already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_prop = (struct sadb_prop*)
+	     kmalloc(sizeof(struct sadb_prop) +
+		    comb_num * sizeof(struct sadb_comb), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_prop,
+	       0,
+	       sizeof(struct sadb_prop) +
+		    comb_num * sizeof(struct sadb_comb));
+	
+	pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
+		    comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
+
+	pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+	pfkey_prop->sadb_prop_replay = replay;
+
+	for (i=0; i<3; i++) {
+		pfkey_prop->sadb_prop_reserved[i] = 0;
+	}
+
+	combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
+	for (i = 0; i < comb_num; i++) {
+		memcpy (combp, &comb[i], sizeof(struct sadb_comb));
+		combp++;
+	}
+
+errlab:
+	return error;
+}
+
+int
+pfkey_supported_build(struct sadb_ext**	pfkey_ext,
+		      uint16_t		exttype,
+		      unsigned int	alg_num,
+		      struct sadb_alg*	alg)
+{
+	int error = 0;
+	unsigned int i;
+	struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
+	struct sadb_alg *pfkey_alg;
+
+	/* sanity checks... */
+	if (pfkey_supported) {
+		PFKEY_DEBUG("why is pfkey_supported already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+
+	if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
+		PFKEY_DEBUG("unsupported extension type=%d.\n", exttype);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_supported = (struct sadb_supported*)
+	     kmalloc(sizeof(struct sadb_supported) +
+					       alg_num *
+					       sizeof(struct sadb_alg), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_supported,
+	       0,
+	       sizeof(struct sadb_supported) +
+					       alg_num *
+					       sizeof(struct sadb_alg));
+	
+	pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
+					       alg_num *
+					       sizeof(struct sadb_alg)) /
+						IPSEC_PFKEYv2_ALIGN;
+	pfkey_supported->sadb_supported_exttype = exttype;
+	pfkey_supported->sadb_supported_reserved = 0;
+
+	pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
+	for (i = 0; i < alg_num; i++) {
+		memcpy (pfkey_alg, &alg[i], sizeof(struct sadb_alg));
+		pfkey_alg->sadb_alg_reserved = 0;
+		pfkey_alg++;
+	}
+	
+errlab:
+	return error;
+}
+
+int
+pfkey_spirange_build(struct sadb_ext**	pfkey_ext,
+		     uint16_t		exttype,
+		     uint32_t		min, /* in network order */
+		     uint32_t		max) /* in network order */
+{
+	int error = 0;
+	struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
+	
+	/* sanity checks... */
+	if (pfkey_spirange) {
+		PFKEY_DEBUG("why is pfkey_spirange already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+	
+        if (ntohl(max) < ntohl(min)) {
+		PFKEY_DEBUG("minspi=%08x must be < maxspi=%08x.\n", ntohl(min), ntohl(max));
+                SENDERR(EINVAL);
+        }
+	
+	if (ntohl(min) <= 255) {
+		PFKEY_DEBUG("minspi=%08x must be > 255.\n", ntohl(min));
+		SENDERR(EEXIST);
+	}
+	
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_spirange = (struct sadb_spirange*)
+	     kmalloc(sizeof(struct sadb_spirange), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_spirange,
+	       0,
+	       sizeof(struct sadb_spirange));
+	
+        pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
+
+	pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+	pfkey_spirange->sadb_spirange_min = min;
+	pfkey_spirange->sadb_spirange_max = max;
+	pfkey_spirange->sadb_spirange_reserved = 0;
+ errlab:
+	return error;
+}
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext**	pfkey_ext)
+{
+	int error = 0;
+	struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
+
+	/* sanity checks... */
+	if (pfkey_x_kmprivate) {
+		PFKEY_DEBUG("why is pfkey_x_kmprivate already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+	
+	pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+
+	PFKEY_DEBUG("Sorry, I can't build exttype=%d yet.\n", (*pfkey_ext)->sadb_ext_type);
+	SENDERR(EINVAL); /* don't process these yet */
+
+	if (!(*pfkey_ext = (struct sadb_ext*)
+	     pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
+	     kmalloc(sizeof(struct sadb_x_kmprivate), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_x_kmprivate,
+	       0,
+	       sizeof(struct sadb_x_kmprivate));
+	
+        pfkey_x_kmprivate->sadb_x_kmprivate_len =
+		sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
+
+        pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE;
+        pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+errlab:
+	return error;
+}
+
+int
+pfkey_x_satype_build(struct sadb_ext**	pfkey_ext,
+		     uint8_t		satype)
+{
+	int error = 0;
+	int i;
+	struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
+
+	PFKEY_DEBUG("called.\n");
+	/* sanity checks... */
+	if (pfkey_x_satype) {
+		PFKEY_DEBUG("why is pfkey_x_satype already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+	
+	if (!satype) {
+		PFKEY_DEBUG("SA type not set, must be non-zero.\n");
+		SENDERR(EINVAL);
+	}
+
+	if (satype > SADB_SATYPE_MAX) {
+		PFKEY_DEBUG("satype %d > max %d\n", 
+			satype, SADB_SATYPE_MAX);
+		SENDERR(EINVAL);
+	}
+
+	if (!(*pfkey_ext = (struct sadb_ext*)pfkey_x_satype = (struct sadb_x_satype*)
+	     kmalloc(sizeof(struct sadb_x_satype), GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	memset(pfkey_x_satype,
+	       0,
+	       sizeof(struct sadb_x_satype));
+	
+        pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
+
+	pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
+	pfkey_x_satype->sadb_x_satype_satype = satype;
+	for (i=0; i<3; i++) {
+		pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
+	}
+
+errlab:
+	return error;
+}
+
+
+int
+pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
+{
+	int error = 0;
+	int ext;
+	int total_size;
+	struct sadb_ext *pfkey_ext;
+	int extensions_seen = 0;
+	
+	if (!extensions[0]) {
+		PFKEY_DEBUG("extensions[0] must be specified (struct sadb_msg).\n");
+		SENDERR(EINVAL);
+	}
+
+	total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+	for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+		if (extensions[ext]) {
+			total_size += (extensions[ext])->sadb_ext_len;
+		}
+        }                
+
+	if (!(*pfkey_msg = (struct sadb_msg*)kmalloc(total_size * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC))) {
+		PFKEY_DEBUG("memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+
+	PFKEY_DEBUG("pfkey_msg=%p allocated %d bytes, &extensions[0]=%p\n", 
+			*pfkey_msg, total_size * IPSEC_PFKEYv2_ALIGN, &extensions[0]);
+	memcpy(*pfkey_msg,
+	       extensions[0],
+	       sizeof(struct sadb_msg));
+	(*pfkey_msg)->sadb_msg_len = total_size;
+	(*pfkey_msg)->sadb_msg_reserved = 0;
+	extensions_seen =  1 ;
+
+	pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
+
+	for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+		/* copy from extension[ext] to buffer */
+		if (extensions[ext]) {    
+			memcpy(pfkey_ext,
+			       extensions[ext],
+			       (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+			((char*)pfkey_ext) += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
+			/* Mark that we have seen this extension and remember the header location */
+			extensions_seen |= ( 1 << ext );
+		}
+	}
+
+errlab:
+
+	return error;
+}
+
+/*
+ * $Log: pfkey_v2_build.c,v $
+ * Revision 1.1.1.1  2001/05/22 06:14:05  miyazawa
+ * kernel for ipsec without FS
+ *
+ * Revision 1.21  2000/11/17 18:10:30  rgb
+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
+ * network byte order since this is the way PF_KEYv2 stored spis.
+ *
+ * Revision 1.20  2000/10/12 00:02:39  rgb
+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
+ *
+ * Revision 1.19  2000/10/10 20:10:20  rgb
+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
+ *
+ * Revision 1.18  2000/09/12 18:59:54  rgb
+ * Added Gerhard's IPv6 support to pfkey parts of libfreeswan.
+ *
+ * Revision 1.17  2000/09/12 03:27:00  rgb
+ * Moved DEBUGGING definition to compile kernel with debug off.
+ *
+ * Revision 1.16  2000/09/08 19:22:12  rgb
+ * Fixed pfkey_prop_build() parameter to be only single indirection.
+ * Fixed struct alg copy.
+ *
+ * Revision 1.15  2000/08/20 21:40:01  rgb
+ * Added an address parameter sanity check to pfkey_address_build().
+ *
+ * Revision 1.14  2000/08/15 17:29:23  rgb
+ * Fixes from SZI to untested pfkey_prop_build().
+ *
+ * Revision 1.13  2000/06/02 22:54:14  rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.12  2000/05/10 19:24:01  rgb
+ * Fleshed out sensitivity, proposal and supported extensions.
+ *
+ * Revision 1.11  2000/03/16 14:07:23  rgb
+ * Renamed ALIGN macro to avoid fighting with others in kernel.
+ *
+ * Revision 1.10  2000/01/24 21:14:35  rgb
+ * Added disabled pluto pfkey lib debug flag.
+ *
+ * Revision 1.9  2000/01/21 06:27:32  rgb
+ * Added address cases for eroute flows.
+ * Removed unused code.
+ * Dropped unused argument to pfkey_x_satype_build().
+ * Indented compiler directives for readability.
+ * Added klipsdebug switching capability.
+ * Fixed SADB_EXT_MAX bug not permitting last extension access.
+ *
+ * Revision 1.8  1999/12/29 21:17:41  rgb
+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
+ * parameter for cleaner manipulation of extensions[] and to guard
+ * against potential memory leaks.
+ * Changed the I/F to pfkey_msg_free() for the same reason.
+ *
+ * Revision 1.7  1999/12/09 23:12:20  rgb
+ * Removed unused cruft.
+ * Added argument to pfkey_sa_build() to do eroutes.
+ * Fixed exttype check in as yet unused pfkey_lifetime_build().
+ *
+ * Revision 1.6  1999/12/07 19:54:29  rgb
+ * Removed static pluto debug flag.
+ * Added functions for pfkey message and extensions initialisation
+ * and cleanup.
+ *
+ * Revision 1.5  1999/12/01 22:20:06  rgb
+ * Changed pfkey_sa_build to accept an SPI in network byte order.
+ * Added <string.h> to quiet userspace compiler.
+ * Moved pfkey_lib_debug variable into the library.
+ * Removed SATYPE check from pfkey_msg_hdr_build so FLUSH will work.
+ * Added extension assembly debugging.
+ * Isolated assignment with brackets to be sure of scope.
+ *
+ * Revision 1.4  1999/11/27 11:57:35  rgb
+ * Added ipv6 headers.
+ * Remove over-zealous algorithm sanity checkers from pfkey_sa_build.
+ * Debugging error messages added.
+ * Fixed missing auth and encrypt assignment bug.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Move parse-after-build check inside pfkey_msg_build().
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ *
+ */
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_ext_bits.c linux25.43-ipsec/net/key/pfkey_v2_ext_bits.c
--- linux-2.5.43/net/key/pfkey_v2_ext_bits.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_ext_bits.c	2002-10-16 15:27:50.000000000 +0900
@@ -0,0 +1,703 @@
+/* this file was derived from FreeS/WAN-1.9. (changed a little) */
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999  Richard Guy Briggs.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_ext_bits.c,v 1.7 2000/09/12 22:35:37 rgb Exp $
+ */
+/*
+ *		Template from klips/net/ipsec/ipsec/ipsec_parse.c.
+ */
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#include <linux/kernel.h>  /* for printk */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/errno.h>  /* error codes */
+#include <linux/types.h>  /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+#include <linux/netdevice.h>   /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/ip.h>          /* struct iphdr */ 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <linux/ipv6.h>
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+
+unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
+
+/* INBOUND EXTENSIONS */
+{
+
+/* PERMITTED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ADD PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_DELETE PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE PERMITTED IN */
+0
+,
+/* SADB_FLUSH PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DELFLOW PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG PERMITTED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_X_EXT_DEBUG
+},
+
+/* REQUIRED IN */
+{
+/* SADB_RESERVED REQUIRED IN */
+0
+,
+/* SADB_GETSPI REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_ADD REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	/*| 1<<SADB_EXT_KEY_AUTH*/
+	/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_DELETE REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE REQUIRED IN */
+0
+,
+/* SADB_FLUSH REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+	/*| 1<<SADB_X_EXT_SATYPE2*/
+	/*| 1<<SADB_X_EXT_SA2*/
+	/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
+,
+/* SADB_X_ADDFLOW REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DELFLOW REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+#endif
+,
+/* SADB_X_DEBUG REQUIRED IN */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_X_EXT_DEBUG
+}
+
+},
+
+/* OUTBOUND EXTENSIONS */
+{
+
+/* PERMITTED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ADD PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_DELETE PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+#if 0
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+#endif
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+#if 0
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+#endif
+,
+/* SADB_ACQUIRE PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+,
+/* SADB_EXPIRE PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_X_PROMISC PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DELFLOW PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG PERMITTED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_X_EXT_DEBUG
+},
+
+/* REQUIRED OUT */
+{
+/* SADB_RESERVED REQUIRED OUT */
+0
+,
+/* SADB_GETSPI REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ADD REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_DELETE REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_ACQUIRE REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	/* | 1<<SADB_EXT_SUPPORTED_AUTH
+	   | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
+,
+/* SADB_EXPIRE REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	/* | 1<<SADB_EXT_LIFETIME_HARD
+	   | 1<<SADB_EXT_LIFETIME_SOFT */
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_X_PROMISC REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_LIFETIME_CURRENT
+	| 1<<SADB_EXT_LIFETIME_HARD
+	| 1<<SADB_EXT_LIFETIME_SOFT
+	| 1<<SADB_EXT_ADDRESS_SRC
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_EXT_ADDRESS_PROXY
+	| 1<<SADB_EXT_KEY_AUTH
+	| 1<<SADB_EXT_KEY_ENCRYPT
+	| 1<<SADB_EXT_IDENTITY_SRC
+	| 1<<SADB_EXT_IDENTITY_DST
+	| 1<<SADB_EXT_SENSITIVITY
+	| 1<<SADB_EXT_PROPOSAL
+	| 1<<SADB_EXT_SUPPORTED_AUTH
+	| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+	| 1<<SADB_EXT_SPIRANGE
+	| 1<<SADB_X_EXT_KMPRIVATE
+	| 1<<SADB_X_EXT_SATYPE2
+	| 1<<SADB_X_EXT_SA2
+	| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_X_ADDFLOW REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_EXT_SA
+	| 1<<SADB_EXT_ADDRESS_DST
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DELFLOW REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	/*| 1<<SADB_EXT_SA*/
+	| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+	| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+#if 0
+	| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+	| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG REQUIRED OUT */
+	1<<SADB_EXT_RESERVED
+	| 1<<SADB_X_EXT_DEBUG
+}
+}
+};
+
+/*
+ * $Log: pfkey_v2_ext_bits.c,v $
+ * Revision 1.2  2001/07/09 00:40:50  miyazawa
+ * remove obsolete file
+ *
+ * Revision 1.7  2000/09/12 22:35:37  rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.6  2000/09/09 06:39:01  rgb
+ * Added comments for clarity.
+ *
+ * Revision 1.5  2000/06/02 22:54:14  rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.4  2000/01/21 06:27:56  rgb
+ * Added address cases for eroute flows.
+ * Added comments for each message type.
+ * Added klipsdebug switching capability.
+ * Fixed GRPSA bitfields.
+ *
+ * Revision 1.3  1999/12/01 22:20:27  rgb
+ * Remove requirement for a proxy address in an incoming getspi message.
+ *
+ * Revision 1.2  1999/11/27 11:57:06  rgb
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Cleaned out unused bits.
+ *
+ */
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg.c linux25.43-ipsec/net/key/pfkey_v2_msg.c
--- linux-2.5.43/net/key/pfkey_v2_msg.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,959 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * pfkey_v2_msg.c is a program for PF_KEY version2 parsing routine, and utilities.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/net.h>
+#include <linux/crypto.h>
+#include <linux/ipsec.h>
+
+#include <net/sock.h>
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+
+#include "pfkey_v2_msg.h"
+#include "sockaddr_utils.h"
+
+#define BUF_SIZE 64
+
+int sadb_msg_sanity_check(struct sadb_msg* msg)
+{
+	int error = 0;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	if (!(msg->sadb_msg_version == PF_KEY_V2 &&
+	      msg->sadb_msg_type > 0 && msg->sadb_msg_type <= SADB_MAX &&
+	      /* msg->sadb_msg_satype >= 0 && */ msg->sadb_msg_satype <= SADB_SATYPE_MAX &&
+	      msg->sadb_msg_reserved == 0))
+		error = -EINVAL;
+
+	PFKEY_DEBUG("sadb_msg_version=%d\n", msg->sadb_msg_version);
+	PFKEY_DEBUG("sadb_msg_type=%d\n", msg->sadb_msg_type);
+	PFKEY_DEBUG("sadb_msg_satype=%d\n", msg->sadb_msg_satype);
+	PFKEY_DEBUG("sadb_msg_len=%d\n", msg->sadb_msg_len);
+	PFKEY_DEBUG("sadb_msg_reserved=%d\n", msg->sadb_msg_reserved);
+
+err:
+	PFKEY_DEBUG("error=%d\n", error);
+	return error;
+}
+
+int sadb_address_to_sockaddr(const struct sadb_address *ext_msg, struct sockaddr* addr)
+{
+	int error = 0, len = 0;
+	struct sockaddr* tmp_addr = NULL;
+#ifdef CONFIG_IPSEC_DEBUG
+	char buf[BUF_SIZE];
+#endif
+
+	if (!ext_msg || !addr) {
+		PFKEY_DEBUG("msg or addr is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	len = ext_msg->sadb_address_len - sizeof(struct sadb_address);
+	if (len < sizeof(struct sockaddr)) {
+		PFKEY_DEBUG("sadb_address_len is small len=%d\n", len);
+		error = -EINVAL;
+		goto err;
+	}
+
+	tmp_addr = (struct sockaddr*)((char*)ext_msg + sizeof(struct sadb_address));
+	if (!tmp_addr) {
+		PFKEY_DEBUG("address==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	switch (tmp_addr->sa_family) {
+
+	case AF_INET:
+#ifdef CONFIG_IPSEC_DEBUG
+		PFKEY_DEBUG("address family is AF_INET\n");
+		sockaddrtoa((struct sockaddr*)tmp_addr, buf, BUF_SIZE);
+		PFKEY_DEBUG("address=%s\n", buf);
+#endif
+		memcpy(addr, tmp_addr, sizeof(struct sockaddr_in)); 
+		break;
+
+	case AF_INET6:
+#ifdef CONFIG_IPSEC_DEBUG
+		PFKEY_DEBUG("address family is AF_INET6\n");
+		sockaddrtoa((struct sockaddr*)tmp_addr, buf, BUF_SIZE);
+		PFKEY_DEBUG("address=%s\n", buf);
+#endif
+		memcpy(addr, tmp_addr, sizeof(struct sockaddr_in6)); 
+		break;
+
+	default:
+		PFKEY_DEBUG("address family is unknown\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+err:
+#ifdef CONFIG_IPSEC_DEBUG
+	if (!error)
+		PFKEY_DEBUG("error=%d\n", error);
+#endif
+	return error;
+}
+
+int sadb_key_to_esp(const __u8 esp_algo, const struct sadb_key* ext_msg, struct ipsec_sa* sa_entry)
+{
+	int error = 0;
+	char *algoname = NULL;
+	struct cipher_implementation *ci=NULL;
+
+	if (!sa_entry) {
+		PFKEY_DEBUG("sa_entry is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	if (esp_algo != SADB_EALG_NULL && !ext_msg) {
+		PFKEY_DEBUG("ext_msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	switch (esp_algo) {
+	case SADB_EALG_DESCBC:
+		algoname = "des-cbc";
+		PFKEY_DEBUG("esp algorithm is DES-CBC\n");
+		if(ext_msg->sadb_key_bits != ESP_DES_KEY_BITS){
+			PFKEY_DEBUG("the key length is not match\n");
+			error = -EINVAL;
+			goto err;
+		} 
+		break;
+	case SADB_EALG_3DESCBC:
+		algoname = "3des-cbc";
+		PFKEY_DEBUG("esp algorithm is 3DES-CBC\n");
+		if(ext_msg->sadb_key_bits != ESP_3DES_KEY_BITS){
+			PFKEY_DEBUG("the key length is not match\n");
+			error = -EINVAL;
+			goto err;
+		}
+		break;
+	case SADB_EALG_NULL:
+		algoname = "null-ecb";
+		PFKEY_DEBUG("esp algorithm is NULL\n");
+		break; 
+	case SADB_EALG_AES:
+		algoname = "aes-cbc";
+		PFKEY_DEBUG("esp algorithm is AES(128-bit)\n");
+		if (ext_msg->sadb_key_bits != ESP_AES_KEY_BITS) {
+			PFKEY_DEBUG("the key length is no match\n");
+			error = -EINVAL;
+			goto err;
+		}
+		break;
+	case SADB_EALG_NONE: /* currently not enter */
+	default:
+		PFKEY_DEBUG("esp_algo is NONE or not supported one\n");
+		error = -EINVAL;
+		goto err;
+	}	
+
+	ci = find_cipher_by_name(algoname, 1);
+	if (!ci) {
+		PFKEY_DEBUG("algorithm %u:%s is not supported\n", esp_algo, algoname);
+		error = -EINVAL;
+		goto err;
+	}
+	ci->lock();
+
+	sa_entry->esp_algo.algo = esp_algo;
+
+	if (esp_algo != SADB_EALG_NULL) {
+		sa_entry->esp_algo.key_len = (ext_msg->sadb_key_bits)/OCTETBITS;
+	} else {
+		sa_entry->esp_algo.key_len = 0;
+	}
+
+	sa_entry->esp_algo.cx = ci->realloc_context (NULL, ci, sa_entry->esp_algo.key_len);
+	if (!sa_entry->esp_algo.cx) {
+		ci->unlock();
+		error = -EINVAL;
+		goto err;
+	}
+	sa_entry->esp_algo.cx->ci = ci;
+
+	if (esp_algo != SADB_EALG_NULL) {
+		sa_entry->esp_algo.key = kmalloc(sa_entry->esp_algo.key_len, GFP_KERNEL);
+		if (!sa_entry->esp_algo.key) {
+			PFKEY_DEBUG("could not allocate memory for key\n");
+			ci->wipe_context(sa_entry->esp_algo.cx);
+			ci->free_context(sa_entry->esp_algo.cx);
+			ci->unlock();
+			error = -ENOMEM;
+			goto err;
+		}
+		memset(sa_entry->esp_algo.key, 0, sa_entry->esp_algo.key_len);
+		memcpy(sa_entry->esp_algo.key, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len);
+
+		memset(sa_entry->esp_algo.cx->keyinfo, 0, ci->key_schedule_size);
+
+		error = ci->set_key(sa_entry->esp_algo.cx, ((char*)ext_msg)+sizeof(struct sadb_key), sa_entry->esp_algo.key_len);
+		if (error < 0) {
+			printk(KERN_DEBUG "set_key failed, weak key?\n");
+			ci->wipe_context(sa_entry->esp_algo.cx);
+			ci->free_context(sa_entry->esp_algo.cx);
+			ci->unlock();
+			goto err;
+		}
+	}
+err:
+	return error;
+
+}
+
+int sadb_key_to_auth(const __u8 auth_algo, const struct sadb_key* ext_msg, struct ipsec_sa* sa_entry)
+{
+	int error = 0;
+	char *algoname = NULL;
+	__u16 digest_len = 0;
+	struct digest_implementation *di = NULL;
+
+	if (!(ext_msg&&sa_entry)) {
+		PFKEY_DEBUG("msg or sa_entry is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	switch (auth_algo) {
+
+	case SADB_AALG_MD5HMAC:
+		algoname = "md5";
+		digest_len = 12; /* 96 bit length */
+		PFKEY_DEBUG("auth algorithm is HMAC-MD5\n");
+
+		if(ext_msg->sadb_key_bits != AUTH_MD5HMAC_KEY_BITS){
+			PFKEY_DEBUG("the key length is %d\n", ext_msg->sadb_key_bits);
+			PFKEY_DEBUG("the key length is not match\n");
+			error = -EINVAL;
+			goto err;
+		} 
+		break;
+
+	case SADB_AALG_SHA1HMAC:
+		algoname = "sha1";
+		digest_len = 12; /* 96 bit length */
+		PFKEY_DEBUG("auth algorithm is HMAC-SHA1\n");
+
+		if (ext_msg->sadb_key_bits != AUTH_SHA1HMAC_KEY_BITS) {
+			PFKEY_DEBUG("the key length is %d\n", ext_msg->sadb_key_bits);
+			PFKEY_DEBUG("the key length is not match\n");
+			error = -EINVAL;
+			goto err;
+		} 
+		break;
+
+	case SADB_AALG_NONE:
+	default:
+		PFKEY_DEBUG("auth_algo is NONE or not supported one\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	di = find_digest_by_name(algoname, 0);
+	if (!di) {
+		PFKEY_DEBUG("algorithm %u:%s is not supported\n", auth_algo, algoname);
+		error = -EINVAL;
+		goto err;
+	}
+	di->lock();
+
+	sa_entry->auth_algo.algo = auth_algo;
+	sa_entry->auth_algo.key_len = (ext_msg->sadb_key_bits)/OCTETBITS;
+	sa_entry->auth_algo.digest_len = digest_len;
+	sa_entry->auth_algo.dx = di->realloc_context(NULL, di);
+	if (!sa_entry->auth_algo.dx) {
+		di->unlock();
+		error = -EINVAL;
+		goto err;
+	}
+	sa_entry->auth_algo.dx->di = di;
+
+	sa_entry->auth_algo.key = kmalloc(sa_entry->auth_algo.key_len, GFP_KERNEL);
+	if (!sa_entry->auth_algo.key) {
+		PFKEY_DEBUG("cannot allocate key\n");
+		di->free_context(sa_entry->auth_algo.dx);
+		di->unlock();
+		error = -ENOMEM;
+		goto err;
+	}
+
+	memcpy(sa_entry->auth_algo.key, (char *)ext_msg+sizeof(struct sadb_key),
+			sa_entry->auth_algo.key_len);
+err:
+	return error;
+}
+
+
+int sadb_lifetime_to_lifetime(const struct sadb_lifetime* ext_msg, struct sa_lifetime* lifetime)
+{
+	int error = 0;
+
+	if (!ext_msg || !lifetime) {
+		PFKEY_DEBUG("param is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	lifetime->allocations 	= ext_msg->sadb_lifetime_allocations;
+	lifetime->bytes 	= ext_msg->sadb_lifetime_bytes;
+	lifetime->addtime	= ext_msg->sadb_lifetime_addtime;
+	lifetime->usetime	= ext_msg->sadb_lifetime_usetime;
+
+err:
+	return error;
+}
+
+int lifetime_to_sadb_lifetime(struct sa_lifetime *lifetime, struct sadb_lifetime *ext_msg, int type)
+{
+	int error = 0;
+	if (!lifetime || !ext_msg) {
+		PFKEY_DEBUG("param is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	error = pfkey_lifetime_build((struct sadb_ext**)&ext_msg, type,
+					lifetime->allocations,
+					lifetime->bytes,
+					lifetime->addtime,
+					lifetime->usetime);
+err:
+	return error;
+}
+
+int sadb_msg_detect_ext(struct sadb_msg* msg, struct sadb_ext **ext_msgs)
+{
+	int error = 0, len = 0, msg_size = 0;
+	struct sadb_ext *ext_ptr = NULL;
+
+	if (!msg || !ext_msgs) {
+		PFKEY_DEBUG("msg or ext_msgs is NULL.\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	error = sadb_msg_sanity_check(msg);
+	if (error) {
+		error = -EINVAL;
+		goto err;
+	}
+
+	ext_ptr = (struct sadb_ext*)((u8*)msg + sizeof(struct sadb_msg));
+	len = (msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_msg);
+
+	while (len >= sizeof(*ext_ptr)) { 
+		PFKEY_DEBUG("ext type %d\n", ext_ptr->sadb_ext_type);
+		PFKEY_DEBUG("ext length %d\n", ext_ptr->sadb_ext_len);
+		msg_size = (ext_ptr->sadb_ext_len) * IPSEC_PFKEYv2_ALIGN;
+		if (len < msg_size)
+			break;	/* error will be set later */
+		ext_msgs[ext_ptr->sadb_ext_type] = ext_ptr;
+		ext_ptr = (struct sadb_ext*)((u8*)ext_ptr + msg_size); 
+		len -= msg_size;
+	}
+
+	if (len)
+		error = -EINVAL;
+
+err:
+	PFKEY_DEBUG("error=%d\n", error);
+	return error;
+}		
+
+int sadb_msg_acquire_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+err:
+	return error;
+}
+
+int sadb_msg_register_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	uint  alg_num = 0;
+	struct sadb_alg algs[5];
+	struct digest_implementation *di = NULL;
+	struct cipher_implementation *ci = NULL;
+	struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1];
+
+	if (!sk || !msg) {
+		PFKEY_DEBUG("msg or sk is NULL\n");
+		error = -EINVAL;
+		PFKEY_DEBUG("msg or *reply is NULL\n");
+		goto err; 	
+	}
+
+	error = sadb_msg_sanity_check(msg);
+	if (error)
+		goto err;
+
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	memset(algs, 0, sizeof(algs));
+
+	switch (msg->sadb_msg_satype) {
+
+	case SADB_SATYPE_AH:
+	case SADB_SATYPE_ESP:
+	case SADB_X_SATYPE_COMP:
+		break;
+	case SADB_SATYPE_RSVP:
+	case SADB_SATYPE_OSPFV2:
+	case SADB_SATYPE_RIPV2:
+	case SADB_SATYPE_MIP:
+	case SADB_X_SATYPE_IPIP:
+	case SADB_X_SATYPE_INT:
+	default:
+		error = -EINVAL;
+		goto err;
+	}
+
+	write_lock_bh(&pfkey_sk_lock);
+	/*
+	 register a socket with the proper SA type's socket list
+	 it will be release in pfkey_release process (file:pfkey_v2.c).
+	*/
+	error = pfkey_list_insert_socket(sk->socket, &pfkey_registered_sockets[msg->sadb_msg_satype]);
+	if (error) {
+		goto err;
+	}
+	write_unlock_bh(&pfkey_sk_lock);
+
+	PFKEY_DEBUG("socket=%p registered, SA type is %d\n", sk->socket, msg->sadb_msg_satype);
+
+	reply_ext_msgs[0] = (struct sadb_ext*)msg;
+
+	if (msg->sadb_msg_satype == SADB_SATYPE_AH || msg->sadb_msg_satype == SADB_SATYPE_ESP) {
+		di = find_digest_by_name("md5", 0 /* atomic */);
+		if (di) {
+			algs[alg_num].sadb_alg_id = SADB_AALG_MD5HMAC;
+			algs[alg_num].sadb_alg_ivlen = 0;
+			algs[alg_num].sadb_alg_minbits = AUTH_MD5HMAC_KEY_BITS;
+			algs[alg_num].sadb_alg_maxbits = AUTH_MD5HMAC_KEY_BITS;
+			algs[alg_num].sadb_alg_reserved = 0;
+			alg_num++;
+			di = NULL;	
+		}
+	
+		di = find_digest_by_name("sha1", 0 /* atomic */);
+		if (di) {
+			algs[alg_num].sadb_alg_id = SADB_AALG_SHA1HMAC;
+			algs[alg_num].sadb_alg_ivlen = 0;
+			algs[alg_num].sadb_alg_minbits = AUTH_SHA1HMAC_KEY_BITS;
+			algs[alg_num].sadb_alg_maxbits = AUTH_SHA1HMAC_KEY_BITS;
+			algs[alg_num].sadb_alg_reserved = 0;
+			alg_num++;
+			di = NULL;
+		}
+
+		if (msg->sadb_msg_satype == SADB_SATYPE_AH) {
+			error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH],
+						SADB_EXT_SUPPORTED_AUTH,
+						alg_num,
+						algs);
+			if (error) goto free_ext_finish;
+		}
+
+	}
+
+	if (msg->sadb_msg_satype == SADB_SATYPE_ESP) {
+		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
+		if (ci) {
+			ci->lock();
+			algs[alg_num].sadb_alg_id = SADB_EALG_DESCBC;
+			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
+			algs[alg_num].sadb_alg_minbits = ESP_DES_KEY_BITS;
+			algs[alg_num].sadb_alg_maxbits = ESP_DES_KEY_BITS;
+			algs[alg_num].sadb_alg_reserved = 0;
+			alg_num++;
+			ci->unlock();
+			ci = NULL;
+		}
+
+		ci = find_cipher_by_name("3des-cbc", 1 /* atomic */);
+		if (ci) {
+			ci->lock();
+			algs[alg_num].sadb_alg_id = SADB_EALG_3DESCBC;
+			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
+			algs[alg_num].sadb_alg_minbits = ESP_3DES_KEY_BITS;
+			algs[alg_num].sadb_alg_maxbits = ESP_3DES_KEY_BITS;
+			algs[alg_num].sadb_alg_reserved = 0;
+			alg_num++;
+			ci->unlock();
+			ci = NULL;
+		}
+		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
+		if (ci) {
+			ci->lock();
+			algs[alg_num].sadb_alg_id = SADB_EALG_AES;
+			algs[alg_num].sadb_alg_ivlen = ci->ivsize;
+			algs[alg_num].sadb_alg_minbits = ESP_AES_KEY_BITS;
+			algs[alg_num].sadb_alg_maxbits = ESP_AES_KEY_BITS;
+			algs[alg_num].sadb_alg_reserved = 0;
+			alg_num++;
+			ci->unlock();
+			ci = NULL;
+		}
+
+		error = pfkey_supported_build(&reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT],
+						SADB_EXT_SUPPORTED_ENCRYPT,
+						alg_num,
+						algs);
+		if (error) goto free_ext_finish;
+
+	}
+
+	pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+
+free_ext_finish:
+
+	if (reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH])
+		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_AUTH]);
+
+	if (reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT])
+		kfree(reply_ext_msgs[SADB_EXT_SUPPORTED_ENCRYPT]);
+
+
+err:
+
+	return error;
+}
+
+int sadb_msg_expire_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = -EINVAL;
+
+#if 0 /* kernel never receive SADB_EXPIRE message */
+
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+err:
+#endif /* kernel never receive SADB_EXPIRE message */
+
+	return error;
+}
+
+int sadb_msg_flush_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	error = sadb_msg_sanity_check(msg);
+
+	if (error) {
+		PFKEY_DEBUG("message is invalid\n");
+		goto err;
+	}
+
+	switch(msg->sadb_msg_satype) {
+	case SADB_SATYPE_AH:
+	case SADB_SATYPE_ESP:
+		sadb_flush_sa(msg->sadb_msg_satype);
+		break;
+	default:
+		sadb_clear_db(); 
+	}
+
+	*reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
+	memcpy(*reply, msg, sizeof(struct sadb_msg));
+err:
+	return error;
+}
+
+int sadb_msg_flush_sp_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	error = sadb_msg_sanity_check(msg);
+
+	if (error) {
+		PFKEY_DEBUG("message is invalid\n");
+		goto err;
+	}
+
+	spd_clear_db();
+
+	*reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL);
+	memcpy(*reply, msg, sizeof(struct sadb_msg));
+err:
+	return error;
+}
+
+int sadb_msg_dump_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+
+	if (!msg) {
+		PFKEY_DEBUG("msg==NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+err:
+	return error;
+}
+
+int sadb_msg_send_expire(struct ipsec_sa *sa)
+{
+	int i=0, error = 0;
+	struct sadb_msg *msg = NULL;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+	struct socket_list *pfkey_socketsp = NULL;
+
+	if (!sa) {
+		PFKEY_DEBUG("sa is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+
+	error = pfkey_msg_hdr_build(&ext_msgs[0],
+				    SADB_EXPIRE,
+				    sa->ipsec_proto,
+				    0,
+				    0,
+				    0);
+	if (error) {
+		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
+		goto free_ext_finish;
+	}
+
+	error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA],
+				   SADB_EXT_SA,
+				   sa->spi,
+				   64,
+				   sa->state,
+				   sa->auth_algo.algo,
+				   sa->esp_algo.algo,
+				   0); /* TODO: add pfs flag to struct ipsec_sa */
+	if (error) {
+		PFKEY_DEBUG("pfkey_sa_build is failed\n");
+		goto free_ext_finish;
+	}
+
+	error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_CURRENT],
+					 SADB_EXT_LIFETIME_CURRENT,
+					 sa->lifetime_c.allocations,
+					 sa->lifetime_c.bytes,
+					 sa->lifetime_c.addtime,
+					 sa->lifetime_c.usetime);
+	if (error) {
+		PFKEY_DEBUG("pfkey_lifetime_build is failed\n");
+		goto free_ext_finish;
+	}
+
+	switch(sa->state) {
+	case SADB_SASTATE_DEAD:
+		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD],
+						 SADB_EXT_LIFETIME_HARD,
+						 sa->lifetime_h.allocations,
+						 sa->lifetime_h.bytes,
+						 sa->lifetime_h.addtime,
+						 sa->lifetime_h.usetime);
+		if (error) {
+			PFKEY_DEBUG("pfkey_liftime_build(hard) is failed\n");
+			goto free_ext_finish;
+		}
+		break;
+
+	case SADB_SASTATE_DYING:
+		error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT],
+						 SADB_EXT_LIFETIME_SOFT,
+						 sa->lifetime_s.allocations,
+						 sa->lifetime_s.bytes,
+						 sa->lifetime_s.addtime,
+						 sa->lifetime_s.usetime);
+		if (error) {
+			PFKEY_DEBUG("pfkey_lifetime_build(soft) is failed\n");
+			goto free_ext_finish;
+		}
+		break;
+
+	case SADB_SASTATE_LARVAL:
+	case SADB_SASTATE_MATURE:
+	default:
+		error = -EINVAL;
+		goto free_ext_finish;
+
+	}
+	
+	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
+					SADB_EXT_ADDRESS_SRC,
+					sa->proto,
+					sa->prefixlen_s,
+					(struct sockaddr*)&sa->src);
+	if (error) goto free_ext_finish;
+
+	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
+					SADB_EXT_ADDRESS_DST,
+					sa->proto,
+					sa->prefixlen_d,
+					(struct sockaddr*)&sa->dst);
+	if (error) goto free_ext_finish;
+
+	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);
+
+	write_lock_bh(&pfkey_sk_lock);
+	for (pfkey_socketsp = pfkey_open_sockets;
+		pfkey_socketsp;
+			pfkey_socketsp = pfkey_socketsp->next)
+	{
+		pfkey_upmsg(pfkey_socketsp->socketp, msg);
+	}
+	write_unlock_bh(&pfkey_sk_lock);
+
+	kfree(msg);
+
+free_ext_finish:
+	for (i=0; i<SADB_MAX+1; i++) {
+		if (ext_msgs[i]) {
+			kfree(ext_msgs[i]);
+		}
+	}
+
+	return 0;
+
+}
+
+int sadb_msg_send_acquire(struct ipsec_sa *sa)
+{
+	int i=0, error = 0;
+	uint  comb_num = 0;
+	struct sadb_comb combs[5];
+	struct digest_implementation *di = NULL;
+	struct cipher_implementation *ci = NULL;
+	struct sadb_msg *msg = NULL;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+	struct socket_list *pfkey_socketsp = NULL;
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(combs, 0, sizeof(combs));
+
+	if (sa->ipsec_proto == SADB_SATYPE_AH || sa->ipsec_proto == SADB_SATYPE_ESP) {
+		di = find_digest_by_name("md5", 0 /* atomic */);
+		if (di) {
+			combs[comb_num].sadb_comb_auth = SADB_AALG_MD5HMAC;
+			combs[comb_num].sadb_comb_auth_minbits = AUTH_MD5HMAC_KEY_BITS;
+			combs[comb_num].sadb_comb_auth_maxbits = AUTH_MD5HMAC_KEY_BITS;
+			combs[comb_num].sadb_comb_reserved = 0;
+			combs[comb_num].sadb_comb_soft_allocations = 0;
+			combs[comb_num].sadb_comb_hard_allocations = 0;
+			combs[comb_num].sadb_comb_soft_bytes = 0;
+			combs[comb_num].sadb_comb_hard_bytes = 0;
+			combs[comb_num].sadb_comb_soft_addtime = 57600;
+			combs[comb_num].sadb_comb_hard_addtime = 86400;
+			combs[comb_num].sadb_comb_soft_usetime = 57600;
+			combs[comb_num].sadb_comb_hard_usetime = 86400;
+			comb_num++;
+			di = NULL;	
+		}
+	
+		di = find_digest_by_name("sha1", 0 /* atomic */);
+		if (di) {
+			combs[comb_num].sadb_comb_auth = SADB_AALG_SHA1HMAC;
+			combs[comb_num].sadb_comb_auth_minbits = AUTH_SHA1HMAC_KEY_BITS;
+			combs[comb_num].sadb_comb_auth_maxbits = AUTH_SHA1HMAC_KEY_BITS;
+			combs[comb_num].sadb_comb_reserved = 0;
+			combs[comb_num].sadb_comb_soft_allocations = 0;
+			combs[comb_num].sadb_comb_hard_allocations = 0;
+			combs[comb_num].sadb_comb_soft_bytes = 0;
+			combs[comb_num].sadb_comb_hard_bytes = 0;
+			combs[comb_num].sadb_comb_soft_addtime = 57600;
+			combs[comb_num].sadb_comb_hard_addtime = 86400;
+			combs[comb_num].sadb_comb_soft_usetime = 57600;
+			combs[comb_num].sadb_comb_hard_usetime = 86400;
+			comb_num++;
+			di = NULL;
+		}
+	}
+
+	if (sa->ipsec_proto == SADB_SATYPE_ESP) {
+		ci = find_cipher_by_name("des-cbc", 1 /* atomic */);
+		if (ci) {
+			combs[comb_num].sadb_comb_encrypt = SADB_EALG_DESCBC;
+			combs[comb_num].sadb_comb_encrypt_minbits = ESP_DES_KEY_BITS;
+			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_DES_KEY_BITS;
+			combs[comb_num].sadb_comb_reserved = 0;
+			combs[comb_num].sadb_comb_soft_allocations = 0;
+			combs[comb_num].sadb_comb_hard_allocations = 0;
+			combs[comb_num].sadb_comb_soft_bytes = 0;
+			combs[comb_num].sadb_comb_hard_bytes = 0;
+			combs[comb_num].sadb_comb_soft_addtime = 57600;
+			combs[comb_num].sadb_comb_hard_addtime = 86400;
+			combs[comb_num].sadb_comb_soft_usetime = 57600;
+			combs[comb_num].sadb_comb_hard_usetime = 86400;
+			comb_num++;
+			ci = NULL;
+		}
+
+		ci = find_cipher_by_name("3des-cbc", 1 /* atomic */);
+		if (ci) {
+			combs[comb_num].sadb_comb_encrypt = SADB_EALG_3DESCBC;
+			combs[comb_num].sadb_comb_encrypt_minbits = ESP_3DES_KEY_BITS;
+			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_3DES_KEY_BITS;
+			combs[comb_num].sadb_comb_reserved = 0;
+			combs[comb_num].sadb_comb_soft_allocations = 0;
+			combs[comb_num].sadb_comb_hard_allocations = 0;
+			combs[comb_num].sadb_comb_soft_bytes = 0;
+			combs[comb_num].sadb_comb_hard_bytes = 0;
+			combs[comb_num].sadb_comb_soft_addtime = 57600;
+			combs[comb_num].sadb_comb_hard_addtime = 86400;
+			combs[comb_num].sadb_comb_soft_usetime = 57600;
+			combs[comb_num].sadb_comb_hard_usetime = 86400;
+			comb_num++;
+			ci = NULL;
+		}
+
+		ci = find_cipher_by_name("aes-cbc", 1 /* atomic */);
+		if (ci) {
+			combs[comb_num].sadb_comb_encrypt = SADB_EALG_AES;
+			combs[comb_num].sadb_comb_encrypt_minbits = ESP_AES_KEY_BITS;
+			combs[comb_num].sadb_comb_encrypt_maxbits = ESP_AES_KEY_BITS;
+			combs[comb_num].sadb_comb_reserved = 0;
+			combs[comb_num].sadb_comb_soft_allocations = 0;
+			combs[comb_num].sadb_comb_hard_allocations = 0;
+			combs[comb_num].sadb_comb_soft_bytes = 0;
+			combs[comb_num].sadb_comb_hard_bytes = 0;
+			combs[comb_num].sadb_comb_soft_addtime = 57600;
+			combs[comb_num].sadb_comb_hard_addtime = 86400;
+			combs[comb_num].sadb_comb_soft_usetime = 57600;
+			combs[comb_num].sadb_comb_hard_usetime = 86400;
+			comb_num++;
+			ci = NULL;
+		}
+	}
+
+	error = pfkey_msg_hdr_build(&ext_msgs[0],
+				    SADB_ACQUIRE,
+				    sa->ipsec_proto,
+				    0,
+				    0,
+				    0);
+	if (error) {
+		PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n");
+		goto free_ext_finish;
+	}
+
+	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC],
+					SADB_EXT_ADDRESS_SRC,
+					sa->proto,
+					sa->prefixlen_s,
+					(struct sockaddr*)&sa->src);
+	if (error) goto free_ext_finish;
+
+	error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST],
+					SADB_EXT_ADDRESS_DST,
+					sa->proto,
+					sa->prefixlen_d,
+					(struct sockaddr*)&sa->dst);
+	if (error) goto free_ext_finish;
+
+	error = pfkey_prop_build(&ext_msgs[SADB_EXT_PROPOSAL],
+					64,
+					comb_num,
+					combs);
+	if (error) goto free_ext_finish;
+
+
+	error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT);
+
+	write_lock_bh(&pfkey_sk_lock);
+	for (pfkey_socketsp = pfkey_registered_sockets[sa->ipsec_proto];
+		pfkey_socketsp;
+			pfkey_socketsp = pfkey_socketsp->next)
+	{
+		pfkey_upmsg(pfkey_socketsp->socketp, msg);
+	}
+	write_unlock_bh(&pfkey_sk_lock);
+
+	kfree(msg);
+free_ext_finish:
+
+	for (i=0; i<SADB_MAX+1; i++) {
+		if (ext_msgs[i]) {
+			kfree(ext_msgs[i]);
+		}
+	}
+
+	return 0;
+}
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg.h linux25.43-ipsec/net/key/pfkey_v2_msg.h
--- linux-2.5.43/net/key/pfkey_v2_msg.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg.h	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,78 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *
+ */
+
+#ifndef __PFKEY_V2_MSG_H
+#define __PFKEY_V2_MSG_H
+
+#include <linux/pfkeyv2.h>
+#include <net/sadb.h>
+
+#define ESP_DES_KEY_BITS	64
+#define ESP_3DES_KEY_BITS	192
+#define ESP_NULL_KEY_BITS	0
+#define ESP_AES_KEY_BITS	128
+
+#define AUTH_MD5HMAC_KEY_BITS 128
+#define AUTH_SHA1HMAC_KEY_BITS 160 
+
+/* thease codes are derived from FreeS/WAN */
+#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
+#define BITS_PER_OCTET 8
+#define OCTETBITS 8
+#define PFKEYBITS 64
+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
+#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
+
+#define PFKEYv2_MAX_MSGSIZE 4096
+
+
+/* utils */
+int sadb_msg_sanity_check(struct sadb_msg* msg);
+int sadb_address_to_sockaddr(const struct sadb_address *ext_msg, struct sockaddr *addr);
+int sadb_key_to_esp(const __u8 esp_algo, const struct sadb_key* ext_msg, struct ipsec_sa *sa_entry);
+int sadb_key_to_auth(const __u8 auth_algo, const struct sadb_key *ext_msg, struct ipsec_sa *sa_entry);
+int sadb_lifetime_to_lifetime(const struct sadb_lifetime* ext_msg, struct sa_lifetime *lifetime);
+int sadb_msg_detect_ext(struct sadb_msg* msg, struct sadb_ext **ext_msgs);
+int lifetime_to_sadb_lifetime(struct sa_lifetime *lifetime, struct sadb_lifetime *ext_msg, int type);
+
+/* parsers */
+int sadb_msg_getspi_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_update_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_add_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_delete_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_get_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_acquire_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_register_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_expire_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_flush_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_flush_sp_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_dump_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_addflow_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+int sadb_msg_delflow_parse(struct sock* sk, struct sadb_msg* msg, struct sadb_msg **reply);
+
+/* send message */
+int sadb_msg_send_expire(struct ipsec_sa* sa);
+int sadb_msg_send_acquire(struct ipsec_sa* sa);
+#endif /* __PFKEY_V2_MSG_H */
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_add.c linux25.43-ipsec/net/key/pfkey_v2_msg_add.c
--- linux-2.5.43/net/key/pfkey_v2_msg_add.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_add.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,217 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * This is a parse routine for a message of SADB_ADD.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+
+#include "pfkey_v2_msg.h"
+
+#define BUFSIZE 64
+
+int sadb_msg_add_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+	struct sadb_sa *sa;
+	struct sadb_address *src;
+	struct sadb_address *dst;
+	struct ipsec_sa *sa_entry = NULL;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto rtn;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+	if (ext_msgs[SADB_EXT_SA] &&
+		ext_msgs[SADB_EXT_ADDRESS_SRC] &&
+		ext_msgs[SADB_EXT_ADDRESS_DST])
+	{
+		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];
+
+		if ( ((!sa->sadb_sa_auth && !sa->sadb_sa_encrypt) && msg->sadb_msg_satype != SADB_X_SATYPE_COMP) || 
+				sa->sadb_sa_auth > SADB_AALG_MAX || 
+				sa->sadb_sa_encrypt > SADB_EALG_MAX ) {
+			PFKEY_DEBUG("SA has no transform or invalid transform value\n");
+			error = -EINVAL;
+			goto rtn;
+		}
+
+		switch (msg->sadb_msg_satype) {
+		case SADB_SATYPE_AH:
+		case SADB_SATYPE_ESP:
+		case SADB_X_SATYPE_COMP:
+			break;
+		case SADB_SATYPE_RSVP:
+		case SADB_SATYPE_OSPFV2:
+		case SADB_SATYPE_RIPV2:
+		case SADB_SATYPE_MIP:
+		default:
+			PFKEY_DEBUG("invalid SA type\n");
+			error = -EINVAL;
+			goto rtn;
+		}
+
+		if (msg->sadb_msg_satype == SADB_SATYPE_ESP && !(sa->sadb_sa_encrypt)) {
+			PFKEY_DEBUG("SA type is esp but no algorithm\n");
+			error = -EINVAL;
+			goto rtn;
+		}
+
+		sa_entry = ipsec_sa_kmalloc();
+		if (!sa_entry) {
+			PFKEY_DEBUG("sa_entry: NULL\n");
+			error = -ENOMEM;
+			goto err;
+		}
+
+		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
+		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+
+		sa_entry->ipsec_proto = msg->sadb_msg_satype;
+
+		/* SPI which is under 255 is reserved by IANA. 
+		 * Additionally, 256 and 257 reserved for our internal use.  */
+		if (ntohl(sa->sadb_sa_spi) < 258 && sa_entry->ipsec_proto != SADB_X_SATYPE_COMP) {
+			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
+			goto err;
+		}
+
+		sa_entry->spi = sa->sadb_sa_spi;
+
+		error = sadb_address_to_sockaddr( src,
+				(struct sockaddr*)&sa_entry->src);
+		if (error) {
+			PFKEY_DEBUG("src translation failed\n");
+			goto err;
+		}
+		error = sadb_address_to_sockaddr( dst,
+				(struct sockaddr*)&sa_entry->dst);
+		if (error) {
+			PFKEY_DEBUG("dst translation failed\n");
+			goto err;
+		}
+
+		if (src->sadb_address_proto == dst->sadb_address_proto) {
+			sa_entry->proto = src->sadb_address_proto;
+		} else {
+			error = -EINVAL;
+			goto err;
+		} 
+
+		sa_entry->prefixlen_s = src->sadb_address_prefixlen;
+		sa_entry->prefixlen_d = dst->sadb_address_prefixlen;
+
+		if (sa->sadb_sa_auth) {
+			if( (ext_msgs[SADB_EXT_KEY_AUTH]) ) {
+				error = sadb_key_to_auth(sa->sadb_sa_auth,
+					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_AUTH], sa_entry);
+				if (error)
+					goto err;
+			} else {
+				PFKEY_DEBUG("SA has auth algo but there is no key for auth\n");
+				error = -EINVAL;
+				goto err;
+			}
+		}
+
+		if (sa->sadb_sa_encrypt) {
+			if (sa->sadb_sa_encrypt == SADB_EALG_NULL && 
+					sa->sadb_sa_auth == SADB_AALG_NONE) {
+				error = -EINVAL;
+				goto err;
+			}
+			if (msg->sadb_msg_satype != SADB_X_SATYPE_COMP) {
+				error = sadb_key_to_esp(sa->sadb_sa_encrypt, 
+					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_ENCRYPT], sa_entry);
+				if (error)
+					goto err;
+			}
+		}
+
+		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
+			printk(KERN_WARNING "PFKEY proxy translation is not supported.\n");
+			goto err;
+		}
+
+		if (ext_msgs[SADB_EXT_LIFETIME_HARD]) {
+			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_HARD],
+						&sa_entry->lifetime_h);
+			if (error) goto err;
+		}
+
+		if (ext_msgs[SADB_EXT_LIFETIME_SOFT]) {
+			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_SOFT],
+						&sa_entry->lifetime_s);
+			if (error) goto err;
+		}
+
+		sa_entry->state = SADB_SASTATE_MATURE;
+
+		error = sadb_append(sa_entry);	
+		if (error) goto err;	
+
+		reply_ext_msgs[0] = (struct sadb_ext*) msg;
+		reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
+		reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
+		reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
+
+		if (ext_msgs[SADB_EXT_LIFETIME_HARD])
+			reply_ext_msgs[SADB_EXT_LIFETIME_HARD] = ext_msgs[SADB_EXT_LIFETIME_HARD];
+
+		if (ext_msgs[SADB_EXT_LIFETIME_SOFT])
+			reply_ext_msgs[SADB_EXT_LIFETIME_SOFT] = ext_msgs[SADB_EXT_LIFETIME_SOFT];
+
+		error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+		goto rtn;
+	} else {
+		PFKEY_DEBUG("extensions not enough\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+err:
+	ipsec_sa_kfree(sa_entry);
+rtn:
+	return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_delete.c linux25.43-ipsec/net/key/pfkey_v2_msg_delete.c
--- linux-2.5.43/net/key/pfkey_v2_msg_delete.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_delete.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,127 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * This is a parse routine for a message of SADB_DELETE.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+
+#include "pfkey_v2_msg.h"
+
+#define BUFSIZE 64
+
+int sadb_msg_delete_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+	struct sadb_sa reply_sa;
+	struct sadb_sa *sa = NULL;
+	struct sadb_address *src = NULL;
+	struct sadb_address *dst = NULL;
+	struct sockaddr_storage saddr, daddr;
+	struct ipsec_sa *ipsec_sa = NULL;
+	uint8_t prefixlen_s, prefixlen_d;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+	if (error) {
+		PFKEY_DEBUG("error in sadb_msg_detect_ext\n");
+		goto err;
+	}
+
+	if (ext_msgs[SADB_EXT_SA] &&
+		ext_msgs[SADB_EXT_ADDRESS_SRC] &&
+		ext_msgs[SADB_EXT_ADDRESS_DST])
+	{
+		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];
+
+		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
+		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+
+		memset(&saddr, 0, sizeof(struct sockaddr_storage));
+		memset(&daddr, 0, sizeof(struct sockaddr_storage));
+
+		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&saddr);
+		if (error) {
+			PFKEY_DEBUG("src translate\n");
+			goto err;
+		}
+		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&daddr);
+		if (error) {
+			PFKEY_DEBUG("dst translate\n");
+			goto err;
+		}
+
+		prefixlen_s = src->sadb_address_prefixlen;
+		prefixlen_d = dst->sadb_address_prefixlen;
+
+		error = sadb_find_by_address_proto_spi( (struct sockaddr*)&saddr, prefixlen_s,
+							(struct sockaddr*)&daddr, prefixlen_d,
+							msg->sadb_msg_satype,
+							sa->sadb_sa_spi,
+							&ipsec_sa);
+
+		if (error == -EEXIST) {
+			ipsec_sa_put(ipsec_sa);
+			sadb_remove(ipsec_sa);
+			error = 0;
+		}else{
+			error = -ESRCH;
+			goto err;
+		}
+	}
+
+	memset(&reply_sa, 0, sizeof(struct sadb_sa));
+	reply_sa.sadb_sa_len = sizeof(struct sadb_sa) / 8;
+	reply_sa.sadb_sa_exttype = SADB_EXT_SA;
+	reply_sa.sadb_sa_spi = sa->sadb_sa_spi;
+	reply_ext_msgs[0] = (struct sadb_ext*) msg;
+	reply_ext_msgs[SADB_EXT_SA] = (struct sadb_ext*)&reply_sa;
+	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
+	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
+	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+err:
+	return error;
+}
+
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_flow.c linux25.43-ipsec/net/key/pfkey_v2_msg_flow.c
--- linux-2.5.43/net/key/pfkey_v2_msg_flow.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_flow.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,474 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ */
+/*
+ * This is a parse routine for messages SADB_EXT_ADDFLOW and SADB_EXT_DELFLOW.
+ * We use FreeS/WAN's user land routine for manipulating SA and Policy.
+ * These are FreeS/WAN specific.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+
+#include "pfkey_v2_msg.h"
+#include "sockaddr_utils.h"
+
+#define BUFSIZE 64
+
+static int sadb_mask_to_prefixlen(const struct sadb_address *ext_msg)
+{
+	int rtn = 0;
+#ifdef CONFIG_IPSEC_DEBUG
+	int len;
+	char buf[BUFSIZE];
+#endif
+
+	struct sockaddr* tmp_addr = NULL;
+
+	if (!ext_msg) {
+		PFKEY_DEBUG("ext_msg is NULL\n");
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_IPSEC_DEBUG
+	len = ext_msg->sadb_address_len - sizeof(struct sadb_address);
+	if (len < sizeof(struct sockaddr)) {
+		PFKEY_DEBUG("sadb_address_len is small len=%d\n", len);
+		return -EINVAL;
+	}
+#endif
+
+	tmp_addr = (struct sockaddr*)((char*)ext_msg + sizeof(struct sadb_address));
+
+	switch (tmp_addr->sa_family) {
+
+	case AF_INET:
+	{
+		int i;
+		__u32 tmp;
+#ifdef CONFIG_IPSEC_DEBUG
+		PFKEY_DEBUG("address family is AF_INET\n");
+		sockaddrtoa(tmp_addr, buf, BUFSIZE);
+		PFKEY_DEBUG("address %s\n", buf);
+#endif
+		tmp = ntohl(((struct sockaddr_in*)tmp_addr)->sin_addr.s_addr);
+		for (i=0; i<32; i++) {
+			if ((tmp>>i)&0x01)
+				break;
+		}
+		rtn = 32 - i;
+	}
+	break;
+
+	case AF_INET6:
+	{
+		int i,j;
+		__u16 tmp;
+#ifdef CONFIG_IPSEC_DEBUG
+		PFKEY_DEBUG("address family is AF_INET6\n");
+		sockaddrtoa(tmp_addr, buf, BUFSIZE);
+		PFKEY_DEBUG("address %s\n", buf);
+#endif
+		for (i=0; i<8; i++ ) {
+			tmp = ntohs(((struct sockaddr_in6*)tmp_addr)->sin6_addr.s6_addr16[7-i]);
+			for (j=0; j<16; j++) {
+				if ((tmp>>j)&0x01) {
+					rtn = 128 - i*16 - j;
+					PFKEY_DEBUG("result i=%d, j=%d\n", i, j);
+					goto err;
+				}
+			}
+		}
+	}
+	break;
+	default:
+		PFKEY_DEBUG("address family is unknown\n");
+		rtn = -EINVAL;
+		goto err;
+	}
+
+err:
+#ifdef CONFIG_IPSEC_DEBUG
+	if (rtn)
+		PFKEY_DEBUG("prefixlen=%d\n", rtn);
+#endif
+	return rtn;
+}
+
+
+int sadb_msg_addflow_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	int tmp = 0;
+	char buf[BUFSIZE];
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+	struct sadb_sa *sa = NULL;
+	struct sadb_address *dst = NULL;
+	struct sadb_address *sflow = NULL;
+	struct sadb_address *dflow = NULL;
+	struct ipsec_sp *policy = NULL;
+	struct sa_index sa_idx;
+	struct selector selector;
+
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+	if (ext_msgs[SADB_EXT_SA] &&
+		ext_msgs[SADB_EXT_ADDRESS_DST] &&
+		ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW] &&
+		ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW])
+	{
+		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];
+		PFKEY_DEBUG("sa.spi=0x%x\n", ntohl(sa->sadb_sa_spi));
+		PFKEY_DEBUG("sa.auth=%u\n", ntohs(sa->sadb_sa_auth));
+		PFKEY_DEBUG("sa.encrypt=%u\n", ntohs(sa->sadb_sa_encrypt));
+#ifdef CONFIG_IPSEC_TUNNEL
+		PFKEY_DEBUG("sa mode=%d\n", sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL);
+#endif
+		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+		sflow = (struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW];
+		dflow = (struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW];
+
+#ifdef CONFIG_IPSEC_TUNNEL
+		selector.mode = sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL
+				? IPSEC_MODE_TUNNEL
+				: IPSEC_MODE_TRANSPORT;
+
+		if (selector.mode == IPSEC_MODE_TRANSPORT) {
+#endif
+			if (sflow->sadb_address_proto == dflow->sadb_address_proto) {
+				selector.proto = sflow->sadb_address_proto;
+			} else {
+				error = -EINVAL;
+				goto err;
+			}
+#ifdef CONFIG_IPSEC_TUNNEL
+		}
+#endif
+		/* assuming an SA is not needed if policy is 
+		 * bypass or discard the packet. */
+		if ((ntohl(sa->sadb_sa_spi) != IPSEC_SPI_DROP)
+				&& (ntohl (sa->sadb_sa_spi) != IPSEC_SPI_BYPASS)) {
+			sa_index_init(&sa_idx);
+
+			sa_idx.ipsec_proto = msg->sadb_msg_satype;
+			sa_idx.spi = sa->sadb_sa_spi;
+
+			sadb_address_to_sockaddr(dst, (struct sockaddr*)&sa_idx.dst);
+			sa_idx.prefixlen_d = dst->sadb_address_prefixlen;
+#ifdef CONFIG_IPSEC_DEBUG
+			memset(buf, 0, BUFSIZE);
+			sockaddrtoa((struct sockaddr*)&sa_idx.dst, buf, BUFSIZE);
+			PFKEY_DEBUG("dst=%s\n", buf);
+#endif /* CONFIG_IPSEC_DEBUG */
+		}
+
+		memset(buf, 0, BUFSIZE);
+		sadb_address_to_sockaddr( sflow, (struct sockaddr*)&selector.src);
+		sockaddrtoa((struct sockaddr*)&selector.src, buf, BUFSIZE);
+		PFKEY_DEBUG("sflow=%s\n", buf);
+
+		memset(buf, 0, BUFSIZE);
+		sadb_address_to_sockaddr( dflow, (struct sockaddr*)&selector.dst);
+		sockaddrtoa((struct sockaddr*)&selector.dst, buf, BUFSIZE);
+		PFKEY_DEBUG("dflow=%s\n", buf);
+
+		selector.prefixlen_s = sflow->sadb_address_prefixlen;
+		PFKEY_DEBUG("prefixlen_s=%d\n", selector.prefixlen_s);
+		selector.prefixlen_d = dflow->sadb_address_prefixlen;
+		PFKEY_DEBUG("prefixlen_d=%d\n", selector.prefixlen_d);
+
+		if (ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK]) {
+			tmp = sadb_mask_to_prefixlen((struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK]);
+			if (tmp<0) {
+				error = tmp;
+				goto err;
+			} else {
+				selector.prefixlen_s = tmp;
+			}
+		}
+
+		if (ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK]) {
+			tmp = sadb_mask_to_prefixlen((struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK]);
+			if (tmp<0) {
+				error = tmp;
+				goto err;
+			} else {
+				selector.prefixlen_d = tmp;
+			}
+		}
+
+		error = spd_find_by_selector(&selector, &policy);
+
+		PFKEY_DEBUG("spd_find error = %d\n", error);
+
+		if (error == -ESRCH) {
+
+			/* It's new one. I append it into spd_list */
+
+			policy = ipsec_sp_kmalloc();
+			if (!policy) {
+				PFKEY_DEBUG("ipsec_sp_kmalloc faild\n");
+				error = -ENOMEM;
+				goto err;
+			}
+			memcpy(&policy->selector, &selector, sizeof(struct selector));
+
+			if (ntohl(sa->sadb_sa_spi) == IPSEC_SPI_DROP) {
+				policy->policy_action = IPSEC_POLICY_DROP;
+				error = 0;
+			} else if (ntohl(sa->sadb_sa_spi) == IPSEC_SPI_BYPASS) {
+				policy->policy_action = IPSEC_POLICY_BYPASS;
+				error = 0;
+			} else {
+				policy->policy_action = IPSEC_POLICY_APPLY;
+				switch (sa_idx.ipsec_proto) {
+				case SADB_SATYPE_AH:
+					policy->auth_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->auth_sa_idx, &sa_idx);
+					break;
+				case SADB_SATYPE_ESP:
+					policy->esp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->esp_sa_idx, &sa_idx);
+					break;
+				case SADB_X_SATYPE_COMP: /* Currently, just set as SA related with ESP which you specify by SPI. */
+					policy->comp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->comp_sa_idx, &sa_idx);
+					printk(KERN_DEBUG "set IPComp policy.\n");
+					break;
+				default:
+					error = -EINVAL;
+					ipsec_sp_put(policy);
+					goto err;
+				}
+			}
+
+			if (!error) {
+				error = spd_append(policy);
+			}
+
+			ipsec_sp_put(policy);
+			error = 0;
+
+		} else if (error == -EEXIST) {
+
+			/* It has already been in spd_list, I append sa_index into it's sa_list */
+			write_lock_bh(&policy->lock);
+			PFKEY_DEBUG("policy=%p\n", policy);
+
+			switch(sa_idx.ipsec_proto) {
+
+			case SADB_SATYPE_AH:
+				if (!policy->auth_sa_idx) {
+					policy->auth_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->auth_sa_idx, &sa_idx);
+
+				} else if (sa->sadb_sa_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
+					sa_index_kfree(policy->auth_sa_idx);
+					policy->auth_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->auth_sa_idx, &sa_idx);
+				}
+
+				break;
+
+			case SADB_SATYPE_ESP:
+				if (!policy->esp_sa_idx) {
+					policy->esp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->esp_sa_idx, &sa_idx);
+
+				} else if (sa->sadb_sa_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
+					sa_index_kfree(policy->esp_sa_idx);
+					policy->esp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->esp_sa_idx, &sa_idx);
+				}
+
+				break;
+
+			case SADB_X_SATYPE_COMP:
+				if (!policy->comp_sa_idx) {
+					policy->comp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->comp_sa_idx, &sa_idx);
+				} else if (sa->sadb_sa_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
+					sa_index_kfree(policy->comp_sa_idx);
+					policy->comp_sa_idx = sa_index_kmalloc();
+					error = sa_index_copy(policy->comp_sa_idx, &sa_idx);
+				}
+
+				break;
+
+			default:
+				error = -EINVAL;
+				write_unlock_bh(&policy->lock);
+				ipsec_sp_put(policy);
+				goto err;
+			}
+
+			if (error) {
+				write_unlock_bh(&policy->lock);
+				ipsec_sp_put(policy);
+				goto err;
+			}
+
+			write_unlock_bh(&policy->lock);
+			ipsec_sp_put(policy);
+			error = 0;
+
+		} else {
+			/* Something is wrong */
+			PFKEY_DEBUG("spd_find_by_selector faild\n");
+			error = -EINVAL;
+			goto err;
+		}
+
+	}
+	
+err:
+	reply_ext_msgs[0] = (struct sadb_ext*) msg;
+	reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
+	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
+	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW] = ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW] = ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK] = ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK] = ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK];
+	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+
+	return error;
+
+}
+
+int sadb_msg_delflow_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	int tmp = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+	struct sadb_sa *sa = NULL;
+	struct sadb_address *sflow = NULL;
+	struct sadb_address *dflow = NULL;
+	struct selector selector;
+
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+	if (ext_msgs[SADB_EXT_SA] &&
+		ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW] &&
+		ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW])
+	{
+		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];
+
+		sflow = (struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW];
+		dflow = (struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW];
+#ifdef CONFIG_IPSEC_TUNNEL
+		selector.mode = sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL
+				? IPSEC_MODE_TUNNEL
+				: IPSEC_MODE_TRANSPORT;
+
+		if (selector.mode == IPSEC_MODE_TRANSPORT) {
+#endif
+			if (sflow->sadb_address_proto == dflow->sadb_address_proto) {
+				selector.proto = sflow->sadb_address_proto;
+			} else {
+				error = -EINVAL;
+				goto err;
+			}	
+#ifdef CONFIG_IPSEC_TUNNEL
+		}
+#endif
+		sadb_address_to_sockaddr( sflow, (struct sockaddr*)&selector.src);
+		sadb_address_to_sockaddr( dflow, (struct sockaddr*)&selector.dst);
+		selector.prefixlen_s = sflow->sadb_address_prefixlen;
+		selector.prefixlen_d = dflow->sadb_address_prefixlen;
+
+		if (ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK]) {
+			tmp = sadb_mask_to_prefixlen(
+				(struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK]);
+			if (tmp<0) {
+				error = tmp;
+				goto err;
+			} else {
+				selector.prefixlen_s = tmp;
+			}
+		}
+
+		if (ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK]) {
+			tmp = sadb_mask_to_prefixlen(
+				(struct sadb_address*)ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK]);
+			if (tmp<0) {
+				error = tmp;
+				goto err;
+			} else {
+				selector.prefixlen_d = tmp;
+			}
+		}
+
+		error = spd_remove(&selector);
+
+		if (error) {
+			PFKEY_DEBUG("spd_remove failed\n");
+			goto err;
+		}
+
+	}
+
+	reply_ext_msgs[0] = (struct sadb_ext*) msg;
+	reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW] = ext_msgs[SADB_X_EXT_ADDRESS_SRC_FLOW];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW] = ext_msgs[SADB_X_EXT_ADDRESS_DST_FLOW];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK] = ext_msgs[SADB_X_EXT_ADDRESS_SRC_MASK];
+	reply_ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK] = ext_msgs[SADB_X_EXT_ADDRESS_DST_MASK];
+	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+
+err:
+	return error;
+
+}
+
+
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_get.c linux25.43-ipsec/net/key/pfkey_v2_msg_get.c
--- linux-2.5.43/net/key/pfkey_v2_msg_get.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_get.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,212 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ */
+/*
+ * This is a parse routine for a message of SADB_GET.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+
+#include "pfkey_v2_msg.h"
+
+#define BUFSIZE 64
+
+int sadb_msg_get_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+        struct sadb_sa *sa_msg = NULL;
+        struct sadb_address *src = NULL;
+        struct sadb_address *dst = NULL;
+        struct ipsec_sa *sa_entry = NULL;
+	struct sockaddr_storage saddr, daddr;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+	if (error) {
+		PFKEY_DEBUG("sadb_msg_detect_ext faild\n");
+		goto err;
+	}
+
+	if (ext_msgs[SADB_EXT_SA] &&
+	    ext_msgs[SADB_EXT_ADDRESS_SRC] &&
+	    ext_msgs[SADB_EXT_ADDRESS_DST])
+	{
+		sa_msg  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];
+
+                src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
+                dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+
+                error = sadb_address_to_sockaddr( src, (struct sockaddr*)&saddr);
+                if (error) {
+                        PFKEY_DEBUG("src translation failed\n");
+                        goto err;
+                }
+                error = sadb_address_to_sockaddr( dst, (struct sockaddr*)&daddr);
+                if (error) {
+                        PFKEY_DEBUG("dst translation failed\n");
+                        goto err;
+                }
+
+		error = sadb_find_by_address_proto_spi((struct sockaddr*)&saddr, src->sadb_address_prefixlen,
+					 (struct sockaddr*)&daddr, dst->sadb_address_prefixlen,
+					 msg->sadb_msg_type,
+					 sa_msg->sadb_sa_spi,
+					 &sa_entry); 
+
+
+		if (error == -EEXIST) {
+
+			read_lock_bh(&sa_entry->lock);
+
+			error=pfkey_sa_build(&reply_ext_msgs[SADB_EXT_SA], SADB_EXT_SA,
+						sa_entry->spi, sa_entry->replay_window.size,
+						sa_entry->state, sa_entry->auth_algo.algo,
+						sa_entry->esp_algo.algo, SADB_SAFLAGS_PFS );
+			if (error) {
+				PFKEY_DEBUG("pfkey_sa_build faild\n");
+				goto err;
+			}
+
+			error = lifetime_to_sadb_lifetime(&sa_entry->lifetime_c,
+							(struct sadb_lifetime*)reply_ext_msgs[SADB_EXT_LIFETIME_CURRENT],
+							SADB_EXT_LIFETIME_CURRENT);
+			if (error) {
+				PFKEY_DEBUG("lifetime_to_sadb_lifetime failed\n");
+				goto err;
+			}
+
+			error = lifetime_to_sadb_lifetime(&sa_entry->lifetime_h,
+							(struct sadb_lifetime*)reply_ext_msgs[SADB_EXT_LIFETIME_HARD],
+							SADB_EXT_LIFETIME_HARD);
+			if (error) {
+				PFKEY_DEBUG("lifetime_to_sadb_lifetime failed\n");
+				goto err;
+			}
+
+			error = lifetime_to_sadb_lifetime(&sa_entry->lifetime_s,
+							(struct sadb_lifetime*)reply_ext_msgs[SADB_EXT_LIFETIME_SOFT],
+							SADB_EXT_LIFETIME_SOFT);
+			if (error) {
+				PFKEY_DEBUG("lifetime_to_sadb_lifetime failed\n");
+				goto err;
+			}
+
+			error = pfkey_address_build((struct sadb_ext**)&reply_ext_msgs[SADB_EXT_ADDRESS_SRC],
+						SADB_EXT_ADDRESS_SRC,
+						sa_entry->proto,
+						sa_entry->prefixlen_s,
+						(struct sockaddr*)&sa_entry->src);
+			if (error) {
+				PFKEY_DEBUG("pfkey_address_build faild\n");
+				goto err;
+			}
+
+			error = pfkey_address_build((struct sadb_ext**)&reply_ext_msgs[SADB_EXT_ADDRESS_DST],
+						SADB_EXT_ADDRESS_DST,
+						sa_entry->proto,
+						sa_entry->prefixlen_d,
+						(struct sockaddr*)&sa_entry->dst);
+			if (error) {
+				PFKEY_DEBUG("pfkey_address_build faild\n");
+				goto err;
+			}
+
+			if (sa_entry->ipsec_proto == SADB_SATYPE_AH) {
+				error = pfkey_key_build((struct sadb_ext**)&reply_ext_msgs[SADB_EXT_KEY_AUTH],
+						SADB_EXT_KEY_AUTH,
+						sa_entry->auth_algo.key_len*sizeof(__u8),
+						sa_entry->auth_algo.key);
+				if (error) {
+					PFKEY_DEBUG("pfkey_key_build faild\n");
+					goto err;
+				}
+			}
+
+			if (sa_entry->ipsec_proto == SADB_SATYPE_ESP) {
+#ifndef CONFIG_IPSEC_DEBUG
+					error = pfkey_key_build((struct sadb_ext**)&reply_ext_msgs[SADB_EXT_KEY_ENCRYPT],
+						SADB_EXT_KEY_ENCRYPT,
+						sa_entry->esp_algo.key_len*sizeof(__u8),
+						(char*)sa_entry->esp_algo.cx->ci);
+#else /* CONFIG_IPSEC_DEBUG */
+				if (sa_entry->esp_algo.algo != SADB_EALG_NULL) {
+					error = pfkey_key_build((struct sadb_ext**)&reply_ext_msgs[SADB_EXT_KEY_ENCRYPT],
+						SADB_EXT_KEY_ENCRYPT,
+						sa_entry->esp_algo.key_len*sizeof(__u8),
+						(char*)sa_entry->esp_algo.cx->ci);
+				} else {
+					struct sadb_key *tmp_key_msg = kmalloc(sizeof(struct sadb_key), GFP_KERNEL);
+					if (tmp_key_msg) {
+						PFKEY_DEBUG("could not allocat tmp_key_msg");
+						error = -ENOMEM;
+						goto err;
+					}
+					tmp_key_msg->sadb_key_len = sizeof(struct sadb_key)/8;
+					tmp_key_msg->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+					tmp_key_msg->sadb_key_bits = 0;
+					tmp_key_msg->sadb_key_reserved = 0;
+					reply_ext_msgs[SADB_EXT_KEY_ENCRYPT] = (struct sadb_ext *)tmp_key_msg;
+				}
+#endif /* CONFIG_IPSEC_DEBUG */
+				if (error) {
+					PFKEY_DEBUG("pfkey_key_build faild\n");
+					goto err;
+				}
+			}
+			
+			read_unlock_bh(&sa_entry->lock);
+			ipsec_sa_put(sa_entry);
+
+		} else {
+			PFKEY_DEBUG("sadb_find_by_address_spi faild\n");
+			goto err;
+		}
+	}
+
+	reply_ext_msgs[0] = (struct sadb_ext*) msg;
+	pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+	pfkey_extensions_free(reply_ext_msgs);
+err:
+	return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_getspi.c linux25.43-ipsec/net/key/pfkey_v2_msg_getspi.c
--- linux-2.5.43/net/key/pfkey_v2_msg_getspi.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_getspi.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,191 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * This is a parse routine for a message of SADB_GETSPI.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+
+#include <linux/pfkeyv2.h>
+#include <linux/pfkey.h>
+#include <net/sadb.h>
+
+#include "pfkey_v2_msg.h"
+
+#define BUFSIZE 64
+
+int sadb_msg_getspi_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply) 
+{
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
+	int error = 0, found_avail = 0;
+	__u32 newspi = 0;
+	__u32 spi_max = 0, spi_min = 0;
+	struct ipsec_sa sadb_entry;
+	struct sadb_address *src, *dst;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+
+	if (error) {
+		PFKEY_DEBUG("error in sadb_msg_detect_ext\n");
+		goto err;
+	}
+
+	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
+
+	if (ext_msgs[SADB_EXT_ADDRESS_SRC] &&
+	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
+	    ext_msgs[SADB_EXT_SPIRANGE])
+	{
+		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
+		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+
+		memset(&sadb_entry, 0, sizeof(struct ipsec_sa));
+		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&sadb_entry.src);
+		if (error) {
+			PFKEY_DEBUG("error in translate src address\n");
+			goto err;
+		}
+		sadb_entry.prefixlen_s = src->sadb_address_prefixlen;
+
+		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&sadb_entry.dst);
+		if (error) {
+			PFKEY_DEBUG("error in translate dst address\n");
+		}
+		sadb_entry.prefixlen_d = dst->sadb_address_prefixlen;
+
+		spi_min = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_min;
+		spi_max = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_max;
+
+		/* SPI which is under 255 is reserved by IANA. 
+		 * Additionally, 256 and 257 reserved ofr internal use.  */
+		if (spi_min < 258) {
+			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
+			goto err;
+		}
+
+		if (spi_min == spi_max) {
+			PFKEY_DEBUG("spi_min and spi_max are equal\n");
+
+			error = sadb_find_by_address_proto_spi((struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
+								(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
+								spi_min, msg->sadb_msg_type, NULL /*only check*/);
+				
+			if (error == -ESRCH) {
+				newspi = spi_min;
+				found_avail = 1;
+			} else {
+				PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
+				goto err;
+			}
+
+		} else if (ntohl(spi_min) < ntohl(spi_max)) {
+			/* This codes are derived from FreeS/WAN */
+			int i = 0;
+                	__u32 rand_val;
+			__u32 spi_diff;
+
+			PFKEY_DEBUG("spi_min and spi_max are defference\n");
+
+			while ( ( i < (spi_diff = (ntohl(spi_max) - ntohl(spi_min)))) && !found_avail ) {
+				get_random_bytes((void*) &rand_val,
+				/* sizeof(extr->tdb->tdb_said.spi) */
+                                         ( (spi_diff < (2^8))  ? 1 :
+                                           ( (spi_diff < (2^16)) ? 2 :
+                                             ( (spi_diff < (2^24)) ? 3 :
+                                           4 ) ) ) );
+				newspi = htonl(ntohl(spi_min) +
+					(rand_val % (spi_diff + 1)));
+				PFKEY_DEBUG("new spi is %d\n", ntohl(newspi));
+
+				i++;
+				error = sadb_find_by_address_proto_spi( (struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
+									(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
+									newspi, msg->sadb_msg_type, NULL /* only check */);
+				if (error == -ESRCH) {
+					found_avail = 1;
+					break;
+				} else {
+					PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
+					goto err;
+				}
+			}
+
+		} else {
+			PFKEY_DEBUG("invalid spi range\n");
+			error = -EINVAL;
+			goto err;
+		}
+
+		if (found_avail) {
+			sadb_entry.spi = newspi;
+			sadb_entry.state = SADB_SASTATE_LARVAL;
+			error = sadb_append(&sadb_entry);
+			if (error) {
+				PFKEY_DEBUG("sadb_append return %d\n", error);
+				goto err;
+			}
+		} else {
+			PFKEY_DEBUG("could not find available spi\n");
+			goto err;
+		}
+
+	} else {
+		PFKEY_DEBUG("necessary ext messages are not available\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	error = pfkey_sa_build(&reply_ext_msgs[SADB_EXT_SA], SADB_EXT_SA,
+			newspi, 0, 0, 0, 0, SADB_SAFLAGS_PFS);
+	if (error) {
+		PFKEY_DEBUG("pfkey_address_build faild\n");
+		goto err;
+	}
+
+	reply_ext_msgs[0] = (struct sadb_ext*) msg;
+	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
+	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
+	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
+err:
+	return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/pfkey_v2_msg_update.c linux25.43-ipsec/net/key/pfkey_v2_msg_update.c
--- linux-2.5.43/net/key/pfkey_v2_msg_update.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/pfkey_v2_msg_update.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,135 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * This is a parse routine for a message of SADB_UPDATE.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/random.h>
+#include <linux/ipsec.h>
+
+#include <linux/pfkeyv2.h>
+#include <net/sadb.h>
+
+#include "pfkey_v2_msg.h"
+
+#define BUFSIZE 64
+
+int sadb_msg_update_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
+{
+	int error = 0;
+	__u32 spi = 0;
+	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];
+	struct sadb_sa *sa = NULL;
+	struct sadb_address *src = NULL;
+	struct sadb_address *dst = NULL;
+	struct ipsec_sa *sa_entry = NULL;
+	struct sockaddr_storage saddr, daddr, paddr;
+
+	if (!msg) {
+		PFKEY_DEBUG("msg is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(ext_msgs, 0, sizeof(ext_msgs));
+	error = sadb_msg_detect_ext(msg, ext_msgs);
+	
+	if (ext_msgs[SADB_EXT_SA] &&
+	    ext_msgs[SADB_EXT_ADDRESS_SRC] &&
+	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
+	   (ext_msgs[SADB_EXT_KEY_AUTH] ||
+	    ext_msgs[SADB_EXT_KEY_ENCRYPT]))
+	{
+		
+		memset(&saddr, 0, sizeof(struct sockaddr_storage));
+		memset(&daddr, 0, sizeof(struct sockaddr_storage));
+		memset(&paddr, 0, sizeof(struct sockaddr_storage));
+
+		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
+		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];
+
+		spi = sa->sadb_sa_spi;
+
+		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&saddr);
+
+		if (error) {
+			PFKEY_DEBUG("src translation failed\n");
+			goto err;
+		}
+		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&daddr);
+		if (error) {
+			PFKEY_DEBUG("dst translation failed\n");
+			goto err;
+		}
+
+		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
+			printk(KERN_WARNING "PFKEY proxy translation is not supported.\n");
+		}
+
+		if (sa->sadb_sa_auth && !(ext_msgs[SADB_EXT_KEY_AUTH])) {
+			PFKEY_DEBUG("SA has auth algo but there is no key for auth\n");
+			error = -EINVAL;
+			goto err;
+		}
+
+		if (sa->sadb_sa_encrypt && !(ext_msgs[SADB_EXT_KEY_ENCRYPT])) {
+			PFKEY_DEBUG("SA has esp algo but there is no key for esp\n");
+			error = -EINVAL;
+			goto err;
+		}
+
+		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) { 
+			PFKEY_DEBUG("PFKEY proxy translation not supported.\n");
+			error = -EINVAL;
+			goto err;
+		}
+
+		if (error) {
+			PFKEY_DEBUG("could not find SA\n");
+			goto err;
+		}
+
+		switch (sa_entry->state) {
+		case SADB_SASTATE_LARVAL:
+		case SADB_SASTATE_MATURE:
+		case SADB_SASTATE_DYING:
+			break;
+		case SADB_SASTATE_DEAD:
+		default:
+		}
+
+	}
+	/* mask auth key and esp key */
+err:
+	return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/sa_index.c linux25.43-ipsec/net/key/sa_index.c
--- linux-2.5.43/net/key/sa_index.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/sa_index.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,143 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ */
+/*
+ * struct ipsec_sa is connected with struct ipsec_sp by struct sa_index
+ * The element sa of sa_index occasionlly NULL.
+ * Note that struct ipsec_sa has a reference count. 
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/ipsec.h>
+#include <net/sadb.h>
+#include "sockaddr_utils.h"
+
+struct sa_index* sa_index_kmalloc()
+{
+	struct sa_index* sa_idx = NULL;
+
+	sa_idx = kmalloc(sizeof(struct sa_index), GFP_ATOMIC);
+
+	if (!sa_idx) {
+		SADB_DEBUG("kmalloc faild\n");
+		return NULL;
+	}
+
+	sa_index_init(sa_idx);
+
+	return sa_idx;
+}
+
+int sa_index_init(struct sa_index *sa)
+{
+	int error = 0;
+
+	if (!sa) {
+		SADB_DEBUG("SA is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(sa, 0, sizeof(struct sa_index));
+	INIT_LIST_HEAD(&sa->entry);
+
+err:
+	return error;
+}
+
+void sa_index_kfree(struct sa_index *sa_idx)
+{
+	if (!sa_idx) {
+		SADB_DEBUG("SA is NULL\n");
+		return;
+	}
+
+	if (sa_idx->sa) {
+		ipsec_sa_put((sa_idx)->sa);
+		SADB_DEBUG("ptr=%p,refcnt=%d\n",
+			   sa_idx->sa, atomic_read(&sa_idx->sa->refcnt));
+		sa_idx->sa = NULL;
+	}
+
+	kfree(sa_idx);
+}
+
+int sa_index_copy(struct sa_index *dst, struct sa_index *src)
+{
+	int error = 0;
+
+	if (!dst || !src) {
+		SADB_DEBUG("dst or src is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	dst->dst	 = src->dst;
+	dst->prefixlen_d = src->prefixlen_d;
+	dst->ipsec_proto = src->ipsec_proto;
+	dst->spi 	 = src->spi;
+	if (src->sa) {
+		dst->sa		 = src->sa;
+		atomic_inc(&dst->sa->refcnt);
+		SADB_DEBUG("ptr=%p,refcnt=%d\n",
+			   dst->sa, atomic_read(&dst->sa->refcnt));
+	}
+
+err:
+	return error;
+}
+
+/* Currently sa_index_compare is used in ipsec6_input.c
+ * If ether sa_idx1 or sa_idx2 has SPI=0xFFFFFFFF, It ignores SPI.
+ * Please take care to use sa_index_compare in other codes.  
+ *
+ * We use SPI=0xFFFFFFFF in policy as SPI is any.
+ */
+int sa_index_compare(struct sa_index *sa_idx1, struct sa_index *sa_idx2)
+{
+	if (!sa_idx1 || !sa_idx2) {
+		SADB_DEBUG("sa_idx1 or sa_idx2 is NULL\n");
+		return -EINVAL;
+	}
+
+	if (sa_idx1->spi != IPSEC_SPI_ANY && sa_idx2->spi != IPSEC_SPI_ANY) {
+		if (sa_idx1->spi != sa_idx2->spi)
+			return 1;
+	}
+
+	if (sa_idx1->ipsec_proto != sa_idx2->ipsec_proto)
+		return 1;
+
+	return sockaddr_prefix_compare((struct sockaddr*)&sa_idx1->dst, sa_idx1->prefixlen_d,
+				       (struct sockaddr*)&sa_idx2->dst, sa_idx2->prefixlen_d); 
+}
diff -uNr -x CVS linux-2.5.43/net/key/sadb.c linux25.43-ipsec/net/key/sadb.c
--- linux-2.5.43/net/key/sadb.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/sadb.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,853 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *
+ * Acknowledgements:
+ *   Joy Latten <latten@austin.ibm.com>
+ *
+ */
+/*
+ * sadb.c is a program for IPsec SADB. It provide functions for SADB manipulation.
+ * struct ipsec_sa represents IPsec SA. It has a reference count and maneges itself.
+ * If you get a reference(pointer) of struct ipsec_sa by sadb_find_by_***, please
+ * call ipsec_sa_put when you abondan the reference. 
+ */ 
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <net/sadb.h>
+#include <net/spd.h>
+
+#include "pfkey_v2_msg.h"
+#include "sockaddr_utils.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#define BUFSIZE 64
+
+/* sa_list   : IPsec Security Association DataBase(SADB) 
+ * sadb_lock : lock for SADB
+ */
+LIST_HEAD(sadb_list);
+rwlock_t sadb_lock = RW_LOCK_UNLOCKED;
+
+struct ipsec_sa *ipsec_sa_kmalloc()
+{
+	struct ipsec_sa *sa = NULL;
+
+	sa = (struct ipsec_sa *)kmalloc(sizeof(struct ipsec_sa), GFP_KERNEL);
+
+	if (!sa) {
+		SADB_DEBUG("SA couldn\'t be allocated\n");
+		return NULL;
+	}
+
+	SADB_DEBUG("kmalloc sa %p\n", sa);
+
+	ipsec_sa_init(sa);
+
+	return sa;
+}
+
+int ipsec_sa_init(struct ipsec_sa *sa)
+{
+	if (!sa) {
+		SADB_DEBUG("SA is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(sa, 0, sizeof(struct ipsec_sa));
+	/* set default replay window size (32) -mk */
+	sa->replay_window.size = 32;
+	sa->init_time = jiffies;
+	sa->lifetime_c.addtime = (sa->init_time) / HZ;
+	sa->timer.expires = 0; /* 0 stands for timer is not added to timer list */
+	atomic_set(&sa->refcnt, 1);
+	init_timer(&sa->timer);
+	sa->lock = RW_LOCK_UNLOCKED;
+
+	return 0;
+}
+
+void ipsec_sa_kfree(struct ipsec_sa *sa)
+{
+	struct cipher_implementation *ci = NULL;
+	struct digest_implementation *di = NULL;
+
+	if (!sa) {
+		SADB_DEBUG("SA is NULL\n");
+		return;
+	}
+
+	if (atomic_read(&sa->refcnt)) {
+		SADB_DEBUG("SA has been referred.\n");
+		return;
+	}
+
+	if (sa->auth_algo.key)
+		kfree(sa->auth_algo.key);
+
+	if (sa->auth_algo.dx && sa->auth_algo.dx->di) {
+		di = sa->auth_algo.dx->di;
+		di->free_context(sa->auth_algo.dx);
+		di->unlock();
+	}
+
+	if (sa->esp_algo.key)
+		kfree(sa->esp_algo.key);
+
+	if (sa->esp_algo.cx && sa->esp_algo.cx->ci) { 
+		ci = sa->esp_algo.cx->ci;
+		ci->wipe_context(sa->esp_algo.cx);
+		ci->free_context(sa->esp_algo.cx);
+		ci->unlock();
+	}
+
+	if (sa->esp_algo.iv)
+		kfree(sa->esp_algo.iv);
+
+	kfree(sa);
+
+}
+/* XXX dx/cx */
+int ipsec_sa_copy(struct ipsec_sa *dst, struct ipsec_sa *src)
+{
+	int error = 0;
+	if (!(src&&dst)) {
+		SADB_DEBUG("src or dst is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memcpy( dst, src, sizeof(struct ipsec_sa));
+
+	if (dst->auth_algo.algo != SADB_AALG_NONE) {
+		if (src->auth_algo.dx->digest_info) {
+			dst->auth_algo.dx->digest_info
+				= kmalloc(dst->auth_algo.dx->di->working_size, GFP_KERNEL);
+			if (!dst->auth_algo.dx->digest_info) {
+				SADB_DEBUG("cannot allocate digest_info\n");
+				error = -ENOMEM;
+				goto err;
+			}
+
+			memcpy(dst->auth_algo.dx->digest_info,
+				src->auth_algo.dx->digest_info,
+				dst->auth_algo.dx->di->working_size);
+		}
+
+		if (src->auth_algo.key) {
+			dst->auth_algo.key
+				= kmalloc(dst->auth_algo.key_len, GFP_KERNEL);
+			if (!dst->auth_algo.key) {
+				SADB_DEBUG("cannot allocate authkey\n");
+				error = -ENOMEM;
+				goto free_digest_info;
+			}
+
+			memcpy(dst->auth_algo.key,
+				src->auth_algo.key,
+				dst->auth_algo.key_len);
+		}
+	}
+
+	if (dst->esp_algo.algo != SADB_EALG_NULL && dst->esp_algo.algo != SADB_EALG_NONE) {
+		if (src->esp_algo.key) {
+			dst->esp_algo.key = kmalloc(dst->esp_algo.key_len, GFP_KERNEL);
+			if (!dst->esp_algo.key) {
+				SADB_DEBUG("cannot allocate espkey\n");
+				error = -ENOMEM;
+				goto free_auth_key;
+			}
+
+			memcpy(dst->esp_algo.key,
+				src->esp_algo.key,
+				dst->esp_algo.key_len);
+		}
+
+
+		if (src->esp_algo.cx->keyinfo && src->esp_algo.cx->ci) {
+			dst->esp_algo.cx->keyinfo
+				= kmalloc(dst->esp_algo.cx->ci->key_schedule_size, GFP_KERNEL);
+			if (!dst->esp_algo.cx->keyinfo) {
+				SADB_DEBUG("cannot allocate keyinfo\n");
+				error = -ENOMEM;
+				goto free_esp_key;
+			}
+
+			memcpy(dst->esp_algo.cx->keyinfo,
+				src->esp_algo.cx->keyinfo,
+				dst->esp_algo.cx->ci->key_schedule_size);
+		}
+
+	}
+
+	atomic_set(&(dst->refcnt),1);
+
+	return error;
+
+free_esp_key:
+	kfree(dst->esp_algo.key);
+free_auth_key:
+	kfree(dst->auth_algo.key);
+free_digest_info:
+	kfree(dst->auth_algo.dx->digest_info);
+err:
+	return error;
+}
+
+void ipsec_sa_put(struct ipsec_sa *sa)
+{
+	if (!sa) {
+		SADB_DEBUG("SA is NULL\n");
+		return;
+	}
+
+	write_lock_bh(&sa->lock);
+	SADB_DEBUG("prt=%p,refcnt=%d-1\n",
+		sa, atomic_read(&sa->refcnt)); 
+	if (atomic_dec_and_test(&sa->refcnt)) {
+
+		SADB_DEBUG("kfree prt=%p,refcnt=%d\n",
+			sa, atomic_read(&sa->refcnt)); 
+		write_unlock_bh(&sa->lock);
+
+		ipsec_sa_kfree(sa);
+
+		return;
+
+	}
+	write_unlock_bh(&sa->lock);
+}
+
+static __inline__ unsigned long __ipsec_sa_next_expire(struct ipsec_sa *sa)
+{
+	unsigned long schedule_time = 0;
+
+	switch(sa->state){
+
+	case SADB_SASTATE_LARVAL:
+	case SADB_SASTATE_MATURE:
+
+		if (sa->lifetime_s.addtime) 
+			schedule_time = sa->init_time + sa->lifetime_s.addtime * HZ;
+
+		if (sa->lifetime_h.addtime) {
+			if (schedule_time) {
+				schedule_time = schedule_time < sa->init_time + sa->lifetime_h.addtime * HZ
+				? schedule_time : sa->init_time + sa->lifetime_h.addtime * HZ;
+			} else {
+				schedule_time = sa->init_time + sa->lifetime_h.addtime * HZ; 
+			}
+		}
+ 
+		if (sa->fuse_time) {
+			if (sa->lifetime_s.usetime) {
+				if (schedule_time) {
+					schedule_time = schedule_time < sa->fuse_time + sa->lifetime_s.usetime * HZ
+					? schedule_time : sa->fuse_time + sa->lifetime_s.usetime * HZ;
+				} else {
+					schedule_time = sa->fuse_time + sa->lifetime_s.usetime * HZ;
+				}
+			}
+
+			if (sa->lifetime_h.usetime) {
+				if (schedule_time) {
+					schedule_time = schedule_time < sa->fuse_time + sa->lifetime_h.usetime * HZ
+					? schedule_time : sa->fuse_time + sa->lifetime_h.usetime * HZ;
+				} else {
+					schedule_time = sa->fuse_time + sa->lifetime_h.usetime * HZ;
+				}
+			}
+		}
+
+		break;
+
+	case SADB_SASTATE_DYING:
+
+		if (sa->lifetime_h.addtime)
+			schedule_time = sa->init_time + sa->lifetime_h.addtime * HZ;
+
+		if (sa->fuse_time) {
+			if (sa->lifetime_h.usetime) {
+				if (schedule_time) {
+					schedule_time = schedule_time < sa->fuse_time + sa->lifetime_h.usetime * HZ
+					? schedule_time : sa->fuse_time + sa->lifetime_h.usetime * HZ;
+				} else {
+					schedule_time = sa->fuse_time + sa->lifetime_h.usetime * HZ;
+				}
+			}
+		}
+
+		break;
+	}
+
+	return schedule_time;
+}
+
+void ipsec_sa_mod_timer(struct ipsec_sa *sa)
+{
+	unsigned long expire_time = 0;
+
+	if (!sa) {
+		SADB_DEBUG("SA is NULL");
+		return;
+	}
+
+	SADB_DEBUG("ipsec_sa_mod_timer called with %p\n", sa);
+
+	expire_time = __ipsec_sa_next_expire(sa);
+
+	if (!expire_time) return;
+
+	SADB_DEBUG("expire_time=%ld, jiffies=%ld\n", expire_time, jiffies);
+
+
+	/* if expire time is 0, it means no timer have added */
+	if (sa->timer.expires) {
+		mod_timer(&sa->timer, expire_time);
+	} else {
+		sa->timer.data = (unsigned long)sa;
+		sa->timer.function = ipsec_sa_lifetime_check;
+		sa->timer.expires = expire_time;
+		ipsec_sa_hold(sa); /* refernce count for timer */
+		add_timer(&sa->timer);
+	}
+}
+
+static __inline__ int __ipsec_sa_lifetime_check(struct ipsec_sa *sa)
+{
+	time_t ctime = jiffies; /* current time */
+
+	if (!sa) {
+		SADB_DEBUG("SA is NULL");
+		return -EINVAL;
+	}
+
+	if ( sa->lifetime_s.addtime && ctime >= (sa->init_time + sa->lifetime_s.addtime * HZ) ) {
+		printk(KERN_INFO "SA soft lifetime(addtime) over !\n");
+		sa->state = SADB_SASTATE_DYING;
+		/* XXX report the information to userland applications ? */
+	}
+
+	if ( sa->lifetime_s.usetime && sa->fuse_time && ctime >= (sa->fuse_time + sa->lifetime_s.usetime * HZ) ) {
+		printk(KERN_INFO "SA soft lifetime(usetime) over !\n");
+		sa->state = SADB_SASTATE_DYING;
+		/* XXX report the information to userland applications ? */
+	}
+
+	if ( sa->lifetime_h.addtime && ctime >= (sa->init_time + sa->lifetime_h.addtime * HZ) ) {
+		printk(KERN_INFO "SA hard lifetime(addtime) over! \n ");
+		sa->state = SADB_SASTATE_DEAD;
+	}
+
+	if ( sa->lifetime_h.usetime && sa->fuse_time && ctime >= (sa->fuse_time + sa->lifetime_h.usetime * HZ) ) {
+		printk(KERN_INFO "SA hard lifetime(usetime) over ! \n ");
+		sa->state = SADB_SASTATE_DEAD;
+	}
+
+
+	return sa->state;
+}
+
+void ipsec_sa_lifetime_check(unsigned long data)
+{
+	struct ipsec_sa *sa = (struct ipsec_sa*)data;
+	__u8 sa_state;
+
+	if(!sa)
+		return;
+
+	write_lock_bh(&sa->lock);
+	sa_state = __ipsec_sa_lifetime_check(sa);
+	SADB_DEBUG("SA state change to %d\n", sa_state);
+	switch(sa_state) {
+	case SADB_SASTATE_DYING:
+		ipsec_sa_mod_timer(sa);
+		sadb_msg_send_expire(sa);
+		sadb_msg_send_acquire(sa);
+		write_unlock_bh(&sa->lock);
+		break;
+	case SADB_SASTATE_DEAD:
+		sadb_msg_send_expire(sa);
+		write_unlock_bh(&sa->lock);
+		sadb_remove(sa);
+		break;
+	case SADB_SASTATE_LARVAL:
+	case SADB_SASTATE_MATURE:
+	default:
+		write_unlock_bh(&sa->lock);
+		break;
+	}
+}
+
+int sadb_append(struct ipsec_sa *sa)
+{
+	int error = 0;
+	struct sa_index tmp;
+
+	if (!sa) {
+		SADB_DEBUG("SA is NULL.\n"); 
+		error = -EINVAL;
+		goto err;
+	}
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	memcpy(&tmp.dst, &sa->dst, (sa->dst.ss_family == AF_INET) ? sizeof(struct sockaddr_in) :
+					(sa->dst.ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) :
+						sizeof(struct sockaddr_storage));
+	tmp.prefixlen_d = sa->prefixlen_d;
+	tmp.ipsec_proto = sa->ipsec_proto;
+	tmp.spi         = sa->spi;
+
+	tmp.sa = sadb_find_by_sa_index(&tmp);
+
+	if (tmp.sa) {
+		SADB_DEBUG("sa already exist\n");
+		error = -EEXIST;
+		goto err;
+	}
+
+	ipsec_sa_mod_timer(sa);
+
+	write_lock_bh(&sadb_lock);
+	list_add_tail(&sa->entry, &sadb_list);
+	write_unlock_bh(&sadb_lock);
+
+	error = 0;
+err:
+	return error;
+}
+
+static void __sadb_remove(struct ipsec_sa *sa)
+{
+	struct list_head *pos = NULL;
+	struct ipsec_sp *tmp_sp = NULL;
+
+	if(!sa)
+		return;
+
+	/* check sp, if any sp has the sa, make it release sa */
+	write_lock_bh(&spd_lock);
+	list_for_each(pos, &spd_list){
+		tmp_sp = list_entry(pos, struct ipsec_sp, entry);
+		write_lock_bh(&tmp_sp->lock); 
+		ipsec_sp_release_invalid_sa(tmp_sp, sa);
+		write_unlock_bh(&tmp_sp->lock); 
+	}
+	write_unlock_bh(&spd_lock);
+
+	if(sa->timer.expires){
+		del_timer(&sa->timer);
+		sa->timer.expires = 0;
+		ipsec_sa_put(sa);
+	}
+	ipsec_sa_put(sa);
+}
+
+void sadb_remove(struct ipsec_sa *sa)
+{
+	struct list_head *pos = NULL;
+	struct ipsec_sa *tmp_sa = NULL;
+
+	SADB_DEBUG("sa=%p\n", sa);
+
+	/* If SA has already chained to sadb_list, SA is removed from sadb */
+	write_lock_bh(&sadb_lock);
+	list_for_each(pos, &sadb_list) {
+		tmp_sa = list_entry(pos, struct ipsec_sa, entry);
+		write_lock_bh(&tmp_sa->lock);
+		if (tmp_sa == sa) {
+			SADB_DEBUG(" I found a SA to be removed.\n");
+			tmp_sa->state = SADB_SASTATE_DEAD;
+			list_del(&tmp_sa->entry);
+			write_unlock_bh(&tmp_sa->lock);
+			break;
+		}
+		write_unlock_bh(&tmp_sa->lock);
+		tmp_sa = NULL;
+	}
+	write_unlock_bh(&sadb_lock);
+
+	if (tmp_sa)
+		__sadb_remove(tmp_sa);
+}
+
+int sadb_update(struct ipsec_sa *entry)
+{
+	int error = 0;
+	if (entry) {
+		SADB_DEBUG("sadb_update entry == null\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	/* TODO: Current code removes old sa and append new sa,
+		 but it is correct to update sa returnd from sa_get_by_said. */
+
+	sadb_remove(entry);
+
+	error = sadb_append(entry);
+	if (error) {
+		SADB_DEBUG("could not append\n");
+		goto err;
+	}
+
+err:
+	return error;
+}
+
+int sadb_find_by_address_proto_spi(struct sockaddr *src, __u8 prefixlen_s,
+				  struct sockaddr *dst, __u8 prefixlen_d,
+				  __u8 ipsec_proto,
+				  __u32 spi,
+				  struct ipsec_sa **sa)
+{
+	int error = -ESRCH;
+	struct list_head *pos = NULL;
+	struct ipsec_sa *tmp = NULL;
+
+	if (!(src&&dst)) {
+		SADB_DEBUG("src or dst is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+
+#ifdef CONFIG_IPSEC_DEBUG
+{
+	char buf[BUFSIZE];
+	sockaddrtoa(src, buf, sizeof(buf));
+	SADB_DEBUG("src=%s\n", buf);
+	sockaddrtoa(dst, buf, sizeof(buf));
+	SADB_DEBUG("dst=%s\n", buf);
+}
+#endif 	
+
+	read_lock_bh(&sadb_lock);
+	list_for_each(pos, &sadb_list){
+		tmp = list_entry(pos, struct ipsec_sa, entry);
+		read_lock_bh(&tmp->lock);
+		if (tmp->ipsec_proto == ipsec_proto && tmp->spi == spi &&
+		    !sockaddr_prefix_compare(dst, prefixlen_d, 
+					     (struct sockaddr*)&tmp->dst, tmp->prefixlen_d) &&
+		    !sockaddr_prefix_compare(src, prefixlen_s, 
+					     (struct sockaddr*)&tmp->src, tmp->prefixlen_s) && 
+		    spi == tmp->spi) { 
+			SADB_DEBUG("found sa matching params.\n");
+			if (sa) {
+				atomic_inc(&tmp->refcnt);
+				*sa = tmp;
+				SADB_DEBUG("ptr=%p,refcnt%d\n",
+					tmp, atomic_read(&tmp->refcnt));
+			}
+			read_unlock_bh(&tmp->lock);
+			error = -EEXIST;
+			break;
+		}
+		read_unlock_bh(&tmp->lock);
+	}
+	read_unlock_bh(&sadb_lock);
+err:
+
+#ifdef CONFIG_IPSEC_DEBUG
+	if (error && (error != -EEXIST))
+		SADB_DEBUG("I could not find any SA.\n");
+#endif
+		
+	return error;
+}
+
+/*
+ * We use SPI=0xFFFFFFFF for a special purpose.
+ * It means sadb_find_by_sa_index() looking for proper SA 
+ * whether SPI value is same or not.
+ *
+ * Please take care to use sadb_find_by_sa_index() to use other places.
+ * 
+ */
+struct ipsec_sa* sadb_find_by_sa_index(struct sa_index *sa_idx)
+{
+	struct list_head *pos;
+	struct ipsec_sa *tmp_sa = NULL;
+
+	if (!sa_idx) {
+		SADB_DEBUG("sa_index is NULL\n");
+		return NULL;
+	}
+
+#ifdef CONFIG_IPSEC_DEBUG
+{
+	char buf[BUFSIZE];
+	sockaddrtoa((struct sockaddr*)&sa_idx->dst, buf, sizeof(buf));
+	SADB_DEBUG("sa_idx->dst=%s\n", buf);
+	SADB_DEBUG("sa_idx->ipsec_proto=%u\n", sa_idx->ipsec_proto);
+	SADB_DEBUG("sa_idx->spi=0x%x\n", ntohl(sa_idx->spi));
+}
+#endif /* CONFIG_IPSEC_DEBUG */
+
+	read_lock(&sadb_lock);
+	list_for_each(pos, &sadb_list){
+		tmp_sa = list_entry(pos, struct ipsec_sa, entry);
+		read_lock_bh(&tmp_sa->lock);
+		if ((sa_idx->spi == IPSEC_SPI_ANY || tmp_sa->spi == sa_idx->spi) &&
+		    tmp_sa->ipsec_proto == sa_idx->ipsec_proto && 
+		    !sockaddr_prefix_compare((struct sockaddr*)&sa_idx->dst, sa_idx->prefixlen_d, 
+					     (struct sockaddr*)&tmp_sa->dst, tmp_sa->prefixlen_d) &&
+		    (tmp_sa->state == SADB_SASTATE_MATURE || tmp_sa->state == SADB_SASTATE_DYING)) {
+			SADB_DEBUG("found SA matching params.\n");
+
+			atomic_inc(&tmp_sa->refcnt);
+			read_unlock_bh(&tmp_sa->lock);
+
+			if (sa_idx->sa)
+				ipsec_sa_put(sa_idx->sa);
+			sa_idx->sa = tmp_sa;
+
+			SADB_DEBUG("ptr=%p,refcnt=%d\n",
+				   tmp_sa, atomic_read(&tmp_sa->refcnt));
+
+			break;
+		}
+		read_unlock_bh(&tmp_sa->lock);
+	}
+	read_unlock(&sadb_lock);
+
+#ifdef CONFIG_IPSEC_DEBUG
+	if (!sa_idx->sa)
+		SADB_DEBUG("I could not find any SA.\n");
+#endif
+		
+	return sa_idx->sa;
+}
+
+int sadb_flush_sa(int satype)
+{
+	struct list_head dead_sa_list;
+	struct list_head *pos = NULL;
+	struct list_head *next = NULL;
+	struct ipsec_sa *tmp = NULL;
+	
+	if (satype != SADB_SATYPE_AH && satype != SADB_SATYPE_ESP) {
+		SADB_DEBUG("satype is not supported\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&dead_sa_list);
+
+	write_lock_bh(&sadb_lock);
+	list_for_each_safe(pos, next, &sadb_list) {
+		tmp = list_entry(pos, struct ipsec_sa, entry);
+		write_lock_bh(&tmp->lock);
+		if (tmp->ipsec_proto == satype) {
+			list_del(&tmp->entry);
+			list_add_tail(&tmp->entry, &dead_sa_list);
+		}
+		write_unlock_bh(&tmp->lock);
+	}
+	write_unlock_bh(&sadb_lock);
+
+	list_for_each_safe(pos, next, &dead_sa_list) {
+		tmp = list_entry(pos, struct ipsec_sa, entry);
+		list_del(&tmp->entry);
+		__sadb_remove(tmp);
+	}
+
+	return 0;
+}
+
+void sadb_clear_db(void)
+{
+	struct list_head dead_sa_list;
+	struct list_head *pos = NULL;
+	struct list_head *next = NULL;
+	struct ipsec_sa *tmp = NULL;
+
+	INIT_LIST_HEAD(&dead_sa_list);
+
+	write_lock_bh(&sadb_lock);
+	list_for_each_safe(pos, next, &sadb_list) {
+		tmp = list_entry(pos, struct ipsec_sa, entry);
+		write_lock_bh(&tmp->lock);
+		/*
+		   A previous pointer of pos must be stored because 
+		   pos indicates tmp->entry and these operations
+		   change tmp->entry. Therefore this loop is broken.
+		*/ 
+		list_del(&tmp->entry);
+		list_add_tail(&tmp->entry, &dead_sa_list);	
+		write_unlock_bh(&tmp->lock);
+	}
+	write_unlock_bh(&sadb_lock);
+
+	list_for_each_safe(pos, next, &dead_sa_list) {
+		tmp = list_entry(pos, struct ipsec_sa, entry);
+		list_del(&tmp->entry);
+		__sadb_remove(tmp);
+	}
+}
+
+#ifdef CONFIG_PROC_FS
+static int sadb_get_info(char *buffer, char **start, off_t offset, int length )
+{
+        int len = 0;
+        off_t pos=0;
+        off_t begin=0;
+	char buf[BUFSIZE]; 
+	struct list_head *list_pos = NULL;
+	struct ipsec_sa *tmp = NULL;
+	read_lock_bh(&sadb_lock);
+	list_for_each(list_pos, &sadb_list){
+		tmp = list_entry(list_pos, struct ipsec_sa, entry);
+		read_lock_bh(&tmp->lock);
+
+		len += sprintf(buffer + len, "sa:%p\n", tmp);
+
+		memset(buf, 0, sizeof(buf));
+		sockaddrtoa((struct sockaddr*)&tmp->src, buf, sizeof(buf));
+		len += sprintf(buffer + len, "%s/%d ", buf, tmp->prefixlen_s);
+
+		memset(buf, 0, sizeof(buf));
+		sockporttoa((struct sockaddr*)&tmp->src, buf, sizeof(buf));
+		len += sprintf(buffer + len, "%s ", buf);
+
+		memset(buf, 0, sizeof(buf));
+		sockaddrtoa((struct sockaddr*)&tmp->dst, buf, sizeof(buf));
+		len += sprintf(buffer + len, "%s/%d ", buf, tmp->prefixlen_d);
+
+		memset(buf, 0, sizeof(buf));
+		sockporttoa((struct sockaddr*)&tmp->dst, buf, sizeof(buf));
+		len += sprintf(buffer + len, "%s ", buf);
+		len += sprintf(buffer + len, "%u %u ", tmp->proto, tmp->ipsec_proto );
+
+		if (tmp->ipsec_proto == SADB_X_SATYPE_COMP) {
+			len += sprintf(buffer + len, "0x%x ", ntohl(tmp->spi)); 
+		} else {
+			len += sprintf(buffer + len, "0x%x ", ntohl(tmp->spi)); 
+		}
+		len += sprintf(buffer + len, "%d ", tmp->auth_algo.algo);
+		len += sprintf(buffer + len, "%d\n", tmp->esp_algo.algo);
+
+		if (tmp->auth_algo.algo == SADB_AALG_MD5HMAC || 
+		    tmp->auth_algo.algo == SADB_AALG_SHA1HMAC) {
+			int i;
+			memset(buf, 0, sizeof(buf));
+			for (i=0; i<tmp->auth_algo.key_len; i++)
+				sprintf(&buf[i*2], "%02x", tmp->auth_algo.key[i]);
+			len += sprintf(buffer + len, "%s\n", buf);
+		} else {
+			len += sprintf(buffer + len, "0\n");
+		}
+
+		if (tmp->esp_algo.algo == SADB_EALG_DESCBC || 
+		    tmp->esp_algo.algo == SADB_EALG_3DESCBC || 
+		    tmp->esp_algo.algo == SADB_EALG_AES) {
+			int i;
+			memset(buf, 0, sizeof(buf));
+			for (i=0; i<tmp->esp_algo.key_len; i++)
+				sprintf(&buf[i*2], "%02x", tmp->esp_algo.key[i]);
+			len += sprintf(buffer + len, "%s\n", buf);
+		} else {
+			len += sprintf(buffer + len, "0\n");
+		}
+
+		len += sprintf(buffer + len, "%u %u %u %u ", tmp->lifetime_s.allocations,
+							    (u32)tmp->lifetime_s.bytes,
+							    (u32)(tmp->lifetime_s.addtime),
+							    (u32)(tmp->lifetime_s.usetime));
+		len += sprintf(buffer + len, "%u %u %u %u ", tmp->lifetime_h.allocations,
+							    (u32)tmp->lifetime_h.bytes,
+							    (u32)(tmp->lifetime_h.addtime),
+							    (u32)(tmp->lifetime_h.usetime));
+		len += sprintf(buffer + len, "%u %u %u %u ", tmp->lifetime_c.allocations,
+							    (u32)tmp->lifetime_c.bytes,
+							    (u32)(tmp->lifetime_c.addtime),
+							    (u32)(tmp->lifetime_c.usetime));
+
+		len += sprintf(buffer + len, "%u ", tmp->state);
+		len += sprintf(buffer + len, "%u\n", atomic_read(&tmp->refcnt) );
+		len += sprintf(buffer + len, "\n");
+
+		read_unlock_bh(&tmp->lock);
+
+		pos=begin+len;
+		if (pos<offset) {
+			len=0;
+			begin=pos;
+		}
+		if (pos>offset+length) {
+			goto done;
+		}
+	}	
+done:
+	read_unlock_bh(&sadb_lock);
+
+        *start=buffer+(offset-begin);
+        len-=(offset-begin);
+        if (len>length)
+                len=length;
+        if (len<0)
+                len=0;
+        return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+int sadb_init(void)
+{
+	int error = 0;
+
+#ifdef CONFIG_PROC_FS
+	proc_net_create("sadb", 0400, sadb_get_info);
+#endif /* CONFIG_PROC_FS */
+
+	pr_info("IPsec Security Association Database (SADB): initialized.\n");
+	return error;
+}
+
+int sadb_cleanup(void)
+{
+	int error = 0;
+
+	INIT_LIST_HEAD(&sadb_list);
+#ifdef CONFIG_PROC_FS
+	proc_net_remove("sadb");
+#endif /* CONFIG_PROC_FS */
+
+	sadb_clear_db();
+
+	pr_info("IPsec SADB: cleaned up\n");
+	return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/sockaddr_utils.c linux25.43-ipsec/net/key/sockaddr_utils.c
--- linux-2.5.43/net/key/sockaddr_utils.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/sockaddr_utils.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,197 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org>
+ *   Mitsuru KANDA <mk@linux-ipv6.org>
+ */
+/*
+ * sadb_utils.c include utility functions for SADB handling.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <net/ipv6.h>
+#include <linux/inet.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <net/sadb.h>
+
+#define BUFSIZE 64
+
+/* XXX: should move these 3 functions to net/ipv6/utils.c */
+static char* 
+in6_ntop(const struct in6_addr *in6, char *buf) { 
+	if (!buf) 
+		return NULL;
+	sprintf(buf,
+		"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+		ntohs(in6->s6_addr16[0]), ntohs(in6->s6_addr16[1]),
+		ntohs(in6->s6_addr16[2]), ntohs(in6->s6_addr16[3]),
+		ntohs(in6->s6_addr16[4]), ntohs(in6->s6_addr16[5]),
+		ntohs(in6->s6_addr16[6]), ntohs(in6->s6_addr16[7]));
+	return buf;
+}
+
+static inline int 
+u32_prefix_cmp(const void *__a1, const void *__a2, int plen)
+{
+	const u32 *a1 = __a1;
+	const u32 *a2 = __a2;
+	int w, b;
+
+	if (plen <= 0)
+		return 0;
+
+	w = plen >> 5;          /* num of whole u32 in prefix */
+	b = plen & 0x1f;        /* num of bits in incomplete u32 in prefix */
+
+	if (w) {
+		if (memcmp(a1, a2, w << 2))
+		return !0;
+	}
+	if (b) {
+		u32 mask = htonl(~0 << (32 - b));
+		return (a1[w] ^ a2[w]) & mask;
+	}
+	return 0;
+}
+
+static inline int 
+ipv6_prefix_cmp(const struct in6_addr *a1, const struct in6_addr *a2, int plen)
+{
+	if (plen > 128)
+		plen = 128;
+	return u32_prefix_cmp(a1->s6_addr, a2->s6_addr, plen);
+}
+
+int
+sockaddrtoa(struct sockaddr *addr, char *buf, size_t buflen)
+{
+	int ret = 0;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		sprintf(buf, "%d.%d.%d.%d", NIPQUAD((((struct sockaddr_in *)addr)->sin_addr)));
+		break;
+	case AF_INET6:
+		in6_ntop(&(((struct sockaddr_in6*)addr)->sin6_addr), buf);
+		break;
+	default:
+		ret = -EAFNOSUPPORT;
+		break;
+	}
+
+	return ret;
+}
+
+int
+sockporttoa(struct sockaddr *addr, char *buf, size_t buflen)
+{
+	int ret = 0;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		sprintf(buf, "%hd", ntohs(((struct sockaddr_in *)addr)->sin_port));
+		break;
+	case AF_INET6:
+		sprintf(buf, "%hd", ntohs(((struct sockaddr_in6*)addr)->sin6_port));
+		break;
+	default:
+		printk(KERN_WARNING "sockporttoa: unrecognized socket family: %d\n", addr->sa_family);
+		ret = -EAFNOSUPPORT;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * addr1, prefixlen1 : packet(must set 128 or 32 befor call this) 
+ * addr2, prefixlen2 : sa/sp
+ */
+int
+sockaddr_prefix_compare(struct sockaddr *addr1, __u8 prefixlen1,
+			struct sockaddr *addr2, __u8 prefixlen2)
+{
+	__u8 prefixlen;
+
+	if (!addr1 || !addr2) {
+		SADB_DEBUG("addr1 or add2 is NULL\n");
+		return -EINVAL;
+	}
+
+	if (addr1->sa_family != addr2->sa_family) {
+		SADB_DEBUG("sa_family not match\n");
+		return 1;
+	}
+
+	if (prefixlen1 < prefixlen2) 
+		prefixlen = prefixlen1;
+	else
+		prefixlen = prefixlen2;
+	SADB_DEBUG("prefixlen: %d, prefixlen1: %d, prefixlen2: %d\n", prefixlen, prefixlen1, prefixlen2);
+
+	switch (addr1->sa_family) {
+	case AF_INET:
+		if (prefixlen > 32 )
+			return 1;
+		return (((struct sockaddr_in *)addr1)->sin_addr.s_addr ^
+			  ((struct sockaddr_in *)addr2)->sin_addr.s_addr) &
+			 htonl((0xffffffff << (32 - prefixlen)));
+	case AF_INET6:
+		if (prefixlen > 128)
+			return 1;
+
+		return ipv6_prefix_cmp(&((struct sockaddr_in6 *)addr1)->sin6_addr,
+				       &((struct sockaddr_in6 *)addr2)->sin6_addr,
+				       prefixlen);
+	default:
+		SADB_DEBUG("unknown sa_family\n");
+		return 1;
+	}
+}
+
+int 
+sockaddr_compare_ports(struct sockaddr *addr1, struct sockaddr *addr2)
+ {
+	if (addr1->sa_family != addr2->sa_family)
+		return -EINVAL;
+
+	switch (addr1->sa_family) {
+	case AF_INET:
+		if (((struct sockaddr_in *)addr1)->sin_port && ((struct sockaddr_in *)addr2)->sin_port)
+			return !( ((struct sockaddr_in *)addr1)->sin_port == ((struct sockaddr_in *)addr2)->sin_port);
+		break;
+	case AF_INET6:
+		if (((struct sockaddr_in6 *)addr1)->sin6_port && ((struct sockaddr_in6 *)addr2)->sin6_port)
+			return !( ((struct sockaddr_in6 *)addr1)->sin6_port == ((struct sockaddr_in6 *)addr2)->sin6_port);
+		break;
+	default:
+		SADB_DEBUG("%s:%d: compare_ports_if_set: unsupported address family: %d\n", 
+			  __FILE__, __LINE__, addr1->sa_family);
+		return -EINVAL;
+		break;
+	}
+
+	return 0; /* should never reach here */
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/sockaddr_utils.h linux25.43-ipsec/net/key/sockaddr_utils.h
--- linux-2.5.43/net/key/sockaddr_utils.h	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/sockaddr_utils.h	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,41 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __SOCKADDR_UTILS_H
+#define __SOCKADDR_UTILS_H
+
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/errno.h>
+
+#include <net/sadb.h>
+#include <net/spd.h>
+
+/* Function addrtoa converts sockaddr to ascii */
+/* It returns the length, if it scceed. Otherwise it return 0.*/
+int sockaddrtoa(struct sockaddr *addr, char *buf, size_t buflen);
+/* Function sockporttoa converts port numbers to ascii */
+/* Returns 0 if successful, -EINVAL on error */
+int sockporttoa(struct sockaddr *addr, char *buf, size_t buflen);
+
+int sockaddr_prefix_compare(struct sockaddr *addr1, __u8 plen1,
+			    struct sockaddr *addr2, __u8 plen2);
+int sockaddr_compare_ports(struct sockaddr *addr1, struct sockaddr *addr2);
+#endif /* __SOCKADDR_UTILS_H */
diff -uNr -x CVS linux-2.5.43/net/key/spd.c linux25.43-ipsec/net/key/spd.c
--- linux-2.5.43/net/key/spd.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/spd.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,487 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ * 
+ * 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.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Kazunori MIYAZAWA <miyazawa@linux-ip.org> / USAGI
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI
+ *
+ * Acknowledgements:
+ *   Joy Latten <latten@austin.ibm.com>
+ */
+/*
+ * spd.c provide manipulatoin routines for IPsec SPD.
+ * struct ipsec_sp represent a policy in IPsec SPD.
+ * struct ipsec_sp refers IPsec SA by struct sa_index.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/ipsec.h>
+#include <linux/pfkeyv2.h>
+#include <net/spd.h>
+#include <net/sadb.h>
+#include "sockaddr_utils.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+#define BUFSIZE 64
+
+/* spd_list : IPsec Security Policy Database(SPD)
+ * spd_lock : lock for SPD
+ */
+LIST_HEAD(spd_list);
+rwlock_t spd_lock = RW_LOCK_UNLOCKED;
+
+
+static int ipsec_selector_compare(struct selector *selector1, struct selector *selector2)
+{
+	int tmp;
+
+	if (!(selector1&&selector2)) {
+		SPD_DEBUG("selector1 or selecotr2 is NULL\n");
+		return -EINVAL;
+	}
+
+	if (selector1->proto && selector2->proto) {
+		if (selector1->proto != selector2->proto) 
+			return -EINVAL;
+	}
+
+#ifdef CONFIG_IPSEC_TUNNEL
+	tmp = !(selector1->mode == selector2->mode);
+	if (tmp)
+		return (tmp);
+#endif
+
+	tmp = sockaddr_prefix_compare((struct sockaddr*)&selector1->src, selector1->prefixlen_s,
+				      (struct sockaddr*)&selector2->src, selector2->prefixlen_s) ||
+	      sockaddr_prefix_compare((struct sockaddr*)&selector1->dst, selector1->prefixlen_d,
+				      (struct sockaddr*)&selector2->dst, selector2->prefixlen_d);
+
+	/* tmp == 0 means successful match so far */
+	if (tmp)
+		return (tmp);
+
+	/* compare ports, if they are set */
+	tmp = sockaddr_compare_ports((struct sockaddr*)&selector1->src, (struct sockaddr*)&selector2->src);
+	if (tmp)
+		return (tmp);
+	tmp = sockaddr_compare_ports((struct sockaddr*)&selector1->dst, (struct sockaddr*)&selector2->dst);
+	if (tmp)
+		return (tmp);
+
+	return 0;       /* everything matches */
+
+}
+struct ipsec_sp *ipsec_sp_kmalloc()
+{
+	struct ipsec_sp *sp = NULL;
+
+	sp = (struct ipsec_sp *)kmalloc(sizeof(struct ipsec_sp), GFP_KERNEL);
+
+	if (!sp) {
+		SPD_DEBUG("entry couldn\'t be allocated.\n");
+		return NULL;
+	}
+
+	ipsec_sp_init(sp);
+
+	return sp;
+}
+
+int ipsec_sp_init(struct ipsec_sp *policy)
+{
+	if (!policy) {
+		SPD_DEBUG("policy is NULL\n");
+		return -EINVAL;
+	}
+
+	memset(policy, 0, sizeof(struct ipsec_sp));
+	policy->auth_sa_idx = NULL;
+	policy->esp_sa_idx = NULL;
+	policy->comp_sa_idx = NULL;
+	atomic_set(&policy->refcnt,1);
+	policy->lock = RW_LOCK_UNLOCKED;
+
+	return 0;
+}
+
+void ipsec_sp_kfree(struct ipsec_sp *policy)
+{
+	if (!policy) {
+		SPD_DEBUG("entry is NULL\n");
+		return;
+	}
+
+	if (atomic_read(&policy->refcnt)) {
+		SPD_DEBUG("policy has been referenced\n");
+		return;
+	}
+
+	if (policy->auth_sa_idx) sa_index_kfree(policy->auth_sa_idx);
+	if (policy->esp_sa_idx) sa_index_kfree(policy->esp_sa_idx);
+	if (policy->comp_sa_idx) sa_index_kfree(policy->comp_sa_idx);
+
+	kfree(policy);
+}
+
+int ipsec_sp_copy(struct ipsec_sp *dst, struct ipsec_sp *src)
+{
+	int error = 0;
+
+	if (!dst || !src) {
+		SPD_DEBUG("dst or src is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	memcpy(&dst->selector, &src->selector, sizeof(struct selector));
+
+	if (dst->auth_sa_idx) sa_index_kfree(dst->auth_sa_idx);
+	if (dst->esp_sa_idx) sa_index_kfree(dst->esp_sa_idx);
+	if (dst->comp_sa_idx) sa_index_kfree(dst->comp_sa_idx);
+
+	if (src->auth_sa_idx) {
+		dst->auth_sa_idx = sa_index_kmalloc();
+		memcpy(dst->auth_sa_idx, src->auth_sa_idx, sizeof(struct sa_index));
+	}
+
+	if (src->esp_sa_idx) {
+		dst->esp_sa_idx = sa_index_kmalloc();
+		memcpy(dst->esp_sa_idx, src->esp_sa_idx, sizeof(struct sa_index));
+	}
+
+	if (src->comp_sa_idx) {
+		dst->comp_sa_idx = sa_index_kmalloc();
+		memcpy(dst->comp_sa_idx, src->comp_sa_idx, sizeof(struct sa_index));
+	}
+
+	dst->policy_action = src->policy_action;
+
+	atomic_set(&dst->refcnt, 1);
+err:
+	return error;
+}
+
+int ipsec_sp_put(struct ipsec_sp *policy)
+{
+	int error = 0;
+
+	if (!policy) {
+		SPD_DEBUG("policy is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	write_lock_bh(&policy->lock);
+	SPD_DEBUG("ptr=%p,refcnt=%d\n",
+			policy, atomic_read(&policy->refcnt));
+
+	if (atomic_dec_and_test(&policy->refcnt)) {
+
+		SPD_DEBUG("ptr=%p,refcnt=%d\n",
+			policy, atomic_read(&policy->refcnt));
+
+		write_unlock_bh(&policy->lock);
+
+		ipsec_sp_kfree(policy);
+
+		return 0;
+	}
+
+	write_unlock_bh(&policy->lock);
+
+err:
+	return error;
+}
+
+void ipsec_sp_release_invalid_sa(struct ipsec_sp *policy, struct ipsec_sa *sa)
+{
+	if (!policy) {
+		SPD_DEBUG("policy is NULL\n");
+		return;
+	}
+
+	if (policy->auth_sa_idx && policy->auth_sa_idx->sa == sa) {
+		ipsec_sa_put(policy->auth_sa_idx->sa);
+		policy->auth_sa_idx->sa = NULL;
+	}
+
+	if (policy->esp_sa_idx && policy->esp_sa_idx->sa == sa) {
+		ipsec_sa_put(policy->esp_sa_idx->sa);
+		policy->esp_sa_idx->sa = NULL;
+	}
+
+	if (policy->comp_sa_idx && policy->comp_sa_idx->sa == sa) {
+		ipsec_sa_put(policy->comp_sa_idx->sa);
+		policy->comp_sa_idx->sa = NULL;
+	}
+}
+
+int spd_append(struct ipsec_sp *policy)
+{
+	int error = 0;
+	struct ipsec_sp *new = NULL;
+
+	if (!policy) {
+		SPD_DEBUG("policy is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	new = ipsec_sp_kmalloc();
+	if (!new) {
+		SPD_DEBUG("ipsec_sp_kmalloc failed\n");
+		error = -ENOMEM;
+		goto err;
+	}
+
+	error = ipsec_sp_init(new);
+	if (error) {
+		SPD_DEBUG("ipsec_sp_init failed\n");
+		goto err;
+	}
+
+	error = ipsec_sp_copy(new, policy);
+	if (error) {
+		SPD_DEBUG("ipsec_sp_copy failed\n");
+		goto err;
+	}
+
+	write_lock_bh(&spd_lock);
+	list_add_tail(&new->entry, &spd_list);
+	write_unlock_bh(&spd_lock);
+err:
+	return error;
+}
+
+int spd_remove(struct selector *selector)
+{
+	int error = -ESRCH;
+	struct list_head *pos = NULL;
+	struct list_head *next = NULL;
+	struct ipsec_sp *tmp_sp = NULL;
+
+	if (!selector) {
+		SPD_DEBUG("selector is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+
+	write_lock_bh(&spd_lock);
+	list_for_each_safe(pos, next, &spd_list){
+		tmp_sp = list_entry(pos, struct ipsec_sp, entry);
+		write_lock_bh(&tmp_sp->lock);
+		if (!ipsec_selector_compare(selector, &tmp_sp->selector)) {
+			SPD_DEBUG("found matched element\n");
+			error = 0;
+			list_del(&tmp_sp->entry);
+			write_unlock_bh(&tmp_sp->lock);
+			ipsec_sp_put(tmp_sp);
+			break;
+		}
+		write_unlock_bh(&tmp_sp->lock);
+	}
+	write_unlock_bh(&spd_lock);
+
+err:
+	SPD_DEBUG("error = %d\n", error);
+	return error;
+}
+
+
+int spd_find_by_selector(struct selector *selector, struct ipsec_sp **policy)
+{
+	int error = -ESRCH;
+	struct list_head *pos = NULL;
+	struct ipsec_sp *tmp_sp = NULL;
+
+	if (!selector) {
+		SPD_DEBUG("selector is NULL\n");
+		error = -EINVAL;
+		goto err;
+	}
+	
+	read_lock(&spd_lock);
+	list_for_each(pos, &spd_list){
+		tmp_sp = list_entry(pos, struct ipsec_sp, entry);
+		read_lock_bh(&tmp_sp->lock);
+		if (!ipsec_selector_compare(selector, &tmp_sp->selector)) {
+			SPD_DEBUG("found matched element\n");
+			error = -EEXIST;
+			*policy = tmp_sp;
+			atomic_inc(&(*policy)->refcnt);
+			read_unlock_bh(&tmp_sp->lock);
+			break;
+		}
+		read_unlock_bh(&tmp_sp->lock);
+	}
+	read_unlock(&spd_lock);
+	
+
+err:
+	return error;
+}
+
+void spd_clear_db()
+{
+	struct list_head *pos;
+	struct list_head *next;
+	struct ipsec_sp *policy;
+
+	write_lock_bh(&spd_lock);
+	list_for_each_safe(pos, next, &spd_list){
+		policy = list_entry(pos, struct ipsec_sp, entry);
+		list_del(&policy->entry);
+		ipsec_sp_kfree(policy);		
+	}
+	write_unlock_bh(&spd_lock);
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int spd_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	int error = 0;
+	int count = 0;
+	int len = 0;
+        off_t pos=0;
+        off_t begin=0;
+        char buf[BUFSIZE]; 
+        struct list_head *list_pos = NULL;
+        struct ipsec_sp *tmp_sp = NULL;
+	
+        read_lock_bh(&spd_lock);
+        list_for_each(list_pos, &spd_list){
+		count = 0;
+                tmp_sp = list_entry(list_pos, struct ipsec_sp, entry);
+		read_lock_bh(&tmp_sp->lock);
+
+		len += sprintf(buffer + len, "spd:%p\n", tmp_sp);
+                memset(buf, 0, BUFSIZE);
+                sockaddrtoa((struct sockaddr*)&tmp_sp->selector.src, buf, BUFSIZE);
+                len += sprintf(buffer + len, "%s/%u ", buf, tmp_sp->selector.prefixlen_s);
+		sockporttoa((struct sockaddr *)&tmp_sp->selector.src, buf, BUFSIZE);
+		len += sprintf(buffer + len, "%s ", buf);
+                memset(buf, 0, BUFSIZE);
+                sockaddrtoa((struct sockaddr*)&tmp_sp->selector.dst, buf, BUFSIZE);
+                len += sprintf(buffer + len, "%s/%u ", buf, tmp_sp->selector.prefixlen_d);
+		sockporttoa((struct sockaddr *)&tmp_sp->selector.dst, buf, BUFSIZE);
+		len += sprintf(buffer + len, "%s ", buf);
+		len += sprintf(buffer + len, "%u ", tmp_sp->selector.proto);
+#ifdef CONFIG_IPSEC_TUNNEL
+		len += sprintf(buffer + len, "%u ", tmp_sp->selector.mode);
+#endif
+		len += sprintf(buffer + len, "%u\n", tmp_sp->policy_action);
+
+		if (tmp_sp->auth_sa_idx) {
+			len += sprintf(buffer + len, "sa(ah):%p ", tmp_sp->auth_sa_idx->sa);
+			sockaddrtoa((struct sockaddr*)&tmp_sp->auth_sa_idx->dst, buf, BUFSIZE);
+			len += sprintf(buffer + len, "%s/%d ", buf, tmp_sp->auth_sa_idx->prefixlen_d);
+			len += sprintf(buffer + len, "%u ",  tmp_sp->auth_sa_idx->ipsec_proto);
+			len += sprintf(buffer + len, "0x%x\n", htonl(tmp_sp->auth_sa_idx->spi));
+		}
+
+		if (tmp_sp->esp_sa_idx) {
+			len += sprintf(buffer + len, "sa(esp):%p ", tmp_sp->esp_sa_idx->sa);
+			sockaddrtoa((struct sockaddr*)&tmp_sp->esp_sa_idx->dst, buf, BUFSIZE);
+			len += sprintf(buffer + len, "%s/%d ", buf, tmp_sp->esp_sa_idx->prefixlen_d);
+			len += sprintf(buffer + len, "%u ",  tmp_sp->esp_sa_idx->ipsec_proto);
+			len += sprintf(buffer + len, "0x%x\n", htonl(tmp_sp->esp_sa_idx->spi));
+		}
+
+		if (tmp_sp->comp_sa_idx) {
+			len += sprintf(buffer + len, "sa(comp):%p ", tmp_sp->comp_sa_idx->sa);
+			sockaddrtoa((struct sockaddr*)&tmp_sp->comp_sa_idx->dst, buf, BUFSIZE);
+			len += sprintf(buffer + len, "%s/%d ", buf, tmp_sp->comp_sa_idx->prefixlen_d);
+			len += sprintf(buffer + len, "%u ",  tmp_sp->comp_sa_idx->ipsec_proto);
+			len += sprintf(buffer + len, "0x%x\n", htonl(tmp_sp->comp_sa_idx->spi));
+		}
+
+		read_unlock_bh(&tmp_sp->lock);
+		len += sprintf(buffer + len, "\n");
+
+                pos=begin+len;
+                if (pos<offset) {
+                        len=0;
+                        begin=pos;
+                }
+                if (pos>offset+length) {
+                        read_unlock_bh(&spd_lock);
+                        goto done;
+                }
+        }       
+        read_unlock_bh(&spd_lock);
+done:
+
+        *start=buffer+(offset-begin);
+        len-=(offset-begin);
+        if (len>length)
+                len=length;
+        if (len<0)
+                len=0;
+        return len;
+
+	goto err;
+err:
+	return error;
+}
+#endif /* CONFIG_PROC_FS */
+
+int spd_init(void)
+{
+        int error = 0;
+
+	INIT_LIST_HEAD(&spd_list);
+	SPD_DEBUG("spd_list.prev=%p\n", spd_list.prev);
+	SPD_DEBUG("spd_list.next=%p\n", spd_list.next);
+#ifdef CONFIG_PROC_FS
+        proc_net_create("spd", 0, spd_get_info);
+#endif /* CONFIG_PROC_FS */
+
+	pr_info("IPsec Security Policy Database (SPD): initialized.\n");
+        return error;
+}
+
+int spd_cleanup(void)
+{
+        int error = 0;
+
+#ifdef CONFIG_PROC_FS
+        proc_net_remove("spd");
+#endif /* CONFIG_PROC_FS */
+
+        spd_clear_db();
+
+	pr_info("IPsec SPD: cleaned up.\n");
+        return error;
+}
+
diff -uNr -x CVS linux-2.5.43/net/key/sysctl_net_ipsec.c linux25.43-ipsec/net/key/sysctl_net_ipsec.c
--- linux-2.5.43/net/key/sysctl_net_ipsec.c	1970-01-01 09:00:00.000000000 +0900
+++ linux25.43-ipsec/net/key/sysctl_net_ipsec.c	2002-10-16 15:43:38.000000000 +0900
@@ -0,0 +1,67 @@
+/* $USAGI: linux25-IPSEC_2_5_43.patch,v 1.1 2002/10/16 09:45:23 mk Exp $ */
+/*
+ * Copyright (C)2001 USAGI/WIDE Project
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Mitsuru KANDA <mk@linux-ipv6.org> / USAGI 
+ *   Kazunori MIYAZAWA <miyazawa@linux-ipv6.org> / USAGI
+ */
+
+#include <linux/config.h>
+#include <linux/sysctl.h>
+
+/* extern */ int sysctl_ipsec_replay_window = 1;
+/* extern */ int sysctl_ipsec_debug_ipv4 = 0;
+/* extern */ int sysctl_ipsec_debug_ipv6 = 0;
+/* extern */ int sysctl_ipsec_debug_pfkey= 0;
+/* extern */ int sysctl_ipsec_debug_sadb = 0;
+/* extern */ int sysctl_ipsec_debug_spd = 0;
+
+ctl_table ipsec_table[] = {
+	{NET_IPSEC_REPLAY_WINDOW, "replay_window_check", &sysctl_ipsec_replay_window, sizeof(int), 0600, NULL, proc_dointvec},
+#ifdef CONFIG_IPSEC_DEBUG
+	{NET_IPSEC_DEBUG_IPV4, "debug_ipv4", &sysctl_ipsec_debug_ipv4, sizeof(int), 0600, NULL, proc_dointvec},
+	{NET_IPSEC_DEBUG_IPV6, "debug_ipv6", &sysctl_ipsec_debug_ipv6, sizeof(int), 0600, NULL, proc_dointvec},
+	{NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &sysctl_ipsec_debug_pfkey, sizeof(int), 0600, NULL, proc_dointvec},
+	{NET_IPSEC_DEBUG_SADB, "debug_sadb", &sysctl_ipsec_debug_sadb, sizeof(int), 0600, NULL, proc_dointvec},
+	{NET_IPSEC_DEBUG_SPD, "debug_spd", &sysctl_ipsec_debug_spd, sizeof(int), 0600, NULL, proc_dointvec},
+#endif /* CONFIG_IPSEC_DEBUG */
+	{0},
+};
+
+static ctl_table ipsec_net_table[] = {
+	{NET_IPSEC, "ipsec", NULL, 0, 0555, ipsec_table},
+	{0}
+};
+
+static ctl_table ipsec_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ipsec_net_table},
+	{0}
+};
+
+static struct ctl_table_header *ipsec_sysctl_header;
+
+void ipsec_sysctl_register(void)
+{
+	ipsec_sysctl_header = register_sysctl_table(ipsec_root_table, 0);
+}
+
+void ipsec_sysctl_unregister(void)
+{
+	unregister_sysctl_table(ipsec_sysctl_header);
+}
+
diff -uNr -x CVS linux-2.5.43/net/netsyms.c linux25.43-ipsec/net/netsyms.c
--- linux-2.5.43/net/netsyms.c	2002-10-16 12:27:54.000000000 +0900
+++ linux25.43-ipsec/net/netsyms.c	2002-10-16 15:27:47.000000000 +0900
@@ -72,6 +72,12 @@
 
 #endif
 
+#ifdef CONFIG_IPSEC
+#include <net/sadb.h>
+#include <net/spd.h>
+#include <linux/ipsec.h>
+#endif 
+
 extern int netdev_finish_unregister(struct net_device *dev);
 
 #include <linux/rtnetlink.h>
@@ -287,6 +293,26 @@
 EXPORT_SYMBOL(dlci_ioctl_hook);
 #endif
 
+#ifdef CONFIG_IPSEC
+/* sa_index */
+EXPORT_SYMBOL(sa_index_init);
+EXPORT_SYMBOL(sa_index_copy);
+EXPORT_SYMBOL(sa_index_compare);
+/* sadb */
+EXPORT_SYMBOL(ipsec_sa_put);
+EXPORT_SYMBOL(sadb_find_by_sa_index);
+EXPORT_SYMBOL(ipsec_sa_mod_timer);
+/* spd */
+EXPORT_SYMBOL(ipsec_sp_put);
+EXPORT_SYMBOL(spd_find_by_selector);
+/* sysctl */
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(sysctl_ipsec_replay_window);
+#ifdef CONFIG_IPSEC_DEBUG
+EXPORT_SYMBOL(sysctl_ipsec_debug_ipv6);
+#endif 
+#endif
+#endif
 
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE)
 /* inet functions common to v4 and v6 */
diff -uNr -x CVS linux-2.5.43/net/socket.c linux25.43-ipsec/net/socket.c
--- linux-2.5.43/net/socket.c	2002-10-16 12:27:51.000000000 +0900
+++ linux25.43-ipsec/net/socket.c	2002-10-16 15:27:47.000000000 +0900
@@ -1721,6 +1721,10 @@
 extern void wanrouter_init(void);
 #endif
 
+#ifdef CONFIG_IPSEC
+extern void pfkey_init(void);
+#endif
+
 void __init sock_init(void)
 {
 	int i;
@@ -1781,6 +1785,10 @@
 #ifdef CONFIG_NETFILTER
 	netfilter_init();
 #endif
+
+#ifdef CONFIG_IPSEC
+	pfkey_init();
+#endif
 }
 
 int socket_get_info(char *buffer, char **start, off_t offset, int length)
